Fix base normal

master
Jeremy Hu 2019-03-09 23:30:19 +09:30
parent 4ac83a9626
commit 69b371adb9
3 changed files with 60 additions and 26 deletions

View File

@ -283,7 +283,7 @@ bool Builder::validateNormal(const QVector3D &normal)
if (normal.isNull()) { if (normal.isNull()) {
return false; return false;
} }
if (std::isnan(normal.x()) || std::isnan(normal.y()) || std::isnan(normal.z())) { if (!validatePosition(normal)) {
return false; return false;
} }
return true; return true;
@ -293,6 +293,13 @@ std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVecto
const std::vector<QVector3D> &positions, const std::vector<QVector3D> &positions,
const std::vector<float> &weights) const std::vector<float> &weights)
{ {
auto calculateTwoPointsNormal = [&](size_t i0, size_t i1) -> std::pair<QVector3D, bool> {
auto normal = QVector3D::crossProduct(directs[i0], directs[i1]).normalized();
if (validateNormal(normal)) {
return {normal, true};
}
return {{}, false};
};
auto calculateThreePointsNormal = [&](size_t i0, size_t i1, size_t i2) -> std::pair<QVector3D, bool> { auto calculateThreePointsNormal = [&](size_t i0, size_t i1, size_t i2) -> std::pair<QVector3D, bool> {
auto normal = QVector3D::normal(positions[i0], positions[i1], positions[i2]); auto normal = QVector3D::normal(positions[i0], positions[i1], positions[i2]);
if (validateNormal(normal)) { if (validateNormal(normal)) {
@ -300,14 +307,21 @@ std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVecto
} }
// >=15 degrees && <= 165 degrees // >=15 degrees && <= 165 degrees
if (abs(QVector3D::dotProduct(directs[i0], directs[i1])) < 0.966) { if (abs(QVector3D::dotProduct(directs[i0], directs[i1])) < 0.966) {
return {QVector3D::crossProduct(directs[i0], directs[i1]).normalized(), true}; auto twoPointsResult = calculateTwoPointsNormal(i0, i1);
} else if (abs(QVector3D::dotProduct(directs[i1], directs[i2])) < 0.966) { if (twoPointsResult.second)
return {QVector3D::crossProduct(directs[i1], directs[i2]).normalized(), true}; return twoPointsResult;
} else if (abs(QVector3D::dotProduct(directs[i2], directs[i0])) < 0.966) {
return {QVector3D::crossProduct(directs[i2], directs[i0]).normalized(), true};
} else {
return {{}, false};
} }
if (abs(QVector3D::dotProduct(directs[i1], directs[i2])) < 0.966) {
auto twoPointsResult = calculateTwoPointsNormal(i1, i2);
if (twoPointsResult.second)
return twoPointsResult;
}
if (abs(QVector3D::dotProduct(directs[i2], directs[i0])) < 0.966) {
auto twoPointsResult = calculateTwoPointsNormal(i2, i0);
if (twoPointsResult.second)
return twoPointsResult;
}
return {{}, false};
}; };
if (directs.size() <= 1) { if (directs.size() <= 1) {
@ -315,7 +329,9 @@ std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVecto
} else if (directs.size() <= 2) { } else if (directs.size() <= 2) {
// >=15 degrees && <= 165 degrees // >=15 degrees && <= 165 degrees
if (abs(QVector3D::dotProduct(directs[0], directs[1])) < 0.966) { if (abs(QVector3D::dotProduct(directs[0], directs[1])) < 0.966) {
return {QVector3D::crossProduct(directs[0], directs[1]).normalized(), true}; auto twoPointsResult = calculateTwoPointsNormal(0, 1);
if (twoPointsResult.second)
return twoPointsResult;
} }
return {{}, false}; return {{}, false};
} else if (directs.size() <= 3) { } else if (directs.size() <= 3) {

View File

@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include <cmath> #include <cmath>
#include <nodemesh/misc.h> #include <nodemesh/misc.h>
#include <nodemesh/positionkey.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel;
typedef CGAL::Surface_mesh<CgalKernel::Point_3> CgalMesh; typedef CGAL::Surface_mesh<CgalKernel::Point_3> CgalMesh;
@ -14,27 +15,40 @@ template <class Kernel>
typename CGAL::Surface_mesh<typename Kernel::Point_3> *buildCgalMesh(const std::vector<QVector3D> &positions, const std::vector<std::vector<size_t>> &indices) typename CGAL::Surface_mesh<typename Kernel::Point_3> *buildCgalMesh(const std::vector<QVector3D> &positions, const std::vector<std::vector<size_t>> &indices)
{ {
typename CGAL::Surface_mesh<typename Kernel::Point_3> *mesh = new typename CGAL::Surface_mesh<typename Kernel::Point_3>; typename CGAL::Surface_mesh<typename Kernel::Point_3> *mesh = new typename CGAL::Surface_mesh<typename Kernel::Point_3>;
std::map<size_t, typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> vertexIndices; std::map<nodemesh::PositionKey, typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> vertexIndices;
for (const auto &face: indices) { for (const auto &face: indices) {
std::vector<typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> faceVertexIndices; std::vector<typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> faceVertexIndices;
bool faceValid = true; bool faceValid = true;
std::vector<nodemesh::PositionKey> positionKeys;
std::vector<QVector3D> positionsInKeys;
std::set<nodemesh::PositionKey> existedKeys;
for (const auto &index: face) { for (const auto &index: face) {
const auto &pos = positions[index]; const auto &position = positions[index];
if (!nodemesh::validatePosition(pos)) { if (!nodemesh::validatePosition(position)) {
faceValid = false; faceValid = false;
break; break;
} }
auto positionKey = nodemesh::PositionKey(position);
if (existedKeys.find(positionKey) != existedKeys.end()) {
continue;
}
existedKeys.insert(positionKey);
positionKeys.push_back(positionKey);
positionsInKeys.push_back(position);
} }
if (!faceValid) if (!faceValid)
continue; continue;
for (const auto &index: face) { if (positionKeys.size() < 3)
auto findIndex = vertexIndices.find(index); continue;
for (size_t index = 0; index < positionKeys.size(); ++index) {
const auto &position = positionsInKeys[index];
const auto &positionKey = positionKeys[index];
auto findIndex = vertexIndices.find(positionKey);
if (findIndex != vertexIndices.end()) { if (findIndex != vertexIndices.end()) {
faceVertexIndices.push_back(findIndex->second); faceVertexIndices.push_back(findIndex->second);
} else { } else {
const auto &pos = positions[index]; auto newIndex = mesh->add_vertex(typename Kernel::Point_3(position.x(), position.y(), position.z()));
auto newIndex = mesh->add_vertex(typename Kernel::Point_3(pos.x(), pos.y(), pos.z())); vertexIndices.insert({positionKey, newIndex});
vertexIndices.insert({index, newIndex});
faceVertexIndices.push_back(newIndex); faceVertexIndices.push_back(newIndex);
} }
} }

View File

@ -18,27 +18,31 @@ Combiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<s
{ {
CgalMesh *cgalMesh = nullptr; CgalMesh *cgalMesh = nullptr;
if (!faces.empty()) { if (!faces.empty()) {
std::vector<QVector3D> triangleVertices = vertices; cgalMesh = buildCgalMesh<CgalKernel>(vertices, faces);
std::vector<std::vector<size_t>> triangles;
if (nodemesh::triangulate(triangleVertices, faces, triangles)) {
cgalMesh = buildCgalMesh<CgalKernel>(triangleVertices, triangles);
if (!CGAL::is_valid_polygon_mesh(*cgalMesh)) { if (!CGAL::is_valid_polygon_mesh(*cgalMesh)) {
qDebug() << "Mesh is not valid polygon"; qDebug() << "Mesh is not valid polygon";
delete cgalMesh; delete cgalMesh;
cgalMesh = nullptr; cgalMesh = nullptr;
} else { } else {
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) { if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true; m_isSelfIntersected = true;
if (removeSelfIntersects) { if (removeSelfIntersects) {
if (!CGAL::Polygon_mesh_processing::remove_self_intersections(*cgalMesh)) { if (!CGAL::Polygon_mesh_processing::remove_self_intersections(*cgalMesh)) {
qDebug() << "Mesh remove_self_intersections failed";
delete cgalMesh; delete cgalMesh;
cgalMesh = nullptr; cgalMesh = nullptr;
} }
} else { } else {
qDebug() << "Mesh does_self_intersect";
delete cgalMesh; delete cgalMesh;
cgalMesh = nullptr; cgalMesh = nullptr;
} }
} }
} else {
qDebug() << "Mesh triangulate failed";
delete cgalMesh;
cgalMesh = nullptr;
} }
} }
} }