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

View File

@ -6,6 +6,7 @@
#include <vector>
#include <cmath>
#include <nodemesh/misc.h>
#include <nodemesh/positionkey.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel;
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> *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) {
std::vector<typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> faceVertexIndices;
bool faceValid = true;
std::vector<nodemesh::PositionKey> positionKeys;
std::vector<QVector3D> positionsInKeys;
std::set<nodemesh::PositionKey> existedKeys;
for (const auto &index: face) {
const auto &pos = positions[index];
if (!nodemesh::validatePosition(pos)) {
const auto &position = positions[index];
if (!nodemesh::validatePosition(position)) {
faceValid = false;
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)
continue;
for (const auto &index: face) {
auto findIndex = vertexIndices.find(index);
if (positionKeys.size() < 3)
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()) {
faceVertexIndices.push_back(findIndex->second);
} else {
const auto &pos = positions[index];
auto newIndex = mesh->add_vertex(typename Kernel::Point_3(pos.x(), pos.y(), pos.z()));
vertexIndices.insert({index, newIndex});
auto newIndex = mesh->add_vertex(typename Kernel::Point_3(position.x(), position.y(), position.z()));
vertexIndices.insert({positionKey, 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;
if (!faces.empty()) {
std::vector<QVector3D> triangleVertices = vertices;
std::vector<std::vector<size_t>> triangles;
if (nodemesh::triangulate(triangleVertices, faces, triangles)) {
cgalMesh = buildCgalMesh<CgalKernel>(triangleVertices, triangles);
cgalMesh = buildCgalMesh<CgalKernel>(vertices, faces);
if (!CGAL::is_valid_polygon_mesh(*cgalMesh)) {
qDebug() << "Mesh is not valid polygon";
delete cgalMesh;
cgalMesh = nullptr;
} else {
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true;
if (removeSelfIntersects) {
if (!CGAL::Polygon_mesh_processing::remove_self_intersections(*cgalMesh)) {
qDebug() << "Mesh remove_self_intersections failed";
delete cgalMesh;
cgalMesh = nullptr;
}
} else {
qDebug() << "Mesh does_self_intersect";
delete cgalMesh;
cgalMesh = nullptr;
}
}
} else {
qDebug() << "Mesh triangulate failed";
delete cgalMesh;
cgalMesh = nullptr;
}
}
}