Salome HOME
Fix compilation errors on Linux
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SketchBuilder.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        GeomAlgoAPI_SketchBuilder.cpp
4 // Created:     02 Jun 2014
5 // Author:      Artem ZHIDKOV
6
7 #include <GeomAlgoAPI_SketchBuilder.h>
8 #include <GeomAPI_PlanarEdges.h>
9
10 #include <BOPAlgo_Builder.hxx>
11 #include <BRep_Builder.hxx>
12 #include <BRepTopAdaptor_FClass2d.hxx>
13 #include <Geom_Plane.hxx>
14 #include <Geom_TrimmedCurve.hxx>
15 #include <Precision.hxx>
16 #include <TopExp.hxx>
17 #include <TopExp_Explorer.hxx>
18 #include <TopoDS.hxx>
19 #include <TopoDS_Edge.hxx>
20 #include <TopTools_ListIteratorOfListOfShape.hxx>
21
22 #include <list>
23 #include <cmath>
24
25
26 static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape)
27 {
28   static const double aTol = Precision::PConfusion();
29
30   TopExp_Explorer anExp(theShape, TopAbs_VERTEX);
31   TopoDS_Vertex aStart = TopoDS::Vertex(anExp.Current());
32   gp_Pnt aStartPnt(BRep_Tool::Pnt(aStart));
33   TopoDS_Vertex aCurrent;
34   gp_Pnt aCurrentPnt;
35
36   for (anExp.Next(); anExp.More(); anExp.Next()) {
37     aCurrent = TopoDS::Vertex(anExp.Current());
38     aCurrentPnt = BRep_Tool::Pnt(aCurrent);
39     if ((aCurrentPnt.X() > aStartPnt.X() + aTol) ||
40         (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() + aTol) ||
41         (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() - aTol &&
42             aCurrentPnt.Z() > aStartPnt.Z() + aTol)) {
43       aStart = aCurrent;
44       aStartPnt = aCurrentPnt;
45     }
46   }
47   return aStart;
48 }
49
50 static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape,
51     const std::list<std::shared_ptr<GeomAPI_Shape> >& theInitialShapes)
52 {
53   // Try to find edge lying on the one of original edges.
54   // First found edge will be taken as a start edge for the result wire
55   std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theInitialShapes.begin();
56   for (; aFeatIt != theInitialShapes.end(); aFeatIt++) {
57     std::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
58     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
59     if (anEdge.ShapeType() != TopAbs_EDGE)
60       continue;
61
62     double aFirst, aLast;
63     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
64     if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
65       aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
66
67     TopExp_Explorer anExp(theShape, TopAbs_EDGE);
68     for (; anExp.More(); anExp.Next()) {
69       const TopoDS_Edge& aShapeEdge = TopoDS::Edge(anExp.Current());
70       double aF, aL;
71       Handle(Geom_Curve) aShapeCurve = BRep_Tool::Curve(aShapeEdge, aF, aL);
72       if (aShapeCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
73         aShapeCurve = Handle(Geom_TrimmedCurve)::DownCast(aShapeCurve)->BasisCurve();
74
75       if (aCurve != aShapeCurve)
76         continue;
77
78       // the edge is found, search vertex
79       TopoDS_Vertex aV1, aV2;
80       TopExp::Vertices(aShapeEdge, aV1, aV2);
81       return fabs(aF - aFirst) <= fabs(aL - aFirst) ? aV1 : aV2;
82     }
83   }
84
85   // start vertex is not found, use algorithm to search vertex with the greatest coordinates
86   return findStartVertex(theShape);
87 }
88
89 void GeomAlgoAPI_SketchBuilder::createFaces(
90     const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
91     const std::shared_ptr<GeomAPI_Dir>& theDirX,
92     const std::shared_ptr<GeomAPI_Dir>& theNorm,
93     const std::list<std::shared_ptr<GeomAPI_Shape> >& theFeatures,
94     std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
95 {
96   if (theFeatures.empty())
97     return;
98
99   BRep_Builder aBuilder;
100   // Planar face, where the sketch was built
101   Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>()));
102   TopoDS_Face aPlnFace;
103   aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion());
104
105   // Use General Fuse algorithm to prepare all subfaces, bounded by given list of edges
106   BOPAlgo_Builder aBB;
107   aBB.AddArgument(aPlnFace);
108
109   BOPCol_ListOfShape anEdges;
110   BOPCol_ListIteratorOfListOfShape aShapeIt;
111   std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
112   for (; aFeatIt != theFeatures.end(); aFeatIt++) {
113     std::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
114     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
115     if (anEdge.ShapeType() == TopAbs_EDGE)
116       aBB.AddArgument(anEdge);
117   }
118   aBB.Perform();
119   if (aBB.ErrorStatus())
120     return;
121
122   // Collect faces
123   const TopTools_ListOfShape& anAreas = aBB.Modified(aPlnFace);
124   TopTools_ListIteratorOfListOfShape anIt(anAreas);
125   for (; anIt.More(); anIt.Next()) {
126     TopoDS_Face aFace = TopoDS::Face(anIt.Value());
127     // avoid infinite faces
128     BRepTopAdaptor_FClass2d aFClass(aFace, Precision::Confusion());
129     if (aFClass.PerformInfinitePoint() == TopAbs_IN)
130       continue;
131
132     // rebuild face
133     TopoDS_Face aNewFace;
134     aBuilder.MakeFace(aNewFace, aPlane, Precision::Confusion());
135
136     // iterate on wires
137     TopExp_Explorer aWireExp(aFace, TopAbs_WIRE);
138     for (; aWireExp.More(); aWireExp.Next()) {
139       TopoDS_Wire aWire = TopoDS::Wire(aWireExp.Current());
140
141       // to make faces equal on different platforms, we will find
142       // a vertex lying on an edge with the lowest index in the list of initial edges
143       TopoDS_Vertex aStartVertex = findStartVertex(aWire, theFeatures);
144
145       TopoDS_Wire aNewWire;
146       aBuilder.MakeWire(aNewWire);
147       std::list<TopoDS_Edge> aSkippedEdges;
148       bool aStartFound = false;
149
150       // remove internal edges from faces and make wire start from found vertex
151       TopExp_Explorer anExp(aWire, TopAbs_EDGE);
152       for (; anExp.More(); anExp.Next()) {
153         if (anExp.Current().Orientation() == TopAbs_INTERNAL)
154           continue;
155         if (!aStartFound) {
156           const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
157           TopoDS_Vertex aV1, aV2;
158           TopExp::Vertices(anEdge, aV1, aV2, Standard_True);
159           if (aV1.IsSame(aStartVertex) == Standard_True)
160             aStartFound = true;
161           else
162             aSkippedEdges.push_back(anEdge);
163         }
164         if (aStartFound)
165           aBuilder.Add(aNewWire, anExp.Current());
166       }
167       // add skipped edges to the end of wire
168       std::list<TopoDS_Edge>::const_iterator aSkIt = aSkippedEdges.begin();
169       for (; aSkIt != aSkippedEdges.end(); ++aSkIt)
170         aBuilder.Add(aNewWire, *aSkIt);
171
172       // check the wire is empty
173       anExp.Init(aNewWire, TopAbs_EDGE);
174       if (anExp.More())
175         aBuilder.Add(aNewFace, aNewWire);
176     }
177
178     // store face
179     aFace = aNewFace;
180     std::shared_ptr<GeomAPI_Shape> aResFace(new GeomAPI_Shape);
181     aResFace->setImpl(new TopoDS_Face(aFace));
182     theResultFaces.push_back(aResFace);
183   }
184 }
185
186 void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
187                                             const std::shared_ptr<GeomAPI_Dir>& theDirX,
188                                             const std::shared_ptr<GeomAPI_Dir>& theNorm,
189                                             const std::shared_ptr<GeomAPI_Shape>& theWire,
190                                 std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
191 {
192   std::shared_ptr<GeomAPI_PlanarEdges> aWire =
193     std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theWire);
194   if(aWire) {
195     // Filter wires, return only faces.
196     createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces);
197   } else { // it may be only one circle
198     std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(theWire);
199     if (anEdge) {
200       std::list<std::shared_ptr<GeomAPI_Shape> > aList;
201       aList.push_back(anEdge);
202       createFaces(theOrigin, theDirX, theNorm, aList, theResultFaces);
203     }
204   }
205 }