Fix base normal
parent
4ac83a9626
commit
69b371adb9
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
if (!CGAL::is_valid_polygon_mesh(*cgalMesh)) {
|
||||
qDebug() << "Mesh is not valid polygon";
|
||||
delete cgalMesh;
|
||||
cgalMesh = nullptr;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue