Salome HOME
Revert "CEA : Lot2 - Normal to a face"
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Fillet1D.cpp
1 // Copyright (C) 2020-2021  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
18 //
19
20 #include <GeomAlgoAPI_Fillet1D.h>
21
22 #include <GeomAlgoAPI_Copy.h>
23 #include <GeomAlgoAPI_MapShapesAndAncestors.h>
24 #include <GeomAlgoAPI_ShapeTools.h>
25
26 #include <GeomAPI_Edge.h>
27 #include <GeomAPI_Pln.h>
28 #include <GeomAPI_Pnt.h>
29 #include <GeomAPI_Wire.h>
30 #include <GeomAPI_WireExplorer.h>
31
32 #include <GEOMImpl_Fillet1d.hxx>
33
34 #include <BRep_Builder.hxx>
35 #include <BRepTools_WireExplorer.hxx>
36 #include <ShapeFix_Wire.hxx>
37 #include <TopoDS.hxx>
38 #include <TopoDS_Wire.hxx>
39
40 static GeomShapePtr convert(const TopoDS_Shape& theShape)
41 {
42   GeomShapePtr aNewShape(new GeomAPI_Shape);
43   aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
44   return aNewShape;
45 }
46
47 static void substituteNewEdge(GeomEdgePtr theEdge,
48     std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>& theMap)
49 {
50   std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>::iterator anIt = theMap.begin();
51   for (; anIt != theMap.end(); ++anIt) {
52     for (ListOfShape::iterator aEIt = anIt->second.begin(); aEIt != anIt->second.end(); ++aEIt)
53       if (theEdge->isEqual(*aEIt)) {
54         // substitute edge and stop iteration
55         *aEIt = theEdge;
56         return;
57       }
58   }
59 }
60
61
62 GeomAlgoAPI_Fillet1D::GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
63                                            const ListOfShape&  theFilletVertices,
64                                            const double        theFilletRadius)
65 {
66   build(theBaseWire, theFilletVertices, theFilletRadius);
67 }
68
69 void GeomAlgoAPI_Fillet1D::build(const GeomShapePtr& theBaseWire,
70                                  const ListOfShape&  theFilletVertices,
71                                  const double        theRadius)
72 {
73   if (!theBaseWire || theFilletVertices.empty() || theRadius < 0.)
74     return;
75
76   myFailedVertices.clear();
77   // store all edges of a base wire as modified, because they will be rebuild by ShapeFix
78   for (GeomAPI_WireExplorer aWExp(theBaseWire->wire()); aWExp.more(); aWExp.next()) {
79     GeomShapePtr aCurrent = aWExp.current();
80     GeomAlgoAPI_Copy aCopy(aCurrent);
81     myModified[aCurrent].push_back(aCopy.shape());
82   }
83
84   GeomAlgoAPI_MapShapesAndAncestors aMapVE(theBaseWire, GeomAPI_Shape::VERTEX,
85                                                         GeomAPI_Shape::EDGE);
86
87   for (ListOfShape::const_iterator aVIt = theFilletVertices.begin();
88        aVIt != theFilletVertices.end(); ++aVIt) {
89     // get edges to perform fillet
90     MapShapeToShapes::const_iterator aVE = aMapVE.map().find(*aVIt);
91     if (aVE == aMapVE.map().end())
92       continue;
93     ListOfShape anEdges;
94     for (SetOfShapes::const_iterator aEIt = aVE->second.begin();
95          aEIt != aVE->second.end(); ++aEIt) {
96       ListOfShape aNewEdges;
97       modified(*aEIt, aNewEdges);
98       if (aNewEdges.empty())
99         anEdges.push_back(*aEIt);
100       else
101         anEdges.insert(anEdges.end(), aNewEdges.begin(), aNewEdges.end());
102     }
103
104     GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
105     if (!aPlane)
106       return; // non-planar edges
107
108     TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.front()->impl<TopoDS_Shape>());
109     TopoDS_Edge anEdge2 = TopoDS::Edge(anEdges.back()->impl<TopoDS_Shape>());
110
111     // create fillet builder
112     GEOMImpl_Fillet1d aFilletBuilder(anEdge1, anEdge2, aPlane->impl<gp_Pln>());
113     bool isOk = aFilletBuilder.Perform(theRadius);
114     TopoDS_Edge aFilletEdge;
115     if (isOk) {
116       GeomPointPtr aPoint = aVE->first->vertex()->point();
117       aFilletEdge = aFilletBuilder.Result(aPoint->impl<gp_Pnt>(), anEdge1, anEdge2);
118       isOk = !aFilletEdge.IsNull();
119     }
120
121     if (!isOk) {
122       // something gone wrong and the fillet edge is not constructed,
123       // just store the failed vertex and continue
124       myFailedVertices.push_back(*aVIt);
125       continue;
126     }
127
128     // store modified shapes
129     myGenerated[aVE->first].push_back(convert(aFilletEdge));
130     SetOfShapes::const_iterator aEIt = aVE->second.begin();
131     myModified[*aEIt].clear();
132     myModified[*aEIt].push_back(convert(anEdge1));
133     myModified[*(++aEIt)].clear();
134     myModified[*aEIt].push_back(convert(anEdge2));
135   }
136
137   // compose a new wire
138   TopoDS_Wire aNewWire;
139   BRep_Builder aBuilder;
140   aBuilder.MakeWire(aNewWire);
141   GeomWirePtr aBaseWire = theBaseWire->wire();
142   GeomAPI_WireExplorer aWExp(aBaseWire);
143   GeomShapePtr aBaseFirstEdge = aWExp.current();
144   for (; aWExp.more(); aWExp.next()) {
145     ListOfShape aNewEdges;
146     modified(aWExp.current(), aNewEdges);
147     if (aNewEdges.empty())
148       aNewEdges.push_back(aWExp.current());
149     for (ListOfShape::iterator anIt = aNewEdges.begin(); anIt != aNewEdges.end(); ++anIt)
150       aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
151   }
152   for (MapModified::iterator aGenIt = myGenerated.begin(); aGenIt != myGenerated.end(); ++aGenIt) {
153     for (ListOfShape::iterator anIt = aGenIt->second.begin(); anIt != aGenIt->second.end(); ++anIt)
154       aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
155   }
156   // fix the wire connectivity
157   ShapeFix_Wire aFixWire;
158   aFixWire.Load(aNewWire);
159   aFixWire.ClosedWireMode() = aBaseWire->isClosed();
160   aFixWire.FixReorder();
161   aNewWire = aFixWire.WireAPIMake();
162   if (aNewWire.IsNull()) {
163     myFailedVertices = theFilletVertices;
164     return;
165   }
166
167   // update the map of modified shapes, because the edges are changed by ShapeFix
168   for (BRepTools_WireExplorer anExp(aNewWire); anExp.More(); anExp.Next()) {
169     GeomEdgePtr aCurrent(new GeomAPI_Edge);
170     aCurrent->setImpl(new TopoDS_Edge(anExp.Current()));
171     substituteNewEdge(aCurrent, myGenerated);
172     substituteNewEdge(aCurrent, myModified);
173   }
174
175   // rebuild the wire once again to get the first edge of fillet wire correspond
176   // to the first edge of original wire
177   TopoDS_Edge aFirstEdge = TopoDS::Edge(aBaseFirstEdge->impl<TopoDS_Shape>());
178   ListOfShape aNewEdges;
179   modified(aBaseFirstEdge, aNewEdges);
180   if (!aNewEdges.empty())
181     aFirstEdge = TopoDS::Edge(aNewEdges.front()->impl<TopoDS_Shape>());
182   TopTools_ListOfShape aKeptForEnd;
183   BRepTools_WireExplorer aNewExp(aNewWire);
184   for (; aNewExp.More(); aNewExp.Next())
185     if (aNewExp.Current().IsEqual(aFirstEdge))
186       break;
187   if (aNewExp.More()) {
188     TopoDS_Wire aReorderedWire;
189     aBuilder.MakeWire(aReorderedWire);
190     for (; aNewExp.More(); aNewExp.Next())
191       aBuilder.Add(aReorderedWire, aNewExp.Current());
192     for (aNewExp.Init(aNewWire); aNewExp.More(); aNewExp.Next()) {
193       if (aNewExp.Current().IsEqual(aFirstEdge))
194         break;
195       aBuilder.Add(aReorderedWire, aNewExp.Current());
196     }
197     aNewWire = aReorderedWire;
198   }
199
200   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
201   aShape->setImpl(new TopoDS_Shape(aNewWire));
202   myModified[theBaseWire].push_back(aShape);
203
204   setShape(aShape);
205   setDone(myFailedVertices.empty());
206 }
207
208 void GeomAlgoAPI_Fillet1D::generated(const GeomShapePtr theOldShape,
209                                      ListOfShape& theNewShapes)
210 {
211   MapModified::iterator aFound = myGenerated.find(theOldShape);
212   if (aFound != myGenerated.end())
213     theNewShapes = aFound->second;
214 }
215
216 void GeomAlgoAPI_Fillet1D::modified(const GeomShapePtr theOldShape,
217                                      ListOfShape& theNewShapes)
218 {
219   MapModified::iterator aFound = myModified.find(theOldShape);
220   if (aFound != myModified.end())
221     theNewShapes = aFound->second;
222 }