// Copyright (c) 1999-2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file // except in compliance with the License. Please obtain a copy of the License // at http://www.opencascade.org and read it completely before using this file. // // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. // // The Original Code and all software distributed under the License is // distributed on an "AS IS" basis, without warranty of any kind, and the // Initial Developer hereby disclaims all such warranties, including without // limitation, any warranties of merchantability, fitness for a particular // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. // pdn 10.12.98: tr9_r0501-ug // pdn 28.12.98: PRO10366 shifting pcurve between two singularities //:k7 abv 5.01.99: USA60022.igs ent 243: FixMissingSeam() improved //:l2 abv 10.01.99: USA60022 7289: corrections for reversed face //gka 11.01.99 file PRO7755.stp #2018: work-around error in BRepLib_MakeFace //:p4 abv, pdn 23.02.99: PRO9234 #15720: call BRepTools::Update() for faces // rln 03.03.99 S4135: transmission of parameter precision to SA_Surface::NbSingularities //:q5 abv 19.03.99 code improvement //%14 pdn 15.03.99 adding function for fixing null area wires //%15 pdn 20.03.99 code improvement // abv 09.04.99 S4136: improve tolerance management; remove unused flag Closed //#4 szv S4163: optimization // smh 31.01.01 BUC60810 : Case of small wire on face in solid // sln 25.09.2001 checking order of 3d and 2d representation curves // abv 19.10.2001 FixAddNaturalBound improved and extracted as separate fix // skl,pdn 14.05.2002 OCC55 (correction precision for small faces) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEB #define DEBUG #endif //======================================================================= //function : ShapeFix_Face //purpose : //======================================================================= ShapeFix_Face::ShapeFix_Face() { myFwd = Standard_True; myStatus = 0; myFixWire = new ShapeFix_Wire; ClearModes(); } //======================================================================= //function : ShapeFix_Face //purpose : //======================================================================= ShapeFix_Face::ShapeFix_Face(const TopoDS_Face &face) { myFwd = Standard_True; myStatus = 0; myFixWire = new ShapeFix_Wire; ClearModes(); Init( face ); } //======================================================================= //function : ClearModes //purpose : //======================================================================= void ShapeFix_Face::ClearModes() { myFixWireMode = -1; myFixOrientationMode = -1; myFixAddNaturalBoundMode = -1; myFixMissingSeamMode = -1; myFixSmallAreaWireMode = -1; myFixIntersectingWiresMode = -1; myFixLoopWiresMode = -1; myFixSplitFaceMode = -1; myAutoCorrectPrecisionMode = 1; myFixPeriodicDegenerated = -1; } //======================================================================= //function : SetMsgRegistrator //purpose : //======================================================================= void ShapeFix_Face::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg) { ShapeFix_Root::SetMsgRegistrator ( msgreg ); myFixWire->SetMsgRegistrator ( msgreg ); } //======================================================================= //function : SetPrecision //purpose : //======================================================================= void ShapeFix_Face::SetPrecision (const Standard_Real preci) { ShapeFix_Root::SetPrecision ( preci ); myFixWire->SetPrecision ( preci ); } //======================================================================= //function : SetMinTolerance //purpose : //======================================================================= void ShapeFix_Face::SetMinTolerance (const Standard_Real mintol) { ShapeFix_Root::SetMinTolerance ( mintol ); myFixWire->SetMinTolerance ( mintol ); } //======================================================================= //function : SetMaxTolerance //purpose : //======================================================================= void ShapeFix_Face::SetMaxTolerance (const Standard_Real maxtol) { ShapeFix_Root::SetMaxTolerance ( maxtol ); myFixWire->SetMaxTolerance ( maxtol ); } //======================================================================= //function : Init //purpose : //======================================================================= void ShapeFix_Face::Init (const Handle(Geom_Surface)& surf, const Standard_Real preci, const Standard_Boolean fwd) { myStatus = 0; Handle(ShapeAnalysis_Surface) sas = new ShapeAnalysis_Surface ( surf ); Init ( sas, preci, fwd ); } //======================================================================= //function : Init //purpose : //======================================================================= void ShapeFix_Face::Init (const Handle(ShapeAnalysis_Surface)& surf, const Standard_Real preci, const Standard_Boolean fwd) { myStatus = 0; mySurf = surf; SetPrecision ( preci ); BRep_Builder B; B.MakeFace ( myFace, mySurf->Surface(), ::Precision::Confusion() ); myShape = myFace; myFwd = fwd; if ( !fwd ) myFace.Orientation(TopAbs_REVERSED); } //======================================================================= //function : Init //purpose : //======================================================================= void ShapeFix_Face::Init (const TopoDS_Face& face) { myStatus = 0; mySurf = new ShapeAnalysis_Surface ( BRep_Tool::Surface (face) ); myFwd = ( face.Orientation() != TopAbs_REVERSED ); myFace = face; myShape = myFace; // myFace = TopoDS::Face(face.EmptyCopied()); // for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next()) // Add (TopoDS::Wire (ws.Value()) ); } //======================================================================= //function : Add //purpose : //======================================================================= void ShapeFix_Face::Add (const TopoDS_Wire& wire) { if ( wire.IsNull() ) return; BRep_Builder B; //szv#4:S4163:12Mar99 SGI warns TopoDS_Shape fc = myFace.Oriented(TopAbs_FORWARD); //:l2 abv 10 Jan 99: Oriented() B.Add ( fc, wire ); } //======================================================================= //function : SplitWire //purpose : auxilary - try to split wire (it is needed if some segments // were removed in ShapeFix_Wire::FixSelfIntersection() //======================================================================= static Standard_Boolean SplitWire(const TopoDS_Face &face, const TopoDS_Wire& wire, TopTools_SequenceOfShape& aResWires) { TColStd_MapOfInteger UsedEdges; Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire); Standard_Integer i,j,k; ShapeAnalysis_Edge sae; for(i=1; i<=sewd->NbEdges(); i++) { if(UsedEdges.Contains(i)) continue; TopoDS_Edge E1 = sewd->Edge(i); UsedEdges.Add(i); TopoDS_Vertex V0,V1,V2; V0 = sae.FirstVertex(E1); V1 = sae.LastVertex(E1); Handle(ShapeExtend_WireData) sewd1 = new ShapeExtend_WireData; sewd1->Add(E1); Standard_Boolean IsConnectedEdge = Standard_True; for(j=2; j<=sewd->NbEdges() && IsConnectedEdge; j++) { TopoDS_Edge E2; for(k=2; k<=sewd->NbEdges(); k++) { if(UsedEdges.Contains(k)) continue; E2 = sewd->Edge(k); TopoDS_Vertex V21 = sae.FirstVertex(E2); TopoDS_Vertex V22 = sae.LastVertex(E2); if( sae.FirstVertex(E2).IsSame(V1) ) { sewd1->Add(E2); UsedEdges.Add(k); V1 = sae.LastVertex(E2); break; } } if(k>sewd->NbEdges()) { IsConnectedEdge = Standard_False; break; } if(V1.IsSame(V0)) { //check that V0 and V1 are same in 2d too Standard_Real a1,b1,a2,b2; Handle (Geom2d_Curve) curve1 = BRep_Tool::CurveOnSurface(E1,face,a1,b1); Handle (Geom2d_Curve) curve2 = BRep_Tool::CurveOnSurface(E2,face,a2,b2); gp_Pnt2d v0,v1; if (E1.Orientation() == TopAbs_REVERSED) a1 = b1; if (E2.Orientation() == TopAbs_REVERSED) b2 = a2; curve1->D0(a1,v0); curve2->D0(b2,v1); GeomAdaptor_Surface anAdaptor(BRep_Tool::Surface(face)); Standard_Real tol = Max(BRep_Tool::Tolerance(V0),BRep_Tool::Tolerance(V1)); Standard_Real maxResolution = 2 * Max ( anAdaptor.UResolution(tol), anAdaptor.VResolution(tol) ); if (v0.SquareDistance(v1) < maxResolution) { // new wire is closed, put it into sequence aResWires.Append(sewd1->Wire()); break; } } } if(!IsConnectedEdge) { // create new notclosed wire aResWires.Append(sewd1->Wire()); } if(UsedEdges.Extent()==sewd->NbEdges()) break; } if(aResWires.Length()>1) { #ifdef DEBUG cout<<"Wire was splitted on "<SetContext ( Context() ); Handle(ShapeFix_Wire) theAdvFixWire = Handle(ShapeFix_Wire)::DownCast(myFixWire); if (theAdvFixWire.IsNull()) return Standard_False; BRep_Builder B; TopoDS_Shape aInitFace = myFace; // perform first part of fixes on wires Standard_Boolean isfixReorder = Standard_False; Standard_Boolean isReplaced = Standard_False; //gka fix in order to avoid lost messages (following OCC21771) TopTools_DataMapOfShapeShape aMapReorderedWires; Standard_Real aSavPreci = Precision(); if ( NeedFix ( myFixWireMode ) ) { theAdvFixWire->SetFace ( myFace ); Standard_Integer usFixLackingMode = theAdvFixWire->FixLackingMode(); Standard_Integer usFixNotchedEdgesMode = theAdvFixWire->FixNotchedEdgesMode(); Standard_Integer usFixSelfIntersectionMode = theAdvFixWire->FixSelfIntersectionMode(); theAdvFixWire->FixLackingMode() = Standard_False; theAdvFixWire->FixNotchedEdgesMode() = Standard_False; theAdvFixWire->FixSelfIntersectionMode() = Standard_False; Standard_Boolean fixed = Standard_False; TopoDS_Shape S = myFace; if ( ! Context().IsNull() ) S = Context()->Apply ( myFace ); TopoDS_Shape emptyCopied = S.EmptyCopied(); TopoDS_Face tmpFace = TopoDS::Face(emptyCopied); tmpFace.Orientation ( TopAbs_FORWARD ); /* // skl 14.05.2002 OCC55 + corrected 03.03.2004 Standard_Real dPreci = aSavPreci*aSavPreci; dPreci*=4; Standard_Real newpreci=dPreci; for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge ( exp.Current() ); Standard_Real first,last; Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last); if(!c3d.IsNull()) { Bnd_Box bb; bb.Add(c3d->Value(first)); bb.Add(c3d->Value(last)); bb.Add(c3d->Value((last+first)/2.)); Standard_Real x1,x2,y1,y2,z1,z2,size; bb.Get(x1,y1,z1,x2,y2,z2); size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1); if(size newpreci && newpreci > Precision::Confusion()) { SetPrecision(newpreci); theAdvFixWire->SetPrecision(newpreci); } // end skl 14.05.2002 */ // skl 29.03.2010 (OCC21623) if( myAutoCorrectPrecisionMode ) { Standard_Real size = ShapeFix::LeastEdgeSize(S); Standard_Real newpreci = Min(aSavPreci,size/2.); newpreci = newpreci*1.00001; if( aSavPreci > newpreci && newpreci > Precision::Confusion()) { SetPrecision(newpreci); theAdvFixWire->SetPrecision(newpreci); } } isfixReorder = Standard_False; for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) { if(iter.Value().ShapeType() != TopAbs_WIRE) { B.Add ( tmpFace, iter.Value() ); continue; } TopoDS_Wire wire = TopoDS::Wire ( iter.Value() ); theAdvFixWire->Load ( wire ); if(theAdvFixWire->NbEdges() == 0) { if(theAdvFixWire->WireData()->NbNonManifoldEdges()) B.Add ( tmpFace, wire ); else { fixed = Standard_True; myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 ); } continue; } if ( theAdvFixWire->Perform() ) { //fixed = Standard_True; isfixReorder = (theAdvFixWire->StatusReorder(ShapeExtend_DONE) || isfixReorder); fixed = (theAdvFixWire->StatusSmall(ShapeExtend_DONE) || theAdvFixWire->StatusConnected(ShapeExtend_DONE) || theAdvFixWire->StatusEdgeCurves(ShapeExtend_DONE) || theAdvFixWire->StatusDegenerated(ShapeExtend_DONE) || theAdvFixWire->StatusClosed(ShapeExtend_DONE)); TopoDS_Wire w = theAdvFixWire->Wire(); if(fixed) { if ( ! Context().IsNull() ) Context()->Replace ( wire, w ); if(theAdvFixWire->NbEdges() == 0) { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 ); continue; } } else if(!wire.IsSame(w)) aMapReorderedWires.Bind(wire,w); wire = w; } B.Add ( tmpFace, wire ); // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) ) // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 ); } theAdvFixWire->FixLackingMode() = usFixLackingMode; theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode; theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode; if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED ); if ( fixed ) { //if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED ); if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace ); //myFace = tmpFace; isReplaced = Standard_True; } if(fixed || isfixReorder) { myFace = tmpFace; if (!theAdvFixWire->StatusReorder(ShapeExtend_DONE5)) { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 ); } } } myResult = myFace; TopoDS_Shape savShape = myFace; //gka BUG 6555 // Specific case for conic surfaces if ( NeedFix(myFixPeriodicDegenerated) ) this->FixPeriodicDegenerated(); // fix missing seam if ( NeedFix ( myFixMissingSeamMode ) ) { if ( FixMissingSeam() ) { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 ); } } // cycle by all possible faces coming from FixMissingSeam // each face is processed as if it was single TopExp_Explorer exp(myResult,TopAbs_FACE); for ( ; exp.More(); exp.Next() ) { myFace = TopoDS::Face ( exp.Current() ); Standard_Boolean NeedCheckSplitWire = Standard_False; // perform second part of fixes on wires if ( NeedFix ( myFixWireMode ) ) { theAdvFixWire->SetFace ( myFace ); Standard_Integer usFixSmallMode = theAdvFixWire->FixSmallMode(); Standard_Integer usFixConnectedMode = theAdvFixWire->FixConnectedMode(); Standard_Integer usFixEdgeCurvesMode =theAdvFixWire->FixEdgeCurvesMode(); Standard_Integer usFixDegeneratedMode = theAdvFixWire->FixDegeneratedMode(); theAdvFixWire->FixSmallMode() = Standard_False; theAdvFixWire->FixConnectedMode() = Standard_False; theAdvFixWire->FixEdgeCurvesMode() = Standard_False; theAdvFixWire->FixDegeneratedMode() = Standard_False; Standard_Boolean fixed = Standard_False; TopoDS_Shape S = myFace; if ( ! Context().IsNull() ) S = Context()->Apply ( myFace ); TopoDS_Shape emptyCopied = S.EmptyCopied(); TopoDS_Face tmpFace = TopoDS::Face(emptyCopied); tmpFace.Orientation ( TopAbs_FORWARD ); for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) { if(iter.Value().ShapeType() != TopAbs_WIRE) { B.Add ( tmpFace,iter.Value()); continue; } TopoDS_Wire wire = TopoDS::Wire ( iter.Value() ); theAdvFixWire->Load ( wire ); if(theAdvFixWire->NbEdges() == 0) { if(theAdvFixWire->WireData()->NbNonManifoldEdges()) B.Add ( tmpFace, wire ); else { fixed = Standard_True; myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 ); } continue; } if ( theAdvFixWire->Perform() ) { isfixReorder = theAdvFixWire->StatusReorder(ShapeExtend_DONE); fixed = (theAdvFixWire->StatusLacking(ShapeExtend_DONE) || theAdvFixWire->StatusSelfIntersection(ShapeExtend_DONE) || theAdvFixWire->StatusNotches(ShapeExtend_DONE)); //Standard_True; TopoDS_Wire w = theAdvFixWire->Wire(); if(fixed) { if ( ! Context().IsNull() ) Context()->Replace ( wire, w ); } else if(!wire.IsSame(w)) aMapReorderedWires.Bind(wire,w); wire = w; } if(theAdvFixWire->StatusRemovedSegment()) NeedCheckSplitWire = Standard_True; //fix for loop of wire TopTools_SequenceOfShape aLoopWires; if(NeedFix ( myFixLoopWiresMode) && FixLoopWire(aLoopWires)) { if (aLoopWires.Length() > 1) SendWarning ( wire, Message_Msg ( "FixAdvFace.FixLoopWire.MSG0" ) );// Wire was splitted on several wires myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 ); fixed = Standard_True; Standard_Integer k=1; for( ; k <= aLoopWires.Length(); k++) B.Add (tmpFace,aLoopWires.Value(k)); } else B.Add ( tmpFace, wire ); } theAdvFixWire->FixSmallMode() = usFixSmallMode; theAdvFixWire->FixConnectedMode() = usFixConnectedMode; theAdvFixWire->FixEdgeCurvesMode() = usFixEdgeCurvesMode; theAdvFixWire->FixDegeneratedMode() = usFixDegeneratedMode; if ( fixed ) { if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED ); if(!isReplaced && !aInitFace.IsSame(myResult) && ! Context().IsNull()) //gka 06.09.04 BUG 6555 Context()->Replace(aInitFace,savShape); if ( ! Context().IsNull() ) Context()->Replace ( S, tmpFace ); myFace = tmpFace; myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 ); } } if(NeedCheckSplitWire) { // try to split wire - it is needed if some segments were removed // in ShapeFix_Wire::FixSelfIntersection() TopoDS_Shape S = myFace; if ( ! Context().IsNull() ) S = Context()->Apply ( myFace ); TopoDS_Shape emptyCopied = S.EmptyCopied(); TopoDS_Face tmpFace = TopoDS::Face(emptyCopied); tmpFace.Orientation ( TopAbs_FORWARD ); TopTools_SequenceOfShape aWires; Standard_Integer nbw=0; for ( TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) { if(iter.Value().ShapeType() != TopAbs_WIRE) { B.Add (tmpFace,iter.Value()); continue; } if(iter.Value().Orientation() != TopAbs_FORWARD && iter.Value().Orientation() != TopAbs_REVERSED) { B.Add (tmpFace,TopoDS::Wire(iter.Value())); continue; } nbw++; TopoDS_Wire wire = TopoDS::Wire ( iter.Value() ); SplitWire(tmpFace,wire,aWires); } if(nbwReplace ( S, tmpFace ); myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 ); myFace = tmpFace; } } // fix intersecting wires if(FixWiresTwoCoincEdges()) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 ); if ( NeedFix ( myFixIntersectingWiresMode ) ) { if ( FixIntersectingWires() ) { myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE6 ); } } // fix orientation TopTools_DataMapOfShapeListOfShape MapWires; MapWires.Clear(); if ( NeedFix ( myFixOrientationMode ) ) { if ( FixOrientation(MapWires) ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE2 ); } BRepTools::Update(myFace); // fix natural bounds Standard_Boolean NeedSplit = Standard_True; if ( NeedFix ( myFixAddNaturalBoundMode ) ) { if ( FixAddNaturalBound() ) { NeedSplit = Standard_False; myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 ); } } // split face if ( NeedFix ( myFixSplitFaceMode ) && NeedSplit && MapWires.Extent()>1 ) { if ( FixSplitFace(MapWires) ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE8 ); } } //return the original preci SetPrecision(aSavPreci); theAdvFixWire->SetPrecision(aSavPreci); // cycle by all possible faces coming from FixAddNaturalBound // each face is processed as if it was single for ( exp.Init(myResult,TopAbs_FACE); exp.More(); exp.Next() ) { myFace = TopoDS::Face ( exp.Current() ); // fix small-area wires if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) ) { if ( FixSmallAreaWire() ) myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 ); } } if ( ! Context().IsNull() ) { if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape)) { //gka fix in order to avoid lost messages (following OCC21771) if(aMapReorderedWires.Extent()) { TopoDS_Iterator aItW(aInitFace,Standard_False); for( ; aItW.More() ; aItW.Next()) { TopoDS_Shape aCurW = aItW.Value(); while(aMapReorderedWires.IsBound(aCurW)) { TopoDS_Shape aFixW = aMapReorderedWires.Find(aCurW); Context()->Replace(aCurW, aFixW); aCurW = aFixW; } } } Context()->Replace(aInitFace, savShape); } myResult = Context()->Apply ( aInitFace ); //gka 06.09.04 } else if(!Status ( ShapeExtend_DONE )) myResult = aInitFace; return Status ( ShapeExtend_DONE ); } //======================================================================= //function : Auxiliary functions //purpose : //======================================================================= // Shift all pcurves of edges in the given wire on the given face // to vector static void Shift2dWire(const TopoDS_Wire w, const TopoDS_Face f, const gp_Vec2d vec, const Handle(ShapeAnalysis_Surface)& mySurf, Standard_Boolean recompute3d = Standard_False) { gp_Trsf2d tr2d; tr2d.SetTranslation(vec.XY()); ShapeAnalysis_Edge sae; ShapeBuild_Edge sbe; BRep_Builder B; for (TopoDS_Iterator ei (w,Standard_False); ei.More(); ei.Next()){ TopoDS_Edge edge = TopoDS::Edge(ei.Value()); Handle (Geom2d_Curve) C2d; Standard_Real cf, cl; if ( ! sae.PCurve(edge, f, C2d, cf, cl, Standard_True) ) continue; C2d->Transform(tr2d); if ( recompute3d ) { // recompute 3d curve and vertex sbe.RemoveCurve3d ( edge ); sbe.BuildCurve3d ( edge ); B.UpdateVertex ( sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0. ); } } } // Cut interval from the sequence of intervals static Standard_Boolean CutInterval (TColgp_SequenceOfPnt2d &intervals, const gp_Pnt2d &toAddI, const Standard_Real period) { if ( intervals.Length() <=0 ) return Standard_False; for ( Standard_Integer j=0; j <2; j++ ) { // try twice, align to bottom and to top for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) { gp_Pnt2d interval = intervals(i); // ACIS907, OCC921 a054a.sat (face 124) Standard_Real shift = ShapeAnalysis::AdjustByPeriod ( ( j ? toAddI.X() : toAddI.Y() ), 0.5*( interval.X() + interval.Y() ),period); gp_Pnt2d toAdd ( toAddI.X() + shift, toAddI.Y() + shift ); if ( toAdd.Y() <= interval.X() || toAdd.X() >= interval.Y() ) continue; if ( toAdd.X() > interval.X() ) { if ( toAdd.Y() < interval.Y() ) { intervals.InsertBefore ( i, interval ); intervals.ChangeValue(i+1).SetX ( toAdd.Y() ); // i++... } intervals.ChangeValue(i).SetY ( toAdd.X() ); } else if ( toAdd.Y() < interval.Y() ) { intervals.ChangeValue(i).SetX ( toAdd.Y() ); } else intervals.Remove ( i-- ); } } return Standard_True; } // Find middle of the biggest interval static Standard_Real FindBestInterval (TColgp_SequenceOfPnt2d &intervals) { Standard_Real shift = 0., max = -1.; for ( Standard_Integer i=1; i <= intervals.Length(); i++ ) { gp_Pnt2d interval = intervals(i); if ( interval.Y() - interval.X() <= max ) continue; max = interval.Y() - interval.X(); shift = interval.X() + 0.5 * max; } return shift; } //======================================================================= //function : FixAddNaturalBound //purpose : //======================================================================= // Detect missing natural bounary on spherical surfaces and add it if // necessary //pdn 981202: add natural bounds if missing (on sphere only) //:abv 28.08.01: rewritten and extended for toruses Standard_Boolean ShapeFix_Face::FixAddNaturalBound() { if ( ! Context().IsNull() ) { TopoDS_Shape S = Context()->Apply ( myFace ); myFace = TopoDS::Face ( S ); } // collect wires in sequence TopTools_SequenceOfShape ws; TopTools_SequenceOfShape vs; TopoDS_Iterator wi (myFace,Standard_False); for ( ; wi.More(); wi.Next()) { if(wi.Value().ShapeType() == TopAbs_WIRE && (wi.Value().Orientation() == TopAbs_FORWARD || wi.Value().Orientation() == TopAbs_REVERSED)) ws.Append (wi.Value()); else vs.Append(wi.Value()); } // deal with case of empty face: just create a new one by standard tool if ( ws.Length() <=0 ) { BRepBuilderAPI_MakeFace mf (mySurf->Surface(), Precision::Confusion()); if ( ! Context().IsNull() ) Context()->Replace ( myFace, mf.Face() ); myFace = mf.Face(); //gka 11.01.99 file PRO7755.stp entity #2018 surface #1895: error BRepLib_MakeFace func IsDegenerated Handle(ShapeFix_Edge) sfe = myFixWire->FixEdgeTool(); for (TopExp_Explorer Eed (myFace, TopAbs_EDGE); Eed.More(); Eed.Next()) { TopoDS_Edge edg = TopoDS::Edge (Eed.Current()); sfe->FixVertexTolerance(edg); } // B.UpdateFace (myFace,myPrecision); SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds BRepTools::Update(myFace); return Standard_True; } // check that surface is double-closed and fix is needed if ( ( mySurf->Adaptor3d()->GetType() != GeomAbs_Sphere && mySurf->Adaptor3d()->GetType() != GeomAbs_Torus ) || ShapeAnalysis::IsOuterBound (myFace) ) return Standard_False; // Collect informations on free intervals in U and V TColgp_SequenceOfPnt2d intU, intV, centers; Standard_Real SUF, SUL, SVF, SVL; mySurf->Bounds(SUF, SUL, SVF, SVL); intU.Append ( gp_Pnt2d(SUF, SUL) ); intV.Append ( gp_Pnt2d(SVF, SVL) ); Standard_Integer nb = ws.Length(); Standard_Integer i; for ( i=1; i <= nb; i ++) { Standard_Real Umin, Vmin, Umax, Vmax; // Bnd_Box2d B; TopoDS_Wire aw = TopoDS::Wire (ws.Value(i)); // PTV 01.11.2002 ACIS907, OCC921 begin // BRepTools::AddUVBounds(myFace,aw,B); // B.Get(Umin, Vmin, Umax, Vmax); TopoDS_Face aWireFace = TopoDS::Face( myFace.EmptyCopied() ); BRep_Builder aB; aB.Add( aWireFace, aw ); ShapeAnalysis::GetFaceUVBounds(aWireFace, Umin, Umax, Vmin, Vmax); // PTV 01.11.2002 ACIS907, OCC921 end if ( mySurf->IsUClosed() ) CutInterval ( intU, gp_Pnt2d(Umin,Umax), SUL-SUF ); if ( mySurf->IsVClosed() ) CutInterval ( intV, gp_Pnt2d(Vmin,Vmax), SVL-SVF ); centers.Append ( gp_Pnt2d ( 0.5*(Umin+Umax), 0.5*(Vmin+Vmax) ) ); } // find best interval and thus compute shift gp_Pnt2d shift(0.,0.); if ( mySurf->IsUClosed() ) shift.SetX ( FindBestInterval ( intU ) ); if ( mySurf->IsVClosed() ) shift.SetY ( FindBestInterval ( intV ) ); // Adjust all other wires to be inside outer one gp_Pnt2d center ( shift.X() + 0.5*(SUL-SUF), shift.Y() + 0.5*(SVL-SVF) ); for ( i=1; i <= nb; i++ ) { TopoDS_Wire wire = TopoDS::Wire (ws.Value(i)); gp_Pnt2d sh(0.,0.); if ( mySurf->IsUClosed() ) sh.SetX ( ShapeAnalysis::AdjustByPeriod ( centers(i).X(), center.X(), SUL-SUF ) ); if ( mySurf->IsVClosed() ) sh.SetY ( ShapeAnalysis::AdjustByPeriod ( centers(i).Y(), center.Y(), SVL-SVF ) ); Shift2dWire ( wire, myFace, sh.XY(), mySurf ); } // Create naturally bounded surface and add that wire to sequence /* variant 1 // Create fictive grid and call ComposeShell Handle(Geom_RectangularTrimmedSurface) RTS = new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(), SVF+shift.Y(), SVL+shift.Y() ); Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 ); grid->SetValue ( 1, 1, RTS ); Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid ); TopLoc_Location L; ShapeFix_ComposeShell CompShell; CompShell.Init ( G, L, myFace, ::Precision::Confusion() ); CompShell.ClosedMode() = Standard_True; CompShell.NaturalBoundMode() = Standard_True; CompShell.SetContext( Context() ); CompShell.SetMaxTolerance(MaxTolerance()); CompShell.Perform(); TopoDS_Shape res = CompShell.Result(); Context()->Replace ( myFace, res ); for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) { myFace = TopoDS::Face ( exp.Current() ); BRepTools::Update(myFace); //:p4 } myResult = Context()->Apply ( myResult ); */ /* variant 2 */ TopLoc_Location L; Handle(Geom_Surface) surf = BRep_Tool::Surface ( myFace, L ); BRepBuilderAPI_MakeFace mf (surf, Precision::Confusion()); TopoDS_Face ftmp = mf.Face(); ftmp.Location ( L ); for (wi.Initialize (ftmp,Standard_False); wi.More(); wi.Next()) { if(wi.Value().ShapeType() != TopAbs_WIRE) continue; TopoDS_Wire wire = TopoDS::Wire ( wi.Value() ); ws.Append ( wire ); if ( shift.XY().Modulus() < ::Precision::PConfusion() ) continue; Shift2dWire ( wire, myFace, shift.XY(), mySurf, Standard_True ); } // Fix possible case on sphere when gap contains degenerated edge // and thus has a common part with natural boundary // Such hole should be merged with boundary if ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere && ws.Length() == nb+1 ) { Handle(ShapeExtend_WireData) bnd = new ShapeExtend_WireData ( TopoDS::Wire ( ws.Last() ) ); // code to become separate method FixTouchingWires() for ( i=1; i <= nb; i++ ) { Handle(ShapeExtend_WireData) sbwd = new ShapeExtend_WireData ( TopoDS::Wire ( ws.Value(i) ) ); for (Standard_Integer j=1; j <= sbwd->NbEdges(); j++ ) { if ( ! BRep_Tool::Degenerated ( sbwd->Edge(j) ) ) continue; // find corresponding place in boundary ShapeAnalysis_Edge sae; TopoDS_Vertex V = sae.FirstVertex ( sbwd->Edge(j) ); Standard_Integer k; for ( k=1; k <= bnd->NbEdges(); k++ ) { if ( ! BRep_Tool::Degenerated ( bnd->Edge(k) ) ) continue; if ( BRepTools::Compare ( V, sae.FirstVertex ( bnd->Edge(k) ) ) ) break; } if ( k > bnd->NbEdges() ) continue; // and insert hole to that place BRep_Builder B; B.Degenerated ( sbwd->Edge(j), Standard_False ); B.Degenerated ( bnd->Edge(k), Standard_False ); sbwd->SetLast ( j ); bnd->Add ( sbwd, k+1 ); ws.Remove ( i-- ); nb--; myFixWire->SetFace ( myFace ); myFixWire->Load ( bnd ); myFixWire->FixConnected(); myFixWire->FixDegenerated(); ws.SetValue ( ws.Length(), bnd->Wire() ); break; } } } // Create resulting face BRep_Builder B; TopoDS_Shape S = myFace.EmptyCopied(); S.Orientation ( TopAbs_FORWARD ); for ( i = 1; i <= ws.Length(); i++ ) B.Add ( S, ws.Value(i) ); for ( i = 1; i <= vs.Length(); i++ ) B.Add ( S, vs.Value(i) ); if ( ! myFwd ) S.Orientation (TopAbs_REVERSED); if ( ! Context().IsNull() ) Context()->Replace ( myFace, S ); myFace = TopoDS::Face ( S ); BRepTools::Update(myFace); /**/ #ifdef DEBUG cout<<"Natural bound on sphere or torus with holes added"<Apply ( myFace ); myFace = TopoDS::Face ( S ); } TopTools_SequenceOfShape ws; TopTools_SequenceOfShape allSubShapes; // smh: BUC60810 : protection against very small wires (one-edge, null-length) TopTools_SequenceOfShape VerySmallWires; for ( TopoDS_Iterator wi (myFace,Standard_False); wi.More(); wi.Next()) { if(wi.Value().ShapeType() == TopAbs_VERTEX || (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) { allSubShapes.Append (wi.Value()); //ws.Append (wi.Value()); continue; } TopoDS_Iterator ei (wi.Value(),Standard_False); TopoDS_Edge anEdge; Standard_Real length = RealLast(); if ( ei.More() ) { anEdge = TopoDS::Edge(ei.Value()); ei.Next(); if ( ! ei.More() ) { length = 0; Standard_Real First, Last; Handle(Geom_Curve) c3d; ShapeAnalysis_Edge sae; if ( sae.Curve3d(anEdge,c3d,First,Last) ) { gp_Pnt pntIni = c3d->Value(First); gp_XYZ prev; prev = pntIni.XYZ(); Standard_Integer NbControl = 10; for ( Standard_Integer j = 1; j < NbControl; j++) { Standard_Real prm = ((NbControl-1-j)*First + j*Last)/(NbControl-1); gp_Pnt pntCurr = c3d->Value(prm); gp_XYZ curr = pntCurr.XYZ(); gp_XYZ delta = curr - prev; length += delta.Modulus(); prev = curr; } } } } else length = 0; if (length > ::Precision::Confusion()) { ws.Append (wi.Value()); allSubShapes.Append (wi.Value()); } else VerySmallWires.Append (wi.Value()); } if ( VerySmallWires.Length() >0 ) done = Standard_True; Standard_Integer nb = ws.Length(); Standard_Integer nbAll = allSubShapes.Length(); BRep_Builder B; // if no wires, just do nothing if ( nb <= 0) return Standard_False; Standard_Integer nbInternal=0; Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) && ( mySurf->Adaptor3d()->GetType() == GeomAbs_Sphere || mySurf->Adaptor3d()->GetType() == GeomAbs_Torus )); TColStd_SequenceOfInteger aSeqReversed; // if wire is only one, check its orientation if ( nb == 1 ) { // skl 12.04.2002 for cases with nbwires>1 (VerySmallWires>1) // make face with only one wire (ws.Value(1)) TopoDS_Shape dummy = myFace.EmptyCopied(); TopoDS_Face af = TopoDS::Face ( dummy ); af.Orientation ( TopAbs_FORWARD ); B.Add (af,ws.Value(1)); if ( ( myFixAddNaturalBoundMode != Standard_True || //: abv 29.08.01: Spatial_firex_lofting.sat ( mySurf->Adaptor3d()->GetType() != GeomAbs_Sphere && mySurf->Adaptor3d()->GetType() != GeomAbs_Torus ) ) && ! ShapeAnalysis::IsOuterBound (af)) { Handle(ShapeExtend_WireData) sbdw = new ShapeExtend_WireData (TopoDS::Wire(ws.Value(1))); sbdw->Reverse ( myFace ); ws.SetValue ( 1, sbdw->Wire() ); SendWarning ( sbdw->Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed done = Standard_True; #ifdef DEBUG cout<<"Wire reversed"< SDB. Si IN, OK, si OUT on inverse // (nb : ici pas myClos donc pas de pb de couture) // Si au moins une inversion, il faut refaire la face (cf myRebil) //:94 abv 30 Jan 98: calculate parametric precision // GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface(); // Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) ); Standard_Boolean uclosed = mySurf->IsUClosed(); Standard_Boolean vclosed = mySurf->IsVClosed(); Standard_Real SUF, SUL, SVF, SVL; mySurf->Bounds(SUF, SUL, SVF, SVL); TopTools_DataMapOfShapeListOfShape MW; TopTools_DataMapOfShapeInteger SI; TopTools_MapOfShape MapIntWires; MW.Clear(); SI.Clear(); MapIntWires.Clear(); Standard_Integer NbOuts=0; Standard_Integer i; for ( i = 1; i <= nb; i ++) { TopoDS_Shape asw = ws.Value(i); TopoDS_Wire aw = TopoDS::Wire (asw); TopoDS_Shape dummy = myFace.EmptyCopied(); TopoDS_Face af = TopoDS::Face ( dummy ); // B.MakeFace (af,mySurf->Surface(),::Precision::Confusion()); af.Orientation ( TopAbs_FORWARD ); B.Add (af,aw); // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787) // tolerance is too big. It is seems that to identify placement of 2d point // it is enough Precision::PConfusion(), cause wea re know that 2d point in TopAbs_ON // BRepTopAdaptor_FClass2d clas (af,toluv); Standard_Boolean CheckShift = Standard_True; BRepTopAdaptor_FClass2d clas (af,::Precision::PConfusion()); TopAbs_State sta = TopAbs_OUT; TopAbs_State staout = clas.PerformInfinitePoint(); TopTools_ListOfShape IntWires; for ( Standard_Integer j = 1; j <= nbAll; j ++) { //if(i==j) continue; TopoDS_Shape aSh2 = allSubShapes.Value(j); if(aw == aSh2) continue; TopAbs_State stb = TopAbs_UNKNOWN; if(aSh2.ShapeType() == TopAbs_VERTEX) { gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aSh2)); gp_Pnt2d p2d = mySurf->ValueOfUV(aP,Precision::Confusion()); stb = clas.Perform (p2d,Standard_False); if(stb == staout && (uclosed || vclosed)) { gp_Pnt2d p2d1; if(uclosed) { Standard_Real period = SUL-SUF; p2d1.SetCoord(p2d.X()+period, p2d.Y()); stb = clas.Perform (p2d1,Standard_False); } if(stb == staout && vclosed) { Standard_Real period = SVL-SVF; p2d1.SetCoord(p2d.X(), p2d.Y()+ period); stb = clas.Perform (p2d1,Standard_False); } } } else if (aSh2.ShapeType() == TopAbs_WIRE) { CheckShift = Standard_True; TopoDS_Wire bw = TopoDS::Wire (aSh2); // Standard_Integer numin =0; TopoDS_Iterator ew (bw); for(;ew.More(); ew.Next()) { TopoDS_Edge ed = TopoDS::Edge (ew.Value()); Standard_Real cf,cl; Handle(Geom2d_Curve) cw = BRep_Tool::CurveOnSurface (ed,myFace,cf,cl); if (cw.IsNull()) continue; gp_Pnt2d unp = cw->Value ((cf+cl)/2.); TopAbs_State ste = clas.Perform (unp,Standard_False); if( ste==TopAbs_OUT || ste==TopAbs_IN ) { if(stb==TopAbs_UNKNOWN) { stb = ste; } else { if(!(stb==ste)) { sta = TopAbs_UNKNOWN; SI.Bind(aw,0); j=nb; break; } } } Standard_Boolean found = Standard_False; gp_Pnt2d unp1; if( stb == staout && CheckShift ) { CheckShift = Standard_False; if(uclosed) { Standard_Real period = SUL-SUF; unp1.SetCoord(unp.X()+period, unp.Y()); found = (staout != clas.Perform (unp1,Standard_False)); if(!found) { unp1.SetX(unp.X()-period); found = (staout != clas.Perform (unp1,Standard_False)); } } if(vclosed&&!found) { Standard_Real period = SVL-SVF; unp1.SetCoord(unp.X(), unp.Y()+period); found = (staout != clas.Perform (unp1,Standard_False)); if(!found) { unp1.SetY(unp.Y()-period); found = (staout != clas.Perform (unp1,Standard_False)); } } } if(found) { if(stb==TopAbs_IN) stb = TopAbs_OUT; else stb = TopAbs_IN; Shift2dWire(bw,myFace,unp1.XY()-unp.XY(), mySurf); } } } if(stb==staout) { sta = TopAbs_IN; } else { IntWires.Append(aSh2); MapIntWires.Add(aSh2); } } if (sta == TopAbs_UNKNOWN) { // ERREUR SendWarning ( aw, Message_Msg ( "FixAdvFace.FixOrientation.MSG11" ) );// Cannot orient wire } else { MW.Bind(aw,IntWires); if(sta==TopAbs_OUT) { NbOuts++; if(staout==TopAbs_IN) { // wire is OUT but InfinitePoint is IN => need to reverse ShapeExtend_WireData sewd (aw); sewd.Reverse(myFace); ws.SetValue (i,sewd.Wire()); SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed aSeqReversed.Append(i); done = Standard_True; SI.Bind(ws.Value(i),1); MapWires.Bind(ws.Value(i),IntWires); } else { SI.Bind(aw,1); MapWires.Bind(aw,IntWires); } } else { if(staout==TopAbs_OUT) SI.Bind(aw,2); else SI.Bind(aw,3); } } } for(i=1; i<=nb; i++) { TopoDS_Wire aw = TopoDS::Wire (ws.Value(i)); Standard_Integer tmpi = SI.Find(aw); if(tmpi>1) { if(!MapIntWires.Contains(aw)) { NbOuts++; const TopTools_ListOfShape& IW = MW.Find(aw); if(tmpi==3) { // wire is OUT but InfinitePoint is IN => need to reverse ShapeExtend_WireData sewd (aw); sewd.Reverse(myFace); ws.SetValue (i,sewd.Wire()); SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed aSeqReversed.Append(i); done = Standard_True; MapWires.Bind(ws.Value(i),IW); } else MapWires.Bind(aw,IW); } else { if(tmpi==2) { // wire is IN but InfinitePoint is OUT => need to reverse ShapeExtend_WireData sewd (aw); sewd.Reverse(myFace); ws.SetValue (i,sewd.Wire()); SendWarning ( sewd.Wire(), Message_Msg ( "FixAdvFace.FixOrientation.MSG5" ) );// Wire on face was reversed aSeqReversed.Append(i); done = Standard_True; } } } } } //done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal Replace ( myFace, S ); myFace = TopoDS::Face ( S ); BRepTools::Update(myFace); Standard_Integer k =1; for( ; k <= aSeqReversed.Length(); k++ ) { #ifdef DEBUG cout<<"Wire no "<Value(l).XY() - c2d->Value(f).XY(); } isuopen = ( Abs ( Abs ( vec.X() ) - dU ) < 0.1 * dU ? ( vec.X() >0 ? 1 : -1 ) : 0 ); isvopen = ( Abs ( Abs ( vec.Y() ) - dV ) < 0.1 * dV ? ( vec.Y() >0 ? 1 : -1 ) : 0 ); return isuopen || isvopen; } //======================================================================= //function : FixMissingSeam //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixMissingSeam() { Standard_Boolean uclosed = mySurf->IsUClosed(); Standard_Boolean vclosed = mySurf->IsVClosed(); if ( ! uclosed && ! vclosed ) return Standard_False; if ( ! Context().IsNull() ) { TopoDS_Shape S = Context()->Apply ( myFace ); myFace = TopoDS::Face ( S ); } //%pdn: surface should be made periodic before (see ShapeCustom_Surface)! if (mySurf->Surface()->IsKind(STANDARD_TYPE (Geom_BSplineSurface))) { Handle (Geom_BSplineSurface) BSpl = Handle (Geom_BSplineSurface)::DownCast (mySurf->Surface()); if (!BSpl->IsUPeriodic() && !BSpl->IsVPeriodic()) return Standard_False; } Standard_Real URange, VRange, SUF, SUL, SVF, SVL; mySurf->Bounds ( SUF, SUL, SVF, SVL ); Standard_Real fU1,fU2,fV1,fV2; BRepTools::UVBounds(myFace,fU1,fU2,fV1,fV2); //pdn OCC55 fix to faces without the wires to avoid identical first and last parameters if ( ::Precision::IsInfinite ( SUF ) || ::Precision::IsInfinite ( SUL ) ) { if ( ::Precision::IsInfinite ( SUF ) ) SUF = fU1; if ( ::Precision::IsInfinite ( SUL ) ) SUL = fU2; if(Abs(SUL-SUF) < ::Precision::PConfusion()) if ( ::Precision::IsInfinite ( SUF ) ) SUF-=1000.; else SUL+=1000.; } if ( ::Precision::IsInfinite ( SVF ) || ::Precision::IsInfinite ( SVL ) ) { if ( ::Precision::IsInfinite ( SVF ) ) SVF = fV1; if ( ::Precision::IsInfinite ( SVL ) ) SVL = fV2; if(Abs(SVL-SVF) < ::Precision::PConfusion()) if ( ::Precision::IsInfinite ( SVF ) ) SVF-=1000.; else SVL+=1000.; } URange = Abs ( SUL - SUF ); VRange = Abs ( SVL - SVF ); // Standard_Real UTol = 0.2 * URange, VTol = 0.2 * VRange; Standard_Integer ismodeu = 0, ismodev = 0; //szv#4:S4163:12Mar99 was Boolean Standard_Integer isdeg1=0, isdeg2=0; TopTools_SequenceOfShape ws; TopTools_SequenceOfShape aSeqNonManif; for ( TopoDS_Iterator wi(myFace,Standard_False); wi.More(); wi.Next() ) { if(wi.Value().ShapeType() != TopAbs_WIRE || (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) { aSeqNonManif.Append(wi.Value()); continue; } ws.Append ( wi.Value() ); } TopoDS_Wire w1, w2; Standard_Integer i; for ( i=1; i <= ws.Length(); i++ ) { TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) ); Standard_Integer isuopen, isvopen; Standard_Boolean isdeg; if ( ! CheckWire ( wire, myFace, URange, VRange, isuopen, isvopen, isdeg ) ) continue; if ( w1.IsNull() ) { w1 = wire; ismodeu = isuopen; ismodev = isvopen; isdeg1 = isdeg ? i : 0; } else if ( w2.IsNull() ) { if ( ismodeu == -isuopen && ismodev == -isvopen ) { w2 = wire; isdeg2 = isdeg ? i : 0; } else if ( ismodeu == isuopen && ismodev == isvopen ) { w2 = wire; isdeg2 = isdeg; //:abv 29.08.01: If wires are contraversal, reverse one of them // If first one is single degenerated edge, reverse it; else second if ( isdeg1 ) { w1.Reverse(); ismodeu = -ismodeu; ismodev = -ismodev; } else { w2.Reverse(); #ifdef DEB if ( ! isdeg2 ) cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << endl; #endif } } #ifdef DEB else cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" << endl; #endif } // else return Standard_False; // abort else { #ifdef DEB cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" << endl; #endif //:abv 30.08.09: if more than one open wires and more than two of them are // completely degenerated, remove any of them if ( isdeg || isdeg1 || isdeg2 ) { ws.Remove ( isdeg ? i : isdeg2 ? isdeg2 : isdeg1 ); w1.Nullify(); w2.Nullify(); i = 0; #ifdef DEB cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" << endl; #endif continue; } } } BRep_Builder B; if ( w1.IsNull() ) return Standard_False; else if ( w2.IsNull() ) { // WARNING!!! Temporarily for spheres only: // If only one of wires limiting face on sphere is open in 2d, // this means that degenerated edge should be added to one of poles, and // then usual procedure applied if ( ismodeu && mySurf->Surface()->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) { gp_Pnt2d p ( ( ismodeu < 0 ? 0. : 2.*M_PI ), ismodeu * 0.5 * M_PI ); gp_Dir2d d ( -ismodeu, 0. ); Handle(Geom2d_Line) line = new Geom2d_Line ( p, d ); TopoDS_Edge edge; B.MakeEdge ( edge ); B.Degenerated ( edge, Standard_True ); B.UpdateEdge ( edge, line, myFace, ::Precision::Confusion() ); B.Range ( edge, myFace, 0., 2*M_PI ); TopoDS_Vertex V; B.MakeVertex ( V, mySurf->Value ( p.X(), p.Y() ), ::Precision::Confusion() ); V.Orientation(TopAbs_FORWARD); B.Add(edge,V); V.Orientation(TopAbs_REVERSED); B.Add(edge,V); B.MakeWire ( w2 ); B.Add ( w2, edge ); ws.Append ( w2 ); } else return Standard_False; } // sort original wires Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire; sfw->SetFace ( myFace ); sfw->SetPrecision ( Precision() ); Handle(ShapeExtend_WireData) wd1 = new ShapeExtend_WireData ( w1 ); Handle(ShapeExtend_WireData) wd2 = new ShapeExtend_WireData ( w2 ); // sorting // Standard_Boolean degenerated = ( secondDeg != firstDeg ); // if ( ! degenerated ) { sfw->Load ( wd1 ); sfw->FixReorder(); // } sfw->Load ( wd2 ); sfw->FixReorder(); //:abv 29.08.01: reconstruct face taking into account reversing TopoDS_Shape dummy = myFace.EmptyCopied(); TopoDS_Face tmpF = TopoDS::Face ( dummy ); tmpF.Orientation ( TopAbs_FORWARD ); for ( i=1; i <= ws.Length(); i++ ) { TopoDS_Wire wire = TopoDS::Wire ( ws.Value(i) ); if ( wire.IsSame ( w1 ) ) wire = w1; else if ( wire.IsSame ( w2 ) ) wire = w2; B.Add ( tmpF, wire ); } tmpF.Orientation ( myFace.Orientation() ); Standard_Real uf=SUF, vf=SVF; // A special kind of FixShifted is necessary for torus-like // surfaces to adjust wires by period ALONG the missing SEAM direction // tr9_r0501-ug.stp #187640 if ( uclosed && vclosed ) { Standard_Integer coord = ( ismodeu ? 1 : 0 ); Standard_Integer isneg = ( ismodeu ? ismodeu : -ismodev ); Standard_Real period = ( ismodeu ? URange : VRange ); TopoDS_Shape S; Standard_Real m1[2][2], m2[2][2]; S = tmpF.EmptyCopied(); B.Add ( S, w1 ); ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m1[0][0], m1[0][1], m1[1][0], m1[1][1]); S = tmpF.EmptyCopied(); B.Add ( S, w2 ); ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]); Standard_Real shiftw2 = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ), 0.5 * ( m1[coord][0] + m1[coord][1] + isneg * ( period + ::Precision::PConfusion() ) ), period ); m1[coord][0] = Min ( m1[coord][0], m2[coord][0] + shiftw2 ); m1[coord][1] = Max ( m1[coord][1], m2[coord][1] + shiftw2 ); for ( TopoDS_Iterator it(tmpF,Standard_False); it.More(); it.Next() ) { if(it.Value().ShapeType() != TopAbs_WIRE) continue; TopoDS_Wire w = TopoDS::Wire ( it.Value() ); if ( w == w1 ) continue; Standard_Real shift; if ( w == w2 ) shift = shiftw2; else { S = tmpF.EmptyCopied(); B.Add ( S, w ); ShapeAnalysis::GetFaceUVBounds (TopoDS::Face(S), m2[0][0], m2[0][1], m2[1][0], m2[1][1]); shift = ShapeAnalysis::AdjustByPeriod ( 0.5 * ( m2[coord][0] + m2[coord][1] ), 0.5 * ( m1[coord][0] + m1[coord][1] ), period ); } if ( shift != 0. ) { gp_Vec2d V(0.,0.); V.SetCoord ( coord+1, shift ); ShapeAnalysis_Edge sae; for ( TopoDS_Iterator iw(w); iw.More(); iw.Next() ) { TopoDS_Edge E = TopoDS::Edge ( iw.Value() ); Handle(Geom2d_Curve) C; Standard_Real a, b; if ( ! sae.PCurve ( E, tmpF, C, a, b ) ) continue; C->Translate ( V ); } } } // abv 05 Feb 02: OCC34 // by the way, select proper split place by V to avoid extra intersections if ( m1[coord][1] - m1[coord][0] <= period ) { Standard_Real other = 0.5 * ( m1[coord][0] + m1[coord][1] - period ); if ( ismodeu ) vf = other; else uf = other; } } // find the best place by u and v to insert a seam // (so as to minimize splitting edges as possible) ShapeAnalysis_Edge sae; Standard_Integer foundU=0, foundV=0; Standard_Integer nb1 = wd1->NbEdges(); Standard_Integer nb2 = wd2->NbEdges(); for ( Standard_Integer i1 = 1; i1 <= nb1 + nb2; i1++ ) { TopoDS_Edge edge1 = ( i1 <= nb1 ? wd1->Edge ( i1 ) : wd2->Edge ( i1-nb1 ) ); Handle(Geom2d_Curve) c2d; Standard_Real f, l; if ( ! sae.PCurve ( edge1, tmpF, c2d, f, l, Standard_True ) ) return Standard_False; gp_Pnt2d pos1 = c2d->Value(l).XY(); // the best place is end of edge which is nearest to 0 Standard_Boolean skipU = ! uclosed; if ( uclosed && ismodeu ) { pos1.SetX ( pos1.X() + ShapeAnalysis::AdjustByPeriod ( pos1.X(), SUF, URange ) ); if ( foundU ==2 && Abs ( pos1.X() ) > Abs(uf) ) skipU = Standard_True; else if ( ! foundU || ( foundU ==1 && Abs ( pos1.X() ) < Abs(uf) ) ) { foundU = 1; uf = pos1.X(); } } Standard_Boolean skipV = ! vclosed; if ( vclosed && ! ismodeu ) { pos1.SetY ( pos1.Y() + ShapeAnalysis::AdjustByPeriod ( pos1.Y(), SVF, URange ) ); if ( foundV ==2 && Abs ( pos1.Y() ) > Abs(vf) ) skipV = Standard_True; else if ( ! foundV || ( foundV ==1 && Abs ( pos1.Y() ) < Abs(vf) ) ) { foundV = 1; vf = pos1.Y(); } } if ( skipU && skipV ) if ( i1 <= nb1 ) continue; else break; // or yet better - if it is end of some edges on both wires for ( Standard_Integer i2 = 1; i1 <= nb1 && i2 <= nb2; i2++ ) { TopoDS_Edge edge2 = wd2->Edge ( i2 ); if ( ! sae.PCurve ( edge2, tmpF, c2d, f, l, Standard_True ) ) return Standard_False; gp_Pnt2d pos2 = c2d->Value(f).XY(); if ( uclosed && ismodeu ) { pos2.SetX ( pos2.X() + ShapeAnalysis::AdjustByPeriod ( pos2.X(), pos1.X(), URange ) ); if ( Abs ( pos2.X() - pos1.X() ) < ::Precision::PConfusion() && ( foundU != 2 || Abs ( pos1.X() ) < Abs ( uf ) ) ) { foundU = 2; uf = pos1.X(); } } if ( vclosed && ! ismodeu ) { pos2.SetY ( pos2.Y() + ShapeAnalysis::AdjustByPeriod ( pos2.Y(), pos1.Y(), VRange ) ); if ( Abs ( pos2.Y() - pos1.Y() ) < ::Precision::PConfusion() && ( foundV != 2 || Abs ( pos1.Y() ) < Abs ( vf ) ) ) { foundV = 2; vf = pos1.Y(); } } } } //pdn fixing RTS on offsets if ( uf < SUF || uf > SUL ) uf+=ShapeAnalysis::AdjustToPeriod(uf,SUF,SUF+URange); if ( vf < SVF || vf > SVL ) vf+=ShapeAnalysis::AdjustToPeriod(vf,SVF,SVF+VRange); // Create fictive grid and call ComposeShell to insert a seam Handle(Geom_RectangularTrimmedSurface) RTS = new Geom_RectangularTrimmedSurface ( mySurf->Surface(), uf, uf+URange, vf, vf+VRange ); Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 ); grid->SetValue ( 1, 1, RTS ); //mySurf->Surface() ); Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid ); TopLoc_Location L; //addition non-manifold topology Standard_Integer j=1; for( ; j <= aSeqNonManif.Length(); j++) B.Add(tmpF,aSeqNonManif.Value(j)); ShapeFix_ComposeShell CompShell; // TopoDS_Face tmpF = myFace; // tmpF.Orientation(TopAbs_FORWARD); CompShell.Init ( G, L, tmpF, ::Precision::Confusion() );//myPrecision if ( Context().IsNull() ) SetContext ( new ShapeBuild_ReShape ); CompShell.ClosedMode() = Standard_True; CompShell.SetContext( Context() ); CompShell.SetMaxTolerance(MaxTolerance()); CompShell.Perform(); // abv 03.07.00: CAX-IF TRJ4: trj4_k1_goe-tu-214.stp: #785: reset mySurf mySurf = new ShapeAnalysis_Surface ( RTS ); myResult = CompShell.Result(); // if ( myFace.Orientation() == TopAbs_REVERSED ) res.Reverse(); Context()->Replace ( myFace, myResult ); for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) { myFace = TopoDS::Face ( exp.Current() ); BRepTools::Update(myFace); //:p4 } SendWarning ( Message_Msg ( "FixAdvFace.FixMissingSeam.MSG0" ) );// Missing seam-edge added return Standard_True; } //======================================================================= //function : FixSmallAreaWire //purpose : //======================================================================= //%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area. Standard_Boolean ShapeFix_Face::FixSmallAreaWire() { if ( ! Context().IsNull() ) { TopoDS_Shape S = Context()->Apply ( myFace ); myFace = TopoDS::Face ( S ); } //smh#8 TopoDS_Shape emptyCopied = myFace.EmptyCopied(); TopoDS_Face face = TopoDS::Face (emptyCopied); Standard_Integer nbRemoved = 0, nbWires = 0; BRep_Builder B; Standard_Real prec = ::Precision::PConfusion()*100; for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) { if(wi.Value().ShapeType() != TopAbs_WIRE && (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) continue; TopoDS_Wire wire = TopoDS::Wire ( wi.Value() ); Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire(wire,myFace,prec); if ( saw->CheckSmallArea(prec) ) { SendWarning ( wire, Message_Msg ("FixAdvFace.FixSmallAreaWire.MSG0") );// Null area wire detected, wire skipped nbRemoved++; } else { B.Add(face,wire); nbWires++; } } if ( nbRemoved <=0 ) return Standard_False; if ( nbWires <=0 ) { #ifdef DEB cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << endl; #endif return Standard_False; } #ifdef DEB cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << endl; #endif if ( ! Context().IsNull() ) Context()->Replace ( myFace, face ); myFace = face; return Standard_True; } //======================================================================= //function : FixLoopWire //purpose : //======================================================================= static void FindNext(const TopoDS_Shape& aVert, const TopoDS_Shape& ainitEdge, TopTools_IndexedMapOfShape& aMapVertices, TopTools_DataMapOfShapeListOfShape& aMapVertexEdges, const TopTools_MapOfShape& aMapSmallEdges, const TopTools_MapOfShape& aMapSeemEdges, TopTools_MapOfShape& aMapEdges, Handle(ShapeExtend_WireData)& aWireData) { TopoDS_Iterator aItV(ainitEdge); TopoDS_Shape anextVert = aVert; Standard_Boolean isFind = Standard_False; for( ; aItV.More() && !isFind; aItV.Next()) { if(!aItV.Value().IsSame(aVert) ) { isFind = Standard_True; anextVert = aItV.Value(); } } if(!isFind && !aMapSmallEdges.Contains(ainitEdge)) return; if(isFind && aMapVertices.Contains(anextVert)) return; const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(anextVert); TopTools_ListIteratorOfListOfShape liter(aledges); isFind = Standard_False; TopoDS_Shape anextEdge; for( ; liter.More() && !isFind; liter.Next()) { if(!aMapEdges.Contains(liter.Value()) && !liter.Value().IsSame(ainitEdge)) { anextEdge = liter.Value(); aWireData->Add(anextEdge); if(aMapSeemEdges.Contains(anextEdge)) aWireData->Add(anextEdge.Reversed()); isFind = Standard_True; aMapEdges.Add(anextEdge); FindNext(anextVert,anextEdge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData); } } return; } static Standard_Boolean isClosed2D(const TopoDS_Face& aFace,const TopoDS_Wire& aWire) { Standard_Boolean isClosed = Standard_True; Handle(ShapeAnalysis_Wire) asaw = new ShapeAnalysis_Wire(aWire,aFace,Precision::Confusion()); for (Standard_Integer i = 1; i <= asaw->NbEdges() && isClosed; i++) { TopoDS_Edge edge1 = asaw->WireData()->Edge(i); //checking that wire is closed in 2D space with tolerance of vertex. ShapeAnalysis_Edge sae; TopoDS_Vertex v1 = sae.FirstVertex(edge1); asaw->SetPrecision(BRep_Tool::Tolerance(v1)); asaw->CheckGap2d(i); isClosed = (asaw->LastCheckStatus(ShapeExtend_OK)); } return isClosed; } //======================================================================= //function : FixLoopWire //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires) { TopTools_IndexedMapOfShape aMapVertices; TopTools_DataMapOfShapeListOfShape aMapVertexEdges; TopTools_MapOfShape aMapSmallEdges; TopTools_MapOfShape aMapSeemEdges; if(!FixWireTool()->Analyzer()->CheckLoop(aMapVertices, aMapVertexEdges,aMapSmallEdges,aMapSeemEdges)) return Standard_False; TopTools_MapOfShape aMapEdges; TopTools_SequenceOfShape aSeqWires; //collecting wires from common vertex belonging more than 2 edges Standard_Integer i =1; for( ; i <= aMapVertices.Extent(); i++) { TopoDS_Shape aVert = aMapVertices.FindKey(i); const TopTools_ListOfShape& aledges = aMapVertexEdges.Find(aVert); TopTools_ListIteratorOfListOfShape liter(aledges); for( ; liter.More(); liter.Next()) { TopoDS_Edge Edge = TopoDS::Edge(liter.Value()); if(aMapEdges.Contains(Edge)) continue; Handle(ShapeExtend_WireData) aWireData = new ShapeExtend_WireData; aWireData->Add(Edge); if(aMapSeemEdges.Contains(Edge)) aWireData->Add(Edge.Reversed()); aMapEdges.Add(Edge); FindNext(aVert,Edge,aMapVertices,aMapVertexEdges,aMapSmallEdges,aMapSeemEdges,aMapEdges,aWireData); if(aWireData->NbEdges() ==1 && aMapSmallEdges.Contains(aWireData->Edge(1))) continue; TopoDS_Vertex aV1,aV2; TopoDS_Wire aWire = aWireData->Wire(); TopExp::Vertices(aWire,aV1,aV2); if(aV1.IsSame(aV2)) { Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire); Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire; asfw->Load(asewd); asfw->FixReorder(); TopoDS_Wire awire2 = asfw->Wire(); aResWires.Append(awire2); } else aSeqWires.Append(aWireData->Wire()); } } if(aSeqWires.Length() ==1) { aResWires.Append(aSeqWires.Value(1)); } else { //collecting whole wire from two not closed wires having two common vertices. for( i =1; i <= aSeqWires.Length(); i++) { TopoDS_Vertex aV1,aV2; TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i)); TopExp::Vertices(aWire,aV1,aV2); Standard_Integer j = i+1; for( ; j <= aSeqWires.Length(); j++) { TopoDS_Vertex aV21,aV22; TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j)); TopExp::Vertices(aWire2,aV21,aV22); if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) && (aV2.IsSame(aV21) || aV2.IsSame(aV22))) { Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire); asewd->Add(aWire2); Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire; asfw->Load(asewd); asfw->FixReorder(); aResWires.Append(asfw->Wire()); aSeqWires.Remove(j--); myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 ); break; } } if(j <= aSeqWires.Length()) aSeqWires.Remove(i--); } if(aSeqWires.Length()<3) { for( i =1; i <= aSeqWires.Length(); i++) aResWires.Append(aSeqWires.Value(i)); } else { //collecting wires having one common vertex for( i =1; i <= aSeqWires.Length(); i++) { TopoDS_Vertex aV1,aV2; TopoDS_Wire aWire = TopoDS::Wire(aSeqWires.Value(i)); TopExp::Vertices(aWire,aV1,aV2); Standard_Integer j =i+1; for( ; j <= aSeqWires.Length(); j++) { TopoDS_Vertex aV21,aV22; TopoDS_Wire aWire2 = TopoDS::Wire(aSeqWires.Value(j)); TopExp::Vertices(aWire2,aV21,aV22); if((aV1.IsSame(aV21) || aV1.IsSame(aV22)) || (aV2.IsSame(aV21) || aV2.IsSame(aV22))) { Handle(ShapeExtend_WireData) asewd = new ShapeExtend_WireData(aWire); asewd->Add(aWire2); Handle(ShapeFix_Wire) asfw = new ShapeFix_Wire; asfw->Load(asewd); asfw->FixReorder(); aWire = asfw->Wire(); TopExp::Vertices(aWire,aV1,aV2); aSeqWires.Remove(j--); myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE7 ); } } aResWires.Append(aWire); } } } Standard_Boolean isClosed = Standard_True; //checking that obtained wires is closed in 2D space if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) { TopoDS_Shape emptyCopied = myFace.EmptyCopied(); TopoDS_Face tmpFace = TopoDS::Face(emptyCopied); tmpFace.Orientation ( TopAbs_FORWARD ); for(i =1; i <= aResWires.Length() && isClosed; i++) { TopoDS_Wire awire = TopoDS::Wire(aResWires.Value(i)); isClosed = isClosed2D(tmpFace,awire); } } Standard_Boolean isDone =(aResWires.Length() && isClosed); if(isDone && aResWires.Length() >1) { #ifdef DEBUG cout<<"Wire was splitted on "<Edge(num); TopoDS_Edge newE1, newE2; ShapeFix_SplitTool aTool; if(aTool.SplitEdge(edge,param,vert,myFace,newE1,newE2,preci,0.01*preci)) { // change context Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData; wd->Add(newE1); wd->Add(newE2); if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() ); for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) { TopoDS_Edge E = TopoDS::Edge ( exp.Current() ); BRepTools::Update(E); } // for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) { // TopoDS_Edge E = sewd->Edge(i); // TopoDS_Shape S = Context()->Apply ( E ); // if ( S == E ) continue; // for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() ) // sewd->Add ( exp.Current(), i++ ); // sewd->Remove ( i-- ); // } // change sewd and boxes sewd->Set(newE1,num); if(num==sewd->NbEdges()) sewd->Add(newE2); else sewd->Add(newE2,num+1); boxes.UnBind(edge); TopLoc_Location L; const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L); Handle(Geom2d_Curve) c2d; Standard_Real cf,cl; ShapeAnalysis_Edge sae; if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) { Bnd_Box2d box; Geom2dAdaptor_Curve gac; Standard_Real aFirst = c2d->FirstParameter(); Standard_Real aLast = c2d->LastParameter(); if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) { //pdn avoiding problems with segment in Bnd_Box gac.Load(c2d); } else gac.Load(c2d,cf,cl); BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box); boxes.Bind(newE1,box); } if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) { Bnd_Box2d box; Geom2dAdaptor_Curve gac; Standard_Real aFirst = c2d->FirstParameter(); Standard_Real aLast = c2d->LastParameter(); if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) { //pdn avoiding problems with segment in Bnd_Box gac.Load(c2d); } else gac.Load(c2d,cf,cl); BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box); boxes.Bind(newE2,box); } return Standard_True; } return Standard_False; } //======================================================================= //function : SplitEdge //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& sewd, const Standard_Integer num, const Standard_Real param1, const Standard_Real param2, const TopoDS_Vertex& vert, const Standard_Real preci, ShapeFix_DataMapOfShapeBox2d& boxes) { TopoDS_Edge edge = sewd->Edge(num); TopoDS_Edge newE1, newE2; ShapeFix_SplitTool aTool; if(aTool.SplitEdge(edge,param1,param2,vert,myFace,newE1,newE2,preci,0.01*preci)) { // change context Handle(ShapeExtend_WireData) wd = new ShapeExtend_WireData; wd->Add(newE1); wd->Add(newE2); if(!Context().IsNull()) Context()->Replace( edge, wd->Wire() ); for (TopExp_Explorer exp ( wd->Wire(), TopAbs_EDGE ); exp.More(); exp.Next() ) { TopoDS_Edge E = TopoDS::Edge ( exp.Current() ); BRepTools::Update(E); } // change sewd and boxes sewd->Set(newE1,num); if(num==sewd->NbEdges()) sewd->Add(newE2); else sewd->Add(newE2,num+1); boxes.UnBind(edge); TopLoc_Location L; const Handle(Geom_Surface)& S = BRep_Tool::Surface(myFace,L); Handle(Geom2d_Curve) c2d; Standard_Real cf,cl; ShapeAnalysis_Edge sae; if(sae.PCurve(newE1,S,L,c2d,cf,cl,Standard_False)) { Bnd_Box2d box; Geom2dAdaptor_Curve gac; Standard_Real aFirst = c2d->FirstParameter(); Standard_Real aLast = c2d->LastParameter(); if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) { //pdn avoiding problems with segment in Bnd_Box gac.Load(c2d); } else gac.Load(c2d,cf,cl); BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box); boxes.Bind(newE1,box); } if(sae.PCurve(newE2,S,L,c2d,cf,cl,Standard_False)) { Bnd_Box2d box; Geom2dAdaptor_Curve gac; Standard_Real aFirst = c2d->FirstParameter(); Standard_Real aLast = c2d->LastParameter(); if(c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)) && (cf < aFirst || cl > aLast)) { //pdn avoiding problems with segment in Bnd_Box gac.Load(c2d); } else gac.Load(c2d,cf,cl); BndLib_Add2dCurve::Add(gac,::Precision::Confusion(),box); boxes.Bind(newE2,box); } return Standard_True; } return Standard_False; } //======================================================================= //function : FixIntersectingWires //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixIntersectingWires() { ShapeFix_IntersectionTool ITool(Context(),Precision(),MaxTolerance()); return ITool.FixIntersectingWires(myFace); } //======================================================================= //function : FixWiresTwoCoincEdges //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixWiresTwoCoincEdges() { if ( ! Context().IsNull() ) { TopoDS_Shape S = Context()->Apply ( myFace ); myFace = TopoDS::Face ( S ); } TopAbs_Orientation ori = myFace.Orientation(); TopoDS_Shape emptyCopied = myFace.EmptyCopied(); TopoDS_Face face = TopoDS::Face (emptyCopied); face.Orientation(TopAbs_FORWARD); Standard_Integer nbWires = 0; BRep_Builder B; for (TopoDS_Iterator it (myFace, Standard_False); it.More(); it.Next()) { if(it.Value().ShapeType() != TopAbs_WIRE || (it.Value().Orientation() != TopAbs_FORWARD && it.Value().Orientation() != TopAbs_REVERSED)) { continue; } nbWires++; } if(nbWires<2) return Standard_False; Standard_Boolean isFixed = Standard_False; for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) { if(wi.Value().ShapeType() != TopAbs_WIRE || (wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED)) { B.Add(face,wi.Value()); continue; } TopoDS_Wire wire = TopoDS::Wire ( wi.Value() ); Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire); if(sewd->NbEdges()==2) { TopoDS_Edge E1 = sewd->Edge(1); TopoDS_Edge E2 = sewd->Edge(2); E1.Orientation(TopAbs_FORWARD); E2.Orientation(TopAbs_FORWARD); if( !(E1==E2) ) { B.Add(face,wire); } else isFixed = Standard_True; } else { B.Add(face,wire); } } if(isFixed) { face.Orientation(ori); if ( ! Context().IsNull() ) Context()->Replace ( myFace, face ); myFace = face; } return isFixed; } //======================================================================= //function : FixSplitFace //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOfShape &MapWires) { BRep_Builder B; TopTools_SequenceOfShape faces; TopoDS_Shape S = myFace; if ( ! Context().IsNull() ) S = Context()->Apply ( myFace ); Standard_Integer NbWires=0, NbWiresNew=0; for(TopoDS_Iterator iter(S,Standard_False); iter.More(); iter.Next()) { if(iter.Value().ShapeType() != TopAbs_WIRE || (iter.Value().Orientation() != TopAbs_FORWARD && iter.Value().Orientation() != TopAbs_REVERSED)) continue; TopoDS_Wire wire = TopoDS::Wire ( iter.Value() ); NbWires++; if(MapWires.IsBound(wire)) { // if wire not closed --> stop split and return false Handle(ShapeExtend_WireData) sewd = new ShapeExtend_WireData(wire); TopoDS_Edge E1 = sewd->Edge(1); TopoDS_Edge E2 = sewd->Edge(sewd->NbEdges()); TopoDS_Vertex V1,V2; ShapeAnalysis_Edge sae; V1=sae.FirstVertex(E1); V2=sae.LastVertex(E2); if(!V1.IsSame(V2)) { cout<<"wire not closed --> stop split"<1) { TopoDS_Compound Comp; B.MakeCompound(Comp); for(Standard_Integer i=1; i<=faces.Length(); i++ ) B.Add(Comp,faces(i)); myResult = Comp; Context()->Replace ( myFace, myResult ); for (TopExp_Explorer exp ( myResult, TopAbs_FACE ); exp.More(); exp.Next() ) { myFace = TopoDS::Face ( exp.Current() ); BRepTools::Update(myFace); } return Standard_True; } return Standard_False; } //======================================================================= //function : IsPeriodicConicalLoop //purpose : Checks whether the passed wire makes up a periodic loop on // passed conical surface //======================================================================= static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf, const TopoDS_Wire& theWire, const Standard_Real theTolerance, Standard_Real& theMinU, Standard_Real& theMaxU, Standard_Real& theMinV, Standard_Real& theMaxV, Standard_Boolean& isUDecrease) { if ( theSurf.IsNull() ) return Standard_False; ShapeAnalysis_Edge aSAE; TopLoc_Location aLoc; Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0; Standard_Real aMinU = RealLast(); Standard_Real aMinV = aMinU; Standard_Real aMaxU = -aMinU; Standard_Real aMaxV = aMaxU; // Iterate over the edges to check whether the wire is periodic on conical surface BRepTools_WireExplorer aWireExp(theWire); for ( ; aWireExp.More(); aWireExp.Next() ) { const TopoDS_Edge& aCurrentEdge = aWireExp.Current(); Handle(Geom2d_Curve) aC2d; Standard_Real aPFirst, aPLast; aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True); if ( aC2d.IsNull() ) return Standard_False; gp_Pnt2d aUVFirst = aC2d->Value(aPFirst), aUVLast = aC2d->Value(aPLast); Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X(); Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y(); Standard_Real aCurMaxU = Max(aUFirst, aULast), aCurMinU = Min(aUFirst, aULast); Standard_Real aCurMaxV = Max(aVFirst, aVLast), aCurMinV = Min(aVFirst, aVLast); if ( aCurMinU < aMinU ) aMinU = aCurMinU; if ( aCurMaxU > aMaxU ) aMaxU = aCurMaxU; if ( aCurMinV < aMinV ) aMinV = aCurMinV; if ( aCurMaxV > aMaxV ) aMaxV = aCurMaxV; Standard_Real aDeltaU = aULast - aUFirst; aCumulDeltaU += aDeltaU; aCumulDeltaUAbs += Abs(aDeltaU); } theMinU = aMinU; theMaxU = aMaxU; theMinV = aMinV; theMaxV = aMaxV; isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False); Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance; Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance; return is2PIDelta && isAroundApex; } //======================================================================= //function : FixPeriodicDegenerated //purpose : //======================================================================= Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated() { /* ===================== * Prepare fix routine * ===================== */ if ( !Context().IsNull() ) { TopoDS_Shape aSh = Context()->Apply(myFace); myFace = TopoDS::Face(aSh); } /* ================================================ * Check if fix can be applied on the passed face * ================================================ */ // Collect all wires owned by the face TopTools_SequenceOfShape aWireSeq; for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() ) { const TopoDS_Shape& aSubSh = aWireIt.Value(); if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD && aSubSh.Orientation() != TopAbs_REVERSED ) ) continue; aWireSeq.Append( aWireIt.Value() ); } // Get number of wires and surface Standard_Integer aNbWires = aWireSeq.Length(); Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace); // Only single wires on conical surfaces are checked if ( aNbWires != 1 || aSurface.IsNull() || aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) ) return Standard_False; // Get the single wire TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) ); // Check whether this wire is belting the conical surface by period Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface); Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0; Standard_Boolean isUDecrease = Standard_False; Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(), aMinLoopU, aMaxLoopU, aMinLoopV, aMaxLoopV, isUDecrease); if ( !isConicLoop ) return Standard_False; /* =============== * Retrieve apex * =============== */ // Get base circle of the conical surface (the circle it was built from) Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0); Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv); // Retrieve conical props Standard_Real aConeBaseR = aConeBaseCirc->Radius(); Standard_Real aSemiAngle = aConeSurf->SemiAngle(); if ( fabs(aSemiAngle) <= Precision::Confusion() ) return Standard_False; // Bad surface // Find the V parameter of the apex Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle); Standard_Real anApexV = -aConeBaseH; // Get apex vertex TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() ); // ==================================== // Build degenerated edge in the apex // ==================================== TopoDS_Edge anApexEdge; BRep_Builder aBuilder; aBuilder.MakeEdge(anApexEdge); // Check if positional relationship between the initial wire and apex // line in 2D is going to be consistent if ( fabs(anApexV - aMinLoopV) <= Precision() || fabs(anApexV - aMaxLoopV) <= Precision() || ( anApexV < aMaxLoopV && anApexV > aMinLoopV ) ) return Standard_False; Handle(Geom2d_Line) anApexCurve2d; // Apex curve below the wire if ( anApexV < aMinLoopV ) { anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) ); if ( !isUDecrease ) aSoleWire.Reverse(); } // Apex curve above the wire if ( anApexV > aMaxLoopV ) { anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) ); if ( isUDecrease ) aSoleWire.Reverse(); } // Create degenerated edge & wire for apex aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() ); aBuilder.Add( anApexEdge, anApex ); aBuilder.Add( anApexEdge, anApex.Reversed() ); aBuilder.Degenerated(anApexEdge, Standard_True); aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) ); TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge); // =============================================================== // Finalize the fix building new face and setting up the results // =============================================================== // Collect the resulting set of wires TopTools_SequenceOfShape aNewWireSeq; aNewWireSeq.Append(aSoleWire); aNewWireSeq.Append(anApexWire); // Assemble new face TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() ); aNewFace.Orientation(TopAbs_FORWARD); BRep_Builder aFaceBuilder; for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ ) { TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) ); aFaceBuilder.Add(aNewFace, aNewWire); } aNewFace.Orientation( myFace.Orientation() ); // Adjust the resulting state of the healing tool myResult = aNewFace; Context()->Replace(myFace, myResult); return Standard_True; }