1
/***************************************************************************
2
* Copyright (c) 2005 Berthold Grupp *
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"
30
#include <Base/Builder3D.h>
31
#include <Base/Sequencer.h>
35
#include "Definitions.h"
39
#include "SetOperations.h"
40
#include "Triangulation.h"
45
using namespace MeshCore;
48
SetOperations::SetOperations(const MeshKernel& cutMesh1,
49
const MeshKernel& cutMesh2,
52
float minDistanceToPoint)
56
, _operationType(opType)
57
, _minDistanceToPoint(minDistanceToPoint)
60
void SetOperations::Do()
62
_minDistanceToPoint = 0.000001f;
63
float saveMinMeshDistance = MeshDefinitions::_fMinPointDistance;
64
MeshDefinitions::SetMinPointDistance(0.000001f);
66
// Base::Sequencer().start("set operation", 5);
70
// Base::Sequencer().next();
71
std::set<FacetIndex> facetsCuttingEdge0, facetsCuttingEdge1;
72
Cut(facetsCuttingEdge0, facetsCuttingEdge1);
74
// no intersection curve of the meshes found
75
if (facetsCuttingEdge0.empty() || facetsCuttingEdge1.empty()) {
76
switch (_operationType) {
78
_resultMesh = _cutMesh0;
79
_resultMesh.Merge(_cutMesh1);
87
_resultMesh = _cutMesh0;
95
MeshDefinitions::SetMinPointDistance(saveMinMeshDistance);
99
for (auto i = 0UL; i < _cutMesh0.CountFacets(); i++) {
100
if (facetsCuttingEdge0.find(i) == facetsCuttingEdge0.end()) {
101
_newMeshFacets[0].push_back(_cutMesh0.GetFacet(i));
105
for (auto i = 0UL; i < _cutMesh1.CountFacets(); i++) {
106
if (facetsCuttingEdge1.find(i) == facetsCuttingEdge1.end()) {
107
_newMeshFacets[1].push_back(_cutMesh1.GetFacet(i));
111
// Base::Sequencer().next();
112
TriangulateMesh(_cutMesh0, 0);
114
// Base::Sequencer().next();
115
TriangulateMesh(_cutMesh1, 1);
117
float mult0 {}, mult1 {};
118
switch (_operationType) {
145
// Base::Sequencer().next();
146
CollectFacets(0, mult0);
147
// Base::Sequencer().next();
148
CollectFacets(1, mult1);
150
std::vector<MeshGeomFacet> facets;
152
std::vector<MeshGeomFacet>::iterator itf;
153
for (itf = _facetsOf[0].begin(); itf != _facetsOf[0].end(); ++itf) {
154
if (_operationType == Difference) { // toggle normal
155
std::swap(itf->_aclPoints[0], itf->_aclPoints[1]);
159
facets.push_back(*itf);
162
for (itf = _facetsOf[1].begin(); itf != _facetsOf[1].end(); ++itf) {
163
facets.push_back(*itf);
166
_resultMesh = facets;
168
// Base::Sequencer().stop();
169
// _builder.saveToFile("c:/temp/vdbg.iv");
171
MeshDefinitions::SetMinPointDistance(saveMinMeshDistance);
174
void SetOperations::Cut(std::set<FacetIndex>& facetsCuttingEdge0,
175
std::set<FacetIndex>& facetsCuttingEdge1)
177
MeshFacetGrid grid1(_cutMesh0, 20);
178
MeshFacetGrid grid2(_cutMesh1, 20);
180
unsigned long ctGx1 {}, ctGy1 {}, ctGz1 {};
181
grid1.GetCtGrids(ctGx1, ctGy1, ctGz1);
183
for (auto gx1 = 0UL; gx1 < ctGx1; gx1++) {
184
for (auto gy1 = 0UL; gy1 < ctGy1; gy1++) {
185
for (auto gz1 = 0UL; gz1 < ctGz1; gz1++) {
186
if (grid1.GetCtElements(gx1, gy1, gz1) > 0) {
187
std::vector<FacetIndex> vecFacets2;
188
grid2.Inside(grid1.GetBoundBox(gx1, gy1, gz1), vecFacets2);
190
if (!vecFacets2.empty()) {
191
std::set<FacetIndex> vecFacets1;
192
grid1.GetElements(gx1, gy1, gz1, vecFacets1);
194
std::set<FacetIndex>::iterator it1;
195
for (it1 = vecFacets1.begin(); it1 != vecFacets1.end(); ++it1) {
196
FacetIndex fidx1 = *it1;
197
MeshGeomFacet f1 = _cutMesh0.GetFacet(*it1);
199
std::vector<FacetIndex>::iterator it2;
200
for (it2 = vecFacets2.begin(); it2 != vecFacets2.end(); ++it2) {
201
FacetIndex fidx2 = *it2;
202
MeshGeomFacet f2 = _cutMesh1.GetFacet(fidx2);
206
int isect = f1.IntersectWithFacet(f2, p0, p1);
208
// optimize cut line if distance to nearest point is too small
209
float minDist1 = _minDistanceToPoint,
210
minDist2 = _minDistanceToPoint;
211
MeshPoint np0 = p0, np1 = p1;
212
for (int i = 0; i < 3; i++) // NOLINT
214
float d1 = (f1._aclPoints[i] - p0).Length();
215
float d2 = (f1._aclPoints[i] - p1).Length();
218
np0 = f1._aclPoints[i];
222
p1 = f1._aclPoints[i];
224
} // for (int i = 0; i < 3; i++)
226
// optimize cut line if distance to nearest point is too small
227
for (int i = 0; i < 3; i++) // NOLINT
229
float d1 = (f2._aclPoints[i] - p0).Length();
230
float d2 = (f2._aclPoints[i] - p1).Length();
233
np0 = f2._aclPoints[i];
237
np1 = f2._aclPoints[i];
239
} // for (int i = 0; i < 3; i++)
245
facetsCuttingEdge0.insert(fidx1);
246
facetsCuttingEdge1.insert(fidx2);
248
_cutPoints.insert(mp0);
249
_cutPoints.insert(mp1);
251
std::pair<std::set<MeshPoint>::iterator, bool> pit0 =
252
_cutPoints.insert(mp0);
253
std::pair<std::set<MeshPoint>::iterator, bool> pit1 =
254
_cutPoints.insert(mp1);
256
_edges[Edge(mp0, mp1)] = EdgeInfo();
258
_facet2points[0][fidx1].push_back(pit0.first);
259
_facet2points[0][fidx1].push_back(pit1.first);
260
_facet2points[1][fidx2].push_back(pit0.first);
261
_facet2points[1][fidx2].push_back(pit1.first);
264
std::pair<std::set<MeshPoint>::iterator, bool> pit =
265
_cutPoints.insert(mp0);
267
// do not insert a facet when only one corner point cuts the
268
// edge if (!((mp0 == f1._aclPoints[0]) || (mp0 ==
269
// f1._aclPoints[1]) || (mp0 == f1._aclPoints[2])))
271
facetsCuttingEdge0.insert(fidx1);
272
_facet2points[0][fidx1].push_back(pit.first);
275
// if (!((mp0 == f2._aclPoints[0]) || (mp0 ==
276
// f2._aclPoints[1]) || (mp0 == f2._aclPoints[2])))
278
facetsCuttingEdge1.insert(fidx2);
279
_facet2points[1][fidx2].push_back(pit.first);
283
} // if (f1.IntersectWithFacet(f2, p0, p1))
284
} // for (it2 = vecFacets2.begin(); it2 != vecFacets2.end(); ++it2)
285
} // for (it1 = vecFacets1.begin(); it1 != vecFacets1.end(); ++it1)
286
} // if (vecFacets2.size() > 0)
287
} // if (grid1.GetCtElements(gx1, gy1, gz1) > 0)
288
} // for (gz1 = 0; gz1 < ctGz1; gz1++)
289
} // for (gy1 = 0; gy1 < ctGy1; gy1++)
290
} // for (gx1 = 0; gx1 < ctGx1; gx1++)
293
void SetOperations::TriangulateMesh(const MeshKernel& cutMesh, int side)
296
std::map<FacetIndex, std::list<std::set<MeshPoint>::iterator>>::iterator it1;
297
for (it1 = _facet2points[side].begin(); it1 != _facet2points[side].end(); ++it1) {
298
std::vector<Vector3f> points;
299
std::set<MeshPoint> pointsSet;
301
FacetIndex fidx = it1->first;
302
MeshGeomFacet f = cutMesh.GetFacet(fidx);
305
// _builder.addSingleTriangle(f._aclPoints[0], f._aclPoints[1], f._aclPoints[2], 3, 0,
308
// facet corner points
309
// const MeshFacet& mf = cutMesh._aclFacetArray[fidx];
310
for (int i = 0; i < 3; i++) // NOLINT
312
pointsSet.insert(f._aclPoints[i]);
313
points.push_back(f._aclPoints[i]);
316
// triangulated facets
317
std::list<std::set<MeshPoint>::iterator>::iterator it2;
318
for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) {
319
if (pointsSet.find(*(*it2)) == pointsSet.end()) {
320
pointsSet.insert(*(*it2));
321
points.push_back(*(*it2));
325
Vector3f normal = f.GetNormal();
326
Vector3f base = points[0];
327
Vector3f dirX = points[1] - points[0];
329
Vector3f dirY = dirX % normal;
331
// project points to 2D plane
332
std::vector<Vector3f>::iterator it;
333
std::vector<Vector3f> vertices;
334
for (it = points.begin(); it != points.end(); ++it) {
336
pv.TransformToCoordinateSystem(base, dirX, dirY);
337
vertices.push_back(pv);
340
DelaunayTriangulator tria;
341
tria.SetPolygon(vertices);
342
tria.TriangulatePolygon();
344
std::vector<MeshFacet> facets = tria.GetFacets();
345
for (auto& it : facets) {
346
if ((it._aulPoints[0] == it._aulPoints[1]) || (it._aulPoints[1] == it._aulPoints[2])
347
|| (it._aulPoints[2] == it._aulPoints[0])) { // two same triangle corner points
351
MeshGeomFacet facet(points[it._aulPoints[0]],
352
points[it._aulPoints[1]],
353
points[it._aulPoints[2]]);
356
// _builder.addSingleTriangle(facet._aclPoints[0], facet._aclPoints[1],
357
// facet._aclPoints[2], true, 3, 0, 1, 1);
359
// if (facet.Area() < 0.0001f)
360
//{ // too small facet
365
facet._aclPoints[0].DistanceToLine(facet._aclPoints[1],
366
facet._aclPoints[1] - facet._aclPoints[2]);
368
facet._aclPoints[1].DistanceToLine(facet._aclPoints[0],
369
facet._aclPoints[0] - facet._aclPoints[2]);
371
facet._aclPoints[2].DistanceToLine(facet._aclPoints[0],
372
facet._aclPoints[0] - facet._aclPoints[1]);
374
if ((dist0 < _minDistanceToPoint) || (dist1 < _minDistanceToPoint)
375
|| (dist2 < _minDistanceToPoint)) {
379
// dist0 = (facet._aclPoints[0] - facet._aclPoints[1]).Length();
380
// dist1 = (facet._aclPoints[1] - facet._aclPoints[2]).Length();
381
// dist2 = (facet._aclPoints[2] - facet._aclPoints[3]).Length();
383
// if ((dist0 < _minDistanceToPoint) || (dist1 < _minDistanceToPoint) || (dist2 <
384
// _minDistanceToPoint))
390
if ((facet.GetNormal() * f.GetNormal()) < 0.0f) { // adjust normal
391
std::swap(facet._aclPoints[0], facet._aclPoints[1]);
396
for (int j = 0; j < 3; j++) {
397
std::map<Edge, EdgeInfo>::iterator eit =
398
_edges.find(Edge(facet._aclPoints[j], facet._aclPoints[(j + 1) % 3]));
400
if (eit != _edges.end()) {
402
if (eit->second.fcounter[side] < 2) {
404
// _builder.addSingleTriangle(facet._aclPoints[0], facet._aclPoints[1],
405
// facet._aclPoints[2], true, 3, 0, 1, 1);
407
eit->second.facet[side] = fidx;
408
eit->second.facets[side][eit->second.fcounter[side]] = facet;
409
eit->second.fcounter[side]++;
411
MeshFacet::MARKED); // set all facets connected to an edge: MARKED
416
_newMeshFacets[side].push_back(facet);
418
} // for (i = 0; i < (out->numberoftriangles * 3); i += 3)
419
} // for (it1 = _facet2points[side].begin(); it1 != _facet2points[side].end(); ++it1)
422
void SetOperations::CollectFacets(int side, float mult)
424
// float distSave = MeshDefinitions::_fMinPointDistance;
425
// MeshDefinitions::SetMinPointDistance(1.0e-4f);
428
MeshBuilder mb(mesh);
429
mb.Initialize(_newMeshFacets[side].size());
430
std::vector<MeshGeomFacet>::iterator it;
431
for (it = _newMeshFacets[side].begin(); it != _newMeshFacets[side].end(); ++it) {
432
// if (it->IsFlag(MeshFacet::MARKED))
434
// _builder.addSingleTriangle(it->_aclPoints[0], it->_aclPoints[1], it->_aclPoints[2],
435
// true, 3.0, 0.0, 1.0, 1.0);
437
mb.AddFacet(*it, true);
441
MeshAlgorithm algo(mesh);
442
algo.ResetFacetFlag(static_cast<MeshFacet::TFlagType>(MeshFacet::VISIT | MeshFacet::TMP0));
444
// bool hasFacetsNotVisited = true; // until facets not visited
445
// search for facet not visited
446
MeshFacetArray::_TConstIterator itf;
447
const MeshFacetArray& rFacets = mesh.GetFacets();
448
for (itf = rFacets.begin(); itf != rFacets.end(); ++itf) {
449
if (!itf->IsFlag(MeshFacet::VISIT)) { // Facet found, visit neighbours
450
std::vector<FacetIndex> facets;
451
facets.push_back(itf - rFacets.begin()); // add seed facet
452
CollectFacetVisitor visitor(mesh, facets, _edges, side, mult, _builder);
453
mesh.VisitNeighbourFacets(visitor, itf - rFacets.begin());
455
if (visitor._addFacets == 0) { // mark all facets to add it to the result
456
algo.SetFacetsFlag(facets, MeshFacet::TMP0);
461
// add all facets to the result vector
462
for (itf = rFacets.begin(); itf != rFacets.end(); ++itf) {
463
if (itf->IsFlag(MeshFacet::TMP0)) {
464
_facetsOf[side].push_back(mesh.GetFacet(*itf));
468
// MeshDefinitions::SetMinPointDistance(distSave);
471
SetOperations::CollectFacetVisitor::CollectFacetVisitor(const MeshKernel& mesh,
472
std::vector<FacetIndex>& facets,
473
std::map<Edge, EdgeInfo>& edges,
476
Base::Builder3D& builder)
485
bool SetOperations::CollectFacetVisitor::Visit(const MeshFacet& rclFacet,
486
const MeshFacet& rclFrom,
488
unsigned long ulLevel)
493
_facets.push_back(ulFInd);
497
// static int matchCounter = 0;
498
bool SetOperations::CollectFacetVisitor::AllowVisit(const MeshFacet& rclFacet,
499
const MeshFacet& rclFrom,
501
unsigned long ulLevel,
502
unsigned short neighbourIndex)
506
if (rclFacet.IsFlag(MeshFacet::MARKED) && rclFrom.IsFlag(MeshFacet::MARKED)) {
507
// facet connected to an edge
508
PointIndex pt0 = rclFrom._aulPoints[neighbourIndex],
509
pt1 = rclFrom._aulPoints[(neighbourIndex + 1) % 3];
510
Edge edge(_mesh.GetPoint(pt0), _mesh.GetPoint(pt1));
512
std::map<Edge, EdgeInfo>::iterator it = _edges.find(edge);
514
if (it != _edges.end()) {
515
if (_addFacets == -1) {
516
// determine if the facets should add or not only once
517
MeshGeomFacet facet = _mesh.GetFacet(rclFrom); // triangulated facet
518
MeshGeomFacet facetOther =
520
.facets[1 - _side][0]; // triangulated facet from same edge and other mesh
521
Vector3f normalOther = facetOther.GetNormal();
522
// Vector3f normal = facet.GetNormal();
524
Vector3f edgeDir = it->first.pt1 - it->first.pt2;
525
Vector3f ocDir = (edgeDir % (facet.GetGravityPoint() - it->first.pt1)) % edgeDir;
527
Vector3f ocDirOther =
528
(edgeDir % (facetOther.GetGravityPoint() - it->first.pt1)) % edgeDir;
529
ocDirOther.Normalize();
531
// Vector3f dir = ocDir % normal;
532
// Vector3f dirOther = ocDirOther % normalOther;
534
bool match = ((ocDir * normalOther) * _mult) < 0.0f;
536
// if (matchCounter == 1)
538
// // _builder.addSingleArrow(it->second.pt1, it->second.pt1 + edgeDir, 3,
541
// _builder.addSingleTriangle(facet._aclPoints[0], facet._aclPoints[1],
542
// facet._aclPoints[2], true, 3.0, 1.0, 0.0, 0.0);
543
// // _builder.addSingleArrow(facet.GetGravityPoint(), facet.GetGravityPoint() +
544
// ocDir, 3, 1.0, 0.0, 0.0); _builder.addSingleArrow(facet.GetGravityPoint(),
545
// facet.GetGravityPoint() + normal, 3, 1.0, 0.5, 0.0);
546
// // _builder.addSingleArrow(facet.GetGravityPoint(), facet.GetGravityPoint() +
547
// dir, 3, 1.0, 1.0, 0.0);
549
// _builder.addSingleTriangle(facetOther._aclPoints[0], facetOther._aclPoints[1],
550
// facetOther._aclPoints[2], true, 3.0, 0.0, 0.0, 1.0);
551
// // _builder.addSingleArrow(facetOther.GetGravityPoint(),
552
// facetOther.GetGravityPoint() + ocDirOther, 3, 0.0, 0.0, 1.0);
553
// _builder.addSingleArrow(facetOther.GetGravityPoint(),
554
// facetOther.GetGravityPoint() + normalOther, 3, 0.0, 0.5, 1.0);
555
// // _builder.addSingleArrow(facetOther.GetGravityPoint(),
556
// facetOther.GetGravityPoint() + dirOther, 3, 0.0, 1.0, 1.0);
560
// float scalar = dir * dirOther * _mult;
561
// bool match = scalar > 0.0f;
564
// MeshPoint pt0 = it->first.pt1;
565
// MeshPoint pt1 = it->first.pt2;
567
// int i, n0 = -1, n1 = -1, m0 = -1, m1 = -1;
568
// for (i = 0; i < 3; i++)
570
// if ((n0 == -1) && (facet._aclPoints[i] == pt0))
572
// if ((n1 == -1) && (facet._aclPoints[i] == pt1))
574
// if ((m0 == -1) && (facetOther._aclPoints[i] == pt0))
576
// if ((m1 == -1) && (facetOther._aclPoints[i] == pt1))
580
// if ((n0 != -1) && (n1 != -1) && (m0 != -1) && (m1 != -1))
582
// bool orient_n = n1 > n0;
583
// bool orient_m = m1 > m0;
585
// Vector3f dirN = facet._aclPoints[n1] - facet._aclPoints[n0];
586
// Vector3f dirM = facetOther._aclPoints[m1] - facetOther._aclPoints[m0];
588
// if (matchCounter == 1)
590
// _builder.addSingleArrow(facet.GetGravityPoint(), facet.GetGravityPoint() +
591
// dirN, 3, 1.0, 1.0, 0.0); _builder.addSingleArrow(facetOther.GetGravityPoint(),
592
// facetOther.GetGravityPoint() + dirM, 3, 0.0, 1.0, 1.0);
596
// match = orient_n == orient_m;
598
// match = orient_n != orient_m;
618
// ----------------------------------------------------------------------------
620
bool MeshIntersection::hasIntersection() const
622
Base::BoundBox3f bbox1 = kernel1.GetBoundBox();
623
Base::BoundBox3f bbox2 = kernel2.GetBoundBox();
624
if (!(bbox1 && bbox2)) {
628
if (testIntersection(kernel1, kernel2)) {
635
void MeshIntersection::getIntersection(std::list<MeshIntersection::Tuple>& intsct) const
637
const MeshKernel& k1 = kernel1;
638
const MeshKernel& k2 = kernel2;
640
// Contains bounding boxes for every facet of 'k1'
641
std::vector<Base::BoundBox3f> boxes1;
642
MeshFacetIterator cMFI1(k1);
643
for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) {
644
boxes1.push_back((*cMFI1).GetBoundBox());
647
// Contains bounding boxes for every facet of 'k2'
648
std::vector<Base::BoundBox3f> boxes2;
649
MeshFacetIterator cMFI2(k2);
650
for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) {
651
boxes2.push_back((*cMFI2).GetBoundBox());
654
// Splits the mesh using grid for speeding up the calculation
655
MeshFacetGrid cMeshFacetGrid(k1);
657
const MeshFacetArray& rFaces2 = k2.GetFacets();
658
Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size());
660
MeshGeomFacet facet1, facet2;
661
Base::Vector3f pt1, pt2;
663
// Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh
664
for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) {
666
std::vector<FacetIndex> elements;
667
cMeshFacetGrid.Inside(boxes2[index], elements, true);
672
for (FacetIndex element : elements) {
673
if (boxes2[index] && boxes1[element]) {
676
int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
690
bool MeshIntersection::testIntersection(const MeshKernel& k1, const MeshKernel& k2)
692
// Contains bounding boxes for every facet of 'k1'
693
std::vector<Base::BoundBox3f> boxes1;
694
MeshFacetIterator cMFI1(k1);
695
for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) {
696
boxes1.push_back((*cMFI1).GetBoundBox());
699
// Contains bounding boxes for every facet of 'k2'
700
std::vector<Base::BoundBox3f> boxes2;
701
MeshFacetIterator cMFI2(k2);
702
for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) {
703
boxes2.push_back((*cMFI2).GetBoundBox());
706
// Splits the mesh using grid for speeding up the calculation
707
MeshFacetGrid cMeshFacetGrid(k1);
709
const MeshFacetArray& rFaces2 = k2.GetFacets();
710
Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size());
712
MeshGeomFacet facet1, facet2;
713
Base::Vector3f pt1, pt2;
715
// Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh
716
for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) {
718
std::vector<FacetIndex> elements;
719
cMeshFacetGrid.Inside(boxes2[index], elements, true);
724
for (FacetIndex element : elements) {
725
if (boxes2[index] && boxes1[element]) {
728
int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
730
// abort after the first detected self-intersection
740
void MeshIntersection::connectLines(bool onlyclosed,
741
const std::list<MeshIntersection::Tuple>& rdata,
742
std::list<std::list<MeshIntersection::Triple>>& lines)
744
float fMinEps = minDistance * minDistance;
746
std::list<Tuple> data = rdata;
747
while (!data.empty()) {
748
std::list<Tuple>::iterator pF;
749
std::list<Triple> newPoly;
751
// add first line and delete from the list
753
front.f1 = data.begin()->f1;
754
front.f2 = data.begin()->f2;
755
front.p = data.begin()->p1; // current start point of the polyline
756
back.f1 = data.begin()->f1;
757
back.f2 = data.begin()->f2;
758
back.p = data.begin()->p2; // current end point of the polyline
759
newPoly.push_back(front);
760
newPoly.push_back(back);
761
data.erase(data.begin());
763
// search for the next line on the begin/end of the polyline and add it
764
std::list<Tuple>::iterator pFront, pEnd;
767
float fFrontMin = fMinEps, fEndMin = fMinEps;
768
bool bFrontFirst = false, bEndFirst = false;
774
for (pF = data.begin(); pF != data.end(); ++pF) {
775
if (Base::DistanceP2(front.p, pF->p1) < fFrontMin) {
776
fFrontMin = Base::DistanceP2(front.p, pF->p1);
780
else if (Base::DistanceP2(back.p, pF->p1) < fEndMin) {
781
fEndMin = Base::DistanceP2(back.p, pF->p1);
785
else if (Base::DistanceP2(front.p, pF->p2) < fFrontMin) {
786
fFrontMin = Base::DistanceP2(front.p, pF->p2);
790
else if (Base::DistanceP2(back.p, pF->p2) < fEndMin) {
791
fEndMin = Base::DistanceP2(back.p, pF->p2);
796
if (fFrontMin == 0.0f || fEndMin == 0.0f) {
801
if (pFront != data.end()) {
804
front.f1 = pFront->f1;
805
front.f2 = pFront->f2;
806
front.p = pFront->p2;
807
newPoly.push_front(front);
810
front.f1 = pFront->f1;
811
front.f2 = pFront->f2;
812
front.p = pFront->p1;
813
newPoly.push_front(front);
819
if (pEnd != data.end()) {
825
newPoly.push_back(back);
831
newPoly.push_back(back);
836
} while (bFoundLine);
839
if (newPoly.size() > 2
840
&& Base::DistanceP2(newPoly.front().p, newPoly.back().p) < fMinEps) {
841
lines.push_back(newPoly);
845
lines.push_back(newPoly);