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 <Bnd_Box.hxx>
32 #include <BndLib_Add2dCurve.hxx>
33 #include <BRep_Builder.hxx>
34 #include <BRep_Tool.hxx>
35 #include <BRepBuilderAPI_MakeFace.hxx>
36 #include <BRepBuilderAPI_MakeVertex.hxx>
37 #include <BRepBuilderAPI_MakeWire.hxx>
38 #include <BRepTools.hxx>
39 #include <BRepTopAdaptor_FClass2d.hxx>
40 #include <Geom2d_BSplineCurve.hxx>
41 #include <Geom2d_Curve.hxx>
42 #include <Geom2d_Line.hxx>
43 #include <Geom2dAdaptor_Curve.hxx>
44 #include <Geom2dInt_GInter.hxx>
45 #include <Geom_BSplineSurface.hxx>
46 #include <Geom_Circle.hxx>
47 #include <Geom_ConicalSurface.hxx>
48 #include <Geom_Curve.hxx>
49 #include <Geom_RectangularTrimmedSurface.hxx>
50 #include <Geom_SphericalSurface.hxx>
51 #include <Geom_ToroidalSurface.hxx>
52 #include <Geom_Surface.hxx>
53 #include <GProp_GProps.hxx>
54 #include <Message_Msg.hxx>
55 #include <NCollection_Array1.hxx>
56 #include <Precision.hxx>
57 #include <ShapeAnalysis.hxx>
58 #include <ShapeAnalysis_Edge.hxx>
59 #include <ShapeAnalysis_Surface.hxx>
60 #include <ShapeBuild_Edge.hxx>
61 #include <ShapeBuild_ReShape.hxx>
62 #include <ShapeExtend_CompositeSurface.hxx>
63 #include <ShapeFix.hxx>
64 #include <ShapeFix_ComposeShell.hxx>
65 #include <ShapeFix_Edge.hxx>
66 #include <ShapeFix_Face.hxx>
67 #include <ShapeFix_IntersectionTool.hxx>
68 #include <ShapeFix_SplitTool.hxx>
69 #include <ShapeFix_Wire.hxx>
70 #include <Standard_Type.hxx>
71 #include <TColGeom_HArray2OfSurface.hxx>
72 #include <TColgp_SequenceOfPnt2d.hxx>
73 #include <TColStd_MapOfInteger.hxx>
75 #include <TopExp_Explorer.hxx>
77 #include <TopoDS_Compound.hxx>
78 #include <TopoDS_Edge.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <TopoDS_Iterator.hxx>
81 #include <TopoDS_Vertex.hxx>
82 #include <TopoDS_Wire.hxx>
83 #include <TopTools_DataMapOfShapeInteger.hxx>
84 #include <TopTools_DataMapOfShapeListOfShape.hxx>
85 #include <TopTools_DataMapOfShapeShape.hxx>
86 #include <TopTools_IndexedMapOfShape.hxx>
87 #include <TopTools_MapOfShape.hxx>
88 #include <TopTools_SequenceOfShape.hxx>
90 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Face,ShapeFix_Root)
96 static Standard_Boolean IsSurfaceUVInfinite(const Handle(Geom_Surface)& theSurf)
98 Standard_Real UMin,UMax,VMin,VMax;
99 theSurf->Bounds(UMin,UMax,VMin,VMax);
101 return (Precision::IsInfinite(UMin) ||
102 Precision::IsInfinite(UMax) ||
103 Precision::IsInfinite(VMin) ||
104 Precision::IsInfinite(VMax) );
107 static Standard_Boolean IsSurfaceUVPeriodic(const Handle(GeomAdaptor_Surface)& theSurf)
109 return ( (theSurf->IsUPeriodic() && theSurf->IsVPeriodic()) || theSurf->GetType() == GeomAbs_Sphere);
112 //=======================================================================
113 //function : ShapeFix_Face
115 //=======================================================================
117 ShapeFix_Face::ShapeFix_Face()
119 myFwd = Standard_True;
121 myFixWire = new ShapeFix_Wire;
125 //=======================================================================
126 //function : ShapeFix_Face
128 //=======================================================================
130 ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face)
132 myFwd = Standard_True;
134 myFixWire = new ShapeFix_Wire;
139 //=======================================================================
140 //function : ClearModes
142 //=======================================================================
144 void ShapeFix_Face::ClearModes()
147 myFixOrientationMode = -1;
148 myFixAddNaturalBoundMode = -1;
149 myFixMissingSeamMode = -1;
150 myFixSmallAreaWireMode = -1;
151 myRemoveSmallAreaFaceMode = -1;
152 myFixIntersectingWiresMode = -1;
153 myFixLoopWiresMode = -1;
154 myFixSplitFaceMode = -1;
155 myAutoCorrectPrecisionMode = 1;
156 myFixPeriodicDegenerated = -1;
159 //=======================================================================
160 //function : SetMsgRegistrator
162 //=======================================================================
164 void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
166 ShapeFix_Root::SetMsgRegistrator ( msgreg );
167 myFixWire->SetMsgRegistrator ( msgreg );
170 //=======================================================================
171 //function : SetPrecision
173 //=======================================================================
175 void ShapeFix_Face::SetPrecision (const Standard_Real preci)
177 ShapeFix_Root::SetPrecision ( preci );
178 myFixWire->SetPrecision ( preci );
181 //=======================================================================
182 //function : SetMinTolerance
184 //=======================================================================
186 void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol)
188 ShapeFix_Root::SetMinTolerance ( mintol );
189 myFixWire->SetMinTolerance ( mintol );
192 //=======================================================================
193 //function : SetMaxTolerance
195 //=======================================================================
197 void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol)
199 ShapeFix_Root::SetMaxTolerance ( maxtol );
200 myFixWire->SetMaxTolerance ( maxtol );
203 //=======================================================================
206 //=======================================================================
208 void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf,
209 const Standard_Real preci, const Standard_Boolean fwd)
212 Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf );
213 Init ( sas, preci, fwd );
216 //=======================================================================
219 //=======================================================================
221 void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf,
222 const Standard_Real preci, const Standard_Boolean fwd)
226 SetPrecision ( preci );
228 B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() );
231 if ( !fwd ) myFace.Orientation(TopAbs_REVERSED);
234 //=======================================================================
237 //=======================================================================
239 void ShapeFix_Face::Init (const TopoDS_Face& face)
242 mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) );
243 myFwd = ( face.Orientation() != TopAbs_REVERSED );
246 // myFace = TopoDS::Face(face.EmptyCopied());
247 // for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next())
248 // Add (TopoDS::Wire (ws.Value()) );
251 //=======================================================================
254 //=======================================================================
256 void ShapeFix_Face::Add (const TopoDS_Wire& wire)
258 if ( wire.IsNull() ) return;
260 //szv#4:S4163:12Mar99 SGI warns
261 TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented()
266 //=======================================================================
267 //function : SplitWire
268 //purpose : auxiliary - try to split wire (it is needed if some segments
269 // were removed in ShapeFix_Wire::FixSelfIntersection() )
270 //=======================================================================
271 static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire,
272 TopTools_SequenceOfShape& aResWires)
274 TColStd_MapOfInteger UsedEdges;
275 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
276 Standard_Integer i,j,k;
277 ShapeAnalysis_Edge sae;
278 for(i=1; i<=sewd->NbEdges(); i++) {
279 if(UsedEdges.Contains(i)) continue;
280 TopoDS_Edge E1 = sewd->Edge(i);
282 TopoDS_Vertex V0,V1,V2;
283 V0 = sae.FirstVertex(E1);
284 V1 = sae.LastVertex(E1);
285 Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData;
287 Standard_Boolean IsConnectedEdge = Standard_True;
288 for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
290 for(k=2; k<=sewd->NbEdges(); k++) {
291 if(UsedEdges.Contains(k)) continue;
293 TopoDS_Vertex V21 = sae.FirstVertex(E2);
294 TopoDS_Vertex V22 = sae.LastVertex(E2);
295 if( sae.FirstVertex(E2).IsSame(V1) ) {
298 V1 = sae.LastVertex(E2);
302 if(k>sewd->NbEdges()) {
303 IsConnectedEdge = Standard_False;
307 //check that V0 and V1 are same in 2d too
308 Standard_Real a1,b1,a2,b2;
309 Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1);
310 Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2);
312 if (E1.Orientation() == TopAbs_REVERSED)
314 if (E2.Orientation() == TopAbs_REVERSED)
318 GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face));
319 Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1));
320 Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) );
321 if (v0.SquareDistance(v1) < maxResolution) {
322 // new wire is closed, put it into sequence
323 aResWires.Append(sewd1->Wire());
328 if(!IsConnectedEdge) {
329 // create new notclosed wire
330 aResWires.Append(sewd1->Wire());
332 if(UsedEdges.Extent()==sewd->NbEdges()) break;
335 if(aResWires.Length()>1) {
337 std::cout<<"Wire was split on "<<aResWires.Length()<<" wires"<< std::endl;
341 return Standard_True;
345 //=======================================================================
348 //=======================================================================
350 Standard_Boolean ShapeFix_Face::Perform()
352 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
353 myFixWire->SetContext ( Context() );
354 Handle(ShapeFix_Wire) theAdvFixWire = myFixWire;
355 if (theAdvFixWire.IsNull()) return Standard_False;
358 TopoDS_Shape aInitFace = myFace;
359 // perform first part of fixes on wires
360 Standard_Boolean isfixReorder = Standard_False;
361 Standard_Boolean isReplaced = Standard_False;
363 //gka fix in order to avoid lost messages (following OCC21771)
364 TopTools_DataMapOfShapeShape aMapReorderedWires;
366 Standard_Real aSavPreci = Precision();
367 if ( NeedFix ( myFixWireMode ) ) {
368 theAdvFixWire->SetFace ( myFace );
370 Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode();
371 //Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode(); // CR0024983
372 Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode();
373 theAdvFixWire->FixLackingMode() = Standard_False;
374 //theAdvFixWire->FixNotchedEdgesMode() = Standard_False; // CR0024983
375 theAdvFixWire->FixSelfIntersectionMode() = Standard_False;
377 Standard_Boolean fixed = Standard_False;
378 TopoDS_Shape S = myFace;
379 if ( ! Context().IsNull() )
380 S = Context()->Apply ( myFace );
381 TopoDS_Shape emptyCopied = S.EmptyCopied();
382 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
383 tmpFace.Orientation ( TopAbs_FORWARD );
386 // skl 14.05.2002 OCC55 + corrected 03.03.2004
387 Standard_Real dPreci = aSavPreci*aSavPreci;
389 Standard_Real newpreci=dPreci;
390 for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) {
391 TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
392 Standard_Real first,last;
393 Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
396 bb.Add(c3d->Value(first));
397 bb.Add(c3d->Value(last));
398 bb.Add(c3d->Value((last+first)/2.));
399 Standard_Real x1,x2,y1,y2,z1,z2,size;
400 bb.Get(x1,y1,z1,x2,y2,z2);
401 size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
402 if(size<newpreci) newpreci=size;
405 newpreci=sqrt(newpreci)/2.*1.00001;
406 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
407 SetPrecision(newpreci);
408 theAdvFixWire->SetPrecision(newpreci);
410 // end skl 14.05.2002
413 // skl 29.03.2010 (OCC21623)
414 if( myAutoCorrectPrecisionMode ) {
415 Standard_Real size = ShapeFix::LeastEdgeSize(S);
416 Standard_Real newpreci = Min(aSavPreci,size/2.);
417 newpreci = newpreci*1.00001;
418 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
419 SetPrecision(newpreci);
420 theAdvFixWire->SetPrecision(newpreci);
424 isfixReorder = Standard_False;
425 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
426 if(iter.Value().ShapeType() != TopAbs_WIRE) {
427 B.Add ( tmpFace, iter.Value() );
430 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
431 theAdvFixWire->Load ( wire );
432 if(theAdvFixWire->NbEdges() == 0) {
433 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
434 B.Add ( tmpFace, wire );
436 fixed = Standard_True;
437 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
441 if ( theAdvFixWire->Perform() ) {
442 //fixed = Standard_True;
443 isfixReorder = (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder);
444 fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) ||
445 theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
446 theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
447 theAdvFixWire->StatusNotches(ShapeExtend_DONE) || // CR0024983
448 theAdvFixWire->StatusFixTails(ShapeExtend_DONE) ||
449 theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
450 theAdvFixWire->StatusClosed(ShapeExtend_DONE));
451 TopoDS_Wire w = theAdvFixWire->Wire();
453 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
454 if(theAdvFixWire->NbEdges() == 0) {
455 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
459 else if(!wire.IsSame(w))
460 aMapReorderedWires.Bind(wire,w);
464 B.Add ( tmpFace, wire );
465 // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) )
466 // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
469 theAdvFixWire->FixLackingMode() = usFixLackingMode;
470 //theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode; // CR0024983
471 theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode;
472 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
475 //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
476 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
478 isReplaced = Standard_True;
480 if(fixed || isfixReorder) {
482 if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) {
483 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
489 TopoDS_Shape savShape = myFace; //gka BUG 6555
491 // Specific case for conic surfaces
492 if ( NeedFix(myFixPeriodicDegenerated) )
493 this->FixPeriodicDegenerated();
496 if ( NeedFix ( myFixMissingSeamMode ) ) {
497 if ( FixMissingSeam() ) {
498 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
502 // cycle by all possible faces coming from FixMissingSeam
503 // each face is processed as if it was single
504 TopExp_Explorer exp(myResult,TopAbs_FACE);
505 for ( ; exp.More(); exp.Next() ) {
506 myFace = TopoDS::Face ( exp.Current() );
507 Standard_Boolean NeedCheckSplitWire = Standard_False;
509 // perform second part of fixes on wires
510 if ( NeedFix ( myFixWireMode ) ) {
511 theAdvFixWire->SetFace ( myFace );
513 Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode();
514 Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode();
515 Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode();
516 Standard_Integer usFixDegeneratedMode = theAdvFixWire->FixDegeneratedMode();
517 theAdvFixWire->FixSmallMode() = Standard_False;
518 theAdvFixWire->FixConnectedMode() = Standard_False;
519 theAdvFixWire->FixEdgeCurvesMode() = Standard_False;
520 theAdvFixWire->FixDegeneratedMode() = Standard_False;
522 Standard_Boolean fixed = Standard_False;
523 TopoDS_Shape S = myFace;
524 if ( ! Context().IsNull() )
525 S = Context()->Apply ( myFace );
526 TopoDS_Shape emptyCopied = S.EmptyCopied();
527 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
528 tmpFace.Orientation ( TopAbs_FORWARD );
529 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
530 if(iter.Value().ShapeType() != TopAbs_WIRE) {
531 B.Add ( tmpFace,iter.Value());
535 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
536 theAdvFixWire->Load ( wire );
537 if(theAdvFixWire->NbEdges() == 0) {
538 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
539 B.Add ( tmpFace, wire );
541 fixed = Standard_True;
542 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
546 if ( theAdvFixWire->Perform() ) {
547 isfixReorder = theAdvFixWire->StatusReorder(ShapeExtend_DONE);
548 fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
549 theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
550 theAdvFixWire->StatusNotches(ShapeExtend_DONE) ||
551 theAdvFixWire->StatusFixTails(ShapeExtend_DONE));
552 TopoDS_Wire w = theAdvFixWire->Wire();
554 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
557 else if(!wire.IsSame(w))
558 aMapReorderedWires.Bind(wire,w);
562 if(theAdvFixWire->StatusRemovedSegment())
563 NeedCheckSplitWire = Standard_True;
565 //fix for loop of wire
566 TopTools_SequenceOfShape aLoopWires;
567 if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) {
568 if (aLoopWires.Length() > 1)
569 SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was split on several wires
570 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
571 fixed = Standard_True;
572 Standard_Integer k=1;
573 for( ; k <= aLoopWires.Length(); k++)
574 B.Add (tmpFace,aLoopWires.Value(k));
577 B.Add ( tmpFace, wire );
580 theAdvFixWire->FixSmallMode() = usFixSmallMode;
581 theAdvFixWire->FixConnectedMode() = usFixConnectedMode;
582 theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode;
583 theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode;
586 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
587 if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555
588 Context()->Replace(aInitFace,savShape);
589 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
591 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
595 if(NeedCheckSplitWire) {
596 // try to split wire - it is needed if some segments were removed
597 // in ShapeFix_Wire::FixSelfIntersection()
598 TopoDS_Shape S = myFace;
599 if ( ! Context().IsNull() )
600 S = Context()->Apply ( myFace );
601 TopoDS_Shape emptyCopied = S.EmptyCopied();
602 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
603 tmpFace.Orientation ( TopAbs_FORWARD );
604 TopTools_SequenceOfShape aWires;
605 Standard_Integer nbw=0;
606 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
607 if(iter.Value().ShapeType() != TopAbs_WIRE) {
608 B.Add (tmpFace,iter.Value());
611 if(iter.Value().Orientation() != TopAbs_FORWARD &&
612 iter.Value().Orientation() != TopAbs_REVERSED) {
613 B.Add (tmpFace,TopoDS::Wire(iter.Value()));
617 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
618 SplitWire(tmpFace,wire,aWires);
620 if(nbw<aWires.Length()) {
621 for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
622 B.Add (tmpFace,aWires.Value(iw));
623 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
624 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
629 // fix intersecting wires
630 if(FixWiresTwoCoincEdges())
631 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
632 if ( NeedFix ( myFixIntersectingWiresMode ) ) {
633 if ( FixIntersectingWires() ) {
634 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
639 TopTools_DataMapOfShapeListOfShape MapWires;
641 if ( NeedFix ( myFixOrientationMode ) ) {
642 if ( FixOrientation(MapWires) )
643 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
646 BRepTools::Update(myFace);
648 // fix natural bounds
649 Standard_Boolean NeedSplit = Standard_True;
650 if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
651 if ( FixAddNaturalBound() ) {
652 NeedSplit = Standard_False;
653 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
658 if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) {
659 if ( FixSplitFace(MapWires) )
660 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
665 //return the original preci
666 SetPrecision(aSavPreci);
667 theAdvFixWire->SetPrecision(aSavPreci);
669 // cycle by all possible faces coming from FixAddNaturalBound
670 // each face is processed as if it was single
671 for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) {
672 myFace = TopoDS::Face ( exp.Current() );
674 // fix small-area wires
675 if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) )
677 const Standard_Boolean isRemoveFace = NeedFix( myRemoveSmallAreaFaceMode, Standard_False );
678 if ( FixSmallAreaWire( isRemoveFace ) )
679 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
683 if ( ! Context().IsNull() ) {
684 if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
686 //gka fix in order to avoid lost messages (following OCC21771)
687 if(aMapReorderedWires.Extent())
689 TopoDS_Iterator aItW(aInitFace,Standard_False);
690 for( ; aItW.More() ; aItW.Next())
692 TopoDS_Shape aCurW = aItW.Value();
693 while(aMapReorderedWires.IsBound(aCurW))
695 TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW);
696 Context()->Replace(aCurW, aFixW);
702 Context()->Replace(aInitFace, savShape);
704 myResult = Context()->Apply ( aInitFace ); //gka 06.09.04
706 else if(!Status ( ShapeExtend_DONE ))
707 myResult = aInitFace;
709 return Status ( ShapeExtend_DONE );
712 //=======================================================================
713 //function : Auxiliary functions
715 //=======================================================================
717 // Shift all pcurves of edges in the given wire on the given face
719 static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f,
721 const Handle(ShapeAnalysis_Surface)& mySurf,
722 Standard_Boolean recompute3d = Standard_False)
725 tr2d.SetTranslation(vec.XY());
726 ShapeAnalysis_Edge sae;
729 for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){
730 TopoDS_Edge edge = TopoDS::Edge(ei.Value());
731 Handle (Geom2d_Curve) C2d;
732 Standard_Real cf, cl;
733 if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue;
734 C2d->Transform(tr2d);
736 // recompute 3d curve and vertex
737 sbe.RemoveCurve3d ( edge );
738 sbe.BuildCurve3d ( edge );
739 B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. );
744 // Cut interval from the sequence of intervals
745 static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals,
746 const gp_Pnt2d &toAddI,
747 const Standard_Real period)
749 if ( intervals.Length() <=0 ) return Standard_False;
750 for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top
751 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
752 gp_Pnt2d interval = intervals(i);
753 // ACIS907, OCC921 a054a.sat (face 124)
754 Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ),
755 0.5*( interval.X() + interval.Y() ),period);
756 gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift );
757 if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue;
758 if ( toAdd.X() > interval.X() ) {
759 if ( toAdd.Y() < interval.Y() ) {
760 intervals.InsertBefore ( i, interval );
761 intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++...
763 intervals.ChangeValue(i).SetY ( toAdd.X() );
765 else if ( toAdd.Y() < interval.Y() ) {
766 intervals.ChangeValue(i).SetX ( toAdd.Y() );
768 else intervals.Remove ( i-- );
771 return Standard_True;
774 // Find middle of the biggest interval
775 static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals)
777 Standard_Real shift = 0., max = -1.;
778 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
779 gp_Pnt2d interval = intervals(i);
780 if ( interval.Y() - interval.X() <= max ) continue;
781 max = interval.Y() - interval.X();
782 shift = interval.X() + 0.5 * max;
787 //=======================================================================
788 //function : FixAddNaturalBound
790 //=======================================================================
791 // Detect missing natural boundary on spherical surfaces and add it if
793 //pdn 981202: add natural bounds if missing (on sphere only)
794 //:abv 28.08.01: rewritten and extended for toruses
796 Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
798 if ( ! Context().IsNull() ) {
799 TopoDS_Shape S = Context()->Apply ( myFace );
800 myFace = TopoDS::Face ( S );
803 // collect wires in sequence
804 TopTools_SequenceOfShape ws;
805 TopTools_SequenceOfShape vs;
806 TopoDS_Iterator wi (myFace,Standard_False);
807 for ( ; wi.More(); wi.Next()) {
808 if(wi.Value().ShapeType() == TopAbs_WIRE &&
809 (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED))
810 ws.Append (wi.Value());
812 vs.Append(wi.Value());
815 // deal with the case of an empty face: just create a new face by a standard tool
816 if (ws.IsEmpty() && !IsSurfaceUVInfinite (mySurf->Surface()))
818 BRepBuilderAPI_MakeFace aFaceBuilder (mySurf->Surface(), Precision::Confusion());
820 TopoDS_Face aNewFace = aFaceBuilder.Face();
821 aNewFace.Orientation (myFace.Orientation());
823 if ( ! Context().IsNull() )
824 Context()->Replace (myFace, aNewFace);
826 // taking into account orientation
829 //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated
830 Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool();
831 for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) {
832 TopoDS_Edge edg = TopoDS::Edge (Eed.Current());
833 sfe->FixVertexTolerance(edg, myFace);
836 // B.UpdateFace (myFace,myPrecision);
837 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
838 BRepTools::Update(myFace);
840 return Standard_True;
843 // check if surface is double-closed and fix is needed
844 if ( !IsSurfaceUVPeriodic (mySurf->Adaptor3d()) || ShapeAnalysis::IsOuterBound (myFace) )
845 return Standard_False;
847 // Collect information on free intervals in U and V
848 TColgp_SequenceOfPnt2d intU, intV, centers;
849 Standard_Real SUF, SUL, SVF, SVL;
850 mySurf->Bounds(SUF, SUL, SVF, SVL);
851 intU.Append ( gp_Pnt2d(SUF, SUL) );
852 intV.Append ( gp_Pnt2d(SVF, SVL) );
853 Standard_Integer nb = ws.Length();
856 for ( i=1; i <= nb; i ++) {
857 Standard_Real Umin, Vmin, Umax, Vmax;
859 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
860 // PTV 01.11.2002 ACIS907, OCC921 begin
861 // BRepTools::AddUVBounds(myFace,aw,B);
862 // B.Get(Umin, Vmin, Umax, Vmax);
863 TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() );
865 aB.Add( aWireFace, aw );
866 ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax);
868 // PTV 01.11.2002 ACIS907, OCC921 end
869 if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF );
870 if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF );
871 centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) );
874 // find best interval and thus compute shift
875 gp_Pnt2d shift(0.,0.);
876 if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) );
877 if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) );
879 // Adjust all other wires to be inside outer one
880 gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) );
881 for ( i=1; i <= nb; i++ ) {
882 TopoDS_Wire wire = TopoDS::Wire (ws.Value(i));
884 if ( mySurf->IsUClosed() )
885 sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) );
886 if ( mySurf->IsVClosed() )
887 sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) );
888 Shift2dWire ( wire, myFace, sh.XY(), mySurf );
891 // Create naturally bounded surface and add that wire to sequence
893 // Create fictive grid and call ComposeShell
894 Handle(Geom_RectangularTrimmedSurface) RTS =
895 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(),
896 SVF+shift.Y(), SVL+shift.Y() );
897 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
898 grid->SetValue ( 1, 1, RTS );
899 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
902 ShapeFix_ComposeShell CompShell;
903 CompShell.Init ( G, L, myFace, ::Precision::Confusion() );
904 CompShell.ClosedMode() = Standard_True;
905 CompShell.NaturalBoundMode() = Standard_True;
906 CompShell.SetContext( Context() );
907 CompShell.SetMaxTolerance(MaxTolerance());
909 TopoDS_Shape res = CompShell.Result();
911 Context()->Replace ( myFace, res );
912 for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) {
913 myFace = TopoDS::Face ( exp.Current() );
914 BRepTools::Update(myFace); //:p4
916 myResult = Context()->Apply ( myResult );
920 Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L );
921 BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion());
922 TopoDS_Face ftmp = mf.Face();
924 for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) {
925 if(wi.Value().ShapeType() != TopAbs_WIRE)
927 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
929 if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue;
930 Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True );
933 // Fix possible case on sphere when gap contains degenerated edge
934 // and thus has a common part with natural boundary
935 // Such hole should be merged with boundary
936 if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere &&
937 ws.Length() == nb+1 ) {
938 Handle(ShapeExtend_WireData) bnd =
939 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) );
940 // code to become separate method FixTouchingWires()
941 for ( i=1; i <= nb; i++ ) {
942 Handle(ShapeExtend_WireData) sbwd =
943 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) );
944 for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
945 if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue;
946 // find corresponding place in boundary
947 ShapeAnalysis_Edge sae;
948 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
950 for ( k=1; k <= bnd->NbEdges(); k++ ) {
951 if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue;
952 if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break;
954 if ( k > bnd->NbEdges() ) continue;
955 // and insert hole to that place
957 B.Degenerated ( sbwd->Edge(j), Standard_False );
958 B.Degenerated ( bnd->Edge(k), Standard_False );
960 bnd->Add ( sbwd, k+1 );
963 myFixWire->SetFace ( myFace );
964 myFixWire->Load ( bnd );
965 myFixWire->FixConnected();
966 myFixWire->FixDegenerated();
967 ws.SetValue ( ws.Length(), bnd->Wire() );
973 // Create resulting face
975 TopoDS_Shape S = myFace.EmptyCopied();
976 S.Orientation ( TopAbs_FORWARD );
977 for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) );
978 for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) );
979 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
980 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
981 myFace = TopoDS::Face ( S );
982 BRepTools::Update(myFace);
986 std::cout<<"Natural bound on sphere or torus with holes added"<<std::endl; // mise au point !
988 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
989 return Standard_True;
993 //=======================================================================
994 //function : FixOrientation
996 //=======================================================================
998 Standard_Boolean ShapeFix_Face::FixOrientation()
1000 TopTools_DataMapOfShapeListOfShape MapWires;
1002 return FixOrientation(MapWires);
1006 //=======================================================================
1007 //function : FixOrientation
1009 //=======================================================================
1011 Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShape &MapWires)
1013 Standard_Boolean done = Standard_False;
1015 if ( ! Context().IsNull() ) {
1016 TopoDS_Shape S = Context()->Apply ( myFace );
1017 myFace = TopoDS::Face ( S );
1019 TopTools_SequenceOfShape ws;
1020 TopTools_SequenceOfShape allSubShapes;
1021 // smh: BUC60810 : protection against very small wires (one-edge, null-length)
1022 TopTools_SequenceOfShape VerySmallWires;
1023 for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) {
1024 if(wi.Value().ShapeType() == TopAbs_VERTEX ||
1025 (wi.Value().Orientation() != TopAbs_FORWARD &&
1026 wi.Value().Orientation() != TopAbs_REVERSED)) {
1027 allSubShapes.Append (wi.Value());
1028 //ws.Append (wi.Value());
1032 TopoDS_Iterator ei (wi.Value(),Standard_False);
1034 Standard_Real length = RealLast();
1036 anEdge = TopoDS::Edge(ei.Value());
1038 if ( ! ei.More() ) {
1040 Standard_Real First, Last;
1041 Handle(Geom_Curve) c3d;
1042 ShapeAnalysis_Edge sae;
1043 if ( sae.Curve3d(anEdge,c3d,First,Last) ) {
1044 gp_Pnt pntIni = c3d->Value(First);
1046 prev = pntIni.XYZ();
1047 Standard_Integer NbControl = 10;
1048 for ( Standard_Integer j = 1; j < NbControl; j++) {
1049 Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1);
1050 gp_Pnt pntCurr = c3d->Value(prm);
1051 gp_XYZ curr = pntCurr.XYZ();
1052 gp_XYZ delta = curr - prev;
1053 length += delta.Modulus();
1060 if (length > ::Precision::Confusion()) {
1061 ws.Append (wi.Value());
1062 allSubShapes.Append (wi.Value());
1064 else VerySmallWires.Append (wi.Value());
1066 if ( VerySmallWires.Length() >0 ) done = Standard_True;
1068 Standard_Integer nb = ws.Length();
1069 Standard_Integer nbAll = allSubShapes.Length();
1072 // if no wires, just do nothing
1073 if ( nb <= 0) return Standard_False;
1074 Standard_Integer nbInternal=0;
1076 Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) && IsSurfaceUVPeriodic(mySurf->Adaptor3d()));
1077 TColStd_SequenceOfInteger aSeqReversed;
1078 // if wire is only one, check its orientation
1080 // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1)
1081 // make face with only one wire (ws.Value(1))
1082 TopoDS_Shape dummy = myFace.EmptyCopied();
1083 TopoDS_Face af = TopoDS::Face ( dummy );
1084 af.Orientation ( TopAbs_FORWARD );
1085 B.Add (af,ws.Value(1));
1087 if ((myFixAddNaturalBoundMode != 1 ||
1088 !IsSurfaceUVPeriodic(mySurf->Adaptor3d())) &&
1089 !ShapeAnalysis::IsOuterBound(af))
1091 Handle(ShapeExtend_WireData) sbdw =
1092 new ShapeExtend_WireData(TopoDS::Wire(ws.Value(1)));
1093 sbdw->Reverse(myFace);
1094 ws.SetValue(1, sbdw->Wire());
1095 SendWarning(sbdw->Wire(), Message_Msg("FixAdvFace.FixOrientation.MSG5"));// Wire on face was reversed
1096 done = Standard_True;
1099 // in case of several wires, perform complex analysis
1101 // Plusieurs wires : orientations relatives
1102 // Chaque wire doit "contenir" tous les autres
1103 // Evidemment, en cas de peau de leopard, il peut y avoir probleme
1105 // On prend chaque wire (NB: pcurves presentes !)
1106 // En principe on devrait rejeter les wires non fermes (cf couture manque ?)
1107 // On le classe par rapport aux autres, qui doivent tous etre, soit IN soit
1108 // OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse
1109 // (nb : ici pas myClos donc pas de pb de couture)
1110 // Si au moins une inversion, il faut refaire la face (cf myRebil)
1112 //:94 abv 30 Jan 98: calculate parametric precision
1114 // GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1115 // Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) );
1116 Standard_Boolean uclosed = mySurf->IsUClosed();
1117 Standard_Boolean vclosed = mySurf->IsVClosed();
1118 Standard_Real SUF, SUL, SVF, SVL;
1119 mySurf->Bounds(SUF, SUL, SVF, SVL);
1120 Standard_Real uRange = SUL - SUF;
1121 Standard_Real vRange = SVL - SVF;
1123 TopTools_DataMapOfShapeListOfShape MW;
1124 TopTools_DataMapOfShapeInteger SI;
1125 TopTools_MapOfShape MapIntWires;
1128 MapIntWires.Clear();
1129 Standard_Integer NbOuts=0;
1132 NCollection_Array1<Bnd_Box2d> aWireBoxes(1, nb);
1133 Standard_Real uMiddle = 0, vMiddle = 0;
1134 Standard_Boolean isFirst = Standard_True;
1135 //create Bounding boxes for each wire
1136 for ( i = 1; i <= nb; i ++) {
1137 TopoDS_Shape aShape = ws.Value(i);
1138 TopoDS_Wire aWire = TopoDS::Wire (aShape);
1140 Standard_Real cf,cl;
1141 TopoDS_Iterator ew (aWire);
1142 for(;ew.More(); ew.Next()) {
1143 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1144 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1149 Geom2dAdaptor_Curve gac;
1150 Standard_Real aFirst = cw->FirstParameter();
1151 Standard_Real aLast = cw->LastParameter();
1152 if(cw->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) {
1153 //avoiding problems with segment in Bnd_Box
1158 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),aBox);
1161 Standard_Real aXMin, aXMax, aYMin, aYMax;
1162 aBox.Get(aXMin, aYMin, aXMax, aYMax);
1164 isFirst = Standard_False;
1165 uMiddle = (aXMin + aXMax) * 0.5;
1166 vMiddle = (aYMin + aYMax) * 0.5;
1169 Standard_Real xShift = 0, yShift = 0;
1170 if ( mySurf->IsUClosed() )
1171 xShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aXMin + aXMax), uMiddle, uRange );
1172 if ( mySurf->IsVClosed() )
1173 yShift = ShapeAnalysis::AdjustByPeriod ( 0.5*(aYMin + aYMax), vMiddle, vRange ) ;
1174 aBox.Update(aXMin + xShift, aYMin + yShift, aXMax + xShift, aYMax + yShift);
1176 aWireBoxes.ChangeValue(i) = aBox;
1179 for ( i = 1; i <= nb; i ++) {
1180 TopoDS_Shape asw = ws.Value(i);
1181 TopoDS_Wire aw = TopoDS::Wire (asw);
1182 Bnd_Box2d aBox1 = aWireBoxes.Value(i);
1183 TopoDS_Shape dummy = myFace.EmptyCopied();
1184 TopoDS_Face af = TopoDS::Face ( dummy );
1185 // B.MakeFace (af,mySurf->Surface(),::Precision::Confusion());
1186 af.Orientation ( TopAbs_FORWARD );
1188 // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787)
1189 // tolerance is too big. It is seems that to identify placement of 2d point
1190 // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON
1191 // BRepTopAdaptor_FClass2d clas (af,toluv);
1192 Standard_Boolean CheckShift = Standard_True;
1193 BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion());
1194 TopAbs_State sta = TopAbs_OUT;
1195 TopAbs_State staout = clas.PerformInfinitePoint();
1196 TopTools_ListOfShape IntWires;
1197 Standard_Integer aWireIt = 0;
1198 for ( Standard_Integer j = 1; j <= nbAll; j ++) {
1200 //if(i==j) continue;
1201 TopoDS_Shape aSh2 = allSubShapes.Value(j);
1204 TopAbs_State stb = TopAbs_UNKNOWN;
1205 if(aSh2.ShapeType() == TopAbs_VERTEX) {
1207 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2));
1208 gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion());
1209 stb = clas.Perform (p2d,Standard_False);
1210 if(stb == staout && (uclosed || vclosed)) {
1213 p2d1.SetCoord(p2d.X()+uRange, p2d.Y());
1214 stb = clas.Perform (p2d1,Standard_False);
1217 if(stb == staout && vclosed) {
1218 p2d1.SetCoord(p2d.X(), p2d.Y()+ vRange);
1219 stb = clas.Perform (p2d1,Standard_False);
1223 else if (aSh2.ShapeType() == TopAbs_WIRE) {
1224 CheckShift = Standard_True;
1225 TopoDS_Wire bw = TopoDS::Wire (aSh2);
1226 //Standard_Integer numin =0;
1227 Bnd_Box2d aBox2 = aWireBoxes.Value(aWireIt);
1228 if (aBox2.IsOut(aBox1))
1231 TopoDS_Iterator ew (bw);
1232 for(;ew.More(); ew.Next()) {
1233 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1234 Standard_Real cf,cl;
1235 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1236 if (cw.IsNull()) continue;
1237 gp_Pnt2d unp = cw->Value ((cf+cl)/2.);
1238 TopAbs_State ste = clas.Perform (unp,Standard_False);
1239 if( ste==TopAbs_OUT || ste==TopAbs_IN ) {
1240 if(stb==TopAbs_UNKNOWN) {
1245 sta = TopAbs_UNKNOWN;
1253 Standard_Boolean found = Standard_False;
1255 if( stb == staout && CheckShift ) {
1256 CheckShift = Standard_False;
1258 unp1.SetCoord(unp.X()+uRange, unp.Y());
1259 found = (staout != clas.Perform (unp1,Standard_False));
1261 unp1.SetX(unp.X()-uRange);
1262 found = (staout != clas.Perform (unp1,Standard_False));
1265 if(vclosed&&!found) {
1266 unp1.SetCoord(unp.X(), unp.Y()+vRange);
1267 found = (staout != clas.Perform (unp1,Standard_False));
1269 unp1.SetY(unp.Y()-vRange);
1270 found = (staout != clas.Perform (unp1,Standard_False));
1273 // Additional check of diagonal steps for toroidal surfaces
1274 if (!found && uclosed && vclosed)
1276 for (Standard_Real dX = -1.0; dX <= 1.0 && !found; dX += 2.0)
1277 for (Standard_Real dY = -1.0; dY <= 1.0 && !found; dY += 2.0)
1279 unp1.SetCoord(unp.X() + uRange * dX, unp.Y() + vRange * dY);
1280 found = (staout != clas.Perform(unp1, Standard_False));
1285 if(stb==TopAbs_IN) stb = TopAbs_OUT;
1286 else stb = TopAbs_IN;
1287 Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf);
1295 IntWires.Append(aSh2);
1296 MapIntWires.Add(aSh2);
1300 if (sta == TopAbs_UNKNOWN) { // ERREUR
1301 SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire
1304 MW.Bind(aw,IntWires);
1305 if(sta==TopAbs_OUT) {
1307 if(staout==TopAbs_IN ) {
1308 // wire is OUT but InfinitePoint is IN => need to reverse
1309 ShapeExtend_WireData sewd (aw);
1310 sewd.Reverse(myFace);
1311 ws.SetValue (i,sewd.Wire());
1312 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1313 aSeqReversed.Append(i);
1314 done = Standard_True;
1315 SI.Bind(ws.Value(i),1);
1316 MapWires.Bind(ws.Value(i),IntWires);
1320 MapWires.Bind(aw,IntWires);
1324 if(staout==TopAbs_OUT) SI.Bind(aw,2);
1331 for(i=1; i<=nb; i++) {
1332 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
1333 Standard_Integer tmpi = SI.Find(aw);
1335 if(!MapIntWires.Contains(aw)) {
1337 const TopTools_ListOfShape& IW = MW.Find(aw);
1339 // wire is OUT but InfinitePoint is IN => need to reverse
1340 ShapeExtend_WireData sewd (aw);
1341 sewd.Reverse(myFace);
1342 ws.SetValue (i,sewd.Wire());
1343 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1344 aSeqReversed.Append(i);
1345 done = Standard_True;
1346 MapWires.Bind(ws.Value(i),IW);
1348 else MapWires.Bind(aw,IW);
1352 // wire is IN but InfinitePoint is OUT => need to reverse
1353 ShapeExtend_WireData sewd (aw);
1354 sewd.Reverse(myFace);
1355 ws.SetValue (i,sewd.Wire());
1356 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1357 aSeqReversed.Append(i);
1358 done = Standard_True;
1366 //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1367 if(isAddNaturalBounds && nb == aSeqReversed.Length())
1368 done = Standard_False;
1370 done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1371 // Faut-il reconstruire ? si myRebil est mis
1373 TopoDS_Shape S = myFace.EmptyCopied();
1374 S.Orientation ( TopAbs_FORWARD );
1375 Standard_Integer i = 1;
1376 for ( ; i <= nb; i++ )
1377 B.Add ( S, ws.Value(i) );
1380 for( i =1; i <= nbAll;i++) {
1381 TopoDS_Shape aS2 = allSubShapes.Value(i);
1382 if(aS2.ShapeType() != TopAbs_WIRE ||
1383 (aS2.Orientation() != TopAbs_FORWARD && aS2.Orientation() != TopAbs_REVERSED))
1388 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
1389 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
1390 myFace = TopoDS::Face ( S );
1391 BRepTools::Update(myFace);
1392 Standard_Integer k =1;
1393 for( ; k <= aSeqReversed.Length(); k++ )
1396 std::cout<<"Wire no "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<std::endl; // mise au point !
1405 //=======================================================================
1406 //function : CheckWire
1407 //purpose : auxiliary for FixMissingSeam
1408 //=======================================================================
1409 //:i7 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp: algorithm of fixing missing seam changed
1410 // test whether the wire is opened on period of periodical surface
1411 static Standard_Boolean CheckWire (const TopoDS_Wire &wire,
1412 const TopoDS_Face &face,
1413 const Standard_Real dU,
1414 const Standard_Real dV,
1415 Standard_Integer &isuopen,
1416 Standard_Integer &isvopen,
1417 Standard_Boolean &isDeg)
1422 ShapeAnalysis_Edge sae;
1424 isuopen = isvopen = 0;
1425 isDeg = Standard_True;
1426 for ( TopoDS_Iterator ed(wire); ed.More(); ed.Next() ) {
1427 TopoDS_Edge edge = TopoDS::Edge ( ed.Value() );
1428 if ( ! BRep_Tool::Degenerated ( edge ) ) isDeg = Standard_False;
1429 Handle(Geom2d_Curve) c2d;
1431 if ( ! sae.PCurve ( edge, face, c2d, f, l, Standard_True ) )
1432 return Standard_False;
1433 vec += c2d->Value(l).XY() - c2d->Value(f).XY();
1436 Standard_Real aDelta = Abs(vec.X())-dU;
1437 if(Abs(aDelta) < 0.1*dU)
1453 aDelta = Abs(vec.Y())-dV;
1454 if(Abs(aDelta) < 0.1*dV)
1470 return isuopen || isvopen;
1473 //=======================================================================
1474 //function : FixMissingSeam
1476 //=======================================================================
1477 Standard_Boolean ShapeFix_Face::FixMissingSeam()
1479 Standard_Boolean uclosed = mySurf->IsUClosed();
1480 Standard_Boolean vclosed = mySurf->IsVClosed();
1482 if ( ! uclosed && ! vclosed ) return Standard_False;
1484 if ( ! Context().IsNull() ) {
1485 TopoDS_Shape S = Context()->Apply ( myFace );
1486 myFace = TopoDS::Face ( S );
1489 //%pdn: surface should be made periodic before (see ShapeCustom_Surface)!
1490 if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) {
1491 Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface());
1492 if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic())
1493 return Standard_False;
1496 Standard_Real URange, VRange, SUF, SUL, SVF, SVL;
1497 mySurf->Bounds ( SUF, SUL, SVF, SVL );
1498 Standard_Real fU1,fU2,fV1,fV2;
1499 BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2);
1501 //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters
1502 if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
1503 if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
1504 if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
1505 if(Abs(SUL-SUF) < ::Precision::PConfusion()) {
1506 if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
1510 if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
1511 if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
1512 if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
1513 if(Abs(SVL-SVF) < ::Precision::PConfusion()) {
1514 if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
1519 URange = Min(Abs (SUL - SUF), Precision::Infinite());
1520 VRange = Min(Abs(SVL - SVF), Precision::Infinite());
1521 // Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1522 Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean
1523 Standard_Integer isdeg1=0, isdeg2=0;
1525 TopTools_SequenceOfShape ws;
1526 TopTools_SequenceOfShape aSeqNonManif;
1527 for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) {
1528 if(wi.Value().ShapeType() != TopAbs_WIRE ||
1529 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
1530 aSeqNonManif.Append(wi.Value());
1533 ws.Append ( wi.Value() );
1538 for ( i=1; i <= ws.Length(); i++ ) {
1539 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1540 Standard_Integer isuopen, isvopen;
1541 Standard_Boolean isdeg;
1542 if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) )
1544 if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; }
1545 else if ( w2.IsNull() ) {
1546 if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; }
1547 else if ( ismodeu == isuopen && ismodev == isvopen ) {
1550 //:abv 29.08.01: If wires are contraversal, reverse one of them
1551 // If first one is single degenerated edge, reverse it; else second
1560 if ( ! isdeg2 ) std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << std::endl;
1565 else std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << std::endl;
1568 // else return Standard_False; // abort
1571 std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << std::endl;
1573 //:abv 30.08.09: if more than one open wires and more than two of them are
1574 // completely degenerated, remove any of them
1575 if ( isdeg || isdeg1 || isdeg2 ) {
1576 ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 );
1581 std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << std::endl;
1589 Handle(Geom_ToroidalSurface) aTorSurf = Handle(Geom_ToroidalSurface)::DownCast(mySurf->Surface());
1590 Standard_Boolean anIsDegeneratedTor = ( aTorSurf.IsNull() ? Standard_False : aTorSurf->MajorRadius() < aTorSurf->MinorRadius() );
1592 if ( w1.IsNull() ) return Standard_False;
1593 else if ( w2.IsNull()) {
1594 // For spheres and BSpline cone-like surfaces(bug 24055):
1595 // If only one of wires limiting face on surface is open in 2d,
1596 // this may means that degenerated edge should be added, and
1597 // then usual procedure applied
1600 Standard_Real aRange;
1602 if( ismodeu && anIsDegeneratedTor )
1604 Standard_Real aRa = aTorSurf->MajorRadius();
1605 Standard_Real aRi = aTorSurf->MinorRadius();
1606 Standard_Real aPhi = ACos (-aRa / aRi);
1607 p.SetCoord (0.0, ( ismodeu > 0 ? M_PI + aPhi : aPhi ));
1609 Standard_Real aXCoord = -ismodeu;
1610 d.SetCoord ( aXCoord, 0.);
1613 else if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
1614 p.SetCoord ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI );
1615 Standard_Real aXCoord = -ismodeu;
1616 d.SetCoord ( aXCoord, 0.);
1619 else if ( ismodev && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1620 Standard_Real uCoord;
1621 if (mySurf->Value(SUF, SVF).Distance(mySurf->Value(SUF, (SVF + SVL) / 2)) < ::Precision::Confusion())
1623 else if (mySurf->Value(SUL, SVF).Distance(mySurf->Value(SUL, (SVF + SVL) / 2)) < ::Precision::Confusion())
1625 else return Standard_False;
1627 p.SetCoord ( uCoord, ( ismodev < 0 ? 0. : VRange ) );
1628 d.SetCoord ( 0., -ismodev);
1631 else if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
1632 Standard_Real vCoord;
1633 if (mySurf->Value(SUF, SVF).Distance(mySurf->Value((SUF + SUL) / 2, SVF)) < ::Precision::Confusion())
1635 else if (mySurf->Value(SUL, SVL).Distance(mySurf->Value((SUF + SUL) / 2, SVL)) < ::Precision::Confusion())
1637 else return Standard_False;
1639 p.SetCoord ( ( ismodeu < 0 ? 0. : URange ), vCoord );
1640 Standard_Real aXCoord = -ismodeu;
1641 d.SetCoord ( aXCoord, 0.);
1644 else return Standard_False;
1646 Handle(Geom2d_Line) line = new Geom2d_Line ( p, d );
1648 B.MakeEdge ( edge );
1649 B.Degenerated ( edge, Standard_True );
1650 B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() );
1651 B.Range ( edge, myFace, 0., aRange );
1653 B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() );
1654 V.Orientation(TopAbs_FORWARD);
1656 V.Orientation(TopAbs_REVERSED);
1663 // Check consistency of orientations of the two wires that need to be connected by a seam
1664 Standard_Real uf=SUF, vf=SVF;
1665 Standard_Integer coord = ( ismodeu ? 1 : 0 );
1666 Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev );
1667 Standard_Real period = ( ismodeu ? URange : VRange );
1669 Standard_Real m1[2][2], m2[2][2];
1670 S = myFace.EmptyCopied();
1672 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]);
1673 S = myFace.EmptyCopied();
1675 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1677 // For the case when surface is closed only in one direction it is necessary to check
1678 // validity of orientation of the open wires in parametric space.
1679 // In case of U closed surface wire with minimal V coordinate should be directed in positive direction by U
1680 // In case of V closed surface wire with minimal U coordinate should be directed in negative direction by V
1681 if (!vclosed || !uclosed || anIsDegeneratedTor)
1683 Standard_Real deltaOther = 0.5 * (m2[coord][0] + m2[coord][1]) - 0.5 * (m1[coord][0] + m1[coord][1]);
1684 if (deltaOther * isneg < 0)
1691 // sort original wires
1692 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
1693 sfw->SetFace ( myFace );
1694 sfw->SetPrecision ( Precision() );
1695 Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 );
1696 Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 );
1701 TopoDS_Wire w11 = wd1->Wire();
1702 TopoDS_Wire w21 = wd2->Wire();
1704 //:abv 29.08.01: reconstruct face taking into account reversing
1705 TopoDS_Shape dummy = myFace.EmptyCopied();
1706 TopoDS_Face tmpF = TopoDS::Face ( dummy );
1707 tmpF.Orientation ( TopAbs_FORWARD );
1708 for ( i=1; i <= ws.Length(); i++ ) {
1709 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1710 if ( wire.IsSame ( w1 ) ) wire = w11;
1711 else if ( wire.IsSame ( w2 ) ) wire = w21;
1714 // other wires (not boundary) are considered as holes; make sure to have them oriented accordingly
1715 TopoDS_Shape curface = tmpF.EmptyCopied();
1716 B.Add(curface,wire);
1717 curface.Orientation ( myFace.Orientation() );
1718 if( ShapeAnalysis::IsOuterBound(TopoDS::Face(curface)))
1721 B.Add ( tmpF, wire );
1724 tmpF.Orientation ( myFace.Orientation() );
1726 // A special kind of FixShifted is necessary for torus-like
1727 // surfaces to adjust wires by period ALONG the missing SEAM direction
1728 // tr9_r0501-ug.stp #187640
1729 if ( uclosed && vclosed && !anIsDegeneratedTor ) {
1730 Standard_Real shiftw2 =
1731 ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1732 0.5 * ( m1[coord][0] + m1[coord][1] +
1733 isneg * ( period + ::Precision::PConfusion() ) ),
1735 m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 );
1736 m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 );
1737 for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) {
1738 if(it.Value().ShapeType() != TopAbs_WIRE)
1740 TopoDS_Wire w = TopoDS::Wire ( it.Value() );
1741 if ( w == w11 ) continue;
1742 Standard_Real shift;
1743 if ( w == w21 ) shift = shiftw2;
1746 S = tmpF.EmptyCopied();
1748 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1749 shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1750 0.5 * ( m1[coord][0] + m1[coord][1] ), period );
1752 if ( shift != 0. ) {
1754 V.SetCoord ( coord+1, shift );
1755 ShapeAnalysis_Edge sae;
1756 for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) {
1757 TopoDS_Edge E = TopoDS::Edge ( iw.Value() );
1758 Handle(Geom2d_Curve) C;
1760 if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue;
1765 // abv 05 Feb 02: OCC34
1766 // by the way, select proper split place by V to avoid extra intersections
1767 if ( m1[coord][1] - m1[coord][0] <= period ) {
1768 Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period );
1769 if ( ismodeu ) vf = other;
1774 // find the best place by u and v to insert a seam
1775 // (so as to minimize splitting edges as possible)
1776 ShapeAnalysis_Edge sae;
1777 Standard_Integer foundU=0, foundV=0;
1778 Standard_Integer nb1 = wd1->NbEdges();
1779 Standard_Integer nb2 = wd2->NbEdges();
1780 for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) {
1781 TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) );
1782 Handle(Geom2d_Curve) c2d;
1784 if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1785 gp_Pnt2d pos1 = c2d->Value(l).XY();
1786 // the best place is end of edge which is nearest to 0
1787 Standard_Boolean skipU = ! uclosed;
1788 if ( uclosed && ismodeu ) {
1789 pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) );
1790 if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True;
1791 else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) {
1796 Standard_Boolean skipV = ! vclosed;
1797 if ( vclosed && ! ismodeu ) {
1798 pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, VRange ) );
1799 if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True;
1800 else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) {
1805 if ( skipU && skipV ) {
1806 if ( i1 <= nb1 ) continue;
1809 // or yet better - if it is end of some edges on both wires
1810 for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
1811 TopoDS_Edge edge2 = wd2->Edge ( i2 );
1812 if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1813 gp_Pnt2d pos2 = c2d->Value(f).XY();
1814 if ( uclosed && ismodeu ) {
1815 pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) );
1816 if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() &&
1817 ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) {
1822 if ( vclosed && ! ismodeu ) {
1823 pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) );
1824 if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() &&
1825 ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) {
1833 //pdn fixing RTS on offsets
1834 if ( uf < SUF || uf > SUL )
1835 uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange);
1836 if ( vf < SVF || vf > SVL )
1837 vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange);
1839 // Create fictive grid and call ComposeShell to insert a seam
1840 Handle(Geom_RectangularTrimmedSurface) RTS =
1841 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange );
1842 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
1843 grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() );
1844 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
1847 //addition non-manifold topology
1848 Standard_Integer j=1;
1849 for( ; j <= aSeqNonManif.Length(); j++)
1850 B.Add(tmpF,aSeqNonManif.Value(j));
1852 ShapeFix_ComposeShell CompShell;
1853 // TopoDS_Face tmpF = myFace;
1854 // tmpF.Orientation(TopAbs_FORWARD);
1855 CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision
1856 if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape );
1857 CompShell.ClosedMode() = Standard_True;
1858 CompShell.SetContext( Context() );
1859 CompShell.SetMaxTolerance(MaxTolerance());
1860 CompShell.Perform();
1862 // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf
1863 mySurf = new ShapeAnalysis_Surface ( RTS );
1865 myResult = CompShell.Result();
1867 Context()->Replace ( myFace, myResult );
1869 // Remove small wires and / or faces that can be generated by ComposeShell
1870 // (see tests bugs step bug30052_4, de step_3 E6)
1871 Standard_Integer nbFaces = 0;
1872 TopExp_Explorer expF ( myResult, TopAbs_FACE );
1873 for (; expF.More(); expF.Next() )
1875 TopoDS_Face aFace = TopoDS::Face(expF.Value());
1876 TopExp_Explorer aExpW(aFace, TopAbs_WIRE);
1877 Standard_Integer nbWires = 0;
1878 for( ;aExpW.More(); aExpW.Next() )
1880 ShapeFix_Wire aSfw(TopoDS::Wire(aExpW.Value()), aFace, Precision());
1881 aSfw.SetContext(Context());
1883 aSfw.FixSmall (Standard_True, Precision());
1886 Context()->Remove(aExpW.Value());
1893 Context()->Remove(aFace);
1899 myResult = Context()->Apply(myResult);
1900 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
1901 myFace = TopoDS::Face ( Context()->Apply(exp.Current() ));
1902 if( myFace.IsNull())
1906 FixSmallAreaWire(Standard_True);
1907 TopoDS_Shape aShape = Context()->Apply(myFace);
1908 if(aShape.IsNull() )
1910 myFace = TopoDS::Face(aShape);
1912 BRepTools::Update(myFace); //:p4
1914 myResult = Context()->Apply(myResult);
1916 SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added
1917 return Standard_True;
1920 //=======================================================================
1921 //function : FixSmallAreaWire
1923 //=======================================================================
1924 //%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
1925 Standard_Boolean ShapeFix_Face::FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace)
1927 if ( !Context().IsNull() )
1929 TopoDS_Shape aShape = Context()->Apply(myFace);
1930 myFace = TopoDS::Face(aShape);
1933 BRep_Builder aBuilder;
1934 Standard_Integer nbRemoved = 0, nbWires = 0;
1936 TopoDS_Shape anEmptyCopy = myFace.EmptyCopied();
1937 TopoDS_Face aFace = TopoDS::Face(anEmptyCopy);
1938 aFace.Orientation (TopAbs_FORWARD);
1940 const Standard_Real aTolerance3d = ShapeFix_Root::Precision();
1941 for (TopoDS_Iterator aWIt(myFace, Standard_False); aWIt.More(); aWIt.Next())
1943 const TopoDS_Shape& aShape = aWIt.Value();
1944 if ( aShape.ShapeType() != TopAbs_WIRE &&
1945 aShape.Orientation() != TopAbs_FORWARD &&
1946 aShape.Orientation() != TopAbs_REVERSED )
1951 const TopoDS_Wire& aWire = TopoDS::Wire(aShape);
1952 Handle(ShapeAnalysis_Wire) anAnalyzer = new ShapeAnalysis_Wire(aWire, myFace, aTolerance3d);
1953 if ( anAnalyzer->CheckSmallArea(aWire) )
1955 // Null area wire detected, wire skipped
1956 SendWarning(aWire, Message_Msg("FixAdvFace.FixSmallAreaWire.MSG0"));
1961 aBuilder.Add(aFace, aWire);
1966 if ( nbRemoved <= 0 )
1967 return Standard_False;
1972 std::cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << std::endl;
1974 if ( theIsRemoveSmallFace && !Context().IsNull() )
1975 Context()->Remove(myFace);
1977 return Standard_False;
1980 std::cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << std::endl;
1982 aFace.Orientation (myFace.Orientation ());
1983 if (!Context ().IsNull ())
1984 Context ()->Replace (myFace, aFace);
1987 return Standard_True;
1989 //=======================================================================
1990 //function : FixLoopWire
1992 //=======================================================================
1993 static void FindNext(const TopoDS_Shape& aVert,
1994 const TopoDS_Shape& ainitEdge,
1995 TopTools_IndexedMapOfShape& aMapVertices,
1996 TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1997 const TopTools_MapOfShape& aMapSmallEdges,
1998 const TopTools_MapOfShape& aMapSeemEdges,
1999 TopTools_MapOfShape& aMapEdges,
2000 Handle(ShapeExtend_WireData)& aWireData)
2002 TopoDS_Iterator aItV(ainitEdge);
2003 TopoDS_Shape anextVert = aVert;
2004 Standard_Boolean isFind = Standard_False;
2005 for( ; aItV.More() && !isFind; aItV.Next())
2007 if(!aItV.Value().IsSame(aVert) ) {
2008 isFind = Standard_True;
2009 anextVert = aItV.Value();
2014 if(!isFind && !aMapSmallEdges.Contains(ainitEdge))
2016 if(isFind && aMapVertices.Contains(anextVert))
2019 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert);
2020 TopTools_ListIteratorOfListOfShape liter(aledges);
2021 isFind = Standard_False;
2022 TopoDS_Shape anextEdge;
2023 for( ; liter.More() && !isFind; liter.Next())
2025 if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) {
2026 anextEdge = liter.Value();
2027 aWireData->Add(anextEdge);
2028 if(aMapSeemEdges.Contains(anextEdge))
2029 aWireData->Add(anextEdge.Reversed());
2030 isFind = Standard_True;
2031 aMapEdges.Add(anextEdge);
2032 FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
2038 static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire)
2040 Standard_Boolean isClosed = Standard_True;
2041 Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion());
2042 for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) {
2043 TopoDS_Edge edge1 = asaw->WireData()->Edge(i);
2044 //checking that wire is closed in 2D space with tolerance of vertex.
2045 ShapeAnalysis_Edge sae;
2046 TopoDS_Vertex v1 = sae.FirstVertex(edge1);
2047 asaw->SetPrecision(BRep_Tool::Tolerance(v1));
2048 asaw->CheckGap2d(i);
2049 isClosed = (asaw->LastCheckStatus(ShapeExtend_OK));
2055 //=======================================================================
2056 //function : FixLoopWire
2058 //=======================================================================
2060 Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires)
2062 TopTools_IndexedMapOfShape aMapVertices;
2063 TopTools_DataMapOfShapeListOfShape aMapVertexEdges;
2064 TopTools_MapOfShape aMapSmallEdges;
2065 TopTools_MapOfShape aMapSeemEdges;
2066 if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges))
2067 return Standard_False;
2070 TopTools_MapOfShape aMapEdges;
2071 TopTools_SequenceOfShape aSeqWires;
2073 //collecting wires from common vertex belonging more than 2 edges
2074 Standard_Integer i =1;
2075 for( ; i <= aMapVertices.Extent(); i++) {
2076 TopoDS_Shape aVert = aMapVertices.FindKey(i);
2077 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert);
2078 TopTools_ListIteratorOfListOfShape liter(aledges);
2079 for( ; liter.More(); liter.Next())
2081 TopoDS_Edge Edge = TopoDS::Edge(liter.Value());
2082 if(aMapEdges.Contains(Edge))
2085 Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
2086 aWireData->Add(Edge);
2087 if(aMapSeemEdges.Contains(Edge))
2088 aWireData->Add(Edge.Reversed());
2089 aMapEdges.Add(Edge);
2090 FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
2091 if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1)))
2093 TopoDS_Vertex aV1,aV2;
2094 TopoDS_Wire aWire = aWireData->Wire();
2095 TopExp::Vertices(aWire,aV1,aV2);
2097 if(aV1.IsSame(aV2)) {
2098 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2099 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2102 TopoDS_Wire awire2 = asfw->Wire();
2103 aResWires.Append(awire2);
2106 else aSeqWires.Append(aWireData->Wire());
2111 if(aSeqWires.Length() ==1) {
2112 aResWires.Append(aSeqWires.Value(1));
2115 //collecting whole wire from two not closed wires having two common vertices.
2116 for( i =1; i <= aSeqWires.Length(); i++) {
2117 TopoDS_Vertex aV1,aV2;
2118 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2119 TopExp::Vertices(aWire,aV1,aV2);
2120 Standard_Integer j = i+1;
2121 for( ; j <= aSeqWires.Length(); j++)
2123 TopoDS_Vertex aV21,aV22;
2124 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2125 TopExp::Vertices(aWire2,aV21,aV22);
2126 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2128 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2130 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2133 aResWires.Append(asfw->Wire());
2134 aSeqWires.Remove(j--);
2135 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2140 if(j <= aSeqWires.Length())
2141 aSeqWires.Remove(i--);
2144 if(aSeqWires.Length()<3) {
2145 for( i =1; i <= aSeqWires.Length(); i++)
2146 aResWires.Append(aSeqWires.Value(i));
2150 //collecting wires having one common vertex
2151 for( i =1; i <= aSeqWires.Length(); i++) {
2152 TopoDS_Vertex aV1,aV2;
2153 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
2154 TopExp::Vertices(aWire,aV1,aV2);
2155 Standard_Integer j =i+1;
2156 for( ; j <= aSeqWires.Length(); j++)
2158 TopoDS_Vertex aV21,aV22;
2159 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
2160 TopExp::Vertices(aWire2,aV21,aV22);
2161 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
2163 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
2165 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
2168 aWire = asfw->Wire();
2169 TopExp::Vertices(aWire,aV1,aV2);
2170 aSeqWires.Remove(j--);
2171 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
2174 aResWires.Append(aWire);
2179 Standard_Boolean isClosed = Standard_True;
2181 //checking that obtained wires is closed in 2D space
2182 if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) {
2184 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2185 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2186 tmpFace.Orientation ( TopAbs_FORWARD );
2188 for(i =1; i <= aResWires.Length() && isClosed; i++) {
2189 TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i));
2190 isClosed = isClosed2D(tmpFace,awire);
2194 Standard_Boolean isDone =(aResWires.Length() && isClosed);
2195 if(isDone && aResWires.Length() >1)
2198 std::cout<<"Wire was split on "<<aResWires.Length()<<" wires"<< std::endl;
2205 //=======================================================================
2206 //function : SplitEdge
2208 //=======================================================================
2210 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2211 const Standard_Integer num,
2212 const Standard_Real param,
2213 const TopoDS_Vertex& vert,
2214 const Standard_Real preci,
2215 ShapeFix_DataMapOfShapeBox2d& boxes)
2217 TopoDS_Edge edge = sewd->Edge(num);
2218 TopoDS_Edge newE1, newE2;
2219 ShapeFix_SplitTool aTool;
2220 if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2222 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2225 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2226 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2227 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2228 BRepTools::Update(E);
2231 // for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) {
2232 // TopoDS_Edge E = sewd->Edge(i);
2233 // TopoDS_Shape S = Context()->Apply ( E );
2234 // if ( S == E ) continue;
2235 // for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
2236 // sewd->Add ( exp.Current(), i++ );
2237 // sewd->Remove ( i-- );
2240 // change sewd and boxes
2241 sewd->Set(newE1,num);
2242 if(num==sewd->NbEdges())
2245 sewd->Add(newE2,num+1);
2249 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2250 Handle(Geom2d_Curve) c2d;
2251 Standard_Real cf,cl;
2252 ShapeAnalysis_Edge sae;
2253 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2255 Geom2dAdaptor_Curve gac;
2256 Standard_Real aFirst = c2d->FirstParameter();
2257 Standard_Real aLast = c2d->LastParameter();
2258 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2259 && (cf < aFirst || cl > aLast)) {
2260 //pdn avoiding problems with segment in Bnd_Box
2264 gac.Load(c2d,cf,cl);
2265 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2266 boxes.Bind(newE1,box);
2268 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2270 Geom2dAdaptor_Curve gac;
2271 Standard_Real aFirst = c2d->FirstParameter();
2272 Standard_Real aLast = c2d->LastParameter();
2273 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2274 && (cf < aFirst || cl > aLast)) {
2275 //pdn avoiding problems with segment in Bnd_Box
2279 gac.Load(c2d,cf,cl);
2280 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2281 boxes.Bind(newE2,box);
2283 return Standard_True;
2285 return Standard_False;
2289 //=======================================================================
2290 //function : SplitEdge
2292 //=======================================================================
2294 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2295 const Standard_Integer num,
2296 const Standard_Real param1,
2297 const Standard_Real param2,
2298 const TopoDS_Vertex& vert,
2299 const Standard_Real preci,
2300 ShapeFix_DataMapOfShapeBox2d& boxes)
2302 TopoDS_Edge edge = sewd->Edge(num);
2303 TopoDS_Edge newE1, newE2;
2304 ShapeFix_SplitTool aTool;
2305 if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2307 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2310 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2311 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2312 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2313 BRepTools::Update(E);
2316 // change sewd and boxes
2317 sewd->Set(newE1,num);
2318 if(num==sewd->NbEdges())
2321 sewd->Add(newE2,num+1);
2325 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2326 Handle(Geom2d_Curve) c2d;
2327 Standard_Real cf,cl;
2328 ShapeAnalysis_Edge sae;
2329 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2331 Geom2dAdaptor_Curve gac;
2332 Standard_Real aFirst = c2d->FirstParameter();
2333 Standard_Real aLast = c2d->LastParameter();
2334 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2335 && (cf < aFirst || cl > aLast)) {
2336 //pdn avoiding problems with segment in Bnd_Box
2340 gac.Load(c2d,cf,cl);
2341 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2342 boxes.Bind(newE1,box);
2344 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2346 Geom2dAdaptor_Curve gac;
2347 Standard_Real aFirst = c2d->FirstParameter();
2348 Standard_Real aLast = c2d->LastParameter();
2349 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2350 && (cf < aFirst || cl > aLast)) {
2351 //pdn avoiding problems with segment in Bnd_Box
2355 gac.Load(c2d,cf,cl);
2356 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2357 boxes.Bind(newE2,box);
2359 return Standard_True;
2361 return Standard_False;
2365 //=======================================================================
2366 //function : FixIntersectingWires
2368 //=======================================================================
2370 Standard_Boolean ShapeFix_Face::FixIntersectingWires()
2372 ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance());
2373 return ITool.FixIntersectingWires(myFace);
2377 //=======================================================================
2378 //function : FixWiresTwoCoincEdges
2380 //=======================================================================
2382 Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges()
2384 if ( ! Context().IsNull() ) {
2385 TopoDS_Shape S = Context()->Apply ( myFace );
2386 myFace = TopoDS::Face ( S );
2389 TopAbs_Orientation ori = myFace.Orientation();
2390 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2391 TopoDS_Face face = TopoDS::Face (emptyCopied);
2392 face.Orientation(TopAbs_FORWARD);
2393 Standard_Integer nbWires = 0;
2396 for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) {
2397 if(it.Value().ShapeType() != TopAbs_WIRE ||
2398 (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) {
2403 if(nbWires<2) return Standard_False;
2404 Standard_Boolean isFixed = Standard_False;
2405 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
2406 if(wi.Value().ShapeType() != TopAbs_WIRE ||
2407 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
2408 B.Add(face,wi.Value());
2411 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
2412 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2413 if(sewd->NbEdges()==2) {
2414 TopoDS_Edge E1 = sewd->Edge(1);
2415 TopoDS_Edge E2 = sewd->Edge(2);
2416 E1.Orientation(TopAbs_FORWARD);
2417 E2.Orientation(TopAbs_FORWARD);
2421 else isFixed = Standard_True;
2428 face.Orientation(ori);
2429 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
2437 //=======================================================================
2438 //function : FixSplitFace
2440 //=======================================================================
2442 Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires)
2445 TopTools_SequenceOfShape faces;
2446 TopoDS_Shape S = myFace;
2447 if ( ! Context().IsNull() )
2448 S = Context()->Apply ( myFace );
2449 Standard_Integer NbWires=0, NbWiresNew=0, NbEdges;
2450 for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
2451 const TopoDS_Shape& aShape = iter.Value();
2452 if(aShape.ShapeType() != TopAbs_WIRE ||
2453 (aShape.Orientation() != TopAbs_FORWARD && aShape.Orientation() != TopAbs_REVERSED))
2455 TopoDS_Wire wire = TopoDS::Wire ( aShape );
2457 if(MapWires.IsBound(wire)) {
2458 // if wire not closed --> stop split and return false
2459 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2460 NbEdges = sewd->NbEdges();
2465 TopoDS_Edge E1 = sewd->Edge(1);
2466 TopoDS_Edge E2 = sewd->Edge(NbEdges);
2467 TopoDS_Vertex V1,V2;
2468 ShapeAnalysis_Edge sae;
2469 V1=sae.FirstVertex(E1);
2470 V2=sae.LastVertex(E2);
2471 if(!V1.IsSame(V2)) {
2473 std::cout<<"wire not closed --> stop split"<<std::endl;
2475 return Standard_False;
2478 TopoDS_Shape emptyCopied = S.EmptyCopied();
2479 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2480 tmpFace.Orientation ( TopAbs_FORWARD );
2481 B.Add(tmpFace,wire);
2483 const TopTools_ListOfShape& IntWires = MapWires.Find(wire);
2484 TopTools_ListIteratorOfListOfShape liter(IntWires);
2485 for( ; liter.More(); liter.Next()) {
2486 TopoDS_Shape aShapeEmptyCopied = tmpFace.EmptyCopied();
2487 TopoDS_Face aFace = TopoDS::Face ( aShapeEmptyCopied);
2488 aFace.Orientation ( TopAbs_FORWARD );
2489 B.Add (aFace,liter.Value());
2490 BRepTopAdaptor_FClass2d clas (aFace,::Precision::PConfusion());
2491 TopAbs_State staout = clas.PerformInfinitePoint();
2492 if (staout == TopAbs_IN)
2493 B.Add(tmpFace,liter.Value());
2495 B.Add(tmpFace,liter.Value().Reversed());
2498 if(!myFwd) tmpFace.Orientation(TopAbs_REVERSED);
2499 faces.Append(tmpFace);
2503 if(NbWires!=NbWiresNew) return Standard_False;
2505 if(faces.Length()>1) {
2506 TopoDS_Compound Comp;
2507 B.MakeCompound(Comp);
2508 for(Standard_Integer i=1; i<=faces.Length(); i++ )
2509 B.Add(Comp,faces(i));
2512 if(!Context().IsNull())
2514 Context()->Replace ( myFace, myResult );
2517 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
2518 myFace = TopoDS::Face ( exp.Current() );
2519 BRepTools::Update(myFace);
2521 return Standard_True;
2524 return Standard_False;
2527 //=======================================================================
2528 //function : IsPeriodicConicalLoop
2529 //purpose : Checks whether the passed wire makes up a periodic loop on
2530 // passed conical surface
2531 //=======================================================================
2533 static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
2534 const TopoDS_Wire& theWire,
2535 const Standard_Real theTolerance,
2536 Standard_Real& theMinU,
2537 Standard_Real& theMaxU,
2538 Standard_Real& theMinV,
2539 Standard_Real& theMaxV,
2540 Standard_Boolean& isUDecrease)
2542 if ( theSurf.IsNull() )
2543 return Standard_False;
2545 ShapeAnalysis_Edge aSAE;
2546 TopLoc_Location aLoc;
2548 Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
2549 Standard_Real aMinU = RealLast();
2550 Standard_Real aMinV = aMinU;
2551 Standard_Real aMaxU = -aMinU;
2552 Standard_Real aMaxV = aMaxU;
2554 // Iterate over the edges to check whether the wire is periodic on conical surface
2555 TopoDS_Iterator aWireIter(theWire, Standard_False);
2556 for ( ; aWireIter.More(); aWireIter.Next() )
2558 const TopoDS_Edge& aCurrentEdge = TopoDS::Edge(aWireIter.Value());
2559 Handle(Geom2d_Curve) aC2d;
2560 Standard_Real aPFirst, aPLast;
2562 aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
2564 if ( aC2d.IsNull() )
2565 return Standard_False;
2567 gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
2568 aUVLast = aC2d->Value(aPLast);
2570 Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
2571 Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
2573 Standard_Real aCurMaxU = Max(aUFirst, aULast),
2574 aCurMinU = Min(aUFirst, aULast);
2575 Standard_Real aCurMaxV = Max(aVFirst, aVLast),
2576 aCurMinV = Min(aVFirst, aVLast);
2578 if ( aCurMinU < aMinU )
2580 if ( aCurMaxU > aMaxU )
2582 if ( aCurMinV < aMinV )
2584 if ( aCurMaxV > aMaxV )
2587 Standard_Real aDeltaU = aULast - aUFirst;
2589 aCumulDeltaU += aDeltaU;
2590 aCumulDeltaUAbs += Abs(aDeltaU);
2597 isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
2599 Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
2600 Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
2602 return is2PIDelta && isAroundApex;
2605 //=======================================================================
2606 //function : FixPeriodicDegenerated
2608 //=======================================================================
2610 Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
2612 /* =====================
2613 * Prepare fix routine
2614 * ===================== */
2616 if ( !Context().IsNull() )
2618 TopoDS_Shape aSh = Context()->Apply(myFace);
2619 myFace = TopoDS::Face(aSh);
2622 /* ================================================
2623 * Check if fix can be applied on the passed face
2624 * ================================================ */
2626 // Collect all wires owned by the face
2627 TopTools_SequenceOfShape aWireSeq;
2628 for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
2630 const TopoDS_Shape& aSubSh = aWireIt.Value();
2631 if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
2632 aSubSh.Orientation() != TopAbs_REVERSED ) )
2635 aWireSeq.Append( aWireIt.Value() );
2638 // Get number of wires and surface
2639 Standard_Integer aNbWires = aWireSeq.Length();
2640 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
2642 // Only single wires on conical surfaces are checked
2643 if ( aNbWires != 1 || aSurface.IsNull() ||
2644 aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
2645 return Standard_False;
2647 // Get the single wire
2648 TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
2650 // Check whether this wire is belting the conical surface by period
2651 Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
2652 Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
2653 Standard_Boolean isUDecrease = Standard_False;
2655 Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
2656 aMinLoopU, aMaxLoopU,
2657 aMinLoopV, aMaxLoopV,
2661 return Standard_False;
2665 * =============== */
2667 // Get base circle of the conical surface (the circle it was built from)
2668 Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
2669 Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
2671 // Retrieve conical props
2672 Standard_Real aConeBaseR = aConeBaseCirc->Radius();
2673 Standard_Real aSemiAngle = aConeSurf->SemiAngle();
2675 if ( fabs(aSemiAngle) <= Precision::Confusion() )
2676 return Standard_False; // Bad surface
2678 // Find the V parameter of the apex
2679 Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
2680 Standard_Real anApexV = -aConeBaseH;
2683 TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
2685 // ====================================
2686 // Build degenerated edge in the apex
2687 // ====================================
2689 TopoDS_Edge anApexEdge;
2690 BRep_Builder aBuilder;
2691 aBuilder.MakeEdge(anApexEdge);
2693 // Check if positional relationship between the initial wire and apex
2694 // line in 2D is going to be consistent
2695 if ( fabs(anApexV - aMinLoopV) <= Precision() ||
2696 fabs(anApexV - aMaxLoopV) <= Precision() ||
2697 ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
2698 return Standard_False;
2700 Handle(Geom2d_Line) anApexCurve2d;
2702 // Apex curve below the wire
2703 if ( anApexV < aMinLoopV )
2705 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
2707 aSoleWire.Reverse();
2710 // Apex curve above the wire
2711 if ( anApexV > aMaxLoopV )
2713 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
2715 aSoleWire.Reverse();
2718 // Create degenerated edge & wire for apex
2719 aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
2720 aBuilder.Add( anApexEdge, anApex );
2721 aBuilder.Add( anApexEdge, anApex.Reversed() );
2722 aBuilder.Degenerated(anApexEdge, Standard_True);
2723 aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
2724 TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
2726 // ===============================================================
2727 // Finalize the fix building new face and setting up the results
2728 // ===============================================================
2730 // Collect the resulting set of wires
2731 TopTools_SequenceOfShape aNewWireSeq;
2732 aNewWireSeq.Append(aSoleWire);
2733 aNewWireSeq.Append(anApexWire);
2735 // Assemble new face
2736 TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
2737 aNewFace.Orientation(TopAbs_FORWARD);
2738 BRep_Builder aFaceBuilder;
2739 for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
2741 TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
2742 aFaceBuilder.Add(aNewFace, aNewWire);
2744 aNewFace.Orientation( myFace.Orientation() );
2746 // Adjust the resulting state of the healing tool
2747 myResult = aNewFace;
2748 Context()->Replace(myFace, myResult);
2750 return Standard_True;