Salome HOME
edff6f1a43832d9d90b3ac0832c0493eb6f13298
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SketchBuilder.cpp
1 // File:        GeomAlgoAPI_SketchBuilder.cpp
2 // Created:     02 Jun 2014
3 // Author:      Artem ZHIDKOV
4
5 #include <GeomAlgoAPI_SketchBuilder.h>
6
7 #include <set>
8
9 #include <gp_Dir.hxx>
10 #include <gp_Pln.hxx>
11
12 #include <BOPAlgo_Builder.hxx>
13 #include <BOPAlgo_Operation.hxx>
14 #include <BOPAlgo_PaveFiller.hxx>
15 #include <BOPTools.hxx>
16 #include <BRep_Builder.hxx>
17 #include <BRep_Curve3D.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepAlgoAPI_Cut.hxx>
20 #include <BRepBuilderAPI_MakeFace.hxx>
21 #include <BRepClass_FaceClassifier.hxx>
22 #include <Geom_Curve.hxx>
23 #include <Geom_Plane.hxx>
24 #include <TopExp.hxx>
25 #include <TopExp_Explorer.hxx>
26 #include <TopoDS_Edge.hxx>
27 #include <TopoDS_Face.hxx>
28 #include <TopoDS_Vertex.hxx>
29 #include <TopoDS_Wire.hxx>
30
31 #include <Precision.hxx>
32
33 #include <assert.h>
34
35 #ifndef DBL_MAX
36 #define DBL_MAX 1.7976931348623158e+308 
37 #endif
38
39 const double tolerance = Precision::Confusion();
40 // This value helps to find direction on the boundaries of curve.
41 // It is not significant for lines, but is used for circles to avoid 
42 // wrong directions of movement (when two edges are tangent on the certain vertex)
43 const double shift = acos(1.0 - 3.0 * tolerance);
44
45 /// \brief Search first vertex - the vertex with lowest x coordinate, which is used in 2 edges at least
46 static const TopoDS_Vertex& findStartVertex(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
47                                            const gp_Dir& theDirX, const gp_Dir& theDirY);
48
49 /// \brief Search the vertex on the sketch candidate to be the next one in the loop
50 static void findNextVertex(const TopoDS_Vertex& theStartVertex,
51                            const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
52                            const gp_Dir& theStartDir, const gp_Dir& theNormal,
53                            TopoDS_Vertex& theNextVertex, TopoDS_Edge& theNextEdge,
54                            gp_Dir& theNextDir);
55
56 /// \brief Create planar face using the edges surrounding it
57 static void createFace(const TopoDS_Vertex& theStartVertex,
58                        const std::list<TopoDS_Edge>::iterator& theStartEdge,
59                        const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
60                        const gp_Pln& thePlane, TopoDS_Face& theResFace);
61
62 /// \bief Create planar wire
63 static void createWireList(const TopoDS_Vertex& theStartVertex,
64                            const std::list<TopoDS_Edge>::iterator& theStartEdge,
65                            const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
66                            const std::set<TopoDS_Edge*>& theEdgesInLoops,
67                            std::list<TopoDS_Wire>& theResWires);
68
69 /// \brief Calculate outer tengency on the edge in specified vertex
70 static gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& theVertex);
71
72 /// \brief Unnecessary edges will be removed from the map.
73 ///        Positions of iterator will be updated
74 static void removeWasteEdges(std::list<TopoDS_Vertex>::iterator& theStartVertex,
75                              std::list<TopoDS_Edge>::iterator& theStartEdge,
76                              const std::list<TopoDS_Vertex>::iterator& theEndOfVertexes,
77                              const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
78                              BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE);
79
80
81 void GeomAlgoAPI_SketchBuilder::createFaces(
82     const boost::shared_ptr<GeomAPI_Pnt>& theOrigin, const boost::shared_ptr<GeomAPI_Dir>& theDirX,
83     const boost::shared_ptr<GeomAPI_Dir>& theDirY, const boost::shared_ptr<GeomAPI_Dir>& theNorm,
84     const std::list<boost::shared_ptr<GeomAPI_Shape> >& theFeatures,
85     std::list<boost::shared_ptr<GeomAPI_Shape> >& theResultFaces,
86     std::list<boost::shared_ptr<GeomAPI_Shape> >& theResultWires)
87 {
88   if (theFeatures.empty())
89     return;
90
91   // Create the list of edges with shared vertexes
92   BOPAlgo_Builder aBuilder;
93   BOPAlgo_PaveFiller aPF;
94   TopoDS_Shape aFeaturesCompound;
95
96   // Obtain only edges from the features list
97   std::list<boost::shared_ptr<GeomAPI_Shape> > anEdges;
98   std::list<boost::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
99   for (; aFeatIt != theFeatures.end(); aFeatIt++) {
100     boost::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
101     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
102     if (anEdge.ShapeType() == TopAbs_EDGE)
103       anEdges.push_back(aShape);
104   }
105
106   if (anEdges.size() == 1) {  // If there is only one feature, BOPAlgo_Builder will decline to work. Need to process it anyway
107     aFeaturesCompound = anEdges.front()->impl<TopoDS_Shape>();
108   } else {
109     std::list<boost::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = anEdges.begin();
110     for (; anIt != anEdges.end(); anIt++) {
111       boost::shared_ptr<GeomAPI_Shape> aPreview(*anIt);
112       aBuilder.AddArgument(aPreview->impl<TopoDS_Edge>());
113     }
114     aPF.SetArguments(aBuilder.Arguments());
115     aPF.Perform();
116     int aErr = aPF.ErrorStatus();
117     if (aErr)
118       return;
119     aBuilder.PerformWithFiller(aPF);
120     aErr = aBuilder.ErrorStatus();
121     if (aErr)
122       return;
123     aFeaturesCompound = aBuilder.Shape();
124   }
125
126   BOPCol_IndexedDataMapOfShapeListOfShape aMapVE;  // map between vertexes and edges
127   BOPTools::MapShapesAndAncestors(aFeaturesCompound, TopAbs_VERTEX, TopAbs_EDGE, aMapVE);
128   if (aMapVE.IsEmpty())  // in case of not-initialized circle
129     return;
130
131   gp_Dir aDirX = theDirX->impl<gp_Dir>();
132   gp_Dir aDirY = theDirY->impl<gp_Dir>();
133   gp_Dir aNorm = theNorm->impl<gp_Dir>();
134
135   gp_Pln aPlane(theOrigin->impl<gp_Pnt>(), aNorm);
136
137   // Set of edges used in loops
138   std::set<TopoDS_Edge*> anEdgesInLoops;
139   // Lists for processed vertexes and edges
140   std::list<TopoDS_Vertex> aProcVertexes;
141   std::list<TopoDS_Edge> aProcEdges;
142
143   // Search the start vertex
144   TopoDS_Vertex aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
145   aProcVertexes.push_back(aStartVertex);
146
147   TopoDS_Vertex aCurVertex = aStartVertex;
148   gp_Dir aCurDir = aDirY.Reversed();
149   gp_Dir aCurNorm = aNorm.Reversed();
150
151   // Go through the edges and find loops
152   TopoDS_Vertex aNextVertex;
153   TopoDS_Edge aBindingEdge;
154   gp_Dir aNextDir;
155   while (aMapVE.Extent() > 0) {
156     if (aCurVertex.IsNull())
157       return;
158     findNextVertex(aCurVertex, aMapVE, aCurDir, aCurNorm, aNextVertex, aBindingEdge, aNextDir);
159     aCurNorm = aNorm;
160
161     // Try to find next vertex in the list of already processed
162     bool isLoopFound = false;
163     std::list<TopoDS_Vertex>::iterator aVertIter = aProcVertexes.begin();
164     std::list<TopoDS_Edge>::iterator anEdgeIter = aProcEdges.begin();
165     for (; aVertIter != aProcVertexes.end(); aVertIter++) {
166       if (aVertIter->IsSame(aNextVertex)) {
167         isLoopFound = true;
168         break;
169       }
170       if (anEdgeIter != aProcEdges.end())
171         anEdgeIter++;
172     }
173
174     bool isCircleFound = (isLoopFound && anEdgeIter == aProcEdges.end());
175     aProcVertexes.push_back(aNextVertex);
176     aProcEdges.push_back(aBindingEdge);
177
178     if (isLoopFound) {
179       // If the binding edge is a full circle, then it may be added recently. Need to update edge iterator
180       if (isCircleFound) {
181         anEdgeIter = aProcEdges.end();
182         anEdgeIter--;
183       }
184       else if (aVertIter != aProcVertexes.begin()) {
185         // Check the orientation of the loop
186         gp_Dir aCN = getOuterEdgeDirection(*anEdgeIter, *aVertIter);
187         gp_Dir aCP = getOuterEdgeDirection(aProcEdges.back(), *aVertIter);
188         aCN.Reverse();
189         aCP.Reverse();
190         if (aCN.DotCross(aCP, aNorm) < -tolerance) {
191           // The found loop has wrong orientation and may contain sub-loops.
192           // Need to check it once again with another initial direction.
193           aCurVertex = *aVertIter;
194           do {
195             aProcVertexes.pop_back();
196             aProcEdges.pop_back();
197           } while (aCurVertex != aProcVertexes.back());
198           aCurDir = aCN.Reversed();
199           //aCurNorm = aNorm.Reversed();
200           continue;
201         }
202       }
203
204       if (!isCircleFound && anEdgeIter != aProcEdges.end() && 
205           anEdgeIter->IsSame(aProcEdges.back())) { // The loop on the same edge taken twice
206         aProcVertexes.pop_back();
207         aProcEdges.pop_back();
208         aCurVertex = aProcVertexes.back();
209         aCurDir = getOuterEdgeDirection(aProcEdges.back(), aCurVertex);
210         aCurNorm = aNorm.Reversed();
211         continue;
212       }
213
214       // When the orientation is correct or the edges looped through
215       // the first element, create new face and remove unnecessary edges.
216       TopoDS_Face aPatch;
217       createFace(*aVertIter, anEdgeIter, aProcEdges.end(), aPlane, aPatch);
218       if (!aPatch.IsNull()) {
219         boost::shared_ptr<GeomAPI_Shape> aFace(new GeomAPI_Shape);
220         aFace->setImpl(new TopoDS_Face(aPatch));
221         theResultFaces.push_back(aFace);
222       }
223       // push the edges used in the loop to the map
224       std::list<TopoDS_Edge>::iterator anIter;
225       for (anIter = anEdgeIter; anIter != aProcEdges.end(); anIter++)
226         anEdgesInLoops.insert(&(*anIter));
227       // remove unnecessary edges
228       std::list<TopoDS_Vertex>::iterator aCopyVLoop = aVertIter;
229       std::list<TopoDS_Edge>::iterator aCopyELoop = anEdgeIter;
230       removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE);
231
232       // Recalculate current vertex and current direction
233       aProcEdges.clear();
234       aProcVertexes.clear();
235       if (aMapVE.Extent() > 0)
236       {
237         aNextVertex = findStartVertex(aMapVE, aDirX, aDirY);
238         aProcVertexes.push_back(aNextVertex);
239       }
240       aNextDir = aDirY.Reversed();
241       aCurNorm = aNorm.Reversed();
242     }
243
244     // if next vertex connected only to alone edge, this is a part of wire (not a closed loop),
245     // we need to go back through the list of already checked edges to find a branching vertex
246     if (!aMapVE.IsEmpty() && aMapVE.Contains(aNextVertex)
247         && aMapVE.FindFromKey(aNextVertex).Size() == 1) {
248       std::list<TopoDS_Vertex>::reverse_iterator aVRIter = aProcVertexes.rbegin();
249       std::list<TopoDS_Edge>::reverse_iterator aERIter = aProcEdges.rbegin();
250       if (aVRIter != aProcVertexes.rend())
251         aVRIter++;
252       if (aERIter != aProcEdges.rend())
253         aERIter++;
254
255       for (; aERIter != aProcEdges.rend(); aERIter++, aVRIter++)
256         if (aMapVE.FindFromKey(*aVRIter).Size() > 2)
257           break;
258       if (aERIter != aProcEdges.rend()
259           || (aVRIter != aProcVertexes.rend() && aMapVE.FindFromKey(*aVRIter).Size() == 1)) {  // the branching vertex was found or current list of edges is a wire without branches
260         std::list<TopoDS_Edge>::iterator aEIter;
261         TopoDS_Edge aCurEdge;
262         if (aERIter != aProcEdges.rend()) {
263           aEIter = aERIter.base();
264           aCurEdge = *aERIter;
265         } else
266           aEIter = aProcEdges.begin();
267         std::list<TopoDS_Wire> aTail;
268         createWireList(*aVRIter, aEIter, aProcEdges.end(), anEdgesInLoops, aTail);
269         std::list<TopoDS_Wire>::const_iterator aTailIter = aTail.begin();
270         for (; aTailIter != aTail.end(); aTailIter++)
271           if (!aTailIter->IsNull()) {
272             boost::shared_ptr<GeomAPI_Shape> aWire(new GeomAPI_Shape);
273             aWire->setImpl(new TopoDS_Shape(*aTailIter));
274             theResultWires.push_back(aWire);
275           }
276         std::list<TopoDS_Vertex>::iterator aVIter = aVRIter.base();
277         std::list<TopoDS_Edge>::iterator aEItCopy = aEIter;
278         removeWasteEdges(--aVIter, aEItCopy, aProcVertexes.end(), aProcEdges.end(), aMapVE);
279
280         aProcEdges.erase(aEIter, aProcEdges.end());
281         aVIter = aVRIter.base();
282         aProcVertexes.erase(aVIter, aProcVertexes.end());
283
284         if (!aProcVertexes.empty()) {
285           aNextVertex = aProcVertexes.back();
286           if (!aCurEdge.IsNull())
287             aNextDir = getOuterEdgeDirection(aCurEdge, aNextVertex);
288         }
289       } else {  // there is no branching vertex in the list of proceeded,
290                 // so we should revert the list and go the opposite way
291         aProcVertexes.reverse();
292         aProcEdges.reverse();
293         aNextVertex = aProcVertexes.back();
294         aNextDir =
295             aProcEdges.empty() ? aDirY : getOuterEdgeDirection(aProcEdges.back(), aNextVertex);
296       }
297     }
298
299     // When all edges of current component of connectivity are processed,
300     // we should repeat procedure for finding initial vertex in the remaining
301     if (!aMapVE.IsEmpty() && !aMapVE.Contains(aNextVertex)) {
302       aProcVertexes.clear();
303       aProcEdges.clear();
304
305       aStartVertex = findStartVertex(aMapVE, aDirX, aDirY);
306       aProcVertexes.push_back(aStartVertex);
307       aNextVertex = aStartVertex;
308       aNextDir = aDirY.Reversed();
309       aCurNorm = aNorm.Reversed();
310     }
311
312     aCurVertex = aNextVertex;
313     aCurDir = aNextDir;
314   }
315
316   if (theResultFaces.size() > 1)
317     fixIntersections(theResultFaces);
318 }
319
320 void GeomAlgoAPI_SketchBuilder::fixIntersections(
321     std::list<boost::shared_ptr<GeomAPI_Shape> >& theFaces)
322 {
323   BRepClass_FaceClassifier aClassifier;
324
325   std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator anIter1 = theFaces.begin();
326   std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator anIter2;
327   for (; anIter1 != theFaces.end(); anIter1++) {
328     anIter2 = anIter1;
329     for (++anIter2; anIter2 != theFaces.end(); anIter2++) {
330       const TopoDS_Face& aF1 = (*anIter1)->impl<TopoDS_Face>();
331       assert(aF1.ShapeType() == TopAbs_FACE);  // all items in result list should be faces
332       TopExp_Explorer aVert2((*anIter2)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
333       for (; aVert2.More(); aVert2.Next()) {
334         const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current();
335         aClassifier.Perform(aF1, BRep_Tool::Pnt(aV), tolerance);
336         TopAbs_State aState = aClassifier.State();
337         if (aState != TopAbs_IN && aState != TopAbs_ON)
338           break;
339       }
340       if (aVert2.More()) {  // second shape is not inside first, change the shapes order and repeat comparision
341         const TopoDS_Face& aF2 = (*anIter2)->impl<TopoDS_Face>();
342         assert(aF2.ShapeType() == TopAbs_FACE);  // all items in result list should be faces
343         TopExp_Explorer aVert1((*anIter1)->impl<TopoDS_Shape>(), TopAbs_VERTEX);
344         for (; aVert1.More(); aVert1.Next()) {
345           const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current();
346           aClassifier.Perform(aF2, BRep_Tool::Pnt(aV), tolerance);
347           TopAbs_State aState = aClassifier.State();
348           if (aState != TopAbs_IN && aState != TopAbs_ON)
349             break;
350         }
351         if (!aVert1.More()) {  // first shape should be cut from the second
352           BRepAlgoAPI_Cut aCut((*anIter2)->impl<TopoDS_Shape>(), (*anIter1)->impl<TopoDS_Shape>());
353           aCut.Build();
354           TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE);
355           bool isFirstFace = true;
356           for (anExp.Next(); anExp.More(); anExp.Next()) {
357             if (anExp.Current().ShapeType() != TopAbs_FACE) continue;
358             if (isFirstFace) {
359               (*anIter2)->setImpl(new TopoDS_Shape(anExp.Current()));
360               isFirstFace = false;
361             } else {
362               boost::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
363               aShape->setImpl(new TopoDS_Shape(anExp.Current()));
364               theFaces.push_back(aShape);
365             }
366           }
367         }
368       } else {  // second shape should be cut from the first
369         BRepAlgoAPI_Cut aCut((*anIter1)->impl<TopoDS_Shape>(), (*anIter2)->impl<TopoDS_Shape>());
370         aCut.Build();
371         TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE);
372         bool isFirstFace = true;
373         for (anExp.Next(); anExp.More(); anExp.Next()) {
374           if (anExp.Current().ShapeType() != TopAbs_FACE) continue;
375           if (isFirstFace) {
376             (*anIter1)->setImpl(new TopoDS_Shape(anExp.Current()));
377             isFirstFace = false;
378           } else {
379             boost::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
380             aShape->setImpl(new TopoDS_Shape(anExp.Current()));
381             theFaces.push_back(aShape);
382           }
383         }
384       }
385     }
386   }
387 }
388
389 // =================== Auxiliary functions ====================================
390 const TopoDS_Vertex& findStartVertex(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE,
391                                     const gp_Dir& theDirX, const gp_Dir& theDirY)
392 {
393   int aStartVertexInd = 1;
394   double aMaxX = -DBL_MAX;
395   double aMaxY = -DBL_MAX;
396   int aNbVert = theMapVE.Extent();
397   for (int i = 1; i <= aNbVert; i++) {
398     const TopoDS_Vertex& aV = (const TopoDS_Vertex&) theMapVE.FindKey(i);
399     const gp_Pnt& aVertPnt = BRep_Tool::Pnt(aV);
400
401     double aX = aVertPnt.XYZ().Dot(theDirX.XYZ());
402     double aY = aVertPnt.XYZ().Dot(theDirY.XYZ());
403     if ((aX > aMaxX || (fabs(aX - aMaxX) < tolerance && aY > aMaxY))
404         && theMapVE.FindFromIndex(i).Extent() > 1) {
405       aMaxX = aX;
406       aMaxY = aY;
407       aStartVertexInd = i;
408     }
409   }
410   return static_cast<const TopoDS_Vertex&>(theMapVE.FindKey(aStartVertexInd));
411 }
412
413 void findNextVertex(const TopoDS_Vertex& theStartVertex,
414                     const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
415                     const gp_Dir& theStartDir, const gp_Dir& theNormal, TopoDS_Vertex& theNextVertex,
416                     TopoDS_Edge& theNextEdge, gp_Dir& theNextDir)
417 {
418   const BOPCol_ListOfShape& anEdgesList = theVertexEdgeMap.FindFromKey(theStartVertex);
419   BOPCol_ListOfShape::Iterator aEdIter(anEdgesList);
420   double aBestEdgeProj = DBL_MAX;
421   for (; aEdIter.More(); aEdIter.Next()) {
422     const TopoDS_Edge& anEdge = static_cast<const TopoDS_Edge&>(aEdIter.Value());
423     gp_Dir aTang = getOuterEdgeDirection(anEdge, theStartVertex);
424     aTang.Reverse();
425
426     // The projection is normalized in segment (-1, 1),
427     // where (-1, 0] corresponds to the angles (pi/2, 0] between theStartDir and aTang
428     // and [0, 1) corresponds to the angles [0, -pi/2)
429     double aProj = (aTang.Dot(theStartDir) - 1.0) * 0.5;
430     if (fabs(fabs(aProj) - 1) < tolerance)
431       continue;
432     if (theStartDir.DotCross(aTang, theNormal) < tolerance)
433       aProj *= -1.0;
434
435     if (aProj < aBestEdgeProj) {
436       aBestEdgeProj = aProj;
437       theNextEdge = anEdge;
438       TopExp_Explorer aVertExp(theNextEdge, TopAbs_VERTEX);
439       for (; aVertExp.More(); aVertExp.Next())
440         if (!aVertExp.Current().IsSame(theStartVertex)) {
441           theNextVertex = static_cast<const TopoDS_Vertex&>(aVertExp.Current());
442           theNextDir = getOuterEdgeDirection(anEdge, theNextVertex);
443           break;
444         }
445       if (!aVertExp.More()) {  // This edge is a full circle
446         TopoDS_Vertex aV1, aV2;
447         TopExp::Vertices(theNextEdge, aV1, aV2);
448         if (aV1.Orientation() == theStartVertex.Orientation())
449           theNextVertex = aV2;
450         else
451           theNextVertex = aV1;
452         theNextDir = getOuterEdgeDirection(anEdge, theNextVertex);
453       }
454     }
455   }
456 }
457
458 static void addEdgeToWire(const TopoDS_Edge& theEdge, const BRep_Builder& theBuilder,
459                           TopoDS_Shape& theSpliceVertex, TopoDS_Wire& theWire)
460 {
461   TopoDS_Edge anEdge = theEdge;
462   bool isCurVertChanged = false;
463   TopoDS_Shape aCurVertChanged;
464
465   TopExp_Explorer aVertExp(theEdge, TopAbs_VERTEX);
466   for (; aVertExp.More(); aVertExp.Next()) {
467     const TopoDS_Shape& aVertex = aVertExp.Current();
468     if (aVertex.IsSame(theSpliceVertex)
469         && aVertex.Orientation() != theEdge.Orientation()) {  // Current vertex is the last for the edge, so its orientation is wrong, need to revert the edge
470       anEdge.Reverse();
471       break;
472     }
473     if (!aVertex.IsSame(theSpliceVertex)) {
474       aCurVertChanged = aVertex;
475       isCurVertChanged = true;
476     }
477   }
478   theSpliceVertex = isCurVertChanged ? aCurVertChanged : aVertExp.Current();
479
480   theBuilder.Add(theWire, anEdge);
481 }
482
483 void createFace(const TopoDS_Vertex& theStartVertex,
484                 const std::list<TopoDS_Edge>::iterator& theStartEdge,
485                 const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
486                 const gp_Pln& thePlane,
487                 TopoDS_Face& theResFace)
488 {
489   TopoDS_Wire aResWire;
490   BRep_Builder aBuilder;
491   aBuilder.MakeWire(aResWire);
492
493   TopoDS_Vertex aCurVertex = theStartVertex;
494   std::list<TopoDS_Edge>::const_iterator anEdgeIter = theStartEdge;
495   for (; anEdgeIter != theEndOfEdges; anEdgeIter++) {
496     if (!anEdgeIter->IsNull())
497       addEdgeToWire(*anEdgeIter, aBuilder, aCurVertex, aResWire);
498   }
499
500   BRepBuilderAPI_MakeFace aFaceBuilder(thePlane, aResWire);
501   if (aFaceBuilder.Error() == BRepBuilderAPI_FaceDone)
502     theResFace = aFaceBuilder.Face();
503 }
504
505 void createWireList(const TopoDS_Vertex& theStartVertex,
506                     const std::list<TopoDS_Edge>::iterator& theStartEdge,
507                     const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
508                     const std::set<TopoDS_Edge*>& theEdgesInLoops,
509                     std::list<TopoDS_Wire>& theResWires)
510 {
511   BRep_Builder aBuilder;
512   bool needNewWire = true;
513   TopoDS_Vertex aCurVertex = theStartVertex;
514
515   std::list<TopoDS_Edge>::iterator anIter = theStartEdge;
516   while (anIter != theEndOfEdges) {
517     while (anIter != theEndOfEdges && needNewWire && theEdgesInLoops.count(&(*anIter)) != 0) {
518       TopExp_Explorer aVertExp(*anIter, TopAbs_VERTEX);
519       for (; aVertExp.More(); aVertExp.Next())
520         if (!aVertExp.Current().IsSame(aCurVertex)) {
521           aCurVertex = static_cast<const TopoDS_Vertex&>(aVertExp.Current());
522           break;
523         }
524       anIter++;
525     }
526     if (anIter == theEndOfEdges)
527       break;
528
529     if (needNewWire) {  // The new wire should be created
530       TopoDS_Wire aWire;
531       aBuilder.MakeWire(aWire);
532       theResWires.push_back(aWire);
533       needNewWire = false;
534     } else if (theEdgesInLoops.count(&(*anIter)) != 0) {  // There was found the edge already used in loop.
535                                                           // Current wire should be released and new one should started
536       needNewWire = true;
537       continue;
538     }
539
540     addEdgeToWire(*anIter, aBuilder, aCurVertex, theResWires.back());
541     anIter++;
542   }
543 }
544
545 gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& theVertex)
546 {
547   gp_Pnt aVertexPnt = BRep_Tool::Pnt(theVertex);
548
549   // Convert the edge to the curve to calculate the tangency.
550   // There should be only one curve in the edge.
551   double aFirst, aLast;
552   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
553
554   gp_Pnt aPnt;
555   gp_Vec aTang;
556   // A direction is determined not in the boundary points but in the points with small shift.
557   // It was done to avoid tangency between circle and other edge in the shared vertex.
558   aCurve->D1(aFirst + shift > aLast ? aFirst : aFirst + shift, aPnt, aTang);
559   aCurve->D0(aFirst, aPnt);
560   if (aVertexPnt.IsEqual(aPnt, tolerance))
561     return gp_Dir(aTang.Reversed());
562
563   aCurve->D1(aLast - shift < aFirst ? aLast : aLast - shift, aPnt, aTang);
564   return gp_Dir(aTang);
565 }
566
567 void removeWasteEdges(std::list<TopoDS_Vertex>::iterator& theStartVertex,
568                       std::list<TopoDS_Edge>::iterator& theStartEdge,
569                       const std::list<TopoDS_Vertex>::iterator& theEndOfVertexes,
570                       const std::list<TopoDS_Edge>::iterator& theEndOfEdges,
571                       BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE)
572 {
573   bool isVertStep = true;
574   while (theStartVertex != theEndOfVertexes && theStartEdge != theEndOfEdges) {
575     BOPCol_ListOfShape& aBunch = theMapVE.ChangeFromKey(*theStartVertex);
576     BOPCol_ListOfShape::Iterator anApprEdge(aBunch);
577     for (; anApprEdge.More(); anApprEdge.Next())
578       if (anApprEdge.Value().IsSame(*theStartEdge))
579         break;
580     if (anApprEdge.More())
581       aBunch.Remove(anApprEdge);
582
583     if (isVertStep)
584       theStartVertex++;
585     else {
586       theStartEdge++;
587       // check current vertex to be a branching point
588       // if so, it will be a new starting point to find a loop
589       if (aBunch.Size() > 1)
590         break;
591     }
592     isVertStep = !isVertStep;
593   }
594
595   // The map of vertex-edges may be changed
596   BOPCol_IndexedDataMapOfShapeListOfShape aMapVECopy;
597   BOPCol_IndexedDataMapOfShapeListOfShape::Iterator aMapIter(theMapVE);
598   for (int ind = 1; aMapIter.More(); aMapIter.Next(), ind++)
599     if (!aMapIter.Value().IsEmpty())
600       aMapVECopy.Add(theMapVE.FindKey(ind), aMapIter.Value());
601   theMapVE.Clear();
602   theMapVE.Exchange(aMapVECopy);
603 }
604