1 // Copyright (C) 2020 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>
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>
32 #include <GEOMImpl_Fillet1d.hxx>
34 #include <BRep_Builder.hxx>
35 #include <BRepTools_WireExplorer.hxx>
36 #include <ShapeFix_Wire.hxx>
38 #include <TopoDS_Wire.hxx>
40 static GeomShapePtr convert(const TopoDS_Shape& theShape)
42 GeomShapePtr aNewShape(new GeomAPI_Shape);
43 aNewShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(theShape));
47 static void substituteNewEdge(GeomEdgePtr theEdge,
48 std::map<GeomShapePtr, ListOfShape, GeomAPI_Shape::Comparator>& theMap)
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
62 GeomAlgoAPI_Fillet1D::GeomAlgoAPI_Fillet1D(const GeomShapePtr& theBaseWire,
63 const ListOfShape& theFilletVertices,
64 const double theFilletRadius)
66 build(theBaseWire, theFilletVertices, theFilletRadius);
69 void GeomAlgoAPI_Fillet1D::build(const GeomShapePtr& theBaseWire,
70 const ListOfShape& theFilletVertices,
71 const double theRadius)
73 if (!theBaseWire || theFilletVertices.empty() || theRadius < 0.)
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());
84 GeomAlgoAPI_MapShapesAndAncestors aMapVE(theBaseWire, GeomAPI_Shape::VERTEX,
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())
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);
101 anEdges.insert(anEdges.end(), aNewEdges.begin(), aNewEdges.end());
104 GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
106 return; // non-planar edges
108 TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.front()->impl<TopoDS_Shape>());
109 TopoDS_Edge anEdge2 = TopoDS::Edge(anEdges.back()->impl<TopoDS_Shape>());
111 // create fillet builder
112 GEOMImpl_Fillet1d aFilletBuilder(anEdge1, anEdge2, aPlane->impl<gp_Pln>());
113 if (!aFilletBuilder.Perform(theRadius)) {
114 // store the failed vertex and continue
115 myFailedVertices.push_back(*aVIt);
119 GeomPointPtr aPoint = aVE->first->vertex()->point();
120 TopoDS_Edge aFilletEdge = aFilletBuilder.Result(aPoint->impl<gp_Pnt>(), anEdge1, anEdge2);
122 // store modified shapes
123 myGenerated[aVE->first].push_back(convert(aFilletEdge));
124 SetOfShapes::const_iterator aEIt = aVE->second.begin();
125 myModified[*aEIt].clear();
126 myModified[*aEIt].push_back(convert(anEdge1));
127 myModified[*(++aEIt)].clear();
128 myModified[*aEIt].push_back(convert(anEdge2));
131 // compose a new wire
132 TopoDS_Wire aNewWire;
133 BRep_Builder aBuilder;
134 aBuilder.MakeWire(aNewWire);
135 GeomWirePtr aBaseWire = theBaseWire->wire();
136 GeomAPI_WireExplorer aWExp(aBaseWire);
137 GeomShapePtr aBaseFirstEdge = aWExp.current();
138 for (; aWExp.more(); aWExp.next()) {
139 ListOfShape aNewEdges;
140 modified(aWExp.current(), aNewEdges);
141 if (aNewEdges.empty())
142 aNewEdges.push_back(aWExp.current());
143 for (ListOfShape::iterator anIt = aNewEdges.begin(); anIt != aNewEdges.end(); ++anIt)
144 aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
146 for (MapModified::iterator aGenIt = myGenerated.begin(); aGenIt != myGenerated.end(); ++aGenIt) {
147 for (ListOfShape::iterator anIt = aGenIt->second.begin(); anIt != aGenIt->second.end(); ++anIt)
148 aBuilder.Add(aNewWire, TopoDS::Edge((*anIt)->impl<TopoDS_Shape>()));
150 // fix the wire connectivity
151 ShapeFix_Wire aFixWire;
152 aFixWire.Load(aNewWire);
153 aFixWire.ClosedWireMode() = aBaseWire->isClosed();
154 aFixWire.FixReorder();
155 aNewWire = aFixWire.WireAPIMake();
156 if (aNewWire.IsNull()) {
157 myFailedVertices = theFilletVertices;
161 // update the map of modified shapes, because the edges are changed by ShapeFix
162 for (BRepTools_WireExplorer anExp(aNewWire); anExp.More(); anExp.Next()) {
163 GeomEdgePtr aCurrent(new GeomAPI_Edge);
164 aCurrent->setImpl(new TopoDS_Edge(anExp.Current()));
165 substituteNewEdge(aCurrent, myGenerated);
166 substituteNewEdge(aCurrent, myModified);
169 // rebuild the wire once again to get the first edge of fillet wire correspond
170 // to the first edge of original wire
171 TopoDS_Edge aFirstEdge = TopoDS::Edge(aBaseFirstEdge->impl<TopoDS_Shape>());
172 ListOfShape aNewEdges;
173 modified(aBaseFirstEdge, aNewEdges);
174 if (!aNewEdges.empty())
175 aFirstEdge = TopoDS::Edge(aNewEdges.front()->impl<TopoDS_Shape>());
176 TopTools_ListOfShape aKeptForEnd;
177 BRepTools_WireExplorer aNewExp(aNewWire);
178 for (; aNewExp.More(); aNewExp.Next())
179 if (aNewExp.Current().IsEqual(aFirstEdge))
181 if (aNewExp.More()) {
182 TopoDS_Wire aReorderedWire;
183 aBuilder.MakeWire(aReorderedWire);
184 for (; aNewExp.More(); aNewExp.Next())
185 aBuilder.Add(aReorderedWire, aNewExp.Current());
186 for (aNewExp.Init(aNewWire); aNewExp.More(); aNewExp.Next()) {
187 if (aNewExp.Current().IsEqual(aFirstEdge))
189 aBuilder.Add(aReorderedWire, aNewExp.Current());
191 aNewWire = aReorderedWire;
194 std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
195 aShape->setImpl(new TopoDS_Shape(aNewWire));
196 myModified[theBaseWire].push_back(aShape);
199 setDone(myFailedVertices.empty());
202 void GeomAlgoAPI_Fillet1D::generated(const GeomShapePtr theOldShape,
203 ListOfShape& theNewShapes)
205 MapModified::iterator aFound = myGenerated.find(theOldShape);
206 if (aFound != myGenerated.end())
207 theNewShapes = aFound->second;
210 void GeomAlgoAPI_Fillet1D::modified(const GeomShapePtr theOldShape,
211 ListOfShape& theNewShapes)
213 MapModified::iterator aFound = myModified.find(theOldShape);
214 if (aFound != myModified.end())
215 theNewShapes = aFound->second;