Skip to content

Commit

Permalink
Part: Add class BRepMesh
Browse files Browse the repository at this point in the history
This refactors the code of TopoShape::getFacesFromDomains and the the private class BrepMesh of the MeshPart module
to reduce code duplication.
  • Loading branch information
wwmayer committed Mar 6, 2024
1 parent da36c0c commit 0d37ea2
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 244 deletions.
173 changes: 37 additions & 136 deletions src/Mod/MeshPart/App/Mesher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -177,111 +137,52 @@ class BrepMesh

Mesh::MeshObject* create(const std::vector<Part::TopoShape::Domain>& domains) const
{
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);
}

bool createSegm = (colors.size() == domains.size());
std::vector<Base::Vector3d> points;
std::vector<Part::TopoShape::Facet> 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<Vertex> 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<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);
}
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);
}

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<MeshCore::FacetIndex> faces;
faces.insert(faces.end(), segm.cbegin(), segm.cend());
return faces;
});
}

Mesh::MeshObject* meshdata = new Mesh::MeshObject();
meshdata->swap(kernel);
Expand Down
134 changes: 134 additions & 0 deletions src/Mod/Part/App/BRepMesh.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 50 additions & 0 deletions src/Mod/Part/App/BRepMesh.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions src/Mod/Part/App/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 0d37ea2

Please sign in to comment.