1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
18 // pdn 10.12.98: tr9_r0501-ug
19 // pdn 28.12.98: PRO10366 shifting pcurve between two singularities
20 //:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved
21 //:l2 abv 10.01.99: USA60022 7289: corrections for reversed face
22 //gka 11.01.99 file PRO7755.stp #2018: work-around error in BRepLib_MakeFace
23 //:p4 abv, pdn 23.02.99: PRO9234 #15720: call BRepTools::Update() for faces
24 // rln 03.03.99 S4135: transmission of parameter precision to SA_Surface::NbSingularities
25 //:q5 abv 19.03.99 code improvement
26 //%14 pdn 15.03.99 adding function for fixing null area wires
27 //%15 pdn 20.03.99 code improvement
28 // abv 09.04.99 S4136: improve tolerance management; remove unused flag Closed
29 //#4 szv S4163: optimization
30 // smh 31.01.01 BUC60810 : Case of small wire on face in solid
31 // sln 25.09.2001 checking order of 3d and 2d representation curves
32 // abv 19.10.2001 FixAddNaturalBound improved and extracted as separate fix
33 // skl,pdn 14.05.2002 OCC55 (correction precision for small faces)
35 #include <ShapeFix_Face.ixx>
37 #include <Standard_Failure.hxx>
38 #include <Standard_ErrorHandler.hxx>
40 #include <Precision.hxx>
42 #include <Geom2d_Curve.hxx>
43 #include <Geom2d_Line.hxx>
44 #include <Geom_Curve.hxx>
45 #include <Geom_BSplineSurface.hxx>
46 #include <GeomAdaptor_HSurface.hxx>
49 #include <TopoDS_Edge.hxx>
50 #include <TopoDS_Vertex.hxx>
51 #include <TopoDS_Shell.hxx>
52 #include <TopoDS_Compound.hxx>
53 #include <TopoDS_Iterator.hxx>
54 #include <TopExp_Explorer.hxx>
55 #include <TopTools_SequenceOfShape.hxx>
57 #include <BRep_Tool.hxx>
58 #include <BRep_Builder.hxx>
59 #include <BRepTopAdaptor_FClass2d.hxx>
60 #include <BRepTools.hxx>
61 #include <BRepTools_WireExplorer.hxx>
62 #include <BRepBuilderAPI_MakeFace.hxx>
63 #include <BRepBuilderAPI_MakeVertex.hxx>
64 #include <BRepBuilderAPI_MakeWire.hxx>
66 #include <Message_Msg.hxx>
67 #include <ShapeBuild_ReShape.hxx>
68 #include <ShapeExtend_WireData.hxx>
69 #include <ShapeAnalysis.hxx>
70 #include <ShapeFix_Wire.hxx>
71 #include <ShapeFix_Edge.hxx>
72 #include <ShapeAnalysis_Edge.hxx>
73 #include <Bnd_Box2d.hxx>
74 #include <Geom_Circle.hxx>
75 #include <Geom_SphericalSurface.hxx>
76 #include <Geom_RectangularTrimmedSurface.hxx>
77 #include <Geom_ConicalSurface.hxx>
78 #include <ShapeAnalysis_Wire.hxx>
79 #include <ShapeAnalysis_Surface.hxx>
81 #include <ShapeExtend_CompositeSurface.hxx>
82 #include <ShapeFix_ComposeShell.hxx>
83 #include <TColGeom_HArray2OfSurface.hxx>
84 #include <ShapeBuild_Edge.hxx>
85 #include <TColgp_SequenceOfPnt2d.hxx>
86 #include <Bnd_Box.hxx>
87 #include <TopTools_IndexedMapOfShape.hxx>
88 #include <TopTools_DataMapOfShapeListOfShape.hxx>
89 #include <TopTools_ListIteratorOfListOfShape.hxx>
90 #include <TopTools_MapOfShape.hxx>
94 #include <ShapeFix.hxx>
95 #include <ShapeFix_DataMapOfShapeBox2d.hxx>
96 #include <BndLib_Add2dCurve.hxx>
97 #include <Geom2dAdaptor_Curve.hxx>
98 #include <IntRes2d_Domain.hxx>
99 #include <Geom2dInt_GInter.hxx>
100 #include <IntRes2d_IntersectionPoint.hxx>
101 #include <IntRes2d_Transition.hxx>
102 #include <TopTools_SequenceOfShape.hxx>
103 #include <IntRes2d_IntersectionSegment.hxx>
104 #include <TopTools_DataMapOfShapeInteger.hxx>
106 #include <ShapeFix_IntersectionTool.hxx>
107 #include <ShapeFix_SplitTool.hxx>
108 #include <TColStd_MapOfInteger.hxx>
109 #include <TopTools_DataMapOfShapeShape.hxx>
115 //=======================================================================
116 //function : ShapeFix_Face
118 //=======================================================================
120 ShapeFix_Face::ShapeFix_Face()
122 myFwd = Standard_True;
124 myFixWire = new ShapeFix_Wire;
128 //=======================================================================
129 //function : ShapeFix_Face
131 //=======================================================================
133 ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face)
135 myFwd = Standard_True;
137 myFixWire = new ShapeFix_Wire;
142 //=======================================================================
143 //function : ClearModes
145 //=======================================================================
147 void ShapeFix_Face::ClearModes()
150 myFixOrientationMode = -1;
151 myFixAddNaturalBoundMode = -1;
152 myFixMissingSeamMode = -1;
153 myFixSmallAreaWireMode = -1;
154 myFixIntersectingWiresMode = -1;
155 myFixLoopWiresMode = -1;
156 myFixSplitFaceMode = -1;
157 myAutoCorrectPrecisionMode = 1;
158 myFixPeriodicDegenerated = -1;
161 //=======================================================================
162 //function : SetMsgRegistrator
164 //=======================================================================
166 void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
168 ShapeFix_Root::SetMsgRegistrator ( msgreg );
169 myFixWire->SetMsgRegistrator ( msgreg );
172 //=======================================================================
173 //function : SetPrecision
175 //=======================================================================
177 void ShapeFix_Face::SetPrecision (const Standard_Real preci)
179 ShapeFix_Root::SetPrecision ( preci );
180 myFixWire->SetPrecision ( preci );
183 //=======================================================================
184 //function : SetMinTolerance
186 //=======================================================================
188 void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol)
190 ShapeFix_Root::SetMinTolerance ( mintol );
191 myFixWire->SetMinTolerance ( mintol );
194 //=======================================================================
195 //function : SetMaxTolerance
197 //=======================================================================
199 void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol)
201 ShapeFix_Root::SetMaxTolerance ( maxtol );
202 myFixWire->SetMaxTolerance ( maxtol );
205 //=======================================================================
208 //=======================================================================
210 void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf,
211 const Standard_Real preci, const Standard_Boolean fwd)
214 Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf );
215 Init ( sas, preci, fwd );
218 //=======================================================================
221 //=======================================================================
223 void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf,
224 const Standard_Real preci, const Standard_Boolean fwd)
228 SetPrecision ( preci );
230 B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() );
233 if ( !fwd ) myFace.Orientation(TopAbs_REVERSED);
236 //=======================================================================
239 //=======================================================================
241 void ShapeFix_Face::Init (const TopoDS_Face& face)
244 mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) );
245 myFwd = ( face.Orientation() != TopAbs_REVERSED );
248 // myFace = TopoDS::Face(face.EmptyCopied());
249 // for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next())
250 // Add (TopoDS::Wire (ws.Value()) );
253 //=======================================================================
256 //=======================================================================
258 void ShapeFix_Face::Add (const TopoDS_Wire& wire)
260 if ( wire.IsNull() ) return;
262 //szv#4:S4163:12Mar99 SGI warns
263 TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented()
268 //=======================================================================
269 //function : SplitWire
270 //purpose : auxilary - try to split wire (it is needed if some segments
271 // were removed in ShapeFix_Wire::FixSelfIntersection()
272 //=======================================================================
273 static Standard_Boolean SplitWire(const TopoDS_Wire& wire,
274 TopTools_SequenceOfShape& aResWires)
276 TColStd_MapOfInteger UsedEdges;
277 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
278 Standard_Integer i,j,k;
279 ShapeAnalysis_Edge sae;
280 for(i=1; i<=sewd->NbEdges(); i++) {
281 if(UsedEdges.Contains(i)) continue;
282 TopoDS_Edge E1 = sewd->Edge(i);
284 TopoDS_Vertex V0,V1,V2;
285 V0 = sae.FirstVertex(E1);
286 V1 = sae.LastVertex(E1);
287 Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData;
289 Standard_Boolean IsConnectedEdge = Standard_True;
290 for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) {
291 for(k=2; k<=sewd->NbEdges(); k++) {
292 if(UsedEdges.Contains(k)) continue;
293 TopoDS_Edge E2 = sewd->Edge(k);
294 TopoDS_Vertex V21 = sae.FirstVertex(E2);
295 TopoDS_Vertex V22 = sae.LastVertex(E2);
296 if( sae.FirstVertex(E2).IsSame(V1) ) {
299 V1 = sae.LastVertex(E2);
304 // new wire is closed, put it into sequence
305 aResWires.Append(sewd1->Wire());
308 if(k>sewd->NbEdges()) {
309 IsConnectedEdge = Standard_False;
313 if(!IsConnectedEdge) {
314 // create new notclosed wire
315 aResWires.Append(sewd1->Wire());
317 if(UsedEdges.Extent()==sewd->NbEdges()) break;
320 if(aResWires.Length()>1) {
322 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
326 return Standard_True;
330 //=======================================================================
333 //=======================================================================
335 Standard_Boolean ShapeFix_Face::Perform()
337 myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
338 myFixWire->SetContext ( Context() );
339 Handle(ShapeFix_Wire) theAdvFixWire = Handle(ShapeFix_Wire)::DownCast(myFixWire);
340 if (theAdvFixWire.IsNull()) return Standard_False;
343 TopoDS_Shape aInitFace = myFace;
344 // perform first part of fixes on wires
345 Standard_Boolean isfixReorder = Standard_False;
346 Standard_Boolean isReplaced = Standard_False;
348 //gka fix in order to avoid lost messages (following OCC21771)
349 TopTools_DataMapOfShapeShape aMapReorderedWires;
351 Standard_Real aSavPreci = Precision();
352 if ( NeedFix ( myFixWireMode ) ) {
353 theAdvFixWire->SetFace ( myFace );
355 Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode();
356 Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode();
357 Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode();
358 theAdvFixWire->FixLackingMode() = Standard_False;
359 theAdvFixWire->FixNotchedEdgesMode() = Standard_False;
360 theAdvFixWire->FixSelfIntersectionMode() = Standard_False;
362 Standard_Boolean fixed = Standard_False;
363 TopoDS_Shape S = myFace;
364 if ( ! Context().IsNull() )
365 S = Context()->Apply ( myFace );
366 TopoDS_Shape emptyCopied = S.EmptyCopied();
367 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
368 tmpFace.Orientation ( TopAbs_FORWARD );
371 // skl 14.05.2002 OCC55 + corrected 03.03.2004
372 Standard_Real dPreci = aSavPreci*aSavPreci;
374 Standard_Real newpreci=dPreci;
375 for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) {
376 TopoDS_Edge edge = TopoDS::Edge ( exp.Current() );
377 Standard_Real first,last;
378 Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last);
381 bb.Add(c3d->Value(first));
382 bb.Add(c3d->Value(last));
383 bb.Add(c3d->Value((last+first)/2.));
384 Standard_Real x1,x2,y1,y2,z1,z2,size;
385 bb.Get(x1,y1,z1,x2,y2,z2);
386 size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
387 if(size<newpreci) newpreci=size;
390 newpreci=sqrt(newpreci)/2.*1.00001;
391 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
392 SetPrecision(newpreci);
393 theAdvFixWire->SetPrecision(newpreci);
395 // end skl 14.05.2002
398 // skl 29.03.2010 (OCC21623)
399 if( myAutoCorrectPrecisionMode ) {
400 Standard_Real size = ShapeFix::LeastEdgeSize(S);
401 Standard_Real newpreci = Min(aSavPreci,size/2.);
402 newpreci = newpreci*1.00001;
403 if( aSavPreci > newpreci && newpreci > Precision::Confusion()) {
404 SetPrecision(newpreci);
405 theAdvFixWire->SetPrecision(newpreci);
409 isfixReorder = Standard_False;
410 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
411 if(iter.Value().ShapeType() != TopAbs_WIRE) {
412 B.Add ( tmpFace, iter.Value() );
415 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
416 theAdvFixWire->Load ( wire );
417 if(theAdvFixWire->NbEdges() == 0) {
418 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
419 B.Add ( tmpFace, wire );
421 fixed = Standard_True;
422 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
426 if ( theAdvFixWire->Perform() ) {
427 //fixed = Standard_True;
428 isfixReorder = (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder);
429 fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) ||
430 theAdvFixWire->StatusConnected(ShapeExtend_DONE) ||
431 theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) ||
432 theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) ||
433 theAdvFixWire->StatusClosed(ShapeExtend_DONE));
434 TopoDS_Wire w = theAdvFixWire->Wire();
436 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
437 if(theAdvFixWire->NbEdges() == 0) {
438 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
442 else if(!wire.IsSame(w))
443 aMapReorderedWires.Bind(wire,w);
447 B.Add ( tmpFace, wire );
448 // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) )
449 // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
452 theAdvFixWire->FixLackingMode() = usFixLackingMode;
453 theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode;
454 theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode;
455 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
458 //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
459 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
461 isReplaced = Standard_True;
462 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
465 if(fixed || isfixReorder)
470 TopoDS_Shape savShape = myFace; //gka BUG 6555
472 // Specific case for conic surfaces
473 if ( NeedFix(myFixPeriodicDegenerated) )
474 this->FixPeriodicDegenerated();
477 if ( NeedFix ( myFixMissingSeamMode ) ) {
478 if ( FixMissingSeam() ) {
479 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
483 // cycle by all possible faces coming from FixMissingSeam
484 // each face is processed as if it was single
485 TopExp_Explorer exp(myResult,TopAbs_FACE);
486 for ( ; exp.More(); exp.Next() ) {
487 myFace = TopoDS::Face ( exp.Current() );
488 Standard_Boolean NeedCheckSplitWire = Standard_False;
490 // perform second part of fixes on wires
491 if ( NeedFix ( myFixWireMode ) ) {
492 theAdvFixWire->SetFace ( myFace );
494 Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode();
495 Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode();
496 Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode();
497 Standard_Integer usFixDegeneratedMode = theAdvFixWire->FixDegeneratedMode();
498 theAdvFixWire->FixSmallMode() = Standard_False;
499 theAdvFixWire->FixConnectedMode() = Standard_False;
500 theAdvFixWire->FixEdgeCurvesMode() = Standard_False;
501 theAdvFixWire->FixDegeneratedMode() = Standard_False;
503 Standard_Boolean fixed = Standard_False;
504 TopoDS_Shape S = myFace;
505 if ( ! Context().IsNull() )
506 S = Context()->Apply ( myFace );
507 TopoDS_Shape emptyCopied = S.EmptyCopied();
508 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
509 tmpFace.Orientation ( TopAbs_FORWARD );
510 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
511 if(iter.Value().ShapeType() != TopAbs_WIRE) {
512 B.Add ( tmpFace,iter.Value());
516 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
517 theAdvFixWire->Load ( wire );
518 if(theAdvFixWire->NbEdges() == 0) {
519 if(theAdvFixWire->WireData()->NbNonManifoldEdges())
520 B.Add ( tmpFace, wire );
522 fixed = Standard_True;
523 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
527 if ( theAdvFixWire->Perform() ) {
528 isfixReorder = theAdvFixWire->StatusReorder(ShapeExtend_DONE);
529 fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) ||
530 theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) ||
531 theAdvFixWire->StatusNotches(ShapeExtend_DONE)); //Standard_True;
532 TopoDS_Wire w = theAdvFixWire->Wire();
534 if ( ! Context().IsNull() ) Context()->Replace ( wire, w );
537 else if(!wire.IsSame(w))
538 aMapReorderedWires.Bind(wire,w);
542 if(theAdvFixWire->StatusRemovedSegment())
543 NeedCheckSplitWire = Standard_True;
545 //fix for loop of wire
546 TopTools_SequenceOfShape aLoopWires;
547 if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) {
548 if (aLoopWires.Length() > 1)
549 SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was splitted on several wires
550 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
551 fixed = Standard_True;
552 Standard_Integer k=1;
553 for( ; k <= aLoopWires.Length(); k++)
554 B.Add (tmpFace,aLoopWires.Value(k));
557 B.Add ( tmpFace, wire );
560 theAdvFixWire->FixSmallMode() = usFixSmallMode;
561 theAdvFixWire->FixConnectedMode() = usFixConnectedMode;
562 theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode;
563 theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode;
566 if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED );
567 if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555
568 Context()->Replace(aInitFace,savShape);
569 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
571 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
575 if(NeedCheckSplitWire) {
576 // try to split wire - it is needed if some segments were removed
577 // in ShapeFix_Wire::FixSelfIntersection()
578 TopoDS_Shape S = myFace;
579 if ( ! Context().IsNull() )
580 S = Context()->Apply ( myFace );
581 TopoDS_Shape emptyCopied = S.EmptyCopied();
582 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
583 tmpFace.Orientation ( TopAbs_FORWARD );
584 TopTools_SequenceOfShape aWires;
585 Standard_Integer nbw=0;
586 for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
587 if(iter.Value().ShapeType() != TopAbs_WIRE) {
588 B.Add (tmpFace,iter.Value());
591 if(iter.Value().Orientation() != TopAbs_FORWARD ||
592 iter.Value().Orientation() != TopAbs_REVERSED) {
593 B.Add (tmpFace,TopoDS::Wire(iter.Value()));
597 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
598 SplitWire(wire,aWires);
600 if(nbw<aWires.Length()) {
601 for(Standard_Integer iw=1; iw<=aWires.Length(); iw++)
602 B.Add (tmpFace,aWires.Value(iw));
603 if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace );
604 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
609 // fix intersecting wires
610 if(FixWiresTwoCoincEdges())
611 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
612 if ( NeedFix ( myFixIntersectingWiresMode ) ) {
613 if ( FixIntersectingWires() ) {
614 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 );
619 TopTools_DataMapOfShapeListOfShape MapWires;
621 if ( NeedFix ( myFixOrientationMode ) ) {
622 if ( FixOrientation(MapWires) )
623 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 );
626 BRepTools::Update(myFace);
628 // fix natural bounds
629 Standard_Boolean NeedSplit = Standard_True;
630 if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
631 if ( FixAddNaturalBound() ) {
632 NeedSplit = Standard_False;
633 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
638 if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) {
639 if ( FixSplitFace(MapWires) )
640 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 );
645 //return the original preci
646 SetPrecision(aSavPreci);
647 theAdvFixWire->SetPrecision(aSavPreci);
649 // cycle by all possible faces coming from FixAddNaturalBound
650 // each face is processed as if it was single
651 for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) {
652 myFace = TopoDS::Face ( exp.Current() );
654 // fix small-area wires
655 if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) ) {
656 if ( FixSmallAreaWire() )
657 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
662 if ( ! Context().IsNull() ) {
663 if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
665 //gka fix in order to avoid lost messages (following OCC21771)
666 if(aMapReorderedWires.Extent())
668 TopoDS_Iterator aItW(aInitFace,Standard_False);
669 for( ; aItW.More() ; aItW.Next())
671 TopoDS_Shape aCurW = aItW.Value();
672 while(aMapReorderedWires.IsBound(aCurW))
674 TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW);
675 Context()->Replace(aCurW, aFixW);
681 Context()->Replace(aInitFace, savShape);
683 myResult = Context()->Apply ( aInitFace ); //gka 06.09.04
685 else if(!Status ( ShapeExtend_DONE ))
686 myResult = aInitFace;
688 return Status ( ShapeExtend_DONE );
691 //=======================================================================
692 //function : Auxiliary functions
694 //=======================================================================
696 // Shift all pcurves of edges in the given wire on the given face
698 static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f,
700 const Handle(ShapeAnalysis_Surface)& mySurf,
701 Standard_Boolean recompute3d = Standard_False)
704 tr2d.SetTranslation(vec.XY());
705 ShapeAnalysis_Edge sae;
708 for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){
709 TopoDS_Edge edge = TopoDS::Edge(ei.Value());
710 Handle (Geom2d_Curve) C2d;
711 Standard_Real cf, cl;
712 if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue;
713 C2d->Transform(tr2d);
715 // recompute 3d curve and vertex
716 sbe.RemoveCurve3d ( edge );
717 sbe.BuildCurve3d ( edge );
718 B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. );
723 // Cut interval from the sequence of intervals
724 static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals,
725 const gp_Pnt2d &toAddI,
726 const Standard_Real period)
728 if ( intervals.Length() <=0 ) return Standard_False;
729 for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top
730 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
731 gp_Pnt2d interval = intervals(i);
732 // ACIS907, OCC921 a054a.sat (face 124)
733 Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ),
734 0.5*( interval.X() + interval.Y() ),period);
735 gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift );
736 if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue;
737 if ( toAdd.X() > interval.X() ) {
738 if ( toAdd.Y() < interval.Y() ) {
739 intervals.InsertBefore ( i, interval );
740 intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++...
742 intervals.ChangeValue(i).SetY ( toAdd.X() );
744 else if ( toAdd.Y() < interval.Y() ) {
745 intervals.ChangeValue(i).SetX ( toAdd.Y() );
747 else intervals.Remove ( i-- );
750 return Standard_True;
753 // Find middle of the biggest interval
754 static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals)
756 Standard_Real shift = 0., max = -1.;
757 for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) {
758 gp_Pnt2d interval = intervals(i);
759 if ( interval.Y() - interval.X() <= max ) continue;
760 max = interval.Y() - interval.X();
761 shift = interval.X() + 0.5 * max;
766 //=======================================================================
767 //function : FixAddNaturalBound
769 //=======================================================================
770 // Detect missing natural bounary on spherical surfaces and add it if
772 //pdn 981202: add natural bounds if missing (on sphere only)
773 //:abv 28.08.01: rewritten and extended for toruses
775 Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
777 if ( ! Context().IsNull() ) {
778 TopoDS_Shape S = Context()->Apply ( myFace );
779 myFace = TopoDS::Face ( S );
782 // collect wires in sequence
783 TopTools_SequenceOfShape ws;
784 TopTools_SequenceOfShape vs;
785 TopoDS_Iterator wi (myFace,Standard_False);
786 for ( ; wi.More(); wi.Next()) {
787 if(wi.Value().ShapeType() == TopAbs_WIRE &&
788 (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED))
789 ws.Append (wi.Value());
791 vs.Append(wi.Value());
794 // deal with case of empty face: just create a new one by standard tool
795 if ( ws.Length() <=0 ) {
796 BRepBuilderAPI_MakeFace mf (mySurf->Surface(), Precision::Confusion());
797 if ( ! Context().IsNull() ) Context()->Replace ( myFace, mf.Face() );
800 //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated
801 Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool();
802 for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) {
803 TopoDS_Edge edg = TopoDS::Edge (Eed.Current());
804 sfe->FixVertexTolerance(edg);
807 // B.UpdateFace (myFace,myPrecision);
808 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
809 BRepTools::Update(myFace);
810 return Standard_True;
813 // check that surface is double-closed and fix is needed
814 if ( ( mySurf->Adaptor3d()->GetType() != GeomAbs_Sphere &&
815 mySurf->Adaptor3d()->GetType() != GeomAbs_Torus ) ||
816 ShapeAnalysis::IsOuterBound (myFace) )
817 return Standard_False;
819 // Collect informations on free intervals in U and V
820 TColgp_SequenceOfPnt2d intU, intV, centers;
821 Standard_Real SUF, SUL, SVF, SVL;
822 mySurf->Bounds(SUF, SUL, SVF, SVL);
823 intU.Append ( gp_Pnt2d(SUF, SUL) );
824 intV.Append ( gp_Pnt2d(SVF, SVL) );
825 Standard_Integer nb = ws.Length();
827 for ( i=1; i <= nb; i ++) {
828 Standard_Real Umin, Vmin, Umax, Vmax;
830 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
831 // PTV 01.11.2002 ACIS907, OCC921 begin
832 // BRepTools::AddUVBounds(myFace,aw,B);
833 // B.Get(Umin, Vmin, Umax, Vmax);
834 TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() );
836 aB.Add( aWireFace, aw );
837 ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax);
838 // PTV 01.11.2002 ACIS907, OCC921 end
839 if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF );
840 if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF );
841 centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) );
844 // find best interval and thus compute shift
845 gp_Pnt2d shift(0.,0.);
846 if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) );
847 if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) );
849 // Adjust all other wires to be inside outer one
850 gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) );
851 for ( i=1; i <= nb; i++ ) {
852 TopoDS_Wire wire = TopoDS::Wire (ws.Value(i));
854 if ( mySurf->IsUClosed() )
855 sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) );
856 if ( mySurf->IsVClosed() )
857 sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) );
858 Shift2dWire ( wire, myFace, sh.XY(), mySurf );
861 // Create naturally bounded surface and add that wire to sequence
863 // Create fictive grid and call ComposeShell
864 Handle(Geom_RectangularTrimmedSurface) RTS =
865 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(),
866 SVF+shift.Y(), SVL+shift.Y() );
867 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
868 grid->SetValue ( 1, 1, RTS );
869 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
872 ShapeFix_ComposeShell CompShell;
873 CompShell.Init ( G, L, myFace, ::Precision::Confusion() );
874 CompShell.ClosedMode() = Standard_True;
875 CompShell.NaturalBoundMode() = Standard_True;
876 CompShell.SetContext( Context() );
877 CompShell.SetMaxTolerance(MaxTolerance());
879 TopoDS_Shape res = CompShell.Result();
881 Context()->Replace ( myFace, res );
882 for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) {
883 myFace = TopoDS::Face ( exp.Current() );
884 BRepTools::Update(myFace); //:p4
886 myResult = Context()->Apply ( myResult );
890 Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L );
891 BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion());
892 TopoDS_Face ftmp = mf.Face();
894 for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) {
895 if(wi.Value().ShapeType() != TopAbs_WIRE)
897 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
899 if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue;
900 Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True );
903 // Fix possible case on sphere when gap contains degenerated edge
904 // and thus has a common part with natural boundary
905 // Such hole should be merged with boundary
906 if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere &&
907 ws.Length() == nb+1 ) {
908 Handle(ShapeExtend_WireData) bnd =
909 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) );
910 // code to become separate method FixTouchingWires()
911 for ( i=1; i <= nb; i++ ) {
912 Handle(ShapeExtend_WireData) sbwd =
913 new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) );
914 for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) {
915 if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue;
916 // find corresponding place in boundary
917 ShapeAnalysis_Edge sae;
918 TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) );
920 for ( k=1; k <= bnd->NbEdges(); k++ ) {
921 if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue;
922 if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break;
924 if ( k > bnd->NbEdges() ) continue;
925 // and insert hole to that place
927 B.Degenerated ( sbwd->Edge(j), Standard_False );
928 B.Degenerated ( bnd->Edge(k), Standard_False );
930 bnd->Add ( sbwd, k+1 );
933 myFixWire->SetFace ( myFace );
934 myFixWire->Load ( bnd );
935 myFixWire->FixConnected();
936 myFixWire->FixDegenerated();
937 ws.SetValue ( ws.Length(), bnd->Wire() );
943 // Create resulting face
945 TopoDS_Shape S = myFace.EmptyCopied();
946 S.Orientation ( TopAbs_FORWARD );
947 for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) );
948 for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) );
949 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
950 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
951 myFace = TopoDS::Face ( S );
952 BRepTools::Update(myFace);
956 cout<<"Natural bound on sphere or torus with holes added"<<endl; // mise au point !
958 SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds
959 return Standard_True;
963 //=======================================================================
964 //function : FixOrientation
966 //=======================================================================
968 Standard_Boolean ShapeFix_Face::FixOrientation()
970 TopTools_DataMapOfShapeListOfShape MapWires;
972 return FixOrientation(MapWires);
976 //=======================================================================
977 //function : FixOrientation
979 //=======================================================================
981 Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShape &MapWires)
983 Standard_Boolean done = Standard_False;
985 if ( ! Context().IsNull() ) {
986 TopoDS_Shape S = Context()->Apply ( myFace );
987 myFace = TopoDS::Face ( S );
989 TopTools_SequenceOfShape ws;
990 TopTools_SequenceOfShape allSubShapes;
991 // smh: BUC60810 : protection against very small wires (one-edge, null-length)
992 TopTools_SequenceOfShape VerySmallWires;
993 for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) {
994 if(wi.Value().ShapeType() == TopAbs_VERTEX ||
995 (wi.Value().Orientation() != TopAbs_FORWARD &&
996 wi.Value().Orientation() != TopAbs_REVERSED)) {
997 allSubShapes.Append (wi.Value());
998 //ws.Append (wi.Value());
1002 TopoDS_Iterator ei (wi.Value(),Standard_False);
1004 Standard_Real length = RealLast();
1006 anEdge = TopoDS::Edge(ei.Value());
1008 if ( ! ei.More() ) {
1010 Standard_Real First, Last;
1011 Handle(Geom_Curve) c3d;
1012 ShapeAnalysis_Edge sae;
1013 if ( sae.Curve3d(anEdge,c3d,First,Last) ) {
1014 gp_Pnt pntIni = c3d->Value(First);
1016 prev = pntIni.XYZ();
1017 Standard_Integer NbControl = 10;
1018 for ( Standard_Integer j = 1; j < NbControl; j++) {
1019 Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1);
1020 gp_Pnt pntCurr = c3d->Value(prm);
1021 gp_XYZ curr = pntCurr.XYZ();
1022 gp_XYZ delta = curr - prev;
1023 length += delta.Modulus();
1030 if (length > ::Precision::Confusion()) {
1031 ws.Append (wi.Value());
1032 allSubShapes.Append (wi.Value());
1034 else VerySmallWires.Append (wi.Value());
1036 if ( VerySmallWires.Length() >0 ) done = Standard_True;
1038 Standard_Integer nb = ws.Length();
1039 Standard_Integer nbAll = allSubShapes.Length();
1042 // if no wires, just do nothing
1043 if ( nb <= 0) return Standard_False;
1044 Standard_Integer nbInternal=0;
1045 Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) &&
1046 ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere ||
1047 mySurf->Adaptor3d()->GetType() == GeomAbs_Torus ));
1048 TColStd_SequenceOfInteger aSeqReversed;
1049 // if wire is only one, check its orientation
1051 // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1)
1052 // make face with only one wire (ws.Value(1))
1053 TopoDS_Shape dummy = myFace.EmptyCopied();
1054 TopoDS_Face af = TopoDS::Face ( dummy );
1055 af.Orientation ( TopAbs_FORWARD );
1056 B.Add (af,ws.Value(1));
1057 if ( ( myFixAddNaturalBoundMode != Standard_True || //: abv 29.08.01: Spatial_firex_lofting.sat
1058 ( mySurf->Adaptor3d()->GetType() != GeomAbs_Sphere &&
1059 mySurf->Adaptor3d()->GetType() != GeomAbs_Torus ) ) &&
1060 ! ShapeAnalysis::IsOuterBound (af)) {
1061 Handle(ShapeExtend_WireData) sbdw =
1062 new ShapeExtend_WireData (TopoDS::Wire(ws.Value(1)));
1063 sbdw->Reverse ( myFace );
1064 ws.SetValue ( 1, sbdw->Wire() );
1065 SendWarning ( sbdw->Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1066 done = Standard_True;
1068 cout<<"Wire reversed"<<endl; // mise au point !
1072 // in case of several wires, perform complex analysis
1074 // Plusieurs wires : orientations relatives
1075 // Chaque wire doit "contenir" tous les autres
1076 // Evidemment, en cas de peau de leopard, il peut y avoir probleme
1078 // On prend chaque wire (NB: pcurves presentes !)
1079 // En principe on devrait rejeter les wires non fermes (cf couture manque ?)
1080 // On le classe par rapport aux autres, qui doivent tous etre, soit IN soit
1081 // OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse
1082 // (nb : ici pas myClos donc pas de pb de couture)
1083 // Si au moins une inversion, il faut refaire la face (cf myRebil)
1085 //:94 abv 30 Jan 98: calculate parametric precision
1087 // GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface();
1088 // Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) );
1089 Standard_Boolean uclosed = mySurf->IsUClosed();
1090 Standard_Boolean vclosed = mySurf->IsVClosed();
1091 Standard_Real SUF, SUL, SVF, SVL;
1092 mySurf->Bounds(SUF, SUL, SVF, SVL);
1094 TopTools_DataMapOfShapeListOfShape MW;
1095 TopTools_DataMapOfShapeInteger SI;
1096 TopTools_MapOfShape MapIntWires;
1099 MapIntWires.Clear();
1100 Standard_Integer NbOuts=0;
1103 for ( i = 1; i <= nb; i ++) {
1104 TopoDS_Shape asw = ws.Value(i);
1105 TopoDS_Wire aw = TopoDS::Wire (asw);
1106 TopoDS_Shape dummy = myFace.EmptyCopied();
1107 TopoDS_Face af = TopoDS::Face ( dummy );
1108 // B.MakeFace (af,mySurf->Surface(),::Precision::Confusion());
1109 af.Orientation ( TopAbs_FORWARD );
1111 // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787)
1112 // tolerance is too big. It is seems that to identify placement of 2d point
1113 // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON
1114 // BRepTopAdaptor_FClass2d clas (af,toluv);
1115 Standard_Boolean CheckShift = Standard_True;
1116 BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion());
1117 TopAbs_State sta = TopAbs_OUT;
1118 TopAbs_State staout = clas.PerformInfinitePoint();
1119 TopTools_ListOfShape IntWires;
1120 for ( Standard_Integer j = 1; j <= nbAll; j ++) {
1121 //if(i==j) continue;
1122 TopoDS_Shape aSh2 = allSubShapes.Value(j);
1125 TopAbs_State stb = TopAbs_UNKNOWN;
1126 if(aSh2.ShapeType() == TopAbs_VERTEX) {
1127 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2));
1128 gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion());
1129 stb = clas.Perform (p2d,Standard_False);
1130 if(stb == staout && (uclosed || vclosed)) {
1133 Standard_Real period = SUL-SUF;
1134 p2d1.SetCoord(p2d.X()+period, p2d.Y());
1135 stb = clas.Perform (p2d1,Standard_False);
1138 if(stb == staout && vclosed) {
1139 Standard_Real period = SVL-SVF;
1140 p2d1.SetCoord(p2d.X(), p2d.Y()+ period);
1141 stb = clas.Perform (p2d1,Standard_False);
1145 else if (aSh2.ShapeType() == TopAbs_WIRE) {
1146 CheckShift = Standard_True;
1147 TopoDS_Wire bw = TopoDS::Wire (aSh2);
1148 // Standard_Integer numin =0;
1149 TopoDS_Iterator ew (bw);
1150 for(;ew.More(); ew.Next()) {
1151 TopoDS_Edge ed = TopoDS::Edge (ew.Value());
1152 Standard_Real cf,cl;
1153 Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl);
1154 if (cw.IsNull()) continue;
1155 gp_Pnt2d unp = cw->Value ((cf+cl)/2.);
1156 TopAbs_State ste = clas.Perform (unp,Standard_False);
1157 if( ste==TopAbs_OUT || ste==TopAbs_IN ) {
1158 if(stb==TopAbs_UNKNOWN) {
1163 sta = TopAbs_UNKNOWN;
1171 Standard_Boolean found = Standard_False;
1173 if( stb == staout && CheckShift ) {
1174 CheckShift = Standard_False;
1176 Standard_Real period = SUL-SUF;
1177 unp1.SetCoord(unp.X()+period, unp.Y());
1178 found = (staout != clas.Perform (unp1,Standard_False));
1180 unp1.SetX(unp.X()-period);
1181 found = (staout != clas.Perform (unp1,Standard_False));
1184 if(vclosed&&!found) {
1185 Standard_Real period = SVL-SVF;
1186 unp1.SetCoord(unp.X(), unp.Y()+period);
1187 found = (staout != clas.Perform (unp1,Standard_False));
1189 unp1.SetY(unp.Y()-period);
1190 found = (staout != clas.Perform (unp1,Standard_False));
1195 if(stb==TopAbs_IN) stb = TopAbs_OUT;
1196 else stb = TopAbs_IN;
1197 Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf);
1205 IntWires.Append(aSh2);
1206 MapIntWires.Add(aSh2);
1210 if (sta == TopAbs_UNKNOWN) { // ERREUR
1211 SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire
1214 MW.Bind(aw,IntWires);
1215 if(sta==TopAbs_OUT) {
1217 if(staout==TopAbs_IN) {
1218 // wire is OUT but InfinitePoint is IN => need to reverse
1219 ShapeExtend_WireData sewd (aw);
1220 sewd.Reverse(myFace);
1221 ws.SetValue (i,sewd.Wire());
1222 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1223 aSeqReversed.Append(i);
1224 done = Standard_True;
1225 SI.Bind(ws.Value(i),1);
1226 MapWires.Bind(ws.Value(i),IntWires);
1230 MapWires.Bind(aw,IntWires);
1234 if(staout==TopAbs_OUT) SI.Bind(aw,2);
1241 for(i=1; i<=nb; i++) {
1242 TopoDS_Wire aw = TopoDS::Wire (ws.Value(i));
1243 Standard_Integer tmpi = SI.Find(aw);
1245 if(!MapIntWires.Contains(aw)) {
1247 const TopTools_ListOfShape& IW = MW.Find(aw);
1249 // wire is OUT but InfinitePoint is IN => need to reverse
1250 ShapeExtend_WireData sewd (aw);
1251 sewd.Reverse(myFace);
1252 ws.SetValue (i,sewd.Wire());
1253 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1254 aSeqReversed.Append(i);
1255 done = Standard_True;
1256 MapWires.Bind(ws.Value(i),IW);
1258 else MapWires.Bind(aw,IW);
1262 // wire is IN but InfinitePoint is OUT => need to reverse
1263 ShapeExtend_WireData sewd (aw);
1264 sewd.Reverse(myFace);
1265 ws.SetValue (i,sewd.Wire());
1266 SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed
1267 aSeqReversed.Append(i);
1268 done = Standard_True;
1276 //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1277 if(isAddNaturalBounds && nb == aSeqReversed.Length())
1278 done = Standard_False;
1280 done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
1281 // Faut-il reconstruire ? si myRebil est mis
1283 TopoDS_Shape S = myFace.EmptyCopied();
1284 S.Orientation ( TopAbs_FORWARD );
1285 Standard_Integer i = 1;
1286 for ( ; i <= nb; i++ )
1287 B.Add ( S, ws.Value(i) );
1290 for( i =1; i <= nbAll;i++) {
1291 TopoDS_Shape aS2 = allSubShapes.Value(i);
1292 if(aS2.ShapeType() != TopAbs_WIRE ||
1293 (aS2.Orientation() != TopAbs_FORWARD && aS2.Orientation() != TopAbs_REVERSED))
1298 if ( ! myFwd ) S.Orientation (TopAbs_REVERSED);
1299 if ( ! Context().IsNull() ) Context()->Replace ( myFace, S );
1300 myFace = TopoDS::Face ( S );
1301 BRepTools::Update(myFace);
1302 Standard_Integer k =1;
1303 for( ; k <= aSeqReversed.Length(); k++ )
1306 cout<<"Wire no "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<endl; // mise au point !
1315 //=======================================================================
1316 //function : CheckWire
1317 //purpose : auxilary for FixMissingSeam
1318 //=======================================================================
1319 //:i7 abv 18 Sep 98: ProSTEP TR9 r0501-ug.stp: algorithm of fixing missing seam changed
1320 // test whether the wire is opened on period of periodical surface
1321 static Standard_Boolean CheckWire (const TopoDS_Wire &wire,
1322 const TopoDS_Face &face,
1323 const Standard_Real dU,
1324 const Standard_Real dV,
1325 Standard_Integer &isuopen,
1326 Standard_Integer &isvopen,
1327 Standard_Boolean &isDeg)
1332 ShapeAnalysis_Edge sae;
1333 isDeg = Standard_True;
1334 for ( TopoDS_Iterator ed(wire); ed.More(); ed.Next() ) {
1335 TopoDS_Edge edge = TopoDS::Edge ( ed.Value() );
1336 if ( ! BRep_Tool::Degenerated ( edge ) ) isDeg = Standard_False;
1337 Handle(Geom2d_Curve) c2d;
1339 if ( ! sae.PCurve ( edge, face, c2d, f, l, Standard_True ) )
1340 return Standard_False;
1341 vec += c2d->Value(l).XY() - c2d->Value(f).XY();
1343 isuopen = ( Abs ( Abs ( vec.X() ) - dU ) < 0.1 * dU ? ( vec.X() >0 ? 1 : -1 ) : 0 );
1344 isvopen = ( Abs ( Abs ( vec.Y() ) - dV ) < 0.1 * dV ? ( vec.Y() >0 ? 1 : -1 ) : 0 );
1345 return isuopen || isvopen;
1349 //=======================================================================
1350 //function : FixMissingSeam
1352 //=======================================================================
1354 Standard_Boolean ShapeFix_Face::FixMissingSeam()
1356 Standard_Boolean uclosed = mySurf->IsUClosed();
1357 Standard_Boolean vclosed = mySurf->IsVClosed();
1359 if ( ! uclosed && ! vclosed ) return Standard_False;
1361 if ( ! Context().IsNull() ) {
1362 TopoDS_Shape S = Context()->Apply ( myFace );
1363 myFace = TopoDS::Face ( S );
1366 //%pdn: surface should be made periodic before (see ShapeCustom_Surface)!
1367 if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) {
1368 Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface());
1369 if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic())
1370 return Standard_False;
1373 Standard_Real URange, VRange, SUF, SUL, SVF, SVL;
1374 mySurf->Bounds ( SUF, SUL, SVF, SVL );
1375 Standard_Real fU1,fU2,fV1,fV2;
1376 BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2);
1378 //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters
1379 if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) {
1380 if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1;
1381 if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2;
1382 if(Abs(SUL-SUF) < ::Precision::PConfusion())
1383 if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.;
1386 if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) {
1387 if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1;
1388 if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2;
1389 if(Abs(SVL-SVF) < ::Precision::PConfusion())
1390 if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.;
1394 URange = Abs ( SUL - SUF );
1395 VRange = Abs ( SVL - SVF );
1396 // Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange;
1397 Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean
1398 Standard_Integer isdeg1=0, isdeg2=0;
1400 TopTools_SequenceOfShape ws;
1401 TopTools_SequenceOfShape aSeqNonManif;
1402 for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) {
1403 if(wi.Value().ShapeType() != TopAbs_WIRE ||
1404 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
1405 aSeqNonManif.Append(wi.Value());
1408 ws.Append ( wi.Value() );
1413 for ( i=1; i <= ws.Length(); i++ ) {
1414 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1415 Standard_Integer isuopen, isvopen;
1416 Standard_Boolean isdeg;
1417 if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) )
1419 if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; }
1420 else if ( w2.IsNull() ) {
1421 if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; }
1422 else if ( ismodeu == isuopen && ismodev == isvopen ) {
1425 //:abv 29.08.01: If wires are contraversal, reverse one of them
1426 // If first one is single degenerated edge, reverse it; else second
1435 if ( ! isdeg2 ) cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << endl;
1440 else cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << endl;
1443 // else return Standard_False; // abort
1446 cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << endl;
1448 //:abv 30.08.09: if more than one open wires and more than two of them are
1449 // completely degenerated, remove any of them
1450 if ( isdeg || isdeg1 || isdeg2 ) {
1451 ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 );
1456 cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << endl;
1464 if ( w1.IsNull() ) return Standard_False;
1465 else if ( w2.IsNull() ) {
1466 // WARNING!!! Temporarily for spheres only:
1467 // If only one of wires limiting face on sphere is open in 2d,
1468 // this means that degenerated edge should be added to one of poles, and
1469 // then usual procedure applied
1470 if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) {
1471 gp_Pnt2d p ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI );
1472 gp_Dir2d d ( -ismodeu, 0. );
1473 Handle(Geom2d_Line) line = new Geom2d_Line ( p, d );
1475 B.MakeEdge ( edge );
1476 B.Degenerated ( edge, Standard_True );
1477 B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() );
1478 B.Range ( edge, myFace, 0., 2*M_PI );
1480 B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() );
1481 V.Orientation(TopAbs_FORWARD);
1483 V.Orientation(TopAbs_REVERSED);
1489 else return Standard_False;
1492 // sort original wires
1493 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
1494 sfw->SetFace ( myFace );
1495 sfw->SetPrecision ( Precision() );
1497 Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 );
1498 Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 );
1501 // Standard_Boolean degenerated = ( secondDeg != firstDeg );
1502 // if ( ! degenerated ) {
1509 //:abv 29.08.01: reconstruct face taking into account reversing
1510 TopoDS_Shape dummy = myFace.EmptyCopied();
1511 TopoDS_Face tmpF = TopoDS::Face ( dummy );
1512 tmpF.Orientation ( TopAbs_FORWARD );
1513 for ( i=1; i <= ws.Length(); i++ ) {
1514 TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) );
1515 if ( wire.IsSame ( w1 ) ) wire = w1;
1516 else if ( wire.IsSame ( w2 ) ) wire = w2;
1517 B.Add ( tmpF, wire );
1519 tmpF.Orientation ( myFace.Orientation() );
1521 Standard_Real uf=SUF, vf=SVF;
1523 // A special kind of FixShifted is necessary for torus-like
1524 // surfaces to adjust wires by period ALONG the missing SEAM direction
1525 // tr9_r0501-ug.stp #187640
1526 if ( uclosed && vclosed ) {
1527 Standard_Integer coord = ( ismodeu ? 1 : 0 );
1528 Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev );
1529 Standard_Real period = ( ismodeu ? URange : VRange );
1531 Standard_Real m1[2][2], m2[2][2];
1532 S = tmpF.EmptyCopied();
1534 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]);
1535 S = tmpF.EmptyCopied();
1537 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1538 Standard_Real shiftw2 =
1539 ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1540 0.5 * ( m1[coord][0] + m1[coord][1] +
1541 isneg * ( period + ::Precision::PConfusion() ) ),
1543 m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 );
1544 m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 );
1545 for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) {
1546 if(it.Value().ShapeType() != TopAbs_WIRE)
1548 TopoDS_Wire w = TopoDS::Wire ( it.Value() );
1549 if ( w == w1 ) continue;
1550 Standard_Real shift;
1551 if ( w == w2 ) shift = shiftw2;
1553 S = tmpF.EmptyCopied();
1555 ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]);
1556 shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ),
1557 0.5 * ( m1[coord][0] + m1[coord][1] ), period );
1559 if ( shift != 0. ) {
1561 V.SetCoord ( coord+1, shift );
1562 ShapeAnalysis_Edge sae;
1563 for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) {
1564 TopoDS_Edge E = TopoDS::Edge ( iw.Value() );
1565 Handle(Geom2d_Curve) C;
1567 if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue;
1572 // abv 05 Feb 02: OCC34
1573 // by the way, select proper split place by V to avoid extra intersections
1574 if ( m1[coord][1] - m1[coord][0] <= period ) {
1575 Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period );
1576 if ( ismodeu ) vf = other;
1581 // find the best place by u and v to insert a seam
1582 // (so as to minimize splitting edges as possible)
1583 ShapeAnalysis_Edge sae;
1584 Standard_Integer foundU=0, foundV=0;
1585 Standard_Integer nb1 = wd1->NbEdges();
1586 Standard_Integer nb2 = wd2->NbEdges();
1587 for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) {
1588 TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) );
1589 Handle(Geom2d_Curve) c2d;
1591 if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1592 gp_Pnt2d pos1 = c2d->Value(l).XY();
1593 // the best place is end of edge which is nearest to 0
1594 Standard_Boolean skipU = ! uclosed;
1595 if ( uclosed && ismodeu ) {
1596 pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) );
1597 if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True;
1598 else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) {
1603 Standard_Boolean skipV = ! vclosed;
1604 if ( vclosed && ! ismodeu ) {
1605 pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, URange ) );
1606 if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True;
1607 else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) {
1612 if ( skipU && skipV )
1613 if ( i1 <= nb1 ) continue;
1615 // or yet better - if it is end of some edges on both wires
1616 for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) {
1617 TopoDS_Edge edge2 = wd2->Edge ( i2 );
1618 if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False;
1619 gp_Pnt2d pos2 = c2d->Value(f).XY();
1620 if ( uclosed && ismodeu ) {
1621 pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) );
1622 if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() &&
1623 ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) {
1628 if ( vclosed && ! ismodeu ) {
1629 pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) );
1630 if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() &&
1631 ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) {
1639 //pdn fixing RTS on offsets
1640 if ( uf < SUF || uf > SUL )
1641 uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange);
1642 if ( vf < SVF || vf > SVL )
1643 vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange);
1645 // Create fictive grid and call ComposeShell to insert a seam
1646 Handle(Geom_RectangularTrimmedSurface) RTS =
1647 new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange );
1648 Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 );
1649 grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() );
1650 Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid );
1653 //addition non-manifold topology
1654 Standard_Integer j=1;
1655 for( ; j <= aSeqNonManif.Length(); j++)
1656 B.Add(tmpF,aSeqNonManif.Value(j));
1658 ShapeFix_ComposeShell CompShell;
1659 // TopoDS_Face tmpF = myFace;
1660 // tmpF.Orientation(TopAbs_FORWARD);
1661 CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision
1662 if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape );
1663 CompShell.ClosedMode() = Standard_True;
1664 CompShell.SetContext( Context() );
1665 CompShell.SetMaxTolerance(MaxTolerance());
1666 CompShell.Perform();
1668 // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf
1669 mySurf = new ShapeAnalysis_Surface ( RTS );
1671 myResult = CompShell.Result();
1672 // if ( myFace.Orientation() == TopAbs_REVERSED ) res.Reverse();
1673 Context()->Replace ( myFace, myResult );
1674 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
1675 myFace = TopoDS::Face ( exp.Current() );
1676 BRepTools::Update(myFace); //:p4
1679 SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added
1680 return Standard_True;
1683 //=======================================================================
1684 //function : FixSmallAreaWire
1686 //=======================================================================
1688 //%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
1689 Standard_Boolean ShapeFix_Face::FixSmallAreaWire()
1691 if ( ! Context().IsNull() ) {
1692 TopoDS_Shape S = Context()->Apply ( myFace );
1693 myFace = TopoDS::Face ( S );
1697 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
1698 TopoDS_Face face = TopoDS::Face (emptyCopied);
1699 Standard_Integer nbRemoved = 0, nbWires = 0;
1701 Standard_Real prec = ::Precision::PConfusion()*100;
1702 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
1703 if(wi.Value().ShapeType() != TopAbs_WIRE &&
1704 (wi.Value().Orientation() != TopAbs_FORWARD || wi.Value().Orientation() != TopAbs_REVERSED))
1706 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
1707 Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire(wire,myFace,prec);
1708 if ( saw->CheckSmallArea(prec) )
1710 SendWarning ( wire, Message_Msg ("FixAdvFace.FixSmallAreaWire.MSG0") );// Null area wire detected, wire skipped
1719 if ( nbRemoved <=0 ) return Standard_False;
1721 if ( nbWires <=0 ) {
1723 cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << endl;
1725 return Standard_False;
1728 cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << endl;
1730 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
1732 return Standard_True;
1734 //=======================================================================
1735 //function : FixLoopWire
1737 //=======================================================================
1738 static void FindNext(const TopoDS_Shape& aVert,
1739 const TopoDS_Shape& ainitEdge,
1740 TopTools_IndexedMapOfShape& aMapVertices,
1741 TopTools_DataMapOfShapeListOfShape& aMapVertexEdges,
1742 const TopTools_MapOfShape& aMapSmallEdges,
1743 const TopTools_MapOfShape& aMapSeemEdges,
1744 TopTools_MapOfShape& aMapEdges,
1745 Handle(ShapeExtend_WireData)& aWireData)
1747 TopoDS_Iterator aItV(ainitEdge);
1748 TopoDS_Shape anextVert = aVert;
1749 Standard_Boolean isFind = Standard_False;
1750 for( ; aItV.More() && !isFind; aItV.Next())
1752 if(!aItV.Value().IsSame(aVert) ) {
1753 isFind = Standard_True;
1754 anextVert = aItV.Value();
1759 if(!isFind && !aMapSmallEdges.Contains(ainitEdge))
1761 if(isFind && aMapVertices.Contains(anextVert))
1764 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert);
1765 TopTools_ListIteratorOfListOfShape liter(aledges);
1766 isFind = Standard_False;
1767 TopoDS_Shape anextEdge;
1768 for( ; liter.More() && !isFind; liter.Next())
1770 if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) {
1771 anextEdge = liter.Value();
1772 aWireData->Add(anextEdge);
1773 if(aMapSeemEdges.Contains(anextEdge))
1774 aWireData->Add(anextEdge.Reversed());
1775 isFind = Standard_True;
1776 aMapEdges.Add(anextEdge);
1777 FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
1783 static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire)
1785 Standard_Boolean isClosed = Standard_True;
1786 Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion());
1787 for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) {
1788 TopoDS_Edge edge1 = asaw->WireData()->Edge(i);
1789 //checking that wire is closed in 2D space with tolerance of vertex.
1790 ShapeAnalysis_Edge sae;
1791 TopoDS_Vertex v1 = sae.FirstVertex(edge1);
1792 asaw->SetPrecision(BRep_Tool::Tolerance(v1));
1793 asaw->CheckGap2d(i);
1794 isClosed = (asaw->LastCheckStatus(ShapeExtend_OK));
1800 //=======================================================================
1801 //function : FixLoopWire
1803 //=======================================================================
1805 Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires)
1807 TopTools_IndexedMapOfShape aMapVertices;
1808 TopTools_DataMapOfShapeListOfShape aMapVertexEdges;
1809 TopTools_MapOfShape aMapSmallEdges;
1810 TopTools_MapOfShape aMapSeemEdges;
1811 if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges))
1812 return Standard_False;
1815 TopTools_MapOfShape aMapEdges;
1816 TopTools_SequenceOfShape aSeqWires;
1818 //collecting wires from common vertex belonging more than 2 edges
1819 Standard_Integer i =1;
1820 for( ; i <= aMapVertices.Extent(); i++) {
1821 TopoDS_Shape aVert = aMapVertices.FindKey(i);
1822 const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert);
1823 TopTools_ListIteratorOfListOfShape liter(aledges);
1824 for( ; liter.More(); liter.Next())
1826 TopoDS_Edge Edge = TopoDS::Edge(liter.Value());
1827 if(aMapEdges.Contains(Edge))
1830 Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData;
1831 aWireData->Add(Edge);
1832 if(aMapSeemEdges.Contains(Edge))
1833 aWireData->Add(Edge.Reversed());
1834 aMapEdges.Add(Edge);
1835 FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData);
1836 if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1)))
1838 TopoDS_Vertex aV1,aV2;
1839 TopoDS_Wire aWire = aWireData->Wire();
1840 TopExp::Vertices(aWire,aV1,aV2);
1842 if(aV1.IsSame(aV2)) {
1843 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1844 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1847 TopoDS_Wire awire2 = asfw->Wire();
1848 aResWires.Append(awire2);
1851 else aSeqWires.Append(aWireData->Wire());
1856 if(aSeqWires.Length() ==1) {
1857 aResWires.Append(aSeqWires.Value(1));
1860 //collecting whole wire from two not closed wires having two common vertices.
1861 for( i =1; i <= aSeqWires.Length(); i++) {
1862 TopoDS_Vertex aV1,aV2;
1863 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
1864 TopExp::Vertices(aWire,aV1,aV2);
1865 Standard_Integer j = i+1;
1866 for( ; j <= aSeqWires.Length(); j++)
1868 TopoDS_Vertex aV21,aV22;
1869 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
1870 TopExp::Vertices(aWire2,aV21,aV22);
1871 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
1873 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1875 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1878 aResWires.Append(asfw->Wire());
1879 aSeqWires.Remove(j--);
1880 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
1885 if(j <= aSeqWires.Length())
1886 aSeqWires.Remove(i--);
1889 if(aSeqWires.Length()<3) {
1890 for( i =1; i <= aSeqWires.Length(); i++)
1891 aResWires.Append(aSeqWires.Value(i));
1895 //collecting wires having one common vertex
1896 for( i =1; i <= aSeqWires.Length(); i++) {
1897 TopoDS_Vertex aV1,aV2;
1898 TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i));
1899 TopExp::Vertices(aWire,aV1,aV2);
1900 Standard_Integer j =i+1;
1901 for( ; j <= aSeqWires.Length(); j++)
1903 TopoDS_Vertex aV21,aV22;
1904 TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j));
1905 TopExp::Vertices(aWire2,aV21,aV22);
1906 if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22)))
1908 Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire);
1910 Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire;
1913 aWire = asfw->Wire();
1914 TopExp::Vertices(aWire,aV1,aV2);
1915 aSeqWires.Remove(j--);
1916 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 );
1919 aResWires.Append(aWire);
1924 Standard_Boolean isClosed = Standard_True;
1926 //checking that obtained wires is closed in 2D space
1927 if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) {
1929 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
1930 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
1931 tmpFace.Orientation ( TopAbs_FORWARD );
1933 for(i =1; i <= aResWires.Length() && isClosed; i++) {
1934 TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i));
1935 isClosed = isClosed2D(tmpFace,awire);
1939 Standard_Boolean isDone =(aResWires.Length() && isClosed);
1940 if(isDone && aResWires.Length() >1)
1943 cout<<"Wire was splitted on "<<aResWires.Length()<<" wires"<< endl;
1951 //=======================================================================
1952 //function : GetPointOnEdge
1953 //purpose : auxiliary
1954 //:h0 abv 29 May 98: PRO10105 1949: like in BRepCheck, point is to be taken
1955 // from 3d curve (but only if edge is SameParameter)
1956 //=======================================================================
1957 static gp_Pnt GetPointOnEdge ( const TopoDS_Edge &edge,
1958 const Handle(ShapeAnalysis_Surface) &surf,
1959 const Handle(Geom2d_Curve) &Crv2d,
1960 const Standard_Real param )
1962 if ( BRep_Tool::SameParameter ( edge ) ) {
1965 const Handle(Geom_Curve) ConS = BRep_Tool::Curve ( edge, L, f, l );
1966 if ( ! ConS.IsNull() )
1967 return ConS->Value ( param ).Transformed ( L.Transformation() );
1969 return surf->Value ( Crv2d->Value ( param ) );
1973 //=======================================================================
1974 //function : SplitEdge
1976 //=======================================================================
1978 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
1979 const Standard_Integer num,
1980 const Standard_Real param,
1981 const TopoDS_Vertex& vert,
1982 const Standard_Real preci,
1983 ShapeFix_DataMapOfShapeBox2d& boxes)
1985 TopoDS_Edge edge = sewd->Edge(num);
1986 TopoDS_Edge newE1, newE2;
1987 ShapeFix_SplitTool aTool;
1988 if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) {
1990 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
1993 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
1994 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
1995 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
1996 BRepTools::Update(E);
1999 // for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) {
2000 // TopoDS_Edge E = sewd->Edge(i);
2001 // TopoDS_Shape S = Context()->Apply ( E );
2002 // if ( S == E ) continue;
2003 // for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() )
2004 // sewd->Add ( exp.Current(), i++ );
2005 // sewd->Remove ( i-- );
2008 // change sewd and boxes
2009 sewd->Set(newE1,num);
2010 if(num==sewd->NbEdges())
2013 sewd->Add(newE2,num+1);
2017 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2018 Handle(Geom2d_Curve) c2d;
2019 Standard_Real cf,cl;
2020 ShapeAnalysis_Edge sae;
2021 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2023 Geom2dAdaptor_Curve gac;
2024 Standard_Real aFirst = c2d->FirstParameter();
2025 Standard_Real aLast = c2d->LastParameter();
2026 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2027 && (cf < aFirst || cl > aLast)) {
2028 //pdn avoiding problems with segment in Bnd_Box
2032 gac.Load(c2d,cf,cl);
2033 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2034 boxes.Bind(newE1,box);
2036 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2038 Geom2dAdaptor_Curve gac;
2039 Standard_Real aFirst = c2d->FirstParameter();
2040 Standard_Real aLast = c2d->LastParameter();
2041 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2042 && (cf < aFirst || cl > aLast)) {
2043 //pdn avoiding problems with segment in Bnd_Box
2047 gac.Load(c2d,cf,cl);
2048 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2049 boxes.Bind(newE2,box);
2051 return Standard_True;
2053 return Standard_False;
2057 //=======================================================================
2058 //function : SplitEdge
2060 //=======================================================================
2062 Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
2063 const Standard_Integer num,
2064 const Standard_Real param1,
2065 const Standard_Real param2,
2066 const TopoDS_Vertex& vert,
2067 const Standard_Real preci,
2068 ShapeFix_DataMapOfShapeBox2d& boxes)
2070 TopoDS_Edge edge = sewd->Edge(num);
2071 TopoDS_Edge newE1, newE2;
2072 ShapeFix_SplitTool aTool;
2073 if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) {
2075 Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData;
2078 if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() );
2079 for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) {
2080 TopoDS_Edge E = TopoDS::Edge ( exp.Current() );
2081 BRepTools::Update(E);
2084 // change sewd and boxes
2085 sewd->Set(newE1,num);
2086 if(num==sewd->NbEdges())
2089 sewd->Add(newE2,num+1);
2093 const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L);
2094 Handle(Geom2d_Curve) c2d;
2095 Standard_Real cf,cl;
2096 ShapeAnalysis_Edge sae;
2097 if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) {
2099 Geom2dAdaptor_Curve gac;
2100 Standard_Real aFirst = c2d->FirstParameter();
2101 Standard_Real aLast = c2d->LastParameter();
2102 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2103 && (cf < aFirst || cl > aLast)) {
2104 //pdn avoiding problems with segment in Bnd_Box
2108 gac.Load(c2d,cf,cl);
2109 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2110 boxes.Bind(newE1,box);
2112 if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) {
2114 Geom2dAdaptor_Curve gac;
2115 Standard_Real aFirst = c2d->FirstParameter();
2116 Standard_Real aLast = c2d->LastParameter();
2117 if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))
2118 && (cf < aFirst || cl > aLast)) {
2119 //pdn avoiding problems with segment in Bnd_Box
2123 gac.Load(c2d,cf,cl);
2124 BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box);
2125 boxes.Bind(newE2,box);
2127 return Standard_True;
2129 return Standard_False;
2133 //=======================================================================
2134 //function : FixIntersectingWires
2136 //=======================================================================
2138 Standard_Boolean ShapeFix_Face::FixIntersectingWires()
2140 ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance());
2141 return ITool.FixIntersectingWires(myFace);
2145 //=======================================================================
2146 //function : FixWiresTwoCoincEdges
2148 //=======================================================================
2150 Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges()
2152 if ( ! Context().IsNull() ) {
2153 TopoDS_Shape S = Context()->Apply ( myFace );
2154 myFace = TopoDS::Face ( S );
2157 TopAbs_Orientation ori = myFace.Orientation();
2158 TopoDS_Shape emptyCopied = myFace.EmptyCopied();
2159 TopoDS_Face face = TopoDS::Face (emptyCopied);
2160 face.Orientation(TopAbs_FORWARD);
2161 Standard_Integer nbWires = 0;
2164 for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) {
2165 if(it.Value().ShapeType() != TopAbs_WIRE ||
2166 (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) {
2171 if(nbWires<2) return Standard_False;
2172 Standard_Boolean isFixed = Standard_False;
2173 for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
2174 if(wi.Value().ShapeType() != TopAbs_WIRE ||
2175 (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) {
2176 B.Add(face,wi.Value());
2179 TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
2180 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2181 if(sewd->NbEdges()==2) {
2182 TopoDS_Edge E1 = sewd->Edge(1);
2183 TopoDS_Edge E2 = sewd->Edge(2);
2184 E1.Orientation(TopAbs_FORWARD);
2185 E2.Orientation(TopAbs_FORWARD);
2189 else isFixed = Standard_True;
2196 face.Orientation(ori);
2197 if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
2205 //=======================================================================
2206 //function : FixSplitFace
2208 //=======================================================================
2210 Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires)
2213 TopTools_SequenceOfShape faces;
2214 TopoDS_Shape S = myFace;
2215 if ( ! Context().IsNull() )
2216 S = Context()->Apply ( myFace );
2217 Standard_Integer NbWires=0, NbWiresNew=0;
2218 for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) {
2219 if(iter.Value().ShapeType() != TopAbs_WIRE ||
2220 (iter.Value().Orientation() != TopAbs_FORWARD && iter.Value().Orientation() != TopAbs_REVERSED))
2222 TopoDS_Wire wire = TopoDS::Wire ( iter.Value() );
2224 if(MapWires.IsBound(wire)) {
2225 // if wire not closed --> stop split and return false
2226 Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire);
2227 TopoDS_Edge E1 = sewd->Edge(1);
2228 TopoDS_Edge E2 = sewd->Edge(sewd->NbEdges());
2229 TopoDS_Vertex V1,V2;
2230 ShapeAnalysis_Edge sae;
2231 V1=sae.FirstVertex(E1);
2232 V2=sae.LastVertex(E2);
2233 if(!V1.IsSame(V2)) {
2234 cout<<"wire not closed --> stop split"<<endl;
2235 return Standard_False;
2238 TopoDS_Shape emptyCopied = S.EmptyCopied();
2239 TopoDS_Face tmpFace = TopoDS::Face(emptyCopied);
2240 tmpFace.Orientation ( TopAbs_FORWARD );
2241 B.Add(tmpFace,wire);
2243 const TopTools_ListOfShape& IntWires = MapWires.Find(wire);
2244 TopTools_ListIteratorOfListOfShape liter(IntWires);
2245 for( ; liter.More(); liter.Next()) {
2246 B.Add(tmpFace,liter.Value());
2249 if(!myFwd) tmpFace.Orientation(TopAbs_REVERSED);
2250 faces.Append(tmpFace);
2254 if(NbWires!=NbWiresNew) return Standard_False;
2256 if(faces.Length()>1) {
2257 TopoDS_Compound Comp;
2258 B.MakeCompound(Comp);
2259 for(Standard_Integer i=1; i<=faces.Length(); i++ )
2260 B.Add(Comp,faces(i));
2262 Context()->Replace ( myFace, myResult );
2263 for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) {
2264 myFace = TopoDS::Face ( exp.Current() );
2265 BRepTools::Update(myFace);
2267 return Standard_True;
2270 return Standard_False;
2273 //=======================================================================
2274 //function : IsPeriodicConicalLoop
2275 //purpose : Checks whether the passed wire makes up a periodic loop on
2276 // passed conical surface
2277 //=======================================================================
2279 static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
2280 const TopoDS_Wire& theWire,
2281 const Standard_Real theTolerance,
2282 Standard_Real& theMinU,
2283 Standard_Real& theMaxU,
2284 Standard_Real& theMinV,
2285 Standard_Real& theMaxV,
2286 Standard_Boolean& isUDecrease)
2288 if ( theSurf.IsNull() )
2289 return Standard_False;
2291 ShapeAnalysis_Edge aSAE;
2292 TopLoc_Location aLoc;
2294 Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
2295 Standard_Real aMinU = RealLast();
2296 Standard_Real aMinV = aMinU;
2297 Standard_Real aMaxU = -aMinU;
2298 Standard_Real aMaxV = aMaxU;
2300 // Iterate over the edges to check whether the wire is periodic on conical surface
2301 BRepTools_WireExplorer aWireExp(theWire);
2302 for ( ; aWireExp.More(); aWireExp.Next() )
2304 const TopoDS_Edge& aCurrentEdge = aWireExp.Current();
2305 Handle(Geom2d_Curve) aC2d;
2306 Standard_Real aPFirst, aPLast;
2308 aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
2310 if ( aC2d.IsNull() )
2311 return Standard_False;
2313 gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
2314 aUVLast = aC2d->Value(aPLast);
2316 Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
2317 Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
2319 Standard_Real aCurMaxU = Max(aUFirst, aULast),
2320 aCurMinU = Min(aUFirst, aULast);
2321 Standard_Real aCurMaxV = Max(aVFirst, aVLast),
2322 aCurMinV = Min(aVFirst, aVLast);
2324 if ( aCurMinU < aMinU )
2326 if ( aCurMaxU > aMaxU )
2328 if ( aCurMinV < aMinV )
2330 if ( aCurMaxV > aMaxV )
2333 Standard_Real aDeltaU = aULast - aUFirst;
2335 aCumulDeltaU += aDeltaU;
2336 aCumulDeltaUAbs += Abs(aDeltaU);
2343 isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
2345 Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
2346 Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
2348 return is2PIDelta && isAroundApex;
2351 //=======================================================================
2352 //function : FixPeriodicDegenerated
2354 //=======================================================================
2356 Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
2358 /* =====================
2359 * Prepare fix routine
2360 * ===================== */
2362 if ( !Context().IsNull() )
2364 TopoDS_Shape aSh = Context()->Apply(myFace);
2365 myFace = TopoDS::Face(aSh);
2368 /* ================================================
2369 * Check if fix can be applied on the passed face
2370 * ================================================ */
2372 // Collect all wires owned by the face
2373 TopTools_SequenceOfShape aWireSeq;
2374 for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
2376 const TopoDS_Shape& aSubSh = aWireIt.Value();
2377 if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
2378 aSubSh.Orientation() != TopAbs_REVERSED ) )
2381 aWireSeq.Append( aWireIt.Value() );
2384 // Get number of wires and surface
2385 Standard_Integer aNbWires = aWireSeq.Length();
2386 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
2388 // Only single wires on conical surfaces are checked
2389 if ( aNbWires != 1 || aSurface.IsNull() ||
2390 aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
2391 return Standard_False;
2393 // Get the single wire
2394 TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
2396 // Check whether this wire is belting the conical surface by period
2397 Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
2398 Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
2399 Standard_Boolean isUDecrease = Standard_False;
2401 Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
2402 aMinLoopU, aMaxLoopU,
2403 aMinLoopV, aMaxLoopV,
2407 return Standard_False;
2411 * =============== */
2413 // Get base circle of the conical surface (the circle it was built from)
2414 Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
2415 Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
2417 // Retrieve conical props
2418 Standard_Real aConeBaseR = aConeBaseCirc->Radius();
2419 Standard_Real aSemiAngle = aConeSurf->SemiAngle();
2421 if ( fabs(aSemiAngle) <= Precision::Confusion() )
2422 return Standard_False; // Bad surface
2424 // Find the V parameter of the apex
2425 Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
2426 Standard_Real anApexV = -aConeBaseH;
2429 TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
2431 // ====================================
2432 // Build degenerated edge in the apex
2433 // ====================================
2435 TopoDS_Edge anApexEdge;
2436 BRep_Builder aBuilder;
2437 aBuilder.MakeEdge(anApexEdge);
2439 // Check if positional relationship between the initial wire and apex
2440 // line in 2D is going to be consistent
2441 if ( fabs(anApexV - aMinLoopV) <= Precision() ||
2442 fabs(anApexV - aMaxLoopV) <= Precision() ||
2443 ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
2444 return Standard_False;
2446 Handle(Geom2d_Line) anApexCurve2d;
2448 // Apex curve below the wire
2449 if ( anApexV < aMinLoopV )
2451 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
2453 aSoleWire.Reverse();
2456 // Apex curve above the wire
2457 if ( anApexV > aMaxLoopV )
2459 anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
2461 aSoleWire.Reverse();
2464 // Create degenerated edge & wire for apex
2465 aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
2466 aBuilder.Add( anApexEdge, anApex );
2467 aBuilder.Add( anApexEdge, anApex.Reversed() );
2468 aBuilder.Degenerated(anApexEdge, Standard_True);
2469 aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
2470 TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
2472 // ===============================================================
2473 // Finalize the fix building new face and setting up the results
2474 // ===============================================================
2476 // Collect the resulting set of wires
2477 TopTools_SequenceOfShape aNewWireSeq;
2478 aNewWireSeq.Append(aSoleWire);
2479 aNewWireSeq.Append(anApexWire);
2481 // Assemble new face
2482 TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
2483 aNewFace.Orientation(TopAbs_FORWARD);
2484 BRep_Builder aFaceBuilder;
2485 for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
2487 TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
2488 aFaceBuilder.Add(aNewFace, aNewWire);
2490 aNewFace.Orientation( myFace.Orientation() );
2492 // Adjust the resulting state of the healing tool
2493 myResult = aNewFace;
2494 Context()->Replace(myFace, myResult);
2496 return Standard_True;