Part: Add class BRepMesh
This refactors the code of TopoShape::getFacesFromDomains and the the private class BrepMesh of the MeshPart module to reduce code duplication.
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Mod/Mesh/App/Mesh.h>
|
||||
#include <Mod/Part/App/BRepMesh.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#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<float>(x);
|
||||
p.y = static_cast<float>(y);
|
||||
p.z = static_cast<float>(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<double>::epsilon();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BrepMesh
|
||||
{
|
||||
bool segments;
|
||||
@@ -177,6 +137,32 @@ public:
|
||||
|
||||
Mesh::MeshObject* create(const std::vector<Part::TopoShape::Domain>& domains) const
|
||||
{
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Part::TopoShape::Facet> facets;
|
||||
Part::BRepMesh mesh;
|
||||
mesh.getFacesFromDomains(domains, points, facets);
|
||||
|
||||
MeshCore::MeshFacetArray faces;
|
||||
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));
|
||||
}
|
||||
|
||||
MeshCore::MeshKernel kernel;
|
||||
kernel.Adopt(verts, faces, true);
|
||||
|
||||
// mesh segments
|
||||
std::vector<std::vector<MeshCore::FacetIndex>> meshSegments;
|
||||
|
||||
std::map<uint32_t, std::vector<std::size_t>> colorMap;
|
||||
for (std::size_t i = 0; i < colors.size(); i++) {
|
||||
colorMap[colors[i]].push_back(i);
|
||||
@@ -184,104 +170,19 @@ public:
|
||||
|
||||
bool createSegm = (colors.size() == domains.size());
|
||||
|
||||
MeshCore::MeshFacetArray faces;
|
||||
std::size_t numTriangles = 0;
|
||||
for (const auto& it : domains) {
|
||||
numTriangles += it.facets.size();
|
||||
// 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<MeshCore::FacetIndex> faces;
|
||||
faces.insert(faces.end(), segm.cbegin(), segm.cend());
|
||||
return faces;
|
||||
});
|
||||
}
|
||||
faces.reserve(numTriangles);
|
||||
|
||||
std::set<Vertex> vertices;
|
||||
Standard_Real x1, y1, z1;
|
||||
Standard_Real x2, y2, z2;
|
||||
Standard_Real x3, y3, z3;
|
||||
|
||||
std::vector<std::vector<MeshCore::FacetIndex>> 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<Vertex>::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<MeshCore::FacetIndex> segment(numDomainFaces);
|
||||
std::generate(segment.begin(),
|
||||
segment.end(),
|
||||
Base::iotaGen<MeshCore::FacetIndex>(numMeshFaces));
|
||||
numMeshFaces += numDomainFaces;
|
||||
meshSegments.push_back(segment);
|
||||
}
|
||||
}
|
||||
|
||||
MeshCore::MeshPointArray verts;
|
||||
verts.resize(vertices.size());
|
||||
for (const auto& it : vertices) {
|
||||
verts[it.i] = it.toPoint();
|
||||
}
|
||||
|
||||
MeshCore::MeshKernel kernel;
|
||||
kernel.Adopt(verts, faces, true);
|
||||
|
||||
Mesh::MeshObject* meshdata = new Mesh::MeshObject();
|
||||
meshdata->swap(kernel);
|
||||
|
||||
134
src/Mod/Part/App/BRepMesh.cpp
Normal file
134
src/Mod/Part/App/BRepMesh.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "BRepMesh.h"
|
||||
#include <Base/Tools.h>
|
||||
|
||||
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<double>::epsilon();
|
||||
|
||||
}
|
||||
|
||||
void BRepMesh::getFacesFromDomains(const std::vector<Domain>& domains,
|
||||
std::vector<Base::Vector3d>& points,
|
||||
std::vector<Facet>& faces)
|
||||
{
|
||||
std::size_t numFaces = 0;
|
||||
for (const auto& it : domains) {
|
||||
numFaces += it.facets.size();
|
||||
}
|
||||
faces.reserve(numFaces);
|
||||
|
||||
std::set<MeshVertex> 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<Base::Vector3d> meshPoints;
|
||||
meshPoints.resize(vertices.size());
|
||||
for (const auto & vertex : vertices) {
|
||||
meshPoints[vertex.i] = vertex.toPoint();
|
||||
}
|
||||
points.swap(meshPoints);
|
||||
}
|
||||
|
||||
std::vector<BRepMesh::Segment> BRepMesh::createSegments() const
|
||||
{
|
||||
std::size_t numMeshFaces = 0;
|
||||
std::vector<Segment> segm;
|
||||
for (size_t numDomainFaces : domainSizes) {
|
||||
Segment segment(numDomainFaces);
|
||||
std::generate(segment.begin(),
|
||||
segment.end(),
|
||||
Base::iotaGen<std::size_t>(numMeshFaces));
|
||||
numMeshFaces += numDomainFaces;
|
||||
segm.push_back(segment);
|
||||
}
|
||||
|
||||
return segm;
|
||||
}
|
||||
50
src/Mod/Part/App/BRepMesh.h
Normal file
50
src/Mod/Part/App/BRepMesh.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef PART_BREPMESH_H
|
||||
#define PART_BREPMESH_H
|
||||
|
||||
#include <Mod/Part/PartGlobal.h>
|
||||
#include <App/ComplexGeoData.h>
|
||||
|
||||
namespace Part {
|
||||
|
||||
class PartExport BRepMesh
|
||||
{
|
||||
public:
|
||||
using Facet = Data::ComplexGeoData::Facet;
|
||||
using Domain = Data::ComplexGeoData::Domain;
|
||||
using Segment = std::vector<std::size_t>;
|
||||
|
||||
void getFacesFromDomains(const std::vector<Domain>& domains,
|
||||
std::vector<Base::Vector3d>& points,
|
||||
std::vector<Facet>& faces);
|
||||
std::vector<Segment> createSegments() const;
|
||||
|
||||
private:
|
||||
std::vector<std::size_t> domainSizes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PART_BREPMESH_H
|
||||
@@ -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
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
#include <Base/Writer.h>
|
||||
|
||||
#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<Domain>& 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<double>::epsilon();
|
||||
|
||||
void TopoShape::getFacesFromDomains(const std::vector<Domain>& domains,
|
||||
std::vector<Base::Vector3d>& points,
|
||||
std::vector<Facet>& faces) const
|
||||
{
|
||||
std::set<MeshVertex> vertices;
|
||||
Standard_Real x1, y1, z1;
|
||||
Standard_Real x2, y2, z2;
|
||||
Standard_Real x3, y3, z3;
|
||||
|
||||
for (const auto & domain : domains) {
|
||||
for (std::vector<Facet>::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<MeshVertex>::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<Base::Vector3d> 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
|
||||
|
||||
Reference in New Issue
Block a user