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