diff --git a/src/Mod/MeshPart/App/Mesher.cpp b/src/Mod/MeshPart/App/Mesher.cpp
index 1cf051a96aea..e5088b914133 100644
--- a/src/Mod/MeshPart/App/Mesher.cpp
+++ b/src/Mod/MeshPart/App/Mesher.cpp
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include "Mesher.h"
@@ -123,47 +124,6 @@ int MeshingOutput::sync()
namespace MeshPart
{
-struct Vertex
-{
- static const double deflection;
- Standard_Real x, y, z;
- Standard_Integer i = 0;
- mutable MeshCore::MeshPoint p;
-
- Vertex(Standard_Real X, Standard_Real Y, Standard_Real Z)
- : x(X)
- , y(Y)
- , z(Z)
- {
- p.x = static_cast(x);
- p.y = static_cast(y);
- p.z = static_cast(z);
- }
-
- const MeshCore::MeshPoint& toPoint() const
- {
- return p;
- }
-
- bool operator<(const Vertex& v) const
- {
- if (fabs(this->x - v.x) >= deflection) {
- return this->x < v.x;
- }
- if (fabs(this->y - v.y) >= deflection) {
- return this->y < v.y;
- }
- if (fabs(this->z - v.z) >= deflection) {
- return this->z < v.z;
- }
- return false; // points are considered to be equal
- }
-};
-
-const double Vertex::deflection = 10 * std::numeric_limits::epsilon();
-
-// ----------------------------------------------------------------------------
-
class BrepMesh
{
bool segments;
@@ -177,111 +137,52 @@ class BrepMesh
Mesh::MeshObject* create(const std::vector& domains) const
{
- std::map> colorMap;
- for (std::size_t i = 0; i < colors.size(); i++) {
- colorMap[colors[i]].push_back(i);
- }
-
- bool createSegm = (colors.size() == domains.size());
+ std::vector points;
+ std::vector facets;
+ Part::BRepMesh mesh;
+ mesh.getFacesFromDomains(domains, points, facets);
MeshCore::MeshFacetArray faces;
- std::size_t numTriangles = 0;
- for (const auto& it : domains) {
- numTriangles += it.facets.size();
+ faces.reserve(facets.size());
+ std::transform(facets.cbegin(),
+ facets.cend(),
+ std::back_inserter(faces),
+ [](const Part::TopoShape::Facet& face) {
+ return MeshCore::MeshFacet(face.I1, face.I2, face.I3);
+ });
+
+ MeshCore::MeshPointArray verts;
+ verts.reserve(points.size());
+ for (const auto& it : points) {
+ verts.emplace_back(float(it.x), float(it.y), float(it.z));
}
- faces.reserve(numTriangles);
- std::set vertices;
- Standard_Real x1, y1, z1;
- Standard_Real x2, y2, z2;
- Standard_Real x3, y3, z3;
+ MeshCore::MeshKernel kernel;
+ kernel.Adopt(verts, faces, true);
+ // mesh segments
std::vector> meshSegments;
- std::size_t numMeshFaces = 0;
-
- for (const auto& domain : domains) {
- std::size_t numDomainFaces = 0;
- for (std::size_t j = 0; j < domain.facets.size(); ++j) {
- const Part::TopoShape::Facet& tria = domain.facets[j];
- x1 = domain.points[tria.I1].x;
- y1 = domain.points[tria.I1].y;
- z1 = domain.points[tria.I1].z;
-
- x2 = domain.points[tria.I2].x;
- y2 = domain.points[tria.I2].y;
- z2 = domain.points[tria.I2].z;
-
- x3 = domain.points[tria.I3].x;
- y3 = domain.points[tria.I3].y;
- z3 = domain.points[tria.I3].z;
-
- std::set::iterator it;
- MeshCore::MeshFacet face;
-
- // 1st vertex
- Vertex v1(x1, y1, z1);
- it = vertices.find(v1);
- if (it == vertices.end()) {
- v1.i = vertices.size();
- face._aulPoints[0] = v1.i;
- vertices.insert(v1);
- }
- else {
- face._aulPoints[0] = it->i;
- }
-
- // 2nd vertex
- Vertex v2(x2, y2, z2);
- it = vertices.find(v2);
- if (it == vertices.end()) {
- v2.i = vertices.size();
- face._aulPoints[1] = v2.i;
- vertices.insert(v2);
- }
- else {
- face._aulPoints[1] = it->i;
- }
-
- // 3rd vertex
- Vertex v3(x3, y3, z3);
- it = vertices.find(v3);
- if (it == vertices.end()) {
- v3.i = vertices.size();
- face._aulPoints[2] = v3.i;
- vertices.insert(v3);
- }
- else {
- face._aulPoints[2] = it->i;
- }
-
- // make sure that we don't insert invalid facets
- if (face._aulPoints[0] != face._aulPoints[1]
- && face._aulPoints[1] != face._aulPoints[2]
- && face._aulPoints[2] != face._aulPoints[0]) {
- faces.push_back(face);
- numDomainFaces++;
- }
- }
- // add a segment for the face
- if (createSegm || this->segments) {
- std::vector segment(numDomainFaces);
- std::generate(segment.begin(),
- segment.end(),
- Base::iotaGen(numMeshFaces));
- numMeshFaces += numDomainFaces;
- meshSegments.push_back(segment);
- }
+ std::map> colorMap;
+ for (std::size_t i = 0; i < colors.size(); i++) {
+ colorMap[colors[i]].push_back(i);
}
- MeshCore::MeshPointArray verts;
- verts.resize(vertices.size());
- for (const auto& it : vertices) {
- verts[it.i] = it.toPoint();
- }
+ bool createSegm = (colors.size() == domains.size());
- MeshCore::MeshKernel kernel;
- kernel.Adopt(verts, faces, true);
+ // add a segment for the face
+ if (createSegm || this->segments) {
+ auto segments = mesh.createSegments();
+ meshSegments.reserve(segments.size());
+ std::transform(segments.cbegin(),
+ segments.cend(),
+ std::back_inserter(meshSegments),
+ [](const Part::BRepMesh::Segment& segm) {
+ std::vector faces;
+ faces.insert(faces.end(), segm.cbegin(), segm.cend());
+ return faces;
+ });
+ }
Mesh::MeshObject* meshdata = new Mesh::MeshObject();
meshdata->swap(kernel);
diff --git a/src/Mod/Part/App/BRepMesh.cpp b/src/Mod/Part/App/BRepMesh.cpp
new file mode 100644
index 000000000000..a13251186f1e
--- /dev/null
+++ b/src/Mod/Part/App/BRepMesh.cpp
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2024 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#endif
+
+#include "BRepMesh.h"
+#include
+
+using namespace Part;
+
+namespace Part {
+struct MeshVertex
+{
+ Base::Vector3d p;
+ std::size_t i;
+
+ explicit MeshVertex(const Base::Vector3d& p)
+ : p(p), i(0)
+ {
+ }
+
+ Base::Vector3d toPoint() const
+ { return p; }
+
+ bool operator < (const MeshVertex &v) const
+ {
+ if (fabs ( p.x - v.p.x) >= epsilon)
+ return p.x < v.p.x;
+ if (fabs ( p.y - v.p.y) >= epsilon)
+ return p.y < v.p.y;
+ if (fabs ( p.z - v.p.z) >= epsilon)
+ return p.z < v.p.z;
+ return false; // points are considered to be equal
+ }
+
+private:
+ static const double epsilon;
+};
+
+const double MeshVertex::epsilon = 10 * std::numeric_limits::epsilon();
+
+}
+
+void BRepMesh::getFacesFromDomains(const std::vector& domains,
+ std::vector& points,
+ std::vector& faces)
+{
+ std::size_t numFaces = 0;
+ for (const auto& it : domains) {
+ numFaces += it.facets.size();
+ }
+ faces.reserve(numFaces);
+
+ std::set vertices;
+ auto addVertex = [&vertices](const Base::Vector3d& pnt, uint32_t& pointIndex) {
+ MeshVertex vertex(pnt);
+ vertex.i = vertices.size();
+ auto it = vertices.insert(vertex);
+ pointIndex = it.first->i;
+ };
+
+ for (const auto & domain : domains) {
+ std::size_t numDomainFaces = 0;
+ for (const Facet& df : domain.facets) {
+ Facet face;
+
+ // 1st vertex
+ addVertex(domain.points[df.I1], face.I1);
+
+ // 2nd vertex
+ addVertex(domain.points[df.I2], face.I2);
+
+ // 3rd vertex
+ addVertex(domain.points[df.I3], face.I3);
+
+ // make sure that we don't insert invalid facets
+ if (face.I1 != face.I2 &&
+ face.I2 != face.I3 &&
+ face.I3 != face.I1) {
+ faces.push_back(face);
+ numDomainFaces++;
+ }
+ }
+
+ domainSizes.push_back(numDomainFaces);
+ }
+
+ std::vector meshPoints;
+ meshPoints.resize(vertices.size());
+ for (const auto & vertex : vertices) {
+ meshPoints[vertex.i] = vertex.toPoint();
+ }
+ points.swap(meshPoints);
+}
+
+std::vector BRepMesh::createSegments() const
+{
+ std::size_t numMeshFaces = 0;
+ std::vector segm;
+ for (size_t numDomainFaces : domainSizes) {
+ Segment segment(numDomainFaces);
+ std::generate(segment.begin(),
+ segment.end(),
+ Base::iotaGen(numMeshFaces));
+ numMeshFaces += numDomainFaces;
+ segm.push_back(segment);
+ }
+
+ return segm;
+}
diff --git a/src/Mod/Part/App/BRepMesh.h b/src/Mod/Part/App/BRepMesh.h
new file mode 100644
index 000000000000..e5edeaa9febd
--- /dev/null
+++ b/src/Mod/Part/App/BRepMesh.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2024 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+#ifndef PART_BREPMESH_H
+#define PART_BREPMESH_H
+
+#include
+#include
+
+namespace Part {
+
+class PartExport BRepMesh
+{
+public:
+ using Facet = Data::ComplexGeoData::Facet;
+ using Domain = Data::ComplexGeoData::Domain;
+ using Segment = std::vector;
+
+ void getFacesFromDomains(const std::vector& domains,
+ std::vector& points,
+ std::vector& faces);
+ std::vector createSegments() const;
+
+private:
+ std::vector domainSizes;
+};
+
+}
+
+#endif // PART_BREPMESH_H
diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt
index 1a85f3b6202c..ab4cd149a97f 100644
--- a/src/Mod/Part/App/CMakeLists.txt
+++ b/src/Mod/Part/App/CMakeLists.txt
@@ -500,6 +500,8 @@ SET(Part_SRCS
Attacher.h
AppPart.cpp
AppPartPy.cpp
+ BRepMesh.cpp
+ BRepMesh.h
BRepOffsetAPI_MakeOffsetFix.cpp
BRepOffsetAPI_MakeOffsetFix.h
BSplineCurveBiArcs.cpp
diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp
index 883d7b3a7783..25266bf35fa0 100644
--- a/src/Mod/Part/App/TopoShape.cpp
+++ b/src/Mod/Part/App/TopoShape.cpp
@@ -172,6 +172,7 @@
#include
#include "TopoShape.h"
+#include "BRepMesh.h"
#include "BRepOffsetAPI_MakeOffsetFix.h"
#include "CrossSection.h"
#include "encodeFilename.h"
@@ -3359,118 +3360,12 @@ void TopoShape::getDomains(std::vector& domains) const
}
}
-namespace Part {
-struct MeshVertex
-{
- Standard_Real x,y,z;
- Standard_Integer i;
-
- MeshVertex(Standard_Real X, Standard_Real Y, Standard_Real Z)
- : x(X),y(Y),z(Z),i(0)
- {
- }
- explicit MeshVertex(const Base::Vector3d& p)
- : x(p.x),y(p.y),z(p.z),i(0)
- {
- }
-
- Base::Vector3d toPoint() const
- { return Base::Vector3d(x,y,z); }
-
- bool operator < (const MeshVertex &v) const
- {
- if (fabs ( this->x - v.x) >= MESH_MIN_PT_DIST)
- return this->x < v.x;
- if (fabs ( this->y - v.y) >= MESH_MIN_PT_DIST)
- return this->y < v.y;
- if (fabs ( this->z - v.z) >= MESH_MIN_PT_DIST)
- return this->z < v.z;
- return false; // points are considered to be equal
- }
-
-private:
- // use the same value as used inside the Mesh module
- static const double MESH_MIN_PT_DIST;
-};
-}
-
-const double MeshVertex::MESH_MIN_PT_DIST = 10 * std::numeric_limits::epsilon();
-
void TopoShape::getFacesFromDomains(const std::vector& domains,
std::vector& points,
std::vector& faces) const
{
- std::set vertices;
- Standard_Real x1, y1, z1;
- Standard_Real x2, y2, z2;
- Standard_Real x3, y3, z3;
-
- for (const auto & domain : domains) {
- for (std::vector::const_iterator jt = domain.facets.begin(); jt != domain.facets.end(); ++jt) {
- x1 = domain.points[jt->I1].x;
- y1 = domain.points[jt->I1].y;
- z1 = domain.points[jt->I1].z;
-
- x2 = domain.points[jt->I2].x;
- y2 = domain.points[jt->I2].y;
- z2 = domain.points[jt->I2].z;
-
- x3 = domain.points[jt->I3].x;
- y3 = domain.points[jt->I3].y;
- z3 = domain.points[jt->I3].z;
-
- TopoShape::Facet face;
- std::set::iterator vIt;
-
- // 1st vertex
- MeshVertex v1(x1,y1,z1);
- vIt = vertices.find(v1);
- if (vIt == vertices.end()) {
- v1.i = vertices.size();
- face.I1 = v1.i;
- vertices.insert(v1);
- }
- else {
- face.I1 = vIt->i;
- }
-
- // 2nd vertex
- MeshVertex v2(x2,y2,z2);
- vIt = vertices.find(v2);
- if (vIt == vertices.end()) {
- v2.i = vertices.size();
- face.I2 = v2.i;
- vertices.insert(v2);
- }
- else {
- face.I2 = vIt->i;
- }
-
- // 3rd vertex
- MeshVertex v3(x3,y3,z3);
- vIt = vertices.find(v3);
- if (vIt == vertices.end()) {
- v3.i = vertices.size();
- face.I3 = v3.i;
- vertices.insert(v3);
- }
- else {
- face.I3 = vIt->i;
- }
-
- // make sure that we don't insert invalid facets
- if (face.I1 != face.I2 &&
- face.I2 != face.I3 &&
- face.I3 != face.I1)
- faces.push_back(face);
- }
- }
-
- std::vector meshPoints;
- meshPoints.resize(vertices.size());
- for (const auto & vertex : vertices)
- meshPoints[vertex.i] = vertex.toPoint();
- points.swap(meshPoints);
+ BRepMesh mesh;
+ mesh.getFacesFromDomains(domains, points, faces);
}
double TopoShape::getAccuracy() const