1
/***************************************************************************
2
* Copyright (c) 2012 Imetric 3D GmbH *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
29
#include "Approximation.h"
30
#include "Segmentation.h"
32
using namespace MeshCore;
34
void MeshSurfaceSegment::Initialize(FacetIndex)
37
bool MeshSurfaceSegment::TestInitialFacet(FacetIndex) const
42
void MeshSurfaceSegment::AddFacet(const MeshFacet&)
45
void MeshSurfaceSegment::AddSegment(const std::vector<FacetIndex>& segm)
47
if (segm.size() >= minFacets) {
48
segments.push_back(segm);
52
MeshSegment MeshSurfaceSegment::FindSegment(FacetIndex index) const
54
for (const auto& segment : segments) {
55
if (std::find(segment.begin(), segment.end(), index) != segment.end()) {
63
// --------------------------------------------------------
65
MeshDistancePlanarSegment::MeshDistancePlanarSegment(const MeshKernel& mesh,
66
unsigned long minFacets,
68
: MeshDistanceSurfaceSegment(mesh, minFacets, tol)
69
, fitter(new PlaneFit)
72
MeshDistancePlanarSegment::~MeshDistancePlanarSegment()
77
void MeshDistancePlanarSegment::Initialize(FacetIndex index)
81
MeshGeomFacet triangle = kernel.GetFacet(index);
82
basepoint = triangle.GetGravityPoint();
83
normal = triangle.GetNormal();
84
fitter->AddPoint(triangle._aclPoints[0]);
85
fitter->AddPoint(triangle._aclPoints[1]);
86
fitter->AddPoint(triangle._aclPoints[2]);
89
bool MeshDistancePlanarSegment::TestFacet(const MeshFacet& face) const
91
if (!fitter->Done()) {
94
MeshGeomFacet triangle = kernel.GetFacet(face);
95
for (auto pnt : triangle._aclPoints) {
96
if (fabs(fitter->GetDistanceToPlane(pnt)) > tolerance) {
104
void MeshDistancePlanarSegment::AddFacet(const MeshFacet& face)
106
MeshGeomFacet triangle = kernel.GetFacet(face);
107
fitter->AddPoint(triangle.GetGravityPoint());
110
// --------------------------------------------------------
112
PlaneSurfaceFit::PlaneSurfaceFit()
113
: fitter(new PlaneFit)
116
PlaneSurfaceFit::PlaneSurfaceFit(const Base::Vector3f& b, const Base::Vector3f& n)
122
PlaneSurfaceFit::~PlaneSurfaceFit()
127
void PlaneSurfaceFit::Initialize(const MeshCore::MeshGeomFacet& tria)
130
basepoint = tria.GetGravityPoint();
131
normal = tria.GetNormal();
135
fitter->AddPoint(tria._aclPoints[0]);
136
fitter->AddPoint(tria._aclPoints[1]);
137
fitter->AddPoint(tria._aclPoints[2]);
142
bool PlaneSurfaceFit::TestTriangle(const MeshGeomFacet&) const
147
void PlaneSurfaceFit::AddTriangle(const MeshCore::MeshGeomFacet& tria)
150
fitter->AddPoint(tria.GetGravityPoint());
154
bool PlaneSurfaceFit::Done() const
160
return fitter->Done();
164
float PlaneSurfaceFit::Fit()
170
return fitter->Fit();
174
float PlaneSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const
177
return pnt.DistanceToPlane(basepoint, normal);
180
return fitter->GetDistanceToPlane(pnt);
184
std::vector<float> PlaneSurfaceFit::Parameters() const
186
Base::Vector3f base = basepoint;
187
Base::Vector3f norm = normal;
189
base = fitter->GetBase();
190
norm = fitter->GetNormal();
193
std::vector<float> c;
203
// --------------------------------------------------------
205
CylinderSurfaceFit::CylinderSurfaceFit()
207
, fitter(new CylinderFit)
213
* \brief CylinderSurfaceFit::CylinderSurfaceFit
214
* Set a predefined cylinder. Internal cylinder fits are not done, then.
216
CylinderSurfaceFit::CylinderSurfaceFit(const Base::Vector3f& b, const Base::Vector3f& a, float r)
223
CylinderSurfaceFit::~CylinderSurfaceFit()
228
void CylinderSurfaceFit::Initialize(const MeshCore::MeshGeomFacet& tria)
232
fitter->AddPoint(tria._aclPoints[0]);
233
fitter->AddPoint(tria._aclPoints[1]);
234
fitter->AddPoint(tria._aclPoints[2]);
238
void CylinderSurfaceFit::AddTriangle(const MeshCore::MeshGeomFacet& tria)
241
fitter->AddPoint(tria._aclPoints[0]);
242
fitter->AddPoint(tria._aclPoints[1]);
243
fitter->AddPoint(tria._aclPoints[2]);
247
bool CylinderSurfaceFit::TestTriangle(const MeshGeomFacet& tria) const
249
// This is to filter out triangles whose points lie on the cylinder and
250
// that whose normals are more or less parallel to the cylinder axis
251
float dot = axis.Dot(tria.GetNormal());
252
return fabs(dot) < 0.5f;
255
bool CylinderSurfaceFit::Done() const
258
return fitter->Done();
264
float CylinderSurfaceFit::Fit()
270
float fit = fitter->Fit();
271
if (fit < FLOAT_MAX) {
272
basepoint = fitter->GetBase();
273
axis = fitter->GetAxis();
274
radius = fitter->GetRadius();
279
float CylinderSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const
281
if (fitter && !fitter->Done()) {
282
// collect some points
285
float dist = pnt.DistanceToLine(basepoint, axis);
286
return (dist - radius);
289
std::vector<float> CylinderSurfaceFit::Parameters() const
291
Base::Vector3f base = basepoint;
292
Base::Vector3f norm = axis;
293
float radval = radius;
295
base = fitter->GetBase();
296
norm = fitter->GetAxis();
297
radval = fitter->GetRadius();
300
std::vector<float> c;
311
// --------------------------------------------------------
313
SphereSurfaceFit::SphereSurfaceFit()
315
, fitter(new SphereFit)
320
SphereSurfaceFit::SphereSurfaceFit(const Base::Vector3f& c, float r)
326
SphereSurfaceFit::~SphereSurfaceFit()
331
void SphereSurfaceFit::Initialize(const MeshCore::MeshGeomFacet& tria)
335
fitter->AddPoint(tria._aclPoints[0]);
336
fitter->AddPoint(tria._aclPoints[1]);
337
fitter->AddPoint(tria._aclPoints[2]);
341
void SphereSurfaceFit::AddTriangle(const MeshCore::MeshGeomFacet& tria)
344
fitter->AddPoint(tria._aclPoints[0]);
345
fitter->AddPoint(tria._aclPoints[1]);
346
fitter->AddPoint(tria._aclPoints[2]);
350
bool SphereSurfaceFit::TestTriangle(const MeshGeomFacet&) const
352
// Already handled by GetDistanceToSurface
356
bool SphereSurfaceFit::Done() const
359
return fitter->Done();
365
float SphereSurfaceFit::Fit()
371
float fit = fitter->Fit();
372
if (fit < FLOAT_MAX) {
373
center = fitter->GetCenter();
374
radius = fitter->GetRadius();
379
float SphereSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const
381
float dist = Base::Distance(pnt, center);
382
return (dist - radius);
385
std::vector<float> SphereSurfaceFit::Parameters() const
387
Base::Vector3f base = center;
388
float radval = radius;
390
base = fitter->GetCenter();
391
radval = fitter->GetRadius();
394
std::vector<float> c;
402
// --------------------------------------------------------
404
MeshDistanceGenericSurfaceFitSegment::MeshDistanceGenericSurfaceFitSegment(AbstractSurfaceFit* fit,
405
const MeshKernel& mesh,
406
unsigned long minFacets,
408
: MeshDistanceSurfaceSegment(mesh, minFacets, tol)
412
MeshDistanceGenericSurfaceFitSegment::~MeshDistanceGenericSurfaceFitSegment()
417
void MeshDistanceGenericSurfaceFitSegment::Initialize(FacetIndex index)
419
MeshGeomFacet triangle = kernel.GetFacet(index);
420
fitter->Initialize(triangle);
423
bool MeshDistanceGenericSurfaceFitSegment::TestInitialFacet(FacetIndex index) const
425
MeshGeomFacet triangle = kernel.GetFacet(index);
426
for (auto pnt : triangle._aclPoints) {
427
if (fabs(fitter->GetDistanceToSurface(pnt)) > tolerance) {
431
return fitter->TestTriangle(triangle);
434
bool MeshDistanceGenericSurfaceFitSegment::TestFacet(const MeshFacet& face) const
436
if (!fitter->Done()) {
439
MeshGeomFacet triangle = kernel.GetFacet(face);
440
for (auto ptIndex : triangle._aclPoints) {
441
if (fabs(fitter->GetDistanceToSurface(ptIndex)) > tolerance) {
446
return fitter->TestTriangle(triangle);
449
void MeshDistanceGenericSurfaceFitSegment::AddFacet(const MeshFacet& face)
451
MeshGeomFacet triangle = kernel.GetFacet(face);
452
fitter->AddTriangle(triangle);
455
std::vector<float> MeshDistanceGenericSurfaceFitSegment::Parameters() const
457
return fitter->Parameters();
460
// --------------------------------------------------------
462
bool MeshCurvaturePlanarSegment::TestFacet(const MeshFacet& rclFacet) const
464
for (PointIndex ptIndex : rclFacet._aulPoints) {
465
const CurvatureInfo& ci = GetInfo(ptIndex);
466
if (fabs(ci.fMinCurvature) > tolerance) {
469
if (fabs(ci.fMaxCurvature) > tolerance) {
477
bool MeshCurvatureCylindricalSegment::TestFacet(const MeshFacet& rclFacet) const
479
for (PointIndex ptIndex : rclFacet._aulPoints) {
480
const CurvatureInfo& ci = GetInfo(ptIndex);
481
float fMax = std::max<float>(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature));
482
float fMin = std::min<float>(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature));
483
if (fMin > toleranceMin) {
486
if (fabs(fMax - curvature) > toleranceMax) {
494
bool MeshCurvatureSphericalSegment::TestFacet(const MeshFacet& rclFacet) const
496
for (PointIndex ptIndex : rclFacet._aulPoints) {
497
const CurvatureInfo& ci = GetInfo(ptIndex);
498
if (ci.fMaxCurvature * ci.fMinCurvature < 0) {
502
diff = fabs(ci.fMinCurvature) - curvature;
503
if (fabs(diff) > tolerance) {
506
diff = fabs(ci.fMaxCurvature) - curvature;
507
if (fabs(diff) > tolerance) {
515
bool MeshCurvatureFreeformSegment::TestFacet(const MeshFacet& rclFacet) const
517
for (PointIndex ptIndex : rclFacet._aulPoints) {
518
const CurvatureInfo& ci = GetInfo(ptIndex);
519
if (fabs(ci.fMinCurvature - c2) > toleranceMin) {
522
if (fabs(ci.fMaxCurvature - c1) > toleranceMax) {
530
// --------------------------------------------------------
532
MeshSurfaceVisitor::MeshSurfaceVisitor(MeshSurfaceSegment& segm, std::vector<FacetIndex>& indices)
537
bool MeshSurfaceVisitor::AllowVisit(const MeshFacet& face,
543
return segm.TestFacet(face);
546
bool MeshSurfaceVisitor::Visit(const MeshFacet& face,
551
indices.push_back(ulFInd);
556
// --------------------------------------------------------
558
void MeshSegmentAlgorithm::FindSegments(std::vector<MeshSurfaceSegmentPtr>& segm)
561
FacetIndex startFacet {};
562
MeshCore::MeshAlgorithm cAlgo(myKernel);
563
cAlgo.ResetFacetFlag(MeshCore::MeshFacet::VISIT);
565
const MeshCore::MeshFacetArray& rFAry = myKernel.GetFacets();
566
MeshCore::MeshFacetArray::_TConstIterator iCur = rFAry.begin();
567
MeshCore::MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
568
MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end();
570
// start from the first not visited facet
571
cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT);
572
std::vector<FacetIndex> resetVisited;
574
for (auto& it : segm) {
575
cAlgo.ResetFacetsFlag(resetVisited, MeshCore::MeshFacet::VISIT);
576
resetVisited.clear();
578
MeshCore::MeshIsNotFlag<MeshCore::MeshFacet> flag;
579
iCur = std::find_if(iBeg, iEnd, [flag](const MeshFacet& f) {
580
return flag(f, MeshFacet::VISIT);
583
startFacet = iCur - iBeg;
586
startFacet = FACET_INDEX_MAX;
588
while (startFacet != FACET_INDEX_MAX) {
589
// collect all facets of the same geometry
590
std::vector<FacetIndex> indices;
591
it->Initialize(startFacet);
592
if (it->TestInitialFacet(startFacet)) {
593
indices.push_back(startFacet);
595
MeshSurfaceVisitor pv(*it, indices);
596
myKernel.VisitNeighbourFacets(pv, startFacet);
598
// add or discard the segment
599
if (indices.size() <= 1) {
600
resetVisited.push_back(startFacet);
603
it->AddSegment(indices);
606
// search for the next start facet
607
iCur = std::find_if(iCur, iEnd, [flag](const MeshFacet& f) {
608
return flag(f, MeshFacet::VISIT);
611
startFacet = iCur - iBeg;
614
startFacet = FACET_INDEX_MAX;