1 // File: ShHealOper_FillHoles.cxx
2 // Created: 26.04.04 17:35:30
3 // Author: Galina KULIKOVA
4 // < MODULE = KERNEL> <PACKAGE = ShHealOper> : <Shape Healing Operations>
5 // Copyright (C) 2003 CEA
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2.1 of the License.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <ShHealOper_FillHoles.hxx>
26 #include <TopAbs_ShapeEnum.hxx>
27 #include <ShapeAnalysis_FreeBounds.hxx>
28 #include <TopoDS_Compound.hxx>
29 #include <TopoDS_Iterator.hxx>
30 #include <Geom_Curve.hxx>
31 #include <BRep_Tool.hxx>
32 #include <TopExp_Explorer.hxx>
33 #include <TopTools_HSequenceOfShape.hxx>
35 #include <Geom_BSplineSurface.hxx>
36 #include <GeomPlate_BuildPlateSurface.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <BRepAdaptor_Curve.hxx>
39 #include <BRepAdaptor_HCurve.hxx>
40 #include <GeomPlate_CurveConstraint.hxx>
41 #include <GeomPlate_Surface.hxx>
42 #include <TColgp_SequenceOfXY.hxx>
43 #include <TColgp_SequenceOfXYZ.hxx>
44 #include <BRep_Builder.hxx>
45 #include <ShapeFix_Face.hxx>
46 #include <BRep_Tool.hxx>
47 #include <TopLoc_Location.hxx>
48 #include <TopTools_IndexedMapOfShape.hxx>
49 #include <TopoDS_Shell.hxx>
50 #include <ShapeFix_Shell.hxx>
51 #include <GeomPlate_PlateG0Criterion.hxx>
52 #include <GeomPlate_MakeApprox.hxx>
53 #include <Precision.hxx>
54 #include <TopTools_ListOfShape.hxx>
55 #include <BRepFill_CurveConstraint.hxx>
56 #include <BRepBuilderAPI_MakeFace.hxx>
59 //=======================================================================
60 //function : ShHealOper_FillHoles()
61 //purpose : Constructor
62 //=======================================================================
63 ShHealOper_FillHoles::ShHealOper_FillHoles ()
68 //=======================================================================
69 //function : ShHealOper_FillHoles
71 //=======================================================================
73 ShHealOper_FillHoles::ShHealOper_FillHoles (const TopoDS_Shape& theShape)
79 //=======================================================================
82 //=======================================================================
84 void ShHealOper_FillHoles::Init(const TopoDS_Shape& theShape)
86 ShHealOper_Tool::Init(theShape);
87 TopExp::MapShapesAndAncestors( myInitShape, TopAbs_EDGE,TopAbs_SHELL , myEdgeShells);
88 TopExp::MapShapesAndAncestors ( myInitShape, TopAbs_EDGE,TopAbs_COMPOUND, myEdgeComps );
90 TopExp::MapShapesAndAncestors ( myInitShape, TopAbs_EDGE,TopAbs_FACE, myEdgeFaces );
92 //=======================================================================
93 //function : InitParameters
95 //=======================================================================
97 void ShHealOper_FillHoles::InitParameters(Standard_Integer theDegree,
98 Standard_Integer theNbPtsOnCur,
99 Standard_Integer theNbIter,
100 Standard_Real theTol3d,
101 Standard_Real theTol2d,
102 Standard_Real theTolAng,
103 Standard_Real theTolCrv,
104 Standard_Integer theMaxDeg,
105 Standard_Integer theMaxSeg)
107 myNbPtsOnCur = theNbPtsOnCur;
108 myNbIter = theNbIter;
112 myTolAng = theTolAng;
113 myTolCrv = theTolCrv;
114 myMaxDeg = theMaxDeg;
117 //=======================================================================
120 //=======================================================================
122 Standard_Boolean ShHealOper_FillHoles::Fill()
124 ShapeAnalysis_FreeBounds sab(myInitShape);
125 TopoDS_Compound aCompClosed = sab.GetClosedWires();
126 TopoDS_Compound aCompOpen = sab.GetOpenWires();
127 TopTools_SequenceOfShape aFillWires;
128 if(!aCompClosed.IsNull()) {
129 TopoDS_Iterator aIt(aCompClosed);
131 for( ; aIt.More(); aIt.Next())
132 aFillWires.Append(aIt.Value());
134 if(!aCompOpen.IsNull()) {
135 TopoDS_Iterator aIt(aCompOpen);
136 for( ; aIt.More(); aIt.Next())
137 aFillWires.Append(aIt.Value());
140 TopExp_Explorer aExp(myInitShape,TopAbs_EDGE,TopAbs_FACE);
142 for( ; aExp.More(); aExp.Next())
143 aFillWires.Append(aExp.Current());
145 return Fill(aFillWires);
148 //=======================================================================
151 //=======================================================================
153 Standard_Boolean ShHealOper_FillHoles::Fill(const TopTools_SequenceOfShape& theFillShapes)
155 myDone = Standard_False;
156 myErrorStatus = ShHealOper_NotError;
157 if(myInitShape.IsNull()) {
158 myErrorStatus = ShHealOper_InvalidParameters;
161 if(!theFillShapes.Length()) {
165 Handle(TopTools_HSequenceOfShape) aSeqWires = new TopTools_HSequenceOfShape;
166 if(!prepareWires(theFillShapes,aSeqWires)) {
167 myErrorStatus = ShHealOper_InvalidParameters;
171 myResultShape = myInitShape;
172 Standard_Integer i =1;
173 for( ; i <= aSeqWires->Length(); i++) {
174 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires->Value(i));
175 Handle(TColGeom2d_HArray1OfCurve) aCurves2d;
176 Handle(TColStd_HArray1OfInteger) aOrders;
177 Handle(TColStd_HArray1OfInteger) aSenses;
178 Handle(Geom_Surface) aSurf = buildSurface(aWire,aCurves2d,aOrders,aSenses);
180 myErrorStatus = ShHealOper_ErrorExecution;
182 myDone = (addFace(aSurf,aWire,aCurves2d,aOrders,aSenses) || myDone);
185 myResultShape = myContext->Apply(myResultShape);
188 //=======================================================================
189 //function : isCircle
191 //=======================================================================
192 static Standard_Boolean isCircle(const TopoDS_Edge theEdge)
194 Standard_Real aFirst, aLast;
195 Handle(Geom_Curve) aC3D = BRep_Tool::Curve(theEdge,aFirst, aLast );
196 if(aC3D.IsNull()) return Standard_False;
197 Standard_Boolean isCirc = (aC3D->Value(aFirst).Distance(aC3D->Value(aLast)) <
198 aC3D->Value(aFirst).Distance(aC3D->Value((aFirst +aLast)/2)));
201 //=======================================================================
202 //function : prepareWires
204 //=======================================================================
206 Standard_Boolean ShHealOper_FillHoles::prepareWires(const TopTools_SequenceOfShape& theFillShapes,
207 Handle(TopTools_HSequenceOfShape)& theSeqWires)
209 Handle(TopTools_HSequenceOfShape) aSeqEdges = new TopTools_HSequenceOfShape;
211 Standard_Integer i =1;
212 for( ; i <= theFillShapes.Length(); i++) {
213 TopExp_Explorer aExp;
214 for (aExp.Init (theFillShapes.Value(i),TopAbs_WIRE); aExp.More(); aExp.Next()) {
215 TopoDS_Iterator aIt(aExp.Current());
216 Standard_Boolean isAdd = Standard_True;
217 for( ; aIt.More() && isAdd; aIt.Next()) {
218 if(myEdgeFaces.Contains(aIt.Value()))
219 isAdd = (myEdgeFaces.FindFromKey(aIt.Value()).Extent() <2);
222 theSeqWires->Append(aExp.Current());
224 for (aExp.Init (theFillShapes.Value(i),TopAbs_EDGE, TopAbs_WIRE); aExp.More(); aExp.Next()) {
225 if (!BRep_Tool::Degenerated (TopoDS::Edge (aExp.Current())))
226 if(myEdgeFaces.Contains(aExp.Current()) && myEdgeFaces.FindFromKey(aExp.Current()).Extent() >1)
228 aSeqEdges->Append(aExp.Current());
232 if(aSeqEdges->Length())
234 Standard_Real aTol = 0.;
235 Standard_Boolean aShared = Standard_True;
236 Handle(TopTools_HSequenceOfShape) aTmpWires = new TopTools_HSequenceOfShape;
237 ShapeAnalysis_FreeBounds::ConnectEdgesToWires(aSeqEdges, aTol, aShared, aTmpWires);
238 Handle(TopTools_HSequenceOfShape) anWiresClosed = new TopTools_HSequenceOfShape,
239 anWiresOpen = new TopTools_HSequenceOfShape;
240 ShapeAnalysis_FreeBounds::SplitWires(aTmpWires, aTol, aShared, anWiresClosed, anWiresOpen);
242 for (i = 1; i <= anWiresClosed->Length(); i++)
243 theSeqWires->Append (anWiresClosed->Value (i));
244 for (i = 1; i <= anWiresOpen->Length(); i++)
245 theSeqWires->Append (anWiresOpen->Value (i));
250 for( i =1; i <= theSeqWires->Length(); i++) {
251 TopoDS_Wire aWire = TopoDS::Wire(theSeqWires->Value(i));
253 TopoDS_Iterator aIt(aWire);
254 Standard_Integer ne =0;
256 for( ; aIt.More(); aIt.Next(), ne++)
257 ae = TopoDS::Edge(aIt.Value());
258 if((ne == 1) && ( !isCircle(ae))) {
259 theSeqWires->Remove(i--);
263 return (theSeqWires->Length());
265 //=======================================================================
266 //function : buildSurface
268 //=======================================================================
270 Handle(Geom_Surface) ShHealOper_FillHoles::buildSurface(const TopoDS_Wire& theWire,
271 Handle(TColGeom2d_HArray1OfCurve)& theCurves2d,
272 Handle(TColStd_HArray1OfInteger)& theOrders,
273 Handle(TColStd_HArray1OfInteger)& theSenses)
275 Handle(Geom_BSplineSurface) aSurf;
278 GeomPlate_BuildPlateSurface aBuilder(myDegree, myNbPtsOnCur, myNbIter,
279 myTol2d, myTol3d, myTolAng, myTolCrv);
280 TopoDS_Iterator aIter;
281 for(aIter.Initialize (theWire); aIter.More(); aIter.Next()) {
283 TopoDS_Edge ae = TopoDS::Edge(aIter.Value());
284 BRepAdaptor_Curve adC(ae);
285 Handle(BRepAdaptor_HCurve) aHAD= new BRepAdaptor_HCurve(adC);
286 Handle(BRepFill_CurveConstraint) aConst =
287 new BRepFill_CurveConstraint (aHAD, (Standard_Integer) GeomAbs_C0, myNbPtsOnCur, myTol3d);
288 //Handle(GeomPlate_CurveConstraint) aConst =
289 // new GeomPlate_CurveConstraint(aHAD, (Standard_Integer) GeomAbs_C0, myNbPtsOnCur, myTol3d);
290 aBuilder.Add (aConst);
293 if(!aBuilder.IsDone())
295 Handle(GeomPlate_Surface) aPlSurf = aBuilder.Surface();
297 //for filling holes without initial specified surface
298 //the initial surface should be build by GeomPlate itself
299 //following code was taken from BRepFill_Filling::Build
301 Standard_Real aDist = aBuilder.G0Error();
302 TColgp_SequenceOfXY S2d;
303 TColgp_SequenceOfXYZ S3d;
306 aBuilder.Disc2dContour(4,S2d);
307 aBuilder.Disc3dContour(4,0,S3d);
308 Standard_Real amaxTol = Max( myTol3d, 10* aDist);
309 GeomPlate_PlateG0Criterion Criterion( S2d, S3d, amaxTol );
310 GeomPlate_MakeApprox Approx( aPlSurf, Criterion, myTol3d, myMaxSeg, myMaxDeg );
311 aSurf = Approx.Surface();
315 theCurves2d = aBuilder.Curves2d();
316 theOrders = aBuilder.Order();
317 theSenses = aBuilder.Sense();
321 catch (Standard_Failure) {
328 //=======================================================================
331 //=======================================================================
333 Standard_Boolean ShHealOper_FillHoles::addFace(const Handle(Geom_Surface)& theSurf,
334 const TopoDS_Wire& theWire,
335 const Handle(TColGeom2d_HArray1OfCurve)& theCurves2d,
336 const Handle(TColStd_HArray1OfInteger)& theOrders,
337 const Handle(TColStd_HArray1OfInteger)& theSenses)
339 BRepBuilderAPI_MakeFace aMakeFace (theSurf);
340 TopoDS_Face aFace = aMakeFace.Face();
348 TopTools_IndexedMapOfShape aMapParent;
349 Standard_Integer aInd = 1;
350 Standard_Boolean hasShell = Standard_False;
351 TopoDS_Iterator aIter(theWire);
352 for ( ; aIter.More(); aIter.Next(), aInd++) {
353 TopoDS_Edge anEdge = TopoDS::Edge (aIter.Value());
354 Standard_Real aF, aL;
355 BRep_Tool::Range (anEdge, aF, aL);
356 TopLoc_Location aLoc;
357 aB.UpdateEdge (anEdge, theCurves2d->Value (aInd),aFace, 0.);
359 aB.Range (anEdge, aFace, aF, aL);
361 // Set orientation of the edge: orientation should be changed
362 // if its orientation does not make sence with curve orientation
363 // recommended by GeomPlate
364 if ((anEdge.Orientation() == TopAbs_FORWARD) ==
365 (theSenses->Value (theOrders->Value (aInd)) == 1)) {
368 aB.SameParameter(anEdge,Standard_False);
369 aB.Add (aWire, anEdge);
370 Standard_Boolean isAdd = Standard_False;
371 TopoDS_Shape aParent;
372 if(!myEdgeFaces.Contains(anEdge))
375 if(myEdgeFaces.FindFromKey(anEdge).Extent() >1)
378 if(myEdgeShells.Contains(anEdge)) {
379 if(myEdgeShells.FindFromKey(anEdge).Extent()) {
380 aParent = myEdgeShells.FindFromKey(anEdge).First();
381 hasShell = Standard_True;
382 aMapParent.Add(aParent);
385 else if(myEdgeComps.Contains(anEdge)) {
386 if(myEdgeComps.FindFromKey(anEdge).Extent()) {
387 aParent = myEdgeComps.FindFromKey(anEdge).First();
388 aMapParent.Add(aParent);
394 Handle(ShapeFix_Face) aSff = new ShapeFix_Face(aFace);
395 aSff->SetContext(myContext);
396 aSff->SetPrecision(myTol3d);
398 if(aSff->Status(ShapeExtend_FAIL)) {
399 myErrorStatus = ShHealOper_ErrorExecution;
400 return Standard_False;
402 //theFace = aSff->Face();
403 TopoDS_Shape aResShape = aSff->Result();
404 getResShape(aResShape,aMapParent,hasShell);
405 return Standard_True;
408 //=======================================================================
409 //function : getResShape
411 //=======================================================================
413 void ShHealOper_FillHoles::getResShape(const TopoDS_Shape& theAddShape,
414 const TopTools_IndexedMapOfShape& aMapParent,
415 const Standard_Boolean theHasShell)
419 if(!aMapParent.Extent()) {
420 TopoDS_Compound aComp;
421 aB.MakeCompound(aComp);
422 TopoDS_Shape aresShape = myContext->Apply(myResultShape);
423 aB.Add(aComp,aresShape);
424 aB.Add(aComp,theAddShape);
425 myResultShape = aComp;
428 Standard_Boolean anhasShell = theHasShell;
429 TopoDS_Shell aTmpShell;
430 aB.MakeShell(aTmpShell);
431 TopTools_SequenceOfShape aseqShells;
434 aB.Add(aTmpShell,theAddShape);
435 Standard_Integer i =1;
436 for( ; i <= aMapParent.Extent(); i++) {
437 TopoDS_Shape aParShape = myContext->Apply(aMapParent.FindKey(i));
438 if(aParShape.ShapeType() == TopAbs_SHELL) {
439 TopExp_Explorer aexp(aParShape,TopAbs_FACE);
440 for( ; aexp.More(); aexp.Next())
441 aB.Add(aTmpShell,aexp.Current());
442 aseqShells.Append(aParShape);
445 anhasShell = aseqShells.Length();
448 Handle(ShapeFix_Shell) asfs = new ShapeFix_Shell;
449 asfs->FixFaceOrientation(aTmpShell);
450 TopoDS_Shape anshape = asfs->Shape();
451 myContext->Replace(aseqShells.Value(1),anshape);
452 Standard_Integer i =2;
453 for( ; i<= aseqShells.Length(); i++)
454 myContext->Remove(aseqShells.Value(i));
458 TopoDS_Compound aComp;
459 aB.MakeCompound(aComp);
460 TopoDS_Shape oldshape = myContext->Apply(aMapParent.FindKey(1));
461 TopoDS_Iterator aIt(oldshape);
462 for( ; aIt.More(); aIt.Next())
463 aB.Add(aComp,aIt.Value());
464 aB.Add(aComp,theAddShape);
465 myContext->Replace( oldshape,aComp);