1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 // pdn 10.12.98: tr9_r0501-ug
15 // pdn 28.12.98: PRO10366 shifting pcurve between two singularities
16 //:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved
17 //:l2 abv 10.01.99: USA60022 7289: corrections for reversed face
18 //gka 11.01.99 file PRO7755.stp #2018: work-around error in BRepLib_MakeFace
19 //:p4 abv, pdn 23.02.99: PRO9234 #15720: call BRepTools::Update() for faces
20 // rln 03.03.99 S4135: transmission of parameter precision to SA_Surface::NbSingularities
21 //:q5 abv 19.03.99 code improvement
22 //%14 pdn 15.03.99 adding function for fixing null area wires
23 //%15 pdn 20.03.99 code improvement
24 // abv 09.04.99 S4136: improve tolerance management; remove unused flag Closed
25 //#4 szv S4163: optimization
26 // smh 31.01.01 BUC60810 : Case of small wire on face in solid
27 // sln 25.09.2001 checking order of 3d and 2d representation curves
28 // abv 19.10.2001 FixAddNaturalBound improved and extracted as separate fix
29 // skl,pdn 14.05.2002 OCC55 (correction precision for small faces)
31 #include <ShapeFix_Face.ixx>
33 #include <Standard_Failure.hxx>
34 #include <Standard_ErrorHandler.hxx>
36 #include <Precision.hxx>
38 #include <Geom2d_Curve.hxx>
39 #include <Geom2d_Line.hxx>
40 #include <Geom2dAdaptor_Curve.hxx>
41 #include <Geom_Curve.hxx>
42 #include <Geom_BSplineSurface.hxx>
43 #include <GeomAdaptor_HSurface.hxx>
46 #include <TopoDS_Edge.hxx>
47 #include <TopoDS_Vertex.hxx>
48 #include <TopoDS_Shell.hxx>
49 #include <TopoDS_Compound.hxx>
50 #include <TopoDS_Iterator.hxx>
51 #include <TopExp_Explorer.hxx>
52 #include <TopTools_SequenceOfShape.hxx>
54 #include <BRep_Tool.hxx>
55 #include <BRep_Builder.hxx>
56 #include <BRepTopAdaptor_FClass2d.hxx>
57 #include <BRepTools.hxx>
58 #include <BRepBuilderAPI_MakeFace.hxx>
59 #include <BRepBuilderAPI_MakeVertex.hxx>
60 #include <BRepBuilderAPI_MakeWire.hxx>
62 #include <Message_Msg.hxx>
63 #include <ShapeBuild_ReShape.hxx>
64 #include <ShapeExtend_WireData.hxx>
65 #include <ShapeAnalysis.hxx>
66 #include <ShapeFix_Wire.hxx>
67 #include <ShapeFix_Edge.hxx>
68 #include <ShapeAnalysis_Edge.hxx>
69 #include <Bnd_Box2d.hxx>
70 #include <Geom_Circle.hxx>
71 #include <Geom_SphericalSurface.hxx>
72 #include <Geom_RectangularTrimmedSurface.hxx>
73 #include <Geom_ConicalSurface.hxx>
74 #include <ShapeAnalysis_Wire.hxx>
75 #include <ShapeAnalysis_Surface.hxx>
77 #include <ShapeExtend_CompositeSurface.hxx>
78 #include <ShapeFix_ComposeShell.hxx>
79 #include <TColGeom_HArray2OfSurface.hxx>
80 #include <ShapeBuild_Edge.hxx>
81 #include <TColgp_SequenceOfPnt2d.hxx>
82 #include <Bnd_Box.hxx>
83 #include <TopTools_IndexedMapOfShape.hxx>
84 #include <TopTools_DataMapOfShapeListOfShape.hxx>
85 #include <TopTools_ListIteratorOfListOfShape.hxx>
86 #include <TopTools_MapOfShape.hxx>
90 #include <ShapeFix.hxx>
91 #include <ShapeFix_DataMapOfShapeBox2d.hxx>
92 #include <BndLib_Add2dCurve.hxx>
93 #include <Geom2dAdaptor_Curve.hxx>
94 #include <IntRes2d_Domain.hxx>
95 #include <Geom2dInt_GInter.hxx>
96 #include <IntRes2d_IntersectionPoint.hxx>
97 #include <IntRes2d_Transition.hxx>
98 #include <TopTools_SequenceOfShape.hxx>
99 #include <IntRes2d_IntersectionSegment.hxx>
100 #include <TopTools_DataMapOfShapeInteger.hxx>
102 #include <ShapeFix_IntersectionTool.hxx>
103 #include <ShapeFix_SplitTool.hxx>
104 #include <TColStd_MapOfInteger.hxx>
105 #include <TopTools_DataMapOfShapeShape.hxx>
111 static Standard_Boolean IsSurfaceUVInfinite(const Handle(Geom_Surface)& theSurf)
113 Standard_Real UMin,UMax,VMin,VMax;
114 theSurf->Bounds(UMin,UMax,VMin,VMax);
116 return (Precision::IsInfinite(UMin) ||
117 Precision::IsInfinite(UMax) ||
118 Precision::IsInfinite(VMin) ||
119 Precision::IsInfinite(VMax) );
122 static Standard_Boolean IsSurfaceUVPeriodic(const Handle(Geom_Surface)& theSurf)
124 return theSurf->IsUPeriodic() && theSurf->IsVPeriodic();
127 //=======================================================================
128 //function : ShapeFix_Face
130 //=======================================================================
132 ShapeFix_Face::ShapeFix_Face()
134 myFwd = Standard_True;
136 myFixWire = new ShapeFix_Wire;
140 //=======================================================================
141 //function : ShapeFix_Face
143 //=======================================================================
145 ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face)
147 myFwd = Standard_True;
149 myFixWire = new ShapeFix_Wire;
154 //=======================================================================
155 //function : ClearModes
157 //=======================================================================
159 void ShapeFix_Face::ClearModes()
162 myFixOrientationMode = -1;
163 myFixAddNaturalBoundMode = -1;
164 myFixMissingSeamMode = -1;
165 myFixSmallAreaWireMode = -1;
166 myFixIntersectingWiresMode = -1;
167 myFixLoopWiresMode = -1;
168 myFixSplitFaceMode = -1;
169 myAutoCorrectPrecisionMode = 1;
170 myFixPeriodicDegenerated = -1;
173 //=======================================================================
174 //function : SetMsgRegistrator
176 //=======================================================================
178 void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
180 ShapeFix_Root::SetMsgRegistrator ( msgreg );
181 myFixWire->SetMsgRegistrator ( msgreg );
184 //=======================================================================
185 //function : SetPrecision
187 //=======================================================================
189 void ShapeFix_Face::SetPrecision (const Standard_Real preci)
191 ShapeFix_Root::SetPrecision ( preci );
192 myFixWire->SetPrecision ( preci );
195 //=======================================================================
196 //function : SetMinTolerance
198 //=======================================================================
200 void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol)
202 ShapeFix_Root::SetMinTolerance ( mintol );
203 myFixWire->SetMinTolerance ( mintol );
206 //=======================================================================
207 //function : SetMaxTolerance
209 //=======================================================================
211 void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol)
213 ShapeFix_Root::SetMaxTolerance ( maxtol );
214 myFixWire->SetMaxTolerance ( maxtol );
217 //=======================================================================
220 //=======================================================================
222 void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf,
223 const Standard_Real preci, const Standard_Boolean fwd)
226 Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf );
227 Init ( sas, preci, fwd );
230 //=======================================================================
233 //=======================================================================
235 void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf,
236 const Standard_Real preci, const Standard_Boolean fwd)
240 SetPrecision ( preci );
242 B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() );
245 if ( !fwd ) myFace.Orientation(TopAbs_REVERSED);
248 //=======================================================================
251 //=======================================================================
253 void ShapeFix_Face::Init (const TopoDS_Face& face)
256 mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) );
257 myFwd = ( face.Orientation() != TopAbs_REVERSED );
260 // myFace = TopoDS::Face(face.EmptyCopied());
261 // for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next())
262 // Add (TopoDS::Wire (ws.Value()) );
265 //=======================================================================
268 //=======================================================================
270 void ShapeFix_Face::Add (const TopoDS_Wire& wire)
272 if ( wire.IsNull() ) return;
274 //szv#4:S4163:12Mar99 SGI warns
275 TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented()
280 //=======================================================================
281 //function : SplitWire
282 //purpose : auxilary - try to split wire (it is needed if some segments
283 // were removed in ShapeFix_Wire::FixSelfIntersection()
284 //=======================================================================
285 static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire,
286 TopTools_SequenceOfShape& aResWires)
288 TColStd_MapOfInteger UsedEdges;
289 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
290 Standard_Integer i,j,k;
291 ShapeAnalysis_Edge sae;
292 for(i=1; i<=sewd->NbEdges(); i++) {
293 if(UsedEdges.Contains(i)) continue;
294 TopoDS_Edge E1 = sewd->Edge(i);
296 TopoDS_Vertex V0,V1,V2;
297 V0 = sae.FirstVertex(E1);
298 V1 = sae.LastVertex(E1);
299 Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData;
301 Standard_Boolean IsConnectedEdge = Standard_True;
302 for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
304 for(k=2; k<=sewd->NbEdges(); k++) {
305 if(UsedEdges.Contains(k)) continue;
307 TopoDS_Vertex V21 = sae.FirstVertex(E2);
308 TopoDS_Vertex V22 = sae.LastVertex(E2);
309 if( sae.FirstVertex(E2).IsSame(V1) ) {
312 V1 = sae.LastVertex(E2);
316 if(k>sewd->NbEdges()) {
317 IsConnectedEdge = Standard_False;
321 //check that V0 and V1 are same in 2d too
322 Standard_Real a1,b1,a2,b2;
323 Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1);
324 Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2);
326 if (E1.Orientation() == TopAbs_REVERSED)
328 if (E2.Orientation() == TopAbs_REVERSED)
332 GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face));
333 Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1));
334 Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) );
335 if (v0.SquareDistance(v1) < maxResolution) {
336 // new wire is closed, put it into sequence
337 aResWires.Append(sewd1->Wire());
342 if(!IsConnectedEdge) {
343 // create new notclosed wire
344 aResWires.Append(sewd1->Wire());
346 if(UsedEdges.Extent()==sewd->NbEdges()) break;
349 if(aResWires.Length()>1) {
351 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
355 return Standard_True;
359 //=======================================================================
362 //=======================================================================
364 Standard_Boolean ShapeFix_Face::Perform()
366 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
367 myFixWire->SetContext ( Context() );
368 Handle(ShapeFix_Wire) theAdvFixWire = Handle(ShapeFix_Wire)::DownCast(myFixWire);
369 if (theAdvFixWire.IsNull()) return Standard_False;
372 TopoDS_Shape aInitFace = myFace;
373 // perform first part of fixes on wires
374 Standard_Boolean isfixReorder = Standard_False;
375 Standard_Boolean isReplaced = Standard_False;
377 //gka fix in order to avoid lost messages (following OCC21771)
378 TopTools_DataMapOfShapeShape aMapReorderedWires;
380 Standard_Real aSavPreci = Precision();
381 if ( NeedFix ( myFixWireMode ) ) {
382 theAdvFixWire->SetFace ( myFace );
384 Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode();
385 Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode();
386 Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode();
387 theAdvFixWire->FixLackingMode() = Standard_False;
388 theAdvFixWire->FixNotchedEdgesMode() = Standard_False;
389 theAdvFixWire->FixSelfIntersectionMode() = Standard_False;
391 Standard_Boolean fixed = Standard_False;
392 TopoDS_Shape S = myFace;
393 if ( ! Context().IsNull() )
394 S = Context()->Apply ( myFace );
395 TopoDS_Shape emptyCopied = S.EmptyCopied();
396 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
397 tmpFace.Orientation ( TopAbs_FORWARD );
400 // skl 14.05.2002 OCC55 + corrected 03.03.2004
401 Standard_Real dPreci = aSavPreci*aSavPreci;
403 Standard_Real newpreci=dPreci;
404 for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) {
405 TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
406 Standard_Real first,last;
407 Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
410 bb.Add(c3d->Value(first));
411 bb.Add(c3d->Value(last));
412 bb.Add(c3d->Value((last+first)/2.));
413 Standard_Real x1,x2,y1,y2,z1,z2,size;
414 bb.Get(x1,y1,z1,x2,y2,z2);
415 size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
416 if(size<newpreci) newpreci=size;
419 newpreci=sqrt(newpreci)/2.*1.00001;
420 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
421 SetPrecision(newpreci);
422 theAdvFixWire->SetPrecision(newpreci);
424 // end skl 14.05.2002
427 // skl 29.03.2010 (OCC21623)
428 if( myAutoCorrectPrecisionMode ) {
429 Standard_Real size = ShapeFix::LeastEdgeSize(S);
430 Standard_Real newpreci = Min(aSavPreci,size/2.);
431 newpreci = newpreci*1.00001;
432 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
433 SetPrecision(newpreci);
434 theAdvFixWire->SetPrecision(newpreci);
438 isfixReorder = Standard_False;
439 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
440 if(iter.Value().ShapeType() != TopAbs_WIRE) {
441 B.Add ( tmpFace, iter.Value() );
444 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
445 theAdvFixWire->Load ( wire );
446 if(theAdvFixWire->NbEdges() == 0) {
447 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
448 B.Add ( tmpFace, wire );
450 fixed = Standard_True;
451 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
455 if ( theAdvFixWire->Perform() ) {
456 //fixed = Standard_True;
457 isfixReorder = (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder);
458 fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) ||
459 theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
460 theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
461 theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
462 theAdvFixWire->StatusClosed(ShapeExtend_DONE));
463 TopoDS_Wire w = theAdvFixWire->Wire();
465 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
466 if(theAdvFixWire->NbEdges() == 0) {
467 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
471 else if(!wire.IsSame(w))
472 aMapReorderedWires.Bind(wire,w);
476 B.Add ( tmpFace, wire );
477 // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) )
478 // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
481 theAdvFixWire->FixLackingMode() = usFixLackingMode;
482 theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode;
483 theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode;
484 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
487 //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
488 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
490 isReplaced = Standard_True;
492 if(fixed || isfixReorder) {
494 if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) {
495 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
501 TopoDS_Shape savShape = myFace; //gka BUG 6555
503 // Specific case for conic surfaces
504 if ( NeedFix(myFixPeriodicDegenerated) )
505 this->FixPeriodicDegenerated();
508 if ( NeedFix ( myFixMissingSeamMode ) ) {
509 if ( FixMissingSeam() ) {
510 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
514 // cycle by all possible faces coming from FixMissingSeam
515 // each face is processed as if it was single
516 TopExp_Explorer exp(myResult,TopAbs_FACE);
517 for ( ; exp.More(); exp.Next() ) {
518 myFace = TopoDS::Face ( exp.Current() );
519 Standard_Boolean NeedCheckSplitWire = Standard_False;
521 // perform second part of fixes on wires
522 if ( NeedFix ( myFixWireMode ) ) {
523 theAdvFixWire->SetFace ( myFace );
525 Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode();
526 Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode();
527 Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode();
528 Standard_Integer usFixDegeneratedMode = theAdvFixWire->FixDegeneratedMode();
529 theAdvFixWire->FixSmallMode() = Standard_False;
530 theAdvFixWire->FixConnectedMode() = Standard_False;
531 theAdvFixWire->FixEdgeCurvesMode() = Standard_False;
532 theAdvFixWire->FixDegeneratedMode() = Standard_False;
534 Standard_Boolean fixed = Standard_False;
535 TopoDS_Shape S = myFace;
536 if ( ! Context().IsNull() )
537 S = Context()->Apply ( myFace );
538 TopoDS_Shape emptyCopied = S.EmptyCopied();
539 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
540 tmpFace.Orientation ( TopAbs_FORWARD );
541 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
542 if(iter.Value().ShapeType() != TopAbs_WIRE) {
543 B.Add ( tmpFace,iter.Value());
547 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
548 theAdvFixWire->Load ( wire );
549 if(theAdvFixWire->NbEdges() == 0) {
550 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
551 B.Add ( tmpFace, wire );
553 fixed = Standard_True;
554 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
558 if ( theAdvFixWire->Perform() ) {
559 isfixReorder = theAdvFixWire->StatusReorder(ShapeExtend_DONE);
560 fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
561 theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
562 theAdvFixWire->StatusNotches(ShapeExtend_DONE)); //Standard_True;
563 TopoDS_Wire w = theAdvFixWire->Wire();
565 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
568 else if(!wire.IsSame(w))
569 aMapReorderedWires.Bind(wire,w);
573 if(theAdvFixWire->StatusRemovedSegment())
574 NeedCheckSplitWire = Standard_True;
576 //fix for loop of wire
577 TopTools_SequenceOfShape aLoopWires;
578 if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) {
579 if (aLoopWires.Length() > 1)
580 SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was splitted on several wires
581 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
582 fixed = Standard_True;
583 Standard_Integer k=1;
584 for( ; k <= aLoopWires.Length(); k++)
585 B.Add (tmpFace,aLoopWires.Value(k));
588 B.Add ( tmpFace, wire );
591 theAdvFixWire->FixSmallMode() = usFixSmallMode;
592 theAdvFixWire->FixConnectedMode() = usFixConnectedMode;
593 theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode;
594 theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode;
597 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
598 if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555
599 Context()->Replace(aInitFace,savShape);
600 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
602 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
606 if(NeedCheckSplitWire) {
607 // try to split wire - it is needed if some segments were removed
608 // in ShapeFix_Wire::FixSelfIntersection()
609 TopoDS_Shape S = myFace;
610 if ( ! Context().IsNull() )
611 S = Context()->Apply ( myFace );
612 TopoDS_Shape emptyCopied = S.EmptyCopied();
613 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
614 tmpFace.Orientation ( TopAbs_FORWARD );
615 TopTools_SequenceOfShape aWires;
616 Standard_Integer nbw=0;
617 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
618 if(iter.Value().ShapeType() != TopAbs_WIRE) {
619 B.Add (tmpFace,iter.Value());
622 if(iter.Value().Orientation() != TopAbs_FORWARD &&
623 iter.Value().Orientation() != TopAbs_REVERSED) {
624 B.Add (tmpFace,TopoDS::Wire(iter.Value()));
628 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
629 SplitWire(tmpFace,wire,aWires);
631 if(nbw<aWires.Length()) {
632 for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
633 B.Add (tmpFace,aWires.Value(iw));
634 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
635 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
640 // fix intersecting wires
641 if(FixWiresTwoCoincEdges())
642 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
643 if ( NeedFix ( myFixIntersectingWiresMode ) ) {
644 if ( FixIntersectingWires() ) {
645 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
650 TopTools_DataMapOfShapeListOfShape MapWires;
652 if ( NeedFix ( myFixOrientationMode ) ) {
653 if ( FixOrientation(MapWires) )
654 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
657 BRepTools::Update(myFace);
659 // fix natural bounds
660 Standard_Boolean NeedSplit = Standard_True;
661 if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
662 if ( FixAddNaturalBound() ) {
663 NeedSplit = Standard_False;
664 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
669 if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) {
670 if ( FixSplitFace(MapWires) )
671 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
676 //return the original preci
677 SetPrecision(aSavPreci);
678 theAdvFixWire->SetPrecision(aSavPreci);
680 // cycle by all possible faces coming from FixAddNaturalBound
681 // each face is processed as if it was single
682 for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) {
683 myFace = TopoDS::Face ( exp.Current() );
685 // fix small-area wires
686 if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) ) {
687 if ( FixSmallAreaWire() )
688 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
693 if ( ! Context().IsNull() ) {
694 if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
696 //gka fix in order to avoid lost messages (following OCC21771)
697 if(aMapReorderedWires.Extent())
699 TopoDS_Iterator aItW(aInitFace,Standard_False);
700 for( ; aItW.More() ; aItW.Next())
702 TopoDS_Shape aCurW = aItW.Value();
703 while(aMapReorderedWires.IsBound(aCurW))
705 TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW);
706 Context()->Replace(aCurW, aFixW);
712 Context()->Replace(aInitFace, savShape);
714 myResult = Context()->Apply ( aInitFace ); //gka 06.09.04
716 else if(!Status ( ShapeExtend_DONE ))
717 myResult = aInitFace;
719 return Status ( ShapeExtend_DONE );
722 //=======================================================================
723 //function : Auxiliary functions
725 //=======================================================================
727 // Shift all pcurves of edges in the given wire on the given face
729 static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f,
731 const Handle(ShapeAnalysis_Surface)& mySurf,
732 Standard_Boolean recompute3d = Standard_False)
735 tr2d.SetTranslation(vec.XY());
736 ShapeAnalysis_Edge sae;
739 for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){
740 TopoDS_Edge edge = TopoDS::Edge(ei.Value());
741 Handle (Geom2d_Curve) C2d;
742 Standard_Real cf, cl;
743 if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue;
744 C2d->Transform(tr2d);
746 // recompute 3d curve and vertex
747 sbe.RemoveCurve3d ( edge );
748 sbe.BuildCurve3d ( edge );
749 B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. );
754 // Cut interval from the sequence of intervals
755 static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals,
756 const gp_Pnt2d &toAddI,
757 const Standard_Real period)
759 if ( intervals.Length() <=0 ) return Standard_False;
760 for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top
761 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
762 gp_Pnt2d interval = intervals(i);
763 // ACIS907, OCC921 a054a.sat (face 124)
764 Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ),
765 0.5*( interval.X() + interval.Y() ),period);
766 gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift );
767 if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue;
768 if ( toAdd.X() > interval.X() ) {
769 if ( toAdd.Y() < interval.Y() ) {
770 intervals.InsertBefore ( i, interval );
771 intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++...
773 intervals.ChangeValue(i).SetY ( toAdd.X() );
775 else if ( toAdd.Y() < interval.Y() ) {
776 intervals.ChangeValue(i).SetX ( toAdd.Y() );
778 else intervals.Remove ( i-- );
781 return Standard_True;
784 // Find middle of the biggest interval
785 static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals)
787 Standard_Real shift = 0., max = -1.;
788 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
789 gp_Pnt2d interval = intervals(i);
790 if ( interval.Y() - interval.X() <= max ) continue;
791 max = interval.Y() - interval.X();
792 shift = interval.X() + 0.5 * max;
797 //=======================================================================
798 //function : FixAddNaturalBound
800 //=======================================================================
801 // Detect missing natural bounary on spherical surfaces and add it if
803 //pdn 981202: add natural bounds if missing (on sphere only)
804 //:abv 28.08.01: rewritten and extended for toruses
806 Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
808 if ( ! Context().IsNull() ) {
809 TopoDS_Shape S = Context()->Apply ( myFace );
810 myFace = TopoDS::Face ( S );
813 // collect wires in sequence
814 TopTools_SequenceOfShape ws;
815 TopTools_SequenceOfShape vs;
816 TopoDS_Iterator wi (myFace,Standard_False);
817 for ( ; wi.More(); wi.Next()) {
818 if(wi.Value().ShapeType() == TopAbs_WIRE &&
819 (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED))
820 ws.Append (wi.Value());
822 vs.Append(wi.Value());
825 // deal with the case of an empty face: just create a new face by a standard tool
826 if (ws.IsEmpty() && !IsSurfaceUVInfinite (mySurf->Surface()))
828 BRepBuilderAPI_MakeFace aFaceBuilder (mySurf->Surface(), Precision::Confusion());
830 TopoDS_Face aNewFace = aFaceBuilder.Face();
831 aNewFace.Orientation (myFace.Orientation());
833 if ( ! Context().IsNull() )
834 Context()->Replace (myFace, aNewFace);
836 // taking into account orientation
839 //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated
840 Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool();
841 for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) {
842 TopoDS_Edge edg = TopoDS::Edge (Eed.Current());
843 sfe->FixVertexTolerance(edg);
846 // B.UpdateFace (myFace,myPrecision);
847 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
848 BRepTools::Update(myFace);
850 return Standard_True;
853 // check if surface is double-closed and fix is needed
854 if ( !IsSurfaceUVPeriodic (mySurf->Surface()) || ShapeAnalysis::IsOuterBound (myFace) )
855 return Standard_False;
857 // Collect informations on free intervals in U and V
858 TColgp_SequenceOfPnt2d intU, intV, centers;
859 Standard_Real SUF, SUL, SVF, SVL;
860 mySurf->Bounds(SUF, SUL, SVF, SVL);
861 intU.Append ( gp_Pnt2d(SUF, SUL) );
862 intV.Append ( gp_Pnt2d(SVF, SVL) );
863 Standard_Integer nb = ws.Length();
865 for ( i=1; i <= nb; i ++) {
866 Standard_Real Umin, Vmin, Umax, Vmax;
868 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
869 // PTV 01.11.2002 ACIS907, OCC921 begin
870 // BRepTools::AddUVBounds(myFace,aw,B);
871 // B.Get(Umin, Vmin, Umax, Vmax);
872 TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() );
874 aB.Add( aWireFace, aw );
875 ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax);
876 // PTV 01.11.2002 ACIS907, OCC921 end
877 if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF );
878 if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF );
879 centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) );
882 // find best interval and thus compute shift
883 gp_Pnt2d shift(0.,0.);
884 if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) );
885 if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) );
887 // Adjust all other wires to be inside outer one
888 gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) );
889 for ( i=1; i <= nb; i++ ) {
890 TopoDS_Wire wire = TopoDS::Wire (ws.Value(i));
892 if ( mySurf->IsUClosed() )
893 sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) );
894 if ( mySurf->IsVClosed() )
895 sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) );
896 Shift2dWire ( wire, myFace, sh.XY(), mySurf );
899 // Create naturally bounded surface and add that wire to sequence
901 // Create fictive grid and call ComposeShell
902 Handle(Geom_RectangularTrimmedSurface) RTS =
903 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(),
904 SVF+shift.Y(), SVL+shift.Y() );
905 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
906 grid->SetValue ( 1, 1, RTS );
907 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
910 ShapeFix_ComposeShell CompShell;
911 CompShell.Init ( G, L, myFace, ::Precision::Confusion() );
912 CompShell.ClosedMode() = Standard_True;
913 CompShell.NaturalBoundMode() = Standard_True;
914 CompShell.SetContext( Context() );
915 CompShell.SetMaxTolerance(MaxTolerance());
917 TopoDS_Shape res = CompShell.Result();
919 Context()->Replace ( myFace, res );
920 for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) {
921 myFace = TopoDS::Face ( exp.Current() );
922 BRepTools::Update(myFace); //:p4
924 myResult = Context()->Apply ( myResult );
928 Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L );
929 BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion());
930 TopoDS_Face ftmp = mf.Face();
932 for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) {
933 if(wi.Value().ShapeType() != TopAbs_WIRE)
935 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
937 if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue;
938 Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True );
941 // Fix possible case on sphere when gap contains degenerated edge
942 // and thus has a common part with natural boundary
943 // Such hole should be merged with boundary
944 if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere &&
945 ws.Length() == nb+1 ) {
946 Handle(ShapeExtend_WireData) bnd =
947 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) );
948 // code to become separate method FixTouchingWires()
949 for ( i=1; i <= nb; i++ ) {
950 Handle(ShapeExtend_WireData) sbwd =
951 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) );
952 for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
953 if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue;
954 // find corresponding place in boundary
955 ShapeAnalysis_Edge sae;
956 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
958 for ( k=1; k <= bnd->NbEdges(); k++ ) {
959 if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue;
960 if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break;
962 if ( k > bnd->NbEdges() ) continue;
963 // and insert hole to that place
965 B.Degenerated ( sbwd->Edge(j), Standard_False );
966 B.Degenerated ( bnd->Edge(k), Standard_False );
968 bnd->Add ( sbwd, k+1 );
971 myFixWire->SetFace ( myFace );
972 myFixWire->Load ( bnd );
973 myFixWire->FixConnected();
974 myFixWire->FixDegenerated();
975 ws.SetValue ( ws.Length(), bnd->Wire() );
981 // Create resulting face
983 TopoDS_Shape S = myFace.EmptyCopied();
984 S.Orientation ( TopAbs_FORWARD );
985 for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) );
986 for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) );
987 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
988 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
989 myFace = TopoDS::Face ( S );
990 BRepTools::Update(myFace);
994 cout<<"Natural bound on sphere or torus with holes added"<<endl; // mise au point !
996 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
997 return Standard_True;
1001 //=======================================================================
1002 //function : FixOrientation
1004 //=======================================================================
1006 Standard_Boolean ShapeFix_Face::FixOrientation()
1008 TopTools_DataMapOfShapeListOfShape MapWires;
1010 return FixOrientation(MapWires);
1014 //=======================================================================
1015 //function : FixOrientation
1017 //=======================================================================
1019 Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShape &MapWires)
1021 Standard_Boolean done = Standard_False;
1023 if ( ! Context().IsNull() ) {
1024 TopoDS_Shape S = Context()->Apply ( myFace );
1025 myFace = TopoDS::Face ( S );
1027 TopTools_SequenceOfShape ws;
1028 TopTools_SequenceOfShape allSubShapes;
1029 // smh: BUC60810 : protection against very small wires (one-edge, null-length)
1030 TopTools_SequenceOfShape VerySmallWires;
1031 for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) {
1032 if(wi.Value().ShapeType() == TopAbs_VERTEX ||
1033 (wi.Value().Orientation() != TopAbs_FORWARD &&
1034 wi.Value().Orientation() != TopAbs_REVERSED)) {
1035 allSubShapes.Append (wi.Value());
1036 //ws.Append (wi.Value());
1040 TopoDS_Iterator ei (wi.Value(),Standard_False);
1042 Standard_Real length = RealLast();
1044 anEdge = TopoDS::Edge(ei.Value());
1046 if ( ! ei.More() ) {
1048 Standard_Real First, Last;
1049 Handle(Geom_Curve) c3d;
1050 ShapeAnalysis_Edge sae;
1051 if ( sae.Curve3d(anEdge,c3d,First,Last) ) {
1052 gp_Pnt pntIni = c3d->Value(First);
1054 prev = pntIni.XYZ();
1055 Standard_Integer NbControl = 10;
1056 for ( Standard_Integer j = 1; j < NbControl; j++) {
1057 Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1);
1058 gp_Pnt pntCurr = c3d->Value(prm);
1059 gp_XYZ curr = pntCurr.XYZ();
1060 gp_XYZ delta = curr - prev;
1061 length += delta.Modulus();
1068 if (length > ::Precision::Confusion()) {
1069 ws.Append (wi.Value());
1070 allSubShapes.Append (wi.Value());
1072 else VerySmallWires.Append (wi.Value());
1074 if ( VerySmallWires.Length() >0 ) done = Standard_True;
1076 Standard_Integer nb = ws.Length();
1077 Standard_Integer nbAll = allSubShapes.Length();
1080 // if no wires, just do nothing
1081 if ( nb <= 0) return Standard_False;
1082 Standard_Integer nbInternal=0;
1083 Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) &&
1084 IsSurfaceUVPeriodic (mySurf->Surface()));
1085 TColStd_SequenceOfInteger aSeqReversed;
1086 // if wire is only one, check its orientation
1088 // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1)
1089 // make face with only one wire (ws.Value(1))
1090 TopoDS_Shape dummy = myFace.EmptyCopied();
1091 TopoDS_Face af = TopoDS::Face ( dummy );
1092 af.Orientation ( TopAbs_FORWARD );
1093 B.Add (af,ws.Value(1));
1094 if ((myFixAddNaturalBoundMode != Standard_True || //: abv 29.08.01: Spatial_firex_lofting.sat
1095 !IsSurfaceUVPeriodic (mySurf->Surface()) ) &&
1096 !ShapeAnalysis::IsOuterBound (af) )
1098 Handle(ShapeExtend_WireData) sbdw =
1099 new ShapeExtend_WireData (TopoDS::Wire(ws.Value(1)));
1100 sbdw->Reverse ( myFace );
1101 ws.SetValue ( 1, sbdw->Wire() );
1102 SendWarning ( sbdw->Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1103 done = Standard_True;
1105 cout<<"Wire reversed"<<endl; // mise au point !
1109 // in case of several wires, perform complex analysis
1111 // Plusieurs wires : orientations relatives
1112 // Chaque wire doit "contenir" tous les autres
1113 // Evidemment, en cas de peau de leopard, il peut y avoir probleme
1115 // On prend chaque wire (NB: pcurves presentes !)
1116 // En principe on devrait rejeter les wires non fermes (cf couture manque ?)
1117 // On le classe par rapport aux autres, qui doivent tous etre, soit IN soit
1118 // OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse
1119 // (nb : ici pas myClos donc pas de pb de couture)
1120 // Si au moins une inversion, il faut refaire la face (cf myRebil)
1122 //:94 abv 30 Jan 98: calculate parametric precision
1124 // GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1125 // Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) );
1126 Standard_Boolean uclosed = mySurf->IsUClosed();
1127 Standard_Boolean vclosed = mySurf->IsVClosed();
1128 Standard_Real SUF, SUL, SVF, SVL;
1129 mySurf->Bounds(SUF, SUL, SVF, SVL);
1131 TopTools_DataMapOfShapeListOfShape MW;
1132 TopTools_DataMapOfShapeInteger SI;
1133 TopTools_MapOfShape MapIntWires;
1136 MapIntWires.Clear();
1137 Standard_Integer NbOuts=0;
1140 for ( i = 1; i <= nb; i ++) {
1141 TopoDS_Shape asw = ws.Value(i);
1142 TopoDS_Wire aw = TopoDS::Wire (asw);
1143 TopoDS_Shape dummy = myFace.EmptyCopied();
1144 TopoDS_Face af = TopoDS::Face ( dummy );
1145 // B.MakeFace (af,mySurf->Surface(),::Precision::Confusion());
1146 af.Orientation ( TopAbs_FORWARD );
1148 // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787)
1149 // tolerance is too big. It is seems that to identify placement of 2d point
1150 // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON
1151 // BRepTopAdaptor_FClass2d clas (af,toluv);
1152 Standard_Boolean CheckShift = Standard_True;
1153 BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion());
1154 TopAbs_State sta = TopAbs_OUT;
1155 TopAbs_State staout = clas.PerformInfinitePoint();
1156 TopTools_ListOfShape IntWires;
1157 for ( Standard_Integer j = 1; j <= nbAll; j ++) {
1158 //if(i==j) continue;
1159 TopoDS_Shape aSh2 = allSubShapes.Value(j);
1162 TopAbs_State stb = TopAbs_UNKNOWN;
1163 if(aSh2.ShapeType() == TopAbs_VERTEX) {
1164 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2));
1165 gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion());
1166 stb = clas.Perform (p2d,Standard_False);
1167 if(stb == staout && (uclosed || vclosed)) {
1170 Standard_Real period = SUL-SUF;
1171 p2d1.SetCoord(p2d.X()+period, p2d.Y());
1172 stb = clas.Perform (p2d1,Standard_False);
1175 if(stb == staout && vclosed) {
1176 Standard_Real period = SVL-SVF;
1177 p2d1.SetCoord(p2d.X(), p2d.Y()+ period);
1178 stb = clas.Perform (p2d1,Standard_False);
1182 else if (aSh2.ShapeType() == TopAbs_WIRE) {
1183 CheckShift = Standard_True;
1184 TopoDS_Wire bw = TopoDS::Wire (aSh2);
1185 // Standard_Integer numin =0;
1186 TopoDS_Iterator ew (bw);
1187 for(;ew.More(); ew.Next()) {
1188 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1189 Standard_Real cf,cl;
1190 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1191 if (cw.IsNull()) continue;
1192 gp_Pnt2d unp = cw->Value ((cf+cl)/2.);
1193 TopAbs_State ste = clas.Perform (unp,Standard_False);
1194 if( ste==TopAbs_OUT || ste==TopAbs_IN ) {
1195 if(stb==TopAbs_UNKNOWN) {
1200 sta = TopAbs_UNKNOWN;
1208 Standard_Boolean found = Standard_False;
1210 if( stb == staout && CheckShift ) {
1211 CheckShift = Standard_False;
1213 Standard_Real period = SUL-SUF;
1214 unp1.SetCoord(unp.X()+period, unp.Y());
1215 found = (staout != clas.Perform (unp1,Standard_False));
1217 unp1.SetX(unp.X()-period);
1218 found = (staout != clas.Perform (unp1,Standard_False));
1221 if(vclosed&&!found) {
1222 Standard_Real period = SVL-SVF;
1223 unp1.SetCoord(unp.X(), unp.Y()+period);
1224 found = (staout != clas.Perform (unp1,Standard_False));
1226 unp1.SetY(unp.Y()-period);
1227 found = (staout != clas.Perform (unp1,Standard_False));
1232 if(stb==TopAbs_IN) stb = TopAbs_OUT;
1233 else stb = TopAbs_IN;
1234 Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf);
1242 IntWires.Append(aSh2);
1243 MapIntWires.Add(aSh2);
1247 if (sta == TopAbs_UNKNOWN) { // ERREUR
1248 SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire
1251 MW.Bind(aw,IntWires);
1252 if(sta==TopAbs_OUT) {
1254 if(staout==TopAbs_IN) {
1255 // wire is OUT but InfinitePoint is IN => need to reverse
1256 ShapeExtend_WireData sewd (aw);
1257 sewd.Reverse(myFace);
1258 ws.SetValue (i,sewd.Wire());
1259 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1260 aSeqReversed.Append(i);
1261 done = Standard_True;
1262 SI.Bind(ws.Value(i),1);
1263 MapWires.Bind(ws.Value(i),IntWires);
1267 MapWires.Bind(aw,IntWires);
1271 if(staout==TopAbs_OUT) SI.Bind(aw,2);
1278 for(i=1; i<=nb; i++) {
1279 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
1280 Standard_Integer tmpi = SI.Find(aw);
1282 if(!MapIntWires.Contains(aw)) {
1284 const TopTools_ListOfShape& IW = MW.Find(aw);
1286 // wire is OUT but InfinitePoint is IN => need to reverse
1287 ShapeExtend_WireData sewd (aw);
1288 sewd.Reverse(myFace);
1289 ws.SetValue (i,sewd.Wire());
1290 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1291 aSeqReversed.Append(i);
1292 done = Standard_True;
1293 MapWires.Bind(ws.Value(i),IW);
1295 else MapWires.Bind(aw,IW);
1299 // wire is IN but InfinitePoint is OUT => need to reverse
1300 ShapeExtend_WireData sewd (aw);
1301 sewd.Reverse(myFace);
1302 ws.SetValue (i,sewd.Wire());
1303 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1304 aSeqReversed.Append(i);
1305 done = Standard_True;
1313 //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1314 if(isAddNaturalBounds && nb == aSeqReversed.Length())
1315 done = Standard_False;
1317 done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1318 // Faut-il reconstruire ? si myRebil est mis
1320 TopoDS_Shape S = myFace.EmptyCopied();
1321 S.Orientation ( TopAbs_FORWARD );
1322 Standard_Integer i = 1;
1323 for ( ; i <= nb; i++ )
1324 B.Add ( S, ws.Value(i) );
1327 for( i =1; i <= nbAll;i++) {
1328 TopoDS_Shape aS2 = allSubShapes.Value(i);
1329 if(aS2.ShapeType() != TopAbs_WIRE ||
1330 (aS2.Orientation() != TopAbs_FORWARD && aS2.Orientation() != TopAbs_REVERSED))
1335 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
1336 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
1337 myFace = TopoDS::Face ( S );
1338 BRepTools::Update(myFace);
1339 Standard_Integer k =1;
1340 for( ; k <= aSeqReversed.Length(); k++ )
1343 cout<<"Wire no "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<endl; // mise au point !
1352 //=======================================================================
1353 //function : CheckWire
1354 //purpose : auxilary for FixMissingSeam
1355 //=======================================================================
1356 //:i7 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp: algorithm of fixing missing seam changed
1357 // test whether the wire is opened on period of periodical surface
1358 static Standard_Boolean CheckWire (const TopoDS_Wire &wire,
1359 const TopoDS_Face &face,
1360 const Standard_Real dU,
1361 const Standard_Real dV,
1362 Standard_Integer &isuopen,
1363 Standard_Integer &isvopen,
1364 Standard_Boolean &isDeg)
1369 ShapeAnalysis_Edge sae;
1370 isDeg = Standard_True;
1371 for ( TopoDS_Iterator ed(wire); ed.More(); ed.Next() ) {
1372 TopoDS_Edge edge = TopoDS::Edge ( ed.Value() );
1373 if ( ! BRep_Tool::Degenerated ( edge ) ) isDeg = Standard_False;
1374 Handle(Geom2d_Curve) c2d;
1376 if ( ! sae.PCurve ( edge, face, c2d, f, l, Standard_True ) )
1377 return Standard_False;
1378 vec += c2d->Value(l).XY() - c2d->Value(f).XY();
1380 isuopen = ( Abs ( Abs ( vec.X() ) - dU ) < 0.1 * dU ? ( vec.X() >0 ? 1 : -1 ) : 0 );
1381 isvopen = ( Abs ( Abs ( vec.Y() ) - dV ) < 0.1 * dV ? ( vec.Y() >0 ? 1 : -1 ) : 0 );
1382 return isuopen || isvopen;
1386 //=======================================================================
1387 //function : FixMissingSeam
1389 //=======================================================================
1391 Standard_Boolean ShapeFix_Face::FixMissingSeam()
1393 Standard_Boolean uclosed = mySurf->IsUClosed();
1394 Standard_Boolean vclosed = mySurf->IsVClosed();
1396 if ( ! uclosed && ! vclosed ) return Standard_False;
1398 if ( ! Context().IsNull() ) {
1399 TopoDS_Shape S = Context()->Apply ( myFace );
1400 myFace = TopoDS::Face ( S );
1403 //%pdn: surface should be made periodic before (see ShapeCustom_Surface)!
1404 if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) {
1405 Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface());
1406 if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic())
1407 return Standard_False;
1410 Standard_Real URange, VRange, SUF, SUL, SVF, SVL;
1411 mySurf->Bounds ( SUF, SUL, SVF, SVL );
1412 Standard_Real fU1,fU2,fV1,fV2;
1413 BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2);
1415 //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters
1416 if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
1417 if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
1418 if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
1419 if(Abs(SUL-SUF) < ::Precision::PConfusion()) {
1420 if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
1424 if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
1425 if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
1426 if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
1427 if(Abs(SVL-SVF) < ::Precision::PConfusion()) {
1428 if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
1433 URange = Abs ( SUL - SUF );
1434 VRange = Abs ( SVL - SVF );
1435 // Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1436 Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean
1437 Standard_Integer isdeg1=0, isdeg2=0;
1439 TopTools_SequenceOfShape ws;
1440 TopTools_SequenceOfShape aSeqNonManif;
1441 for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) {
1442 if(wi.Value().ShapeType() != TopAbs_WIRE ||
1443 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
1444 aSeqNonManif.Append(wi.Value());
1447 ws.Append ( wi.Value() );
1452 for ( i=1; i <= ws.Length(); i++ ) {
1453 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1454 Standard_Integer isuopen, isvopen;
1455 Standard_Boolean isdeg;
1456 if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) )
1458 if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; }
1459 else if ( w2.IsNull() ) {
1460 if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; }
1461 else if ( ismodeu == isuopen && ismodev == isvopen ) {
1464 //:abv 29.08.01: If wires are contraversal, reverse one of them
1465 // If first one is single degenerated edge, reverse it; else second
1474 if ( ! isdeg2 ) cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << endl;
1479 else cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << endl;
1482 // else return Standard_False; // abort
1485 cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << endl;
1487 //:abv 30.08.09: if more than one open wires and more than two of them are
1488 // completely degenerated, remove any of them
1489 if ( isdeg || isdeg1 || isdeg2 ) {
1490 ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 );
1495 cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << endl;
1503 if ( w1.IsNull() ) return Standard_False;
1504 else if ( w2.IsNull() ) {
1505 // WARNING!!! Temporarily for spheres only:
1506 // If only one of wires limiting face on sphere is open in 2d,
1507 // this means that degenerated edge should be added to one of poles, and
1508 // then usual procedure applied
1509 if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
1510 gp_Pnt2d p ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI );
1511 gp_Dir2d d ( -ismodeu, 0. );
1512 Handle(Geom2d_Line) line = new Geom2d_Line ( p, d );
1514 B.MakeEdge ( edge );
1515 B.Degenerated ( edge, Standard_True );
1516 B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() );
1517 B.Range ( edge, myFace, 0., 2*M_PI );
1519 B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() );
1520 V.Orientation(TopAbs_FORWARD);
1522 V.Orientation(TopAbs_REVERSED);
1528 else return Standard_False;
1531 // sort original wires
1532 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
1533 sfw->SetFace ( myFace );
1534 sfw->SetPrecision ( Precision() );
1536 Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 );
1537 Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 );
1540 // Standard_Boolean degenerated = ( secondDeg != firstDeg );
1541 // if ( ! degenerated ) {
1548 //:abv 29.08.01: reconstruct face taking into account reversing
1549 TopoDS_Shape dummy = myFace.EmptyCopied();
1550 TopoDS_Face tmpF = TopoDS::Face ( dummy );
1551 tmpF.Orientation ( TopAbs_FORWARD );
1552 for ( i=1; i <= ws.Length(); i++ ) {
1553 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1554 if ( wire.IsSame ( w1 ) ) wire = w1;
1555 else if ( wire.IsSame ( w2 ) ) wire = w2;
1556 B.Add ( tmpF, wire );
1558 tmpF.Orientation ( myFace.Orientation() );
1560 Standard_Real uf=SUF, vf=SVF;
1562 // A special kind of FixShifted is necessary for torus-like
1563 // surfaces to adjust wires by period ALONG the missing SEAM direction
1564 // tr9_r0501-ug.stp #187640
1565 if ( uclosed && vclosed ) {
1566 Standard_Integer coord = ( ismodeu ? 1 : 0 );
1567 Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev );
1568 Standard_Real period = ( ismodeu ? URange : VRange );
1570 Standard_Real m1[2][2], m2[2][2];
1571 S = tmpF.EmptyCopied();
1573 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]);
1574 S = tmpF.EmptyCopied();
1576 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1577 Standard_Real shiftw2 =
1578 ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1579 0.5 * ( m1[coord][0] + m1[coord][1] +
1580 isneg * ( period + ::Precision::PConfusion() ) ),
1582 m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 );
1583 m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 );
1584 for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) {
1585 if(it.Value().ShapeType() != TopAbs_WIRE)
1587 TopoDS_Wire w = TopoDS::Wire ( it.Value() );
1588 if ( w == w1 ) continue;
1589 Standard_Real shift;
1590 if ( w == w2 ) shift = shiftw2;
1592 S = tmpF.EmptyCopied();
1594 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1595 shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1596 0.5 * ( m1[coord][0] + m1[coord][1] ), period );
1598 if ( shift != 0. ) {
1600 V.SetCoord ( coord+1, shift );
1601 ShapeAnalysis_Edge sae;
1602 for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) {
1603 TopoDS_Edge E = TopoDS::Edge ( iw.Value() );
1604 Handle(Geom2d_Curve) C;
1606 if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue;
1611 // abv 05 Feb 02: OCC34
1612 // by the way, select proper split place by V to avoid extra intersections
1613 if ( m1[coord][1] - m1[coord][0] <= period ) {
1614 Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period );
1615 if ( ismodeu ) vf = other;
1620 // find the best place by u and v to insert a seam
1621 // (so as to minimize splitting edges as possible)
1622 ShapeAnalysis_Edge sae;
1623 Standard_Integer foundU=0, foundV=0;
1624 Standard_Integer nb1 = wd1->NbEdges();
1625 Standard_Integer nb2 = wd2->NbEdges();
1626 for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) {
1627 TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) );
1628 Handle(Geom2d_Curve) c2d;
1630 if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1631 gp_Pnt2d pos1 = c2d->Value(l).XY();
1632 // the best place is end of edge which is nearest to 0
1633 Standard_Boolean skipU = ! uclosed;
1634 if ( uclosed && ismodeu ) {
1635 pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) );
1636 if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True;
1637 else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) {
1642 Standard_Boolean skipV = ! vclosed;
1643 if ( vclosed && ! ismodeu ) {
1644 pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, URange ) );
1645 if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True;
1646 else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) {
1651 if ( skipU && skipV ) {
1652 if ( i1 <= nb1 ) continue;
1655 // or yet better - if it is end of some edges on both wires
1656 for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
1657 TopoDS_Edge edge2 = wd2->Edge ( i2 );
1658 if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1659 gp_Pnt2d pos2 = c2d->Value(f).XY();
1660 if ( uclosed && ismodeu ) {
1661 pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) );
1662 if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() &&
1663 ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) {
1668 if ( vclosed && ! ismodeu ) {
1669 pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) );
1670 if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() &&
1671 ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) {
1679 //pdn fixing RTS on offsets
1680 if ( uf < SUF || uf > SUL )
1681 uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange);
1682 if ( vf < SVF || vf > SVL )
1683 vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange);
1685 // Create fictive grid and call ComposeShell to insert a seam
1686 Handle(Geom_RectangularTrimmedSurface) RTS =
1687 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange );
1688 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
1689 grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() );
1690 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
1693 //addition non-manifold topology
1694 Standard_Integer j=1;
1695 for( ; j <= aSeqNonManif.Length(); j++)
1696 B.Add(tmpF,aSeqNonManif.Value(j));
1698 ShapeFix_ComposeShell CompShell;
1699 // TopoDS_Face tmpF = myFace;
1700 // tmpF.Orientation(TopAbs_FORWARD);
1701 CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision
1702 if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape );
1703 CompShell.ClosedMode() = Standard_True;
1704 CompShell.SetContext( Context() );
1705 CompShell.SetMaxTolerance(MaxTolerance());
1706 CompShell.Perform();
1708 // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf
1709 mySurf = new ShapeAnalysis_Surface ( RTS );
1711 myResult = CompShell.Result();
1712 // if ( myFace.Orientation() == TopAbs_REVERSED ) res.Reverse();
1713 Context()->Replace ( myFace, myResult );
1714 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
1715 myFace = TopoDS::Face ( exp.Current() );
1716 BRepTools::Update(myFace); //:p4
1719 SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added
1720 return Standard_True;
1723 //=======================================================================
1724 //function : FixSmallAreaWire
1726 //=======================================================================
1728 //%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
1729 Standard_Boolean ShapeFix_Face::FixSmallAreaWire()
1731 if ( ! Context().IsNull() ) {
1732 TopoDS_Shape S = Context()->Apply ( myFace );
1733 myFace = TopoDS::Face ( S );
1737 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
1738 TopoDS_Face face = TopoDS::Face (emptyCopied);
1739 Standard_Integer nbRemoved = 0, nbWires = 0;
1741 Standard_Real prec = ::Precision::PConfusion()*100;
1742 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
1743 if(wi.Value().ShapeType() != TopAbs_WIRE &&
1744 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED))
1746 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
1747 Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire(wire,myFace,prec);
1748 if ( saw->CheckSmallArea(prec) )
1750 SendWarning ( wire, Message_Msg ("FixAdvFace.FixSmallAreaWire.MSG0") );// Null area wire detected, wire skipped
1759 if ( nbRemoved <=0 ) return Standard_False;
1761 if ( nbWires <=0 ) {
1763 cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << endl;
1765 return Standard_False;
1768 cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << endl;
1770 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
1772 return Standard_True;
1774 //=======================================================================
1775 //function : FixLoopWire
1777 //=======================================================================
1778 static void FindNext(const TopoDS_Shape& aVert,
1779 const TopoDS_Shape& ainitEdge,
1780 TopTools_IndexedMapOfShape& aMapVertices,
1781 TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1782 const TopTools_MapOfShape& aMapSmallEdges,
1783 const TopTools_MapOfShape& aMapSeemEdges,
1784 TopTools_MapOfShape& aMapEdges,
1785 Handle(ShapeExtend_WireData)& aWireData)
1787 TopoDS_Iterator aItV(ainitEdge);
1788 TopoDS_Shape anextVert = aVert;
1789 Standard_Boolean isFind = Standard_False;
1790 for( ; aItV.More() && !isFind; aItV.Next())
1792 if(!aItV.Value().IsSame(aVert) ) {
1793 isFind = Standard_True;
1794 anextVert = aItV.Value();
1799 if(!isFind && !aMapSmallEdges.Contains(ainitEdge))
1801 if(isFind && aMapVertices.Contains(anextVert))
1804 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert);
1805 TopTools_ListIteratorOfListOfShape liter(aledges);
1806 isFind = Standard_False;
1807 TopoDS_Shape anextEdge;
1808 for( ; liter.More() && !isFind; liter.Next())
1810 if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) {
1811 anextEdge = liter.Value();
1812 aWireData->Add(anextEdge);
1813 if(aMapSeemEdges.Contains(anextEdge))
1814 aWireData->Add(anextEdge.Reversed());
1815 isFind = Standard_True;
1816 aMapEdges.Add(anextEdge);
1817 FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
1823 static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire)
1825 Standard_Boolean isClosed = Standard_True;
1826 Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion());
1827 for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) {
1828 TopoDS_Edge edge1 = asaw->WireData()->Edge(i);
1829 //checking that wire is closed in 2D space with tolerance of vertex.
1830 ShapeAnalysis_Edge sae;
1831 TopoDS_Vertex v1 = sae.FirstVertex(edge1);
1832 asaw->SetPrecision(BRep_Tool::Tolerance(v1));
1833 asaw->CheckGap2d(i);
1834 isClosed = (asaw->LastCheckStatus(ShapeExtend_OK));
1840 //=======================================================================
1841 //function : FixLoopWire
1843 //=======================================================================
1845 Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires)
1847 TopTools_IndexedMapOfShape aMapVertices;
1848 TopTools_DataMapOfShapeListOfShape aMapVertexEdges;
1849 TopTools_MapOfShape aMapSmallEdges;
1850 TopTools_MapOfShape aMapSeemEdges;
1851 if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges))
1852 return Standard_False;
1855 TopTools_MapOfShape aMapEdges;
1856 TopTools_SequenceOfShape aSeqWires;
1858 //collecting wires from common vertex belonging more than 2 edges
1859 Standard_Integer i =1;
1860 for( ; i <= aMapVertices.Extent(); i++) {
1861 TopoDS_Shape aVert = aMapVertices.FindKey(i);
1862 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert);
1863 TopTools_ListIteratorOfListOfShape liter(aledges);
1864 for( ; liter.More(); liter.Next())
1866 TopoDS_Edge Edge = TopoDS::Edge(liter.Value());
1867 if(aMapEdges.Contains(Edge))
1870 Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
1871 aWireData->Add(Edge);
1872 if(aMapSeemEdges.Contains(Edge))
1873 aWireData->Add(Edge.Reversed());
1874 aMapEdges.Add(Edge);
1875 FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
1876 if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1)))
1878 TopoDS_Vertex aV1,aV2;
1879 TopoDS_Wire aWire = aWireData->Wire();
1880 TopExp::Vertices(aWire,aV1,aV2);
1882 if(aV1.IsSame(aV2)) {
1883 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1884 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1887 TopoDS_Wire awire2 = asfw->Wire();
1888 aResWires.Append(awire2);
1891 else aSeqWires.Append(aWireData->Wire());
1896 if(aSeqWires.Length() ==1) {
1897 aResWires.Append(aSeqWires.Value(1));
1900 //collecting whole wire from two not closed wires having two common vertices.
1901 for( i =1; i <= aSeqWires.Length(); i++) {
1902 TopoDS_Vertex aV1,aV2;
1903 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
1904 TopExp::Vertices(aWire,aV1,aV2);
1905 Standard_Integer j = i+1;
1906 for( ; j <= aSeqWires.Length(); j++)
1908 TopoDS_Vertex aV21,aV22;
1909 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
1910 TopExp::Vertices(aWire2,aV21,aV22);
1911 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
1913 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1915 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1918 aResWires.Append(asfw->Wire());
1919 aSeqWires.Remove(j--);
1920 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
1925 if(j <= aSeqWires.Length())
1926 aSeqWires.Remove(i--);
1929 if(aSeqWires.Length()<3) {
1930 for( i =1; i <= aSeqWires.Length(); i++)
1931 aResWires.Append(aSeqWires.Value(i));
1935 //collecting wires having one common vertex
1936 for( i =1; i <= aSeqWires.Length(); i++) {
1937 TopoDS_Vertex aV1,aV2;
1938 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
1939 TopExp::Vertices(aWire,aV1,aV2);
1940 Standard_Integer j =i+1;
1941 for( ; j <= aSeqWires.Length(); j++)
1943 TopoDS_Vertex aV21,aV22;
1944 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
1945 TopExp::Vertices(aWire2,aV21,aV22);
1946 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
1948 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1950 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1953 aWire = asfw->Wire();
1954 TopExp::Vertices(aWire,aV1,aV2);
1955 aSeqWires.Remove(j--);
1956 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
1959 aResWires.Append(aWire);
1964 Standard_Boolean isClosed = Standard_True;
1966 //checking that obtained wires is closed in 2D space
1967 if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) {
1969 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
1970 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
1971 tmpFace.Orientation ( TopAbs_FORWARD );
1973 for(i =1; i <= aResWires.Length() && isClosed; i++) {
1974 TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i));
1975 isClosed = isClosed2D(tmpFace,awire);
1979 Standard_Boolean isDone =(aResWires.Length() && isClosed);
1980 if(isDone && aResWires.Length() >1)
1983 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
1990 //=======================================================================
1991 //function : SplitEdge
1993 //=======================================================================
1995 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
1996 const Standard_Integer num,
1997 const Standard_Real param,
1998 const TopoDS_Vertex& vert,
1999 const Standard_Real preci,
2000 ShapeFix_DataMapOfShapeBox2d& boxes)
2002 TopoDS_Edge edge = sewd->Edge(num);
2003 TopoDS_Edge newE1, newE2;
2004 ShapeFix_SplitTool aTool;
2005 if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2007 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2010 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2011 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2012 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2013 BRepTools::Update(E);
2016 // for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) {
2017 // TopoDS_Edge E = sewd->Edge(i);
2018 // TopoDS_Shape S = Context()->Apply ( E );
2019 // if ( S == E ) continue;
2020 // for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
2021 // sewd->Add ( exp.Current(), i++ );
2022 // sewd->Remove ( i-- );
2025 // change sewd and boxes
2026 sewd->Set(newE1,num);
2027 if(num==sewd->NbEdges())
2030 sewd->Add(newE2,num+1);
2034 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2035 Handle(Geom2d_Curve) c2d;
2036 Standard_Real cf,cl;
2037 ShapeAnalysis_Edge sae;
2038 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2040 Geom2dAdaptor_Curve gac;
2041 Standard_Real aFirst = c2d->FirstParameter();
2042 Standard_Real aLast = c2d->LastParameter();
2043 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2044 && (cf < aFirst || cl > aLast)) {
2045 //pdn avoiding problems with segment in Bnd_Box
2049 gac.Load(c2d,cf,cl);
2050 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2051 boxes.Bind(newE1,box);
2053 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2055 Geom2dAdaptor_Curve gac;
2056 Standard_Real aFirst = c2d->FirstParameter();
2057 Standard_Real aLast = c2d->LastParameter();
2058 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2059 && (cf < aFirst || cl > aLast)) {
2060 //pdn avoiding problems with segment in Bnd_Box
2064 gac.Load(c2d,cf,cl);
2065 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2066 boxes.Bind(newE2,box);
2068 return Standard_True;
2070 return Standard_False;
2074 //=======================================================================
2075 //function : SplitEdge
2077 //=======================================================================
2079 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2080 const Standard_Integer num,
2081 const Standard_Real param1,
2082 const Standard_Real param2,
2083 const TopoDS_Vertex& vert,
2084 const Standard_Real preci,
2085 ShapeFix_DataMapOfShapeBox2d& boxes)
2087 TopoDS_Edge edge = sewd->Edge(num);
2088 TopoDS_Edge newE1, newE2;
2089 ShapeFix_SplitTool aTool;
2090 if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2092 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2095 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2096 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2097 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2098 BRepTools::Update(E);
2101 // change sewd and boxes
2102 sewd->Set(newE1,num);
2103 if(num==sewd->NbEdges())
2106 sewd->Add(newE2,num+1);
2110 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2111 Handle(Geom2d_Curve) c2d;
2112 Standard_Real cf,cl;
2113 ShapeAnalysis_Edge sae;
2114 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2116 Geom2dAdaptor_Curve gac;
2117 Standard_Real aFirst = c2d->FirstParameter();
2118 Standard_Real aLast = c2d->LastParameter();
2119 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2120 && (cf < aFirst || cl > aLast)) {
2121 //pdn avoiding problems with segment in Bnd_Box
2125 gac.Load(c2d,cf,cl);
2126 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2127 boxes.Bind(newE1,box);
2129 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2131 Geom2dAdaptor_Curve gac;
2132 Standard_Real aFirst = c2d->FirstParameter();
2133 Standard_Real aLast = c2d->LastParameter();
2134 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2135 && (cf < aFirst || cl > aLast)) {
2136 //pdn avoiding problems with segment in Bnd_Box
2140 gac.Load(c2d,cf,cl);
2141 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2142 boxes.Bind(newE2,box);
2144 return Standard_True;
2146 return Standard_False;
2150 //=======================================================================
2151 //function : FixIntersectingWires
2153 //=======================================================================
2155 Standard_Boolean ShapeFix_Face::FixIntersectingWires()
2157 ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance());
2158 return ITool.FixIntersectingWires(myFace);
2162 //=======================================================================
2163 //function : FixWiresTwoCoincEdges
2165 //=======================================================================
2167 Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges()
2169 if ( ! Context().IsNull() ) {
2170 TopoDS_Shape S = Context()->Apply ( myFace );
2171 myFace = TopoDS::Face ( S );
2174 TopAbs_Orientation ori = myFace.Orientation();
2175 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2176 TopoDS_Face face = TopoDS::Face (emptyCopied);
2177 face.Orientation(TopAbs_FORWARD);
2178 Standard_Integer nbWires = 0;
2181 for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) {
2182 if(it.Value().ShapeType() != TopAbs_WIRE ||
2183 (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) {
2188 if(nbWires<2) return Standard_False;
2189 Standard_Boolean isFixed = Standard_False;
2190 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
2191 if(wi.Value().ShapeType() != TopAbs_WIRE ||
2192 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
2193 B.Add(face,wi.Value());
2196 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
2197 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2198 if(sewd->NbEdges()==2) {
2199 TopoDS_Edge E1 = sewd->Edge(1);
2200 TopoDS_Edge E2 = sewd->Edge(2);
2201 E1.Orientation(TopAbs_FORWARD);
2202 E2.Orientation(TopAbs_FORWARD);
2206 else isFixed = Standard_True;
2213 face.Orientation(ori);
2214 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
2222 //=======================================================================
2223 //function : FixSplitFace
2225 //=======================================================================
2227 Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires)
2230 TopTools_SequenceOfShape faces;
2231 TopoDS_Shape S = myFace;
2232 if ( ! Context().IsNull() )
2233 S = Context()->Apply ( myFace );
2234 Standard_Integer NbWires=0, NbWiresNew=0, NbEdges;
2235 for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
2236 const TopoDS_Shape& aShape = iter.Value();
2237 if(aShape.ShapeType() != TopAbs_WIRE ||
2238 (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
2240 TopoDS_Wire wire = TopoDS::Wire ( aShape );
2242 if(MapWires.IsBound(wire)) {
2243 // if wire not closed --> stop split and return false
2244 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2245 NbEdges = sewd->NbEdges();
2250 TopoDS_Edge E1 = sewd->Edge(1);
2251 TopoDS_Edge E2 = sewd->Edge(NbEdges);
2252 TopoDS_Vertex V1,V2;
2253 ShapeAnalysis_Edge sae;
2254 V1=sae.FirstVertex(E1);
2255 V2=sae.LastVertex(E2);
2256 if(!V1.IsSame(V2)) {
2257 cout<<"wire not closed --> stop split"<<endl;
2258 return Standard_False;
2261 TopoDS_Shape emptyCopied = S.EmptyCopied();
2262 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2263 tmpFace.Orientation ( TopAbs_FORWARD );
2264 B.Add(tmpFace,wire);
2266 const TopTools_ListOfShape& IntWires = MapWires.Find(wire);
2267 TopTools_ListIteratorOfListOfShape liter(IntWires);
2268 for( ; liter.More(); liter.Next()) {
2269 B.Add(tmpFace,liter.Value());
2272 if(!myFwd) tmpFace.Orientation(TopAbs_REVERSED);
2273 faces.Append(tmpFace);
2277 if(NbWires!=NbWiresNew) return Standard_False;
2279 if(faces.Length()>1) {
2280 TopoDS_Compound Comp;
2281 B.MakeCompound(Comp);
2282 for(Standard_Integer i=1; i<=faces.Length(); i++ )
2283 B.Add(Comp,faces(i));
2285 Context()->Replace ( myFace, myResult );
2286 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
2287 myFace = TopoDS::Face ( exp.Current() );
2288 BRepTools::Update(myFace);
2290 return Standard_True;
2293 return Standard_False;
2296 //=======================================================================
2297 //function : IsPeriodicConicalLoop
2298 //purpose : Checks whether the passed wire makes up a periodic loop on
2299 // passed conical surface
2300 //=======================================================================
2302 static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
2303 const TopoDS_Wire& theWire,
2304 const Standard_Real theTolerance,
2305 Standard_Real& theMinU,
2306 Standard_Real& theMaxU,
2307 Standard_Real& theMinV,
2308 Standard_Real& theMaxV,
2309 Standard_Boolean& isUDecrease)
2311 if ( theSurf.IsNull() )
2312 return Standard_False;
2314 ShapeAnalysis_Edge aSAE;
2315 TopLoc_Location aLoc;
2317 Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
2318 Standard_Real aMinU = RealLast();
2319 Standard_Real aMinV = aMinU;
2320 Standard_Real aMaxU = -aMinU;
2321 Standard_Real aMaxV = aMaxU;
2323 // Iterate over the edges to check whether the wire is periodic on conical surface
2324 TopoDS_Iterator aWireIter(theWire, Standard_False);
2325 for ( ; aWireIter.More(); aWireIter.Next() )
2327 const TopoDS_Edge& aCurrentEdge = TopoDS::Edge(aWireIter.Value());
2328 Handle(Geom2d_Curve) aC2d;
2329 Standard_Real aPFirst, aPLast;
2331 aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
2333 if ( aC2d.IsNull() )
2334 return Standard_False;
2336 gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
2337 aUVLast = aC2d->Value(aPLast);
2339 Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
2340 Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
2342 Standard_Real aCurMaxU = Max(aUFirst, aULast),
2343 aCurMinU = Min(aUFirst, aULast);
2344 Standard_Real aCurMaxV = Max(aVFirst, aVLast),
2345 aCurMinV = Min(aVFirst, aVLast);
2347 if ( aCurMinU < aMinU )
2349 if ( aCurMaxU > aMaxU )
2351 if ( aCurMinV < aMinV )
2353 if ( aCurMaxV > aMaxV )
2356 Standard_Real aDeltaU = aULast - aUFirst;
2358 aCumulDeltaU += aDeltaU;
2359 aCumulDeltaUAbs += Abs(aDeltaU);
2366 isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
2368 Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
2369 Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
2371 return is2PIDelta && isAroundApex;
2374 //=======================================================================
2375 //function : FixPeriodicDegenerated
2377 //=======================================================================
2379 Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
2381 /* =====================
2382 * Prepare fix routine
2383 * ===================== */
2385 if ( !Context().IsNull() )
2387 TopoDS_Shape aSh = Context()->Apply(myFace);
2388 myFace = TopoDS::Face(aSh);
2391 /* ================================================
2392 * Check if fix can be applied on the passed face
2393 * ================================================ */
2395 // Collect all wires owned by the face
2396 TopTools_SequenceOfShape aWireSeq;
2397 for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
2399 const TopoDS_Shape& aSubSh = aWireIt.Value();
2400 if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
2401 aSubSh.Orientation() != TopAbs_REVERSED ) )
2404 aWireSeq.Append( aWireIt.Value() );
2407 // Get number of wires and surface
2408 Standard_Integer aNbWires = aWireSeq.Length();
2409 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
2411 // Only single wires on conical surfaces are checked
2412 if ( aNbWires != 1 || aSurface.IsNull() ||
2413 aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
2414 return Standard_False;
2416 // Get the single wire
2417 TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
2419 // Check whether this wire is belting the conical surface by period
2420 Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
2421 Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
2422 Standard_Boolean isUDecrease = Standard_False;
2424 Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
2425 aMinLoopU, aMaxLoopU,
2426 aMinLoopV, aMaxLoopV,
2430 return Standard_False;
2434 * =============== */
2436 // Get base circle of the conical surface (the circle it was built from)
2437 Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
2438 Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
2440 // Retrieve conical props
2441 Standard_Real aConeBaseR = aConeBaseCirc->Radius();
2442 Standard_Real aSemiAngle = aConeSurf->SemiAngle();
2444 if ( fabs(aSemiAngle) <= Precision::Confusion() )
2445 return Standard_False; // Bad surface
2447 // Find the V parameter of the apex
2448 Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
2449 Standard_Real anApexV = -aConeBaseH;
2452 TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
2454 // ====================================
2455 // Build degenerated edge in the apex
2456 // ====================================
2458 TopoDS_Edge anApexEdge;
2459 BRep_Builder aBuilder;
2460 aBuilder.MakeEdge(anApexEdge);
2462 // Check if positional relationship between the initial wire and apex
2463 // line in 2D is going to be consistent
2464 if ( fabs(anApexV - aMinLoopV) <= Precision() ||
2465 fabs(anApexV - aMaxLoopV) <= Precision() ||
2466 ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
2467 return Standard_False;
2469 Handle(Geom2d_Line) anApexCurve2d;
2471 // Apex curve below the wire
2472 if ( anApexV < aMinLoopV )
2474 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
2476 aSoleWire.Reverse();
2479 // Apex curve above the wire
2480 if ( anApexV > aMaxLoopV )
2482 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
2484 aSoleWire.Reverse();
2487 // Create degenerated edge & wire for apex
2488 aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
2489 aBuilder.Add( anApexEdge, anApex );
2490 aBuilder.Add( anApexEdge, anApex.Reversed() );
2491 aBuilder.Degenerated(anApexEdge, Standard_True);
2492 aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
2493 TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
2495 // ===============================================================
2496 // Finalize the fix building new face and setting up the results
2497 // ===============================================================
2499 // Collect the resulting set of wires
2500 TopTools_SequenceOfShape aNewWireSeq;
2501 aNewWireSeq.Append(aSoleWire);
2502 aNewWireSeq.Append(anApexWire);
2504 // Assemble new face
2505 TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
2506 aNewFace.Orientation(TopAbs_FORWARD);
2507 BRep_Builder aFaceBuilder;
2508 for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
2510 TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
2511 aFaceBuilder.Add(aNewFace, aNewWire);
2513 aNewFace.Orientation( myFace.Orientation() );
2515 // Adjust the resulting state of the healing tool
2516 myResult = aNewFace;
2517 Context()->Replace(myFace, myResult);
2519 return Standard_True;