From 51a849d7702ca6314a56742deef93f3d5bdc84c4 Mon Sep 17 00:00:00 2001 From: jgv Date: Fri, 22 Mar 2013 17:31:43 +0400 Subject: [PATCH] 0023845: New auxiliary method concatenating a wire into an edge based on C0-continuous curve. Fix of exception in old method (ConcatenateWire). Adding test case for this fix --- src/BRepAlgo/BRepAlgo.cdl | 6 + src/BRepAlgo/BRepAlgo.cxx | 373 +++++++++++++++++++++++- src/BRepTest/BRepTest_CurveCommands.cxx | 30 ++ tests/bugs/modalg_5/bug23845 | 19 ++ 4 files changed, 426 insertions(+), 2 deletions(-) create mode 100755 tests/bugs/modalg_5/bug23845 diff --git a/src/BRepAlgo/BRepAlgo.cdl b/src/BRepAlgo/BRepAlgo.cdl index fe8fb19b5d..510a32e7b2 100755 --- a/src/BRepAlgo/BRepAlgo.cdl +++ b/src/BRepAlgo/BRepAlgo.cdl @@ -118,6 +118,12 @@ is -- Option can be G1 or C1. returns Wire from TopoDS; + ConcatenateWireC0(Wire : Wire from TopoDS) + ---Purpose: this method makes an edge from a wire. + -- Junction points between edges of wire may be sharp, + -- resulting curve of the resulting edge may be C0. + returns Edge from TopoDS; + --BRepAlgoAPI f IsValid(S: Shape from TopoDS) diff --git a/src/BRepAlgo/BRepAlgo.cxx b/src/BRepAlgo/BRepAlgo.cxx index 224e48f201..da2b79ab83 100755 --- a/src/BRepAlgo/BRepAlgo.cxx +++ b/src/BRepAlgo/BRepAlgo.cxx @@ -40,6 +40,21 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Temporary +#//include + + //======================================================================= //function : ConcatenateWire //purpose : @@ -82,8 +97,9 @@ TopoDS_Wire BRepAlgo::ConcatenateWire(const TopoDS_Wire& W, for (index=0 ;indexTransform(L.Transformation()); GeomConvert::C0BSplineToC1BSplineCurve(tab(index),Precision::Confusion()); @@ -213,6 +229,359 @@ TopoDS_Wire BRepAlgo::ConcatenateWire(const TopoDS_Wire& W, } +//======================================================================= +//function : ConcatenateWireC0 +//purpose : +//======================================================================= +TopoDS_Edge BRepAlgo::ConcatenateWireC0(const TopoDS_Wire& aWire) +{ + Standard_Real LinTol = Precision::Confusion(); + Standard_Real AngTol = Precision::Angular(); + TopoDS_Edge ResEdge; + TopoDS_Wire theWire = aWire; + BRepLib::BuildCurves3d(theWire); + Handle(ShapeFix_Shape) Fixer = new ShapeFix_Shape(theWire); + Fixer->SetPrecision(LinTol); + Fixer->SetMaxTolerance(LinTol); + Fixer->Perform(); + theWire = TopoDS::Wire(Fixer->Shape()); + + TColGeom_SequenceOfCurve CurveSeq; + TopTools_SequenceOfShape LocSeq; + TColStd_SequenceOfReal FparSeq; + TColStd_SequenceOfReal LparSeq; + TColStd_SequenceOfReal TolSeq; + GeomAbs_CurveType CurType; + TopoDS_Vertex FirstVertex, LastVertex; + Standard_Boolean FinalReverse = Standard_False; + + BRepTools_WireExplorer wexp(theWire) ; + for (; wexp.More(); wexp.Next()) + { + TopoDS_Edge anEdge = wexp.Current(); + Standard_Real fpar, lpar; + TopLoc_Location aLoc; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aLoc, fpar, lpar); + if (aCurve.IsNull()) + continue; + + BRepAdaptor_Curve BAcurve(anEdge); + GeomAbs_CurveType aType = BAcurve.GetType(); + + Handle(Geom_Curve) aBasisCurve = BAcurve.Curve().Curve(); + + if (aBasisCurve->IsPeriodic()) + ElCLib::AdjustPeriodic(aBasisCurve->FirstParameter(), aBasisCurve->LastParameter(), + Precision::PConfusion(), fpar, lpar); + + if (CurveSeq.IsEmpty()) + { + CurveSeq.Append(aCurve); + TopoDS_Shape aLocShape; + aLocShape.Location(aLoc); + aLocShape.Orientation(wexp.Orientation()); + LocSeq.Append(aLocShape); + FparSeq.Append(fpar); + LparSeq.Append(lpar); + CurType = aType; + FirstVertex = wexp.CurrentVertex(); + if (anEdge.Orientation() == TopAbs_REVERSED) + FinalReverse = Standard_True; + } + else + { + Standard_Boolean Done = Standard_False; + Standard_Real NewFpar, NewLpar; + GeomAdaptor_Curve GAprevcurve(CurveSeq.Last()); + TopoDS_Vertex CurVertex = wexp.CurrentVertex(); + TopoDS_Vertex CurFirstVer = TopExp::FirstVertex(anEdge); + TopAbs_Orientation ConnectByOrigin = (CurVertex.IsSame(CurFirstVer))? TopAbs_FORWARD : TopAbs_REVERSED; + if (aCurve == CurveSeq.Last()) + { + NewFpar = fpar; + NewLpar = lpar; + if (aBasisCurve->IsPeriodic()) + { + if (NewLpar < NewFpar) + NewLpar += aBasisCurve->Period(); + if (ConnectByOrigin == TopAbs_FORWARD) + ElCLib::AdjustPeriodic(FparSeq.Last(), + FparSeq.Last() + aBasisCurve->Period(), + Precision::PConfusion(), NewFpar, NewLpar); + else + ElCLib::AdjustPeriodic(FparSeq.Last() - aBasisCurve->Period(), + FparSeq.Last(), + Precision::PConfusion(), NewFpar, NewLpar); + } + Done = Standard_True; + } + else if (aType == CurType && + aType != GeomAbs_BezierCurve && + aType != GeomAbs_BSplineCurve && + aType != GeomAbs_OtherCurve) + switch (aType) + { + case GeomAbs_Line: + { + gp_Lin aLine = BAcurve.Line(); + gp_Lin PrevLine = GAprevcurve.Line(); + if (aLine.Contains(PrevLine.Location(), LinTol) && + aLine.Direction().IsParallel(PrevLine.Direction(), AngTol)) + { + gp_Pnt P1 = ElCLib::Value(fpar, aLine); + gp_Pnt P2 = ElCLib::Value(lpar, aLine); + NewFpar = ElCLib::Parameter(PrevLine, P1); + NewLpar = ElCLib::Parameter(PrevLine, P2); + if (NewLpar < NewFpar) + { + Standard_Real MemNewFpar = NewFpar; + NewFpar = NewLpar; + NewLpar = MemNewFpar; + ConnectByOrigin = TopAbs::Reverse(ConnectByOrigin); + } + Done = Standard_True; + } + break; + } + case GeomAbs_Circle: + { + gp_Circ aCircle = BAcurve.Circle(); + gp_Circ PrevCircle = GAprevcurve.Circle(); + if (aCircle.Location().Distance(PrevCircle.Location()) <= LinTol && + Abs(aCircle.Radius() - PrevCircle.Radius()) <= LinTol && + aCircle.Axis().IsParallel(PrevCircle.Axis(), AngTol)) + { + if (aCircle.Axis().Direction() * PrevCircle.Axis().Direction() < 0.) + { + Standard_Real memfpar = fpar; + fpar = lpar; + lpar = memfpar; + ConnectByOrigin = TopAbs::Reverse(ConnectByOrigin); + } + gp_Pnt P1 = ElCLib::Value(fpar, aCircle); + gp_Pnt P2 = ElCLib::Value(lpar, aCircle); + NewFpar = ElCLib::Parameter(PrevCircle, P1); + NewLpar = ElCLib::Parameter(PrevCircle, P2); + if (NewLpar < NewFpar) + NewLpar += 2.*M_PI; + //Standard_Real MemNewFpar = NewFpar, MemNewLpar = NewLpar; + if (ConnectByOrigin == TopAbs_FORWARD) + ElCLib::AdjustPeriodic(FparSeq.Last(), + FparSeq.Last() + 2.*M_PI, + Precision::PConfusion(), NewFpar, NewLpar); + else + ElCLib::AdjustPeriodic(FparSeq.Last() - 2.*M_PI, + FparSeq.Last(), + Precision::PConfusion(), NewFpar, NewLpar); + Done = Standard_True; + } + break; + } + case GeomAbs_Ellipse: + { + gp_Elips anEllipse = BAcurve.Ellipse(); + gp_Elips PrevEllipse = GAprevcurve.Ellipse(); + if (anEllipse.Focus1().Distance(PrevEllipse.Focus1()) <= LinTol && + anEllipse.Focus2().Distance(PrevEllipse.Focus2()) <= LinTol && + Abs(anEllipse.MajorRadius() - PrevEllipse.MajorRadius()) <= LinTol && + Abs(anEllipse.MinorRadius() - PrevEllipse.MinorRadius()) <= LinTol && + anEllipse.Axis().IsParallel(PrevEllipse.Axis(), AngTol)) + { + if (anEllipse.Axis().Direction() * PrevEllipse.Axis().Direction() < 0.) + { + Standard_Real memfpar = fpar; + fpar = lpar; + lpar = memfpar; + ConnectByOrigin = TopAbs::Reverse(ConnectByOrigin); + } + gp_Pnt P1 = ElCLib::Value(fpar, anEllipse); + gp_Pnt P2 = ElCLib::Value(lpar, anEllipse); + NewFpar = ElCLib::Parameter(PrevEllipse, P1); + NewLpar = ElCLib::Parameter(PrevEllipse, P2); + if (NewLpar < NewFpar) + NewLpar += 2.*M_PI; + if (ConnectByOrigin == TopAbs_FORWARD) + ElCLib::AdjustPeriodic(FparSeq.Last(), + FparSeq.Last() + 2.*M_PI, + Precision::PConfusion(), NewFpar, NewLpar); + else + ElCLib::AdjustPeriodic(FparSeq.Last() - 2.*M_PI, + FparSeq.Last(), + Precision::PConfusion(), NewFpar, NewLpar); + Done = Standard_True; + } + break; + } + case GeomAbs_Hyperbola: + { + gp_Hypr aHypr = BAcurve.Hyperbola(); + gp_Hypr PrevHypr = GAprevcurve.Hyperbola(); + if (aHypr.Focus1().Distance(PrevHypr.Focus1()) <= LinTol && + aHypr.Focus2().Distance(PrevHypr.Focus2()) <= LinTol && + Abs(aHypr.MajorRadius() - PrevHypr.MajorRadius()) <= LinTol && + Abs(aHypr.MinorRadius() - PrevHypr.MinorRadius()) <= LinTol && + aHypr.Axis().IsParallel(PrevHypr.Axis(), AngTol)) + { + gp_Pnt P1 = ElCLib::Value(fpar, aHypr); + gp_Pnt P2 = ElCLib::Value(lpar, aHypr); + NewFpar = ElCLib::Parameter(PrevHypr, P1); + NewLpar = ElCLib::Parameter(PrevHypr, P2); + if (NewLpar < NewFpar) + { + Standard_Real MemNewFpar = NewFpar; + NewFpar = NewLpar; + NewLpar = MemNewFpar; + ConnectByOrigin = TopAbs::Reverse(ConnectByOrigin); + } + Done = Standard_True; + } + break; + } + case GeomAbs_Parabola: + { + gp_Parab aParab = BAcurve.Parabola(); + gp_Parab PrevParab = GAprevcurve.Parabola(); + if (aParab.Location().Distance(PrevParab.Location()) <= LinTol && + aParab.Focus().Distance(PrevParab.Focus()) <= LinTol && + Abs(aParab.Focal() - PrevParab.Focal()) <= LinTol && + aParab.Axis().IsParallel(PrevParab.Axis(), AngTol)) + { + gp_Pnt P1 = ElCLib::Value(fpar, aParab); + gp_Pnt P2 = ElCLib::Value(lpar, aParab); + NewFpar = ElCLib::Parameter(PrevParab, P1); + NewLpar = ElCLib::Parameter(PrevParab, P2); + if (NewLpar < NewFpar) + { + Standard_Real MemNewFpar = NewFpar; + NewFpar = NewLpar; + NewLpar = MemNewFpar; + ConnectByOrigin = TopAbs::Reverse(ConnectByOrigin); + } + Done = Standard_True; + } + break; + } + } //end of switch and else + if (Done) + { + if (NewFpar < FparSeq.Last()) + FparSeq(FparSeq.Length()) = NewFpar; + else + LparSeq(LparSeq.Length()) = NewLpar; + } + else + { + CurveSeq.Append(aCurve); + TopoDS_Shape aLocShape; + aLocShape.Location(aLoc); + aLocShape.Orientation(wexp.Orientation()); + LocSeq.Append(aLocShape); + FparSeq.Append(fpar); + LparSeq.Append(lpar); + TolSeq.Append(BRep_Tool::Tolerance(CurVertex)); + CurType = aType; + } + } //end of else (not first time) + } + LastVertex = wexp.CurrentVertex(); + TolSeq.Append(BRep_Tool::Tolerance(LastVertex)); + + TopoDS_Vertex FirstVtx_final = (FinalReverse)? LastVertex : FirstVertex; + FirstVtx_final.Orientation(TopAbs_FORWARD); + TopoDS_Vertex LastVtx_final = (FinalReverse)? FirstVertex : LastVertex; + LastVtx_final.Orientation(TopAbs_REVERSED); + + if (CurveSeq.IsEmpty()) + return ResEdge; + + Standard_Integer nb_curve = CurveSeq.Length(); //number of curves + TColGeom_Array1OfBSplineCurve tab(0,nb_curve-1); //array of the curves + TColStd_Array1OfReal tabtolvertex(0,nb_curve-1); //(0,nb_curve-2); //array of the tolerances + + Standard_Integer i; + + if (nb_curve > 1) + { + for (i = 1; i <= nb_curve; i++) + { + if (CurveSeq(i)->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve))) + CurveSeq(i) = (*((Handle(Geom_TrimmedCurve)*)&(CurveSeq(i))))->BasisCurve(); + + Handle(Geom_TrimmedCurve) aTrCurve = new Geom_TrimmedCurve(CurveSeq(i), FparSeq(i), LparSeq(i)); + tab(i-1) = GeomConvert::CurveToBSplineCurve(aTrCurve); + tab(i-1)->Transform(LocSeq(i).Location().Transformation()); + GeomConvert::C0BSplineToC1BSplineCurve(tab(i-1), Precision::Confusion()); + if (LocSeq(i).Orientation() == TopAbs_REVERSED) + tab(i-1)->Reverse(); + + //Temporary + //char* name = new char[100]; + //sprintf(name, "c%d", i); + //DrawTrSurf::Set(name, tab(i-1)); + + if (i > 1) + tabtolvertex(i-2) = TolSeq(i-1) * 5.; + } + tabtolvertex(nb_curve-1) = TolSeq(TolSeq.Length()) * 5.; + + Standard_Boolean closed_flag = Standard_False; + Standard_Real closed_tolerance = 0.; + if (FirstVertex.IsSame(LastVertex) && + GeomLProp::Continuity(tab(0), tab(nb_curve-1), + tab(0)->FirstParameter(), + tab(nb_curve-1)->LastParameter(), + Standard_False, Standard_False, LinTol, AngTol) >= GeomAbs_G1) + { + closed_flag = Standard_True ; + closed_tolerance = BRep_Tool::Tolerance(FirstVertex); + } + + Handle(TColGeom_HArray1OfBSplineCurve) concatcurve; //array of the concatenated curves + Handle(TColStd_HArray1OfInteger) ArrayOfIndices; //array of the remining Vertex + GeomConvert::ConcatC1(tab, + tabtolvertex, + ArrayOfIndices, + concatcurve, + closed_flag, + closed_tolerance); //C1 concatenation + + if (concatcurve->Length() > 1) + { + Standard_Real MaxTolVer = LinTol; + for (i = 1; i <= TolSeq.Length(); i++) + if (TolSeq(i) > MaxTolVer) + MaxTolVer = TolSeq(i); + MaxTolVer *= 5.; + + GeomConvert_CompCurveToBSplineCurve Concat(concatcurve->Value(concatcurve->Lower())); + + for (i = concatcurve->Lower()+1; i <= concatcurve->Upper(); i++) + Concat.Add( concatcurve->Value(i), MaxTolVer, Standard_True ); + + concatcurve->SetValue(concatcurve->Lower(), Concat.BSplineCurve()); + } + + ResEdge = BRepLib_MakeEdge(concatcurve->Value(concatcurve->Lower()), + FirstVtx_final, LastVtx_final, + concatcurve->Value(concatcurve->Lower())->FirstParameter(), + concatcurve->Value(concatcurve->Lower())->LastParameter()); + } + else + { + if (CurveSeq(1)->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve))) + CurveSeq(1) = (*((Handle(Geom_TrimmedCurve)*)&(CurveSeq(1))))->BasisCurve(); + + CurveSeq(1)->Transform(LocSeq(1).Location().Transformation()); + ResEdge = BRepLib_MakeEdge(CurveSeq(1), + FirstVtx_final, LastVtx_final, + FparSeq(1), LparSeq(1)); + } + + if (FinalReverse) + ResEdge.Reverse(); + + return ResEdge; +} diff --git a/src/BRepTest/BRepTest_CurveCommands.cxx b/src/BRepTest/BRepTest_CurveCommands.cxx index 1010e2e0cf..ac1579ba75 100755 --- a/src/BRepTest/BRepTest_CurveCommands.cxx +++ b/src/BRepTest/BRepTest_CurveCommands.cxx @@ -1639,6 +1639,30 @@ Standard_Integer edgeintersector(Draw_Interpretor& di, return 0; } + +//======================================================================= +//function : concatC0wire +//purpose : +//======================================================================= + +Standard_Integer concatC0wire(Draw_Interpretor&, Standard_Integer n, const char** c) +{ + if ( n < 3 ) return 1; + + TopoDS_Shape S = DBRep::Get(c[2],TopAbs_WIRE) ; + + if (S.IsNull()) + return 1; //test if the shape is empty + + TopoDS_Wire W = TopoDS::Wire(S) ; + TopoDS_Shape res; + + + res = BRepAlgo::ConcatenateWireC0(W); //treatment + DBRep::Set(c[1], res); + return 0; +} + //======================================================================= //function : concatwire //purpose : reduce the multiply degree of the knots to the minimum without @@ -1828,6 +1852,12 @@ void BRepTest::CurveCommands(Draw_Interpretor& theCommands) "reducepcurves shape1 shape2 ...", reducepcurves, g); + theCommands.Add("concatC0wire", + "concatC0wire result wire", + __FILE__, + concatC0wire, + g); + theCommands.Add("concatwire", "concatwire result wire [option](G1/C1)", __FILE__, diff --git a/tests/bugs/modalg_5/bug23845 b/tests/bugs/modalg_5/bug23845 new file mode 100755 index 0000000000..0e41e4c746 --- /dev/null +++ b/tests/bugs/modalg_5/bug23845 @@ -0,0 +1,19 @@ +puts "================" +puts "OCC23845" +puts "================" +puts "" +####################################################################### +# New auxilary method concatenating a wire into an edge based on C0-continuous curve. +####################################################################### + +restore [locate_data_file bug23845_profil_0a.brep] a +restore [locate_data_file bug23845_profil_1a.brep] b + +concatC0wire aa a +concatC0wire bb b + +tolerance aa +checkshape aa + +tolerance bb +checkshape bb