Salome HOME
Issue #1834: Fix length of lines
[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 <Precision.hxx>
15 #include <TopExp.hxx>
16 #include <TopExp_Explorer.hxx>
17 #include <TopoDS.hxx>
18 #include <TopoDS_Edge.hxx>
19 #include <TopTools_ListIteratorOfListOfShape.hxx>
20
21 #include <list>
22 #include <cmath>
23
24
25 static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape)
26 {
27   static const double aTol = Precision::PConfusion();
28
29   TopExp_Explorer anExp(theShape, TopAbs_VERTEX);
30   TopoDS_Vertex aStart = TopoDS::Vertex(anExp.Current());
31   gp_Pnt aStartPnt(BRep_Tool::Pnt(aStart));
32   TopoDS_Vertex aCurrent;
33   gp_Pnt aCurrentPnt;
34
35   for (anExp.Next(); anExp.More(); anExp.Next()) {
36     aCurrent = TopoDS::Vertex(anExp.Current());
37     aCurrentPnt = BRep_Tool::Pnt(aCurrent);
38     if ((aCurrentPnt.X() > aStartPnt.X() + aTol) ||
39         (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() + aTol) ||
40         (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() - aTol &&
41             aCurrentPnt.Z() > aStartPnt.Z() + aTol)) {
42       aStart = aCurrent;
43       aStartPnt = aCurrentPnt;
44     }
45   }
46   return aStart;
47 }
48
49 void GeomAlgoAPI_SketchBuilder::createFaces(
50     const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
51     const std::shared_ptr<GeomAPI_Dir>& theDirX,
52     const std::shared_ptr<GeomAPI_Dir>& theNorm,
53     const std::list<std::shared_ptr<GeomAPI_Shape> >& theFeatures,
54     std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
55 {
56   if (theFeatures.empty())
57     return;
58
59   BRep_Builder aBuilder;
60   // Planar face, where the sketch was built
61   Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>()));
62   TopoDS_Face aPlnFace;
63   aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion());
64
65   // Use General Fuse algorithm to prepare all subfaces, bounded by given list of edges
66   BOPAlgo_Builder aBB;
67   aBB.AddArgument(aPlnFace);
68
69   BOPCol_ListOfShape anEdges;
70   BOPCol_ListIteratorOfListOfShape aShapeIt;
71   std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
72   for (; aFeatIt != theFeatures.end(); aFeatIt++) {
73     std::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
74     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
75     if (anEdge.ShapeType() == TopAbs_EDGE)
76       aBB.AddArgument(anEdge);
77   }
78   aBB.Perform();
79   if (aBB.ErrorStatus())
80     return;
81
82   // Collect faces
83   const TopTools_ListOfShape& anAreas = aBB.Modified(aPlnFace);
84   TopTools_ListIteratorOfListOfShape anIt(anAreas);
85   for (; anIt.More(); anIt.Next()) {
86     TopoDS_Face aFace = TopoDS::Face(anIt.Value());
87     // avoid infinite faces
88     BRepTopAdaptor_FClass2d aFClass(aFace, Precision::Confusion());
89     if (aFClass.PerformInfinitePoint() == TopAbs_IN)
90       continue;
91
92     // rebuild face
93     TopoDS_Face aNewFace;
94     aBuilder.MakeFace(aNewFace, aPlane, Precision::Confusion());
95
96     // iterate on wires
97     TopExp_Explorer aWireExp(aFace, TopAbs_WIRE);
98     for (; aWireExp.More(); aWireExp.Next()) {
99       TopoDS_Wire aWire = TopoDS::Wire(aWireExp.Current());
100
101       // to make faces equal on different platforms, we will find
102       // a vertex with greater coordinates and start wire from it
103       TopoDS_Vertex aStartVertex = findStartVertex(aWire);
104
105       TopoDS_Wire aNewWire;
106       aBuilder.MakeWire(aNewWire);
107       std::list<TopoDS_Edge> aSkippedEdges;
108       bool aStartFound = false;
109
110       // remove internal edges from faces and make wire start from found vertex
111       TopExp_Explorer anExp(aWire, TopAbs_EDGE);
112       for (; anExp.More(); anExp.Next()) {
113         if (anExp.Current().Orientation() == TopAbs_INTERNAL)
114           continue;
115         if (!aStartFound) {
116           const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
117           TopoDS_Vertex aV1, aV2;
118           TopExp::Vertices(anEdge, aV1, aV2, Standard_True);
119           if (aV1.IsSame(aStartVertex) == Standard_True)
120             aStartFound = true;
121           else
122             aSkippedEdges.push_back(anEdge);
123         }
124         if (aStartFound)
125           aBuilder.Add(aNewWire, anExp.Current());
126       }
127       // add skipped edges to the end of wire
128       std::list<TopoDS_Edge>::const_iterator aSkIt = aSkippedEdges.begin();
129       for (; aSkIt != aSkippedEdges.end(); ++aSkIt)
130         aBuilder.Add(aNewWire, *aSkIt);
131
132       // check the wire is empty
133       anExp.Init(aNewWire, TopAbs_EDGE);
134       if (anExp.More())
135         aBuilder.Add(aNewFace, aNewWire);
136     }
137
138     // store face
139     aFace = aNewFace;
140     std::shared_ptr<GeomAPI_Shape> aResFace(new GeomAPI_Shape);
141     aResFace->setImpl(new TopoDS_Face(aFace));
142     theResultFaces.push_back(aResFace);
143   }
144 }
145
146 void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
147                                             const std::shared_ptr<GeomAPI_Dir>& theDirX,
148                                             const std::shared_ptr<GeomAPI_Dir>& theNorm,
149                                             const std::shared_ptr<GeomAPI_Shape>& theWire,
150                                 std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
151 {
152   std::shared_ptr<GeomAPI_PlanarEdges> aWire = 
153     std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theWire);
154   if(aWire) {
155     // Filter wires, return only faces.
156     createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces);
157   } else { // it may be only one circle
158     std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(theWire);
159     if (anEdge) {
160       std::list<std::shared_ptr<GeomAPI_Shape> > aList;
161       aList.push_back(anEdge);
162       createFaces(theOrigin, theDirX, theNorm, aList, theResultFaces);
163     }
164   }
165 }