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