1 // Copyright (C) 2020-2022 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <GeomAlgoAPI_Fillet1D.h>
22 #include <GeomAlgoAPI_Copy.h>
23 #include <GeomAlgoAPI_MapShapesAndAncestors.h>
24 #include <GeomAlgoAPI_ShapeTools.h>
25 #include <GeomAlgoAPI_CompoundBuilder.h>
27 #include <GeomAPI_Edge.h>
28 #include <GeomAPI_Pln.h>
29 #include <GeomAPI_Pnt.h>
30 #include <GeomAPI_Wire.h>
31 #include <GeomAPI_WireExplorer.h>
32 #include <GeomAPI_ShapeIterator.h>
34 #include <GEOMImpl_Fillet1d.hxx>
36 #include <BRep_Builder.hxx>
37 #include <BRepTools_WireExplorer.hxx>
38 #include <ShapeFix_Wire.hxx>
40 #include <TopoDS_Wire.hxx>
42 static GeomShapePtr convert(const TopoDS_Shape& theShape)
44 GeomShapePtr aNewShape(new GeomAPI_Shape);
45 aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
49 static void substituteNewEdge(GeomEdgePtr theEdge,
50 std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>& theMap)
52 std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>::iterator anIt = theMap.begin();
53 for (; anIt != theMap.end(); ++anIt) {
54 for (ListOfShape::iterator aEIt = anIt->second.begin(); aEIt != anIt->second.end(); ++aEIt)
55 if (theEdge->isEqual(*aEIt)) {
56 // substitute edge and stop iteration
64 GeomAlgoAPI_Fillet1D::GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
65 const ListOfShape& theFilletVertices,
66 const double theFilletRadius)
68 build(theBaseWire, theFilletVertices, theFilletRadius);
71 void GeomAlgoAPI_Fillet1D::build(const GeomShapePtr& theBaseShape,
72 const ListOfShape& theFilletVertices,
73 const double theRadius)
75 if (!theBaseShape.get() || theFilletVertices.empty() || theRadius < 0.)
78 myFailedVertices.clear();
81 if (theBaseShape->isWire())
82 aShape = buildWire(theBaseShape, theFilletVertices, theRadius);
83 else if (theBaseShape->isCompound()) {
84 std::list<GeomShapePtr> aShapes;
85 for (GeomAPI_ShapeIterator it (theBaseShape); it.more(); it.next()) {
86 GeomShapePtr aSubShape = it.current();
87 if (aSubShape->isWire()) {
88 // get only fillet vertices of current wire
89 ListOfShape aFilletVertices;
90 std::set<GeomShapePtr, GeomAPI_Shape::Comparator> aFilletVerticesSet
91 (theFilletVertices.begin(), theFilletVertices.end());
92 for (GeomAPI_WireExplorer anExp(aSubShape->wire()); anExp.more(); anExp.next()) {
93 if (aFilletVerticesSet.find(anExp.currentVertex()) != aFilletVerticesSet.end())
94 aFilletVertices.push_back(anExp.currentVertex());
97 GeomShapePtr aShape_i = buildWire(aSubShape, aFilletVertices, theRadius);
98 if (aShape_i.get() != NULL)
99 aShapes.push_back(aShape_i);
101 aShapes.push_back(aSubShape);
105 myError = "Input shape for fillet is neither a wire nor a compound of wires";
109 aShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
110 myModified[theBaseShape].push_back(aShape);
113 myError = "Input shape for fillet is neither a wire nor a compound";
118 setDone(myFailedVertices.empty());
121 GeomShapePtr GeomAlgoAPI_Fillet1D::buildWire(const GeomShapePtr& theBaseWire,
122 const ListOfShape& theFilletVertices,
123 const double theRadius)
125 std::shared_ptr<GeomAPI_Shape> aShape;
126 if (!theBaseWire.get() || theFilletVertices.empty() || theRadius < 0.)
129 // store all edges of a base wire as modified, because they will be rebuild by ShapeFix
130 for (GeomAPI_WireExplorer aWExp(theBaseWire->wire()); aWExp.more(); aWExp.next()) {
131 GeomShapePtr aCurrent = aWExp.current();
132 GeomAlgoAPI_Copy aCopy(aCurrent);
133 myModified[aCurrent].push_back(aCopy.shape());
136 GeomAlgoAPI_MapShapesAndAncestors aMapVE(theBaseWire, GeomAPI_Shape::VERTEX,
137 GeomAPI_Shape::EDGE);
139 for (ListOfShape::const_iterator aVIt = theFilletVertices.begin();
140 aVIt != theFilletVertices.end(); ++aVIt) {
141 // get edges to perform fillet
142 MapShapeToShapes::const_iterator aVE = aMapVE.map().find(*aVIt);
143 if (aVE == aMapVE.map().end())
146 for (SetOfShapes::const_iterator aEIt = aVE->second.begin();
147 aEIt != aVE->second.end(); ++aEIt) {
148 ListOfShape aNewEdges;
149 modified(*aEIt, aNewEdges);
150 if (aNewEdges.empty())
151 anEdges.push_back(*aEIt);
153 anEdges.insert(anEdges.end(), aNewEdges.begin(), aNewEdges.end());
156 GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
158 return aShape; // non-planar edges
160 TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.front()->impl<TopoDS_Shape>());
161 TopoDS_Edge anEdge2 = TopoDS::Edge(anEdges.back()->impl<TopoDS_Shape>());
163 // create fillet builder
164 GEOMImpl_Fillet1d aFilletBuilder(anEdge1, anEdge2, aPlane->impl<gp_Pln>());
165 bool isOk = aFilletBuilder.Perform(theRadius);
166 TopoDS_Edge aFilletEdge;
168 GeomPointPtr aPoint = aVE->first->vertex()->point();
169 aFilletEdge = aFilletBuilder.Result(aPoint->impl<gp_Pnt>(), anEdge1, anEdge2);
170 isOk = !aFilletEdge.IsNull();
174 // something gone wrong and the fillet edge is not constructed,
175 // just store the failed vertex and continue
176 myFailedVertices.push_back(*aVIt);
180 // store modified shapes
181 myGenerated[aVE->first].push_back(convert(aFilletEdge));
182 SetOfShapes::const_iterator aEIt = aVE->second.begin();
183 myModified[*aEIt].clear();
184 myModified[*aEIt].push_back(convert(anEdge1));
185 myModified[*(++aEIt)].clear();
186 myModified[*aEIt].push_back(convert(anEdge2));
189 // compose a new wire
190 TopoDS_Wire aNewWire;
191 BRep_Builder aBuilder;
192 aBuilder.MakeWire(aNewWire);
193 GeomWirePtr aBaseWire = theBaseWire->wire();
194 GeomAPI_WireExplorer aWExp(aBaseWire);
195 GeomShapePtr aBaseFirstEdge = aWExp.current();
196 for (; aWExp.more(); aWExp.next()) {
197 ListOfShape aNewEdges;
198 modified(aWExp.current(), aNewEdges);
199 if (aNewEdges.empty())
200 aNewEdges.push_back(aWExp.current());
201 for (ListOfShape::iterator anIt = aNewEdges.begin(); anIt != aNewEdges.end(); ++anIt)
202 aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
204 ListOfShape aNewEdges1;
205 generated(aWExp.currentVertex(), aNewEdges1);
206 for (ListOfShape::iterator anIt = aNewEdges1.begin(); anIt != aNewEdges1.end(); ++anIt)
207 aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
209 // fix the wire connectivity
210 ShapeFix_Wire aFixWire;
211 aFixWire.Load(aNewWire);
212 aFixWire.ClosedWireMode() = aBaseWire->isClosed();
213 aFixWire.FixReorder();
214 aNewWire = aFixWire.WireAPIMake();
215 if (aNewWire.IsNull()) {
216 myFailedVertices = theFilletVertices;
220 // update the map of modified shapes, because the edges are changed by ShapeFix
221 for (BRepTools_WireExplorer anExp(aNewWire); anExp.More(); anExp.Next()) {
222 GeomEdgePtr aCurrent(new GeomAPI_Edge);
223 aCurrent->setImpl(new TopoDS_Edge(anExp.Current()));
224 substituteNewEdge(aCurrent, myGenerated);
225 substituteNewEdge(aCurrent, myModified);
228 // rebuild the wire once again to get the first edge of fillet wire correspond
229 // to the first edge of original wire
230 TopoDS_Edge aFirstEdge = TopoDS::Edge(aBaseFirstEdge->impl<TopoDS_Shape>());
231 ListOfShape aNewEdges;
232 modified(aBaseFirstEdge, aNewEdges);
233 if (!aNewEdges.empty())
234 aFirstEdge = TopoDS::Edge(aNewEdges.front()->impl<TopoDS_Shape>());
235 TopTools_ListOfShape aKeptForEnd;
236 BRepTools_WireExplorer aNewExp(aNewWire);
237 for (; aNewExp.More(); aNewExp.Next())
238 if (aNewExp.Current().IsEqual(aFirstEdge))
240 if (aNewExp.More()) {
241 TopoDS_Wire aReorderedWire;
242 aBuilder.MakeWire(aReorderedWire);
243 for (; aNewExp.More(); aNewExp.Next())
244 aBuilder.Add(aReorderedWire, aNewExp.Current());
245 for (aNewExp.Init(aNewWire); aNewExp.More(); aNewExp.Next()) {
246 if (aNewExp.Current().IsEqual(aFirstEdge))
248 aBuilder.Add(aReorderedWire, aNewExp.Current());
250 aNewWire = aReorderedWire;
253 std::shared_ptr<GeomAPI_Shape> aResShape(new GeomAPI_Shape);
254 aResShape->setImpl(new TopoDS_Shape(aNewWire));
255 myModified[theBaseWire].push_back(aResShape);
259 void GeomAlgoAPI_Fillet1D::generated(const GeomShapePtr theOldShape,
260 ListOfShape& theNewShapes)
262 MapModified::iterator aFound = myGenerated.find(theOldShape);
263 if (aFound != myGenerated.end())
264 theNewShapes = aFound->second;
267 void GeomAlgoAPI_Fillet1D::modified(const GeomShapePtr theOldShape,
268 ListOfShape& theNewShapes)
270 MapModified::iterator aFound = myModified.find(theOldShape);
271 if (aFound != myModified.end())
272 theNewShapes = aFound->second;