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