From: bugmaster Date: Tue, 10 Nov 2015 10:09:07 +0000 (+0300) Subject: Preparing OCCT development branch X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=cefb2f9ddd1202b779fe8cf792c036b3b7d3f7ae;p=occt-copy.git Preparing OCCT development branch --- diff --git a/src/DrawResources/DrawPlugin b/src/DrawResources/DrawPlugin index dc17bad4db..42bee02a08 100755 --- a/src/DrawResources/DrawPlugin +++ b/src/DrawResources/DrawPlugin @@ -37,8 +37,11 @@ DATAEXCHANGEKERNEL : XSDRAW OCAF : VISUALIZATION, OCAFKERNEL DATAEXCHANGE : XDE, VISUALIZATION XDE : DATAEXCHANGEKERNEL, XDEDRAW +HELIX : TestHelix +UNFOLDING : TestUnfolding FULL : MODELING, OCAFKERNEL, VISUALIZATION -ALL : MODELING, OCAFKERNEL, DATAEXCHANGE +ALL : MODELING, OCAFKERNEL, DATAEXCHANGE, HELIX, UNFOLDING + TOPTEST : TKTopTest DCAF : TKDCAF @@ -49,3 +52,5 @@ TOBJ : TKTObjDRAW DFBROWSER : TKDFBrowser QAcommands : TKQADraw VIS : TKIVtkDraw +TestHelix : TKHelix +TestUnfolding : TKUnfoldingTest \ No newline at end of file diff --git a/src/DrawResources/DrawPlugin.bak b/src/DrawResources/DrawPlugin.bak new file mode 100644 index 0000000000..dc17bad4db --- /dev/null +++ b/src/DrawResources/DrawPlugin.bak @@ -0,0 +1,51 @@ +! Description of available plugins for DRAW Test Harness +! ***************************************************************************** +! +! Format of the file is compliant with the standard Open CASCADE resource files +! (see the Resource_Manager.cdl file for details). +! +! Each key defines a sequence of either further keys or a name of the dynamic +! library. Keys can be nested down to an arbitrary level. However, make sure +! there are no cyclic dependencies (internal checks are not performed). +! +! For details how to implement a DRAW plugin refer to the Test Harness User's +! Guide. +! +! To load a plugin use the following command in DRAW: +! +! Draw> pload [-PluginFileName] [[Key1] [Key2]...], where: +! <-PluginFileName> - Defines the name of a resource file. +! If this parameter is omitted then the default name DrawPlugin +! is used. +! According to the Open CASCADE resource file management rules +! the environment variable CSF_Defaults must +! be set and point to the directory storing the file. If it is +! omitted then it defaults to $CASROOT/src/DrawResources. +! [Key] - Defines the key(s) enumerating plugins to be loaded. +! If no keys are specified then the key named DEFAULT is used +! (if there is no such in the file then no plugins are loaded). +! +! +! NOTE: Make sure the DATAEXCHANGE or XDE key succeeds the OCAF key in a sequence +! + +DEFAULT : MODELING +MODELING : TOPTEST +VISUALIZATION : AISV +OCAFKERNEL : DCAF +DATAEXCHANGEKERNEL : XSDRAW +OCAF : VISUALIZATION, OCAFKERNEL +DATAEXCHANGE : XDE, VISUALIZATION +XDE : DATAEXCHANGEKERNEL, XDEDRAW +FULL : MODELING, OCAFKERNEL, VISUALIZATION +ALL : MODELING, OCAFKERNEL, DATAEXCHANGE + +TOPTEST : TKTopTest +DCAF : TKDCAF +AISV : TKViewerTest +XSDRAW : TKXSDRAW +XDEDRAW : TKXDEDRAW +TOBJ : TKTObjDRAW +DFBROWSER : TKDFBrowser +QAcommands : TKQADraw +VIS : TKIVtkDraw diff --git a/src/HelixBRep/HelixBRep.cdl b/src/HelixBRep/HelixBRep.cdl new file mode 100644 index 0000000000..07617d0926 --- /dev/null +++ b/src/HelixBRep/HelixBRep.cdl @@ -0,0 +1,21 @@ +-- File: HelixBRep.cdl + + +package HelixBRep + + ---Purpose: + +uses + gp, + TopoDS, + GeomAbs, + TColStd, + TopTools, + HelixGeom + +is + class BuilderHelix; + + +end HelixBRep; + diff --git a/src/HelixBRep/HelixBRep_BuilderHelix.cdl b/src/HelixBRep/HelixBRep_BuilderHelix.cdl new file mode 100644 index 0000000000..54df5d26ca --- /dev/null +++ b/src/HelixBRep/HelixBRep_BuilderHelix.cdl @@ -0,0 +1,145 @@ +-- File: HelixBRep_BuilderHelix.cdl + +class BuilderHelix from HelixBRep + ---Purpose: Implementation of building helix wire + -- Values of Error Status returned by algo: + -- 0 - OK + -- 1 - object is just initialized, it means that no input parameters were set + -- 2 - approximation fails + -- + -- 10 - R < tolerance - starting point is too close to axis + -- 11 - step (Pitch) < tolerancee + -- 12 - Height < tolerance + -- 13 - TaperAngle < 0 or TaperAngle > Pi/2 - TolAng + -- Warning Status: + -- 0 - OK + -- 1 - tolerance reached by approximation > requested tolerance. + +uses + Ax1 from gp, + Ax3 from gp, + Pnt from gp, + Array1OfReal from TColStd, + HArray1OfReal from TColStd, + Array1OfBoolean from TColStd, + HArray1OfBoolean from TColStd, + Shape from GeomAbs, + Shape from TopoDS, + Wire from TopoDS, + Edge from TopoDS, + ListOfShape from TopTools + +is + + Create + ---Purpose: Empty constructor + returns BuilderHelix from HelixBRep; + ---C++: alias "Standard_EXPORT virtual ~HelixBRep_BuilderHelix();" + + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiams: Array1OfReal from TColStd; + theHeights: Array1OfReal from TColStd ; + thePitches: Array1OfReal from TColStd ; + theIsPitches: Array1OfBoolean from TColStd); + ---Purpose: Sets parameters of general composite helix + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiam: Real from Standard; + theHeights: Array1OfReal from TColStd ; + thePitches: Array1OfReal from TColStd ; + theIsPitches: Array1OfBoolean from TColStd); + ---Purpose: Sets parameters of pure helix + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiam1: Real from Standard; + theDiam2: Real from Standard; + theHeights: Array1OfReal from TColStd ; + thePitches: Array1OfReal from TColStd ; + theIsPitches: Array1OfBoolean from TColStd); + ---Purpose: Sets parameters of pure spiral + + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiams: Array1OfReal from TColStd; + thePitches: Array1OfReal from TColStd ; + theNbTurns: Array1OfReal from TColStd); + ---Purpose: Sets parameters of general composite helix + + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiam: Real from Standard; + thePitches: Array1OfReal from TColStd ; + theNbTurns: Array1OfReal from TColStd); + ---Purpose: Sets parameters of pure helix + + SetParameters(me:out; theAxis: Ax3 from gp; + theDiam1: Real from Standard; + theDiam2: Real from Standard; + thePitches: Array1OfReal from TColStd ; + theNbTurns: Array1OfReal from TColStd); + ---Purpose: Sets parameters of pure spiral + + + SetApproxParameters(me:out; theTolerance: Real from Standard; + theMaxDegree: Integer from Standard; + theContinuity: Shape from GeomAbs); + ---Purpose: Sets parameters for approximation + + + Perform(me:out) ; + ---Purpose: Performs calculations + + ToleranceReached(me) returns Real from Standard; + ---Purpose: Gets tolerance reached by approximation + + ErrorStatus(me) + ---Purpose: Returns error status of algorithm + returns Integer from Standard; + + WarningStatus(me) + ---Purpose: Returns warning status of algorithm + returns Integer from Standard; + + Shape(me) returns Shape from TopoDS; + ---Purpose: Gets result of algorithm + ---C++: return const & + + BuildPart(me:in out; theAxis: Ax1 from gp; + thePStart: Pnt from gp; + theHeight: Real from Standard; + thePitch: Real from Standard; + theTaperAngle: Real from Standard; + theIsClockwise: Boolean from Standard; + thePart: out Wire from TopoDS) + + is private; + + Smoothing(me: in out; theParts: in out ListOfShape from TopTools) + is private; + + SmoothingEdges(me: in out; thePrev, theNext: in out Edge from TopoDS) + is private; + +fields + myAxis3: Ax3 from gp is protected; + myDiams: HArray1OfReal from TColStd is protected; + myHeights: HArray1OfReal from TColStd is protected; + myPitches: HArray1OfReal from TColStd is protected; + myIsPitches: HArray1OfBoolean from TColStd is protected; + myNParts: Integer from Standard; + + myTolerance: Real from Standard is protected; + myTolReached: Real from Standard is protected; + myContinuity: Shape from GeomAbs is protected; + myMaxDegree: Integer from Standard is protected; + myMaxSegments: Integer from Standard is protected; + + myErrorStatus : Integer from Standard is protected; + myWarningStatus : Integer from Standard is protected; + + myShape: Shape from TopoDS is protected; + + +end BuilderHelix; + diff --git a/src/HelixBRep/HelixBRep_BuilderHelix.cxx b/src/HelixBRep/HelixBRep_BuilderHelix.cxx new file mode 100644 index 0000000000..d58e1f44f6 --- /dev/null +++ b/src/HelixBRep/HelixBRep_BuilderHelix.cxx @@ -0,0 +1,630 @@ +// File: HelixBRep_BuilderHelix.cxx + +#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 + +//======================================================================= +//function : +//purpose : +//======================================================================= +HelixBRep_BuilderHelix::HelixBRep_BuilderHelix() + +{ + gp_Pnt aP0(0.,0.,0); + // + myAxis3.SetDirection(gp::DZ()); + myAxis3.SetLocation(aP0); + myDiams = NULL; + myHeights = NULL; + myPitches = NULL; + myIsPitches = NULL; + myNParts = 1; + myShape.Nullify(); + + // + myTolerance=0.0001; + myContinuity=GeomAbs_C1; + myMaxDegree=8; + myMaxSegments=1000; + // + myTolReached=99.; + // + myErrorStatus = 1; + myWarningStatus = 1; +} +//======================================================================= +//function : ~ +//purpose : +//======================================================================= +HelixBRep_BuilderHelix::~HelixBRep_BuilderHelix() +{ +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const TColStd_Array1OfReal& theDiams, + const TColStd_Array1OfReal& theHeights, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfBoolean& bIsPitches) +{ + myNParts = theDiams.Length() - 1; + + myAxis3 = theAxis; + + myDiams = NULL; + myHeights = NULL; + myPitches = NULL; + myShape.Nullify(); + + myErrorStatus = 1; + myWarningStatus = 1; + + if(myNParts != theHeights.Length() || myNParts != thePitches.Length() || myNParts != bIsPitches.Length()) { + Standard_ConstructionError:: + Raise("HelixBRep_BuilderHelix::SetParameters: wrong array dimension"); + } + + myDiams = new TColStd_HArray1OfReal(1, myNParts+1); + myHeights = new TColStd_HArray1OfReal(1, myNParts); + myPitches = new TColStd_HArray1OfReal(1, myNParts); + myIsPitches = new TColStd_HArray1OfBoolean(1, myNParts); + + + myDiams->ChangeArray1() = theDiams; + myHeights->ChangeArray1() = theHeights; + myPitches->ChangeArray1() = thePitches; + myIsPitches->ChangeArray1() = bIsPitches; + + myErrorStatus = 0; + myWarningStatus = 0; + +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const Standard_Real theDiam, + const TColStd_Array1OfReal& theHeights, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfBoolean& bIsPitches) +{ + Standard_Integer aNbParts = theHeights.Length(); + TColStd_Array1OfReal aDiams(1, aNbParts+1); + aDiams.Init(theDiam); + SetParameters(theAxis, aDiams, theHeights, thePitches, bIsPitches); +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const Standard_Real theDiam1, + const Standard_Real theDiam2, + const TColStd_Array1OfReal& theHeights, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfBoolean& bIsPitches) +{ + Standard_Integer aNbParts = theHeights.Length(); + TColStd_Array1OfReal aDiams(1, aNbParts+1); + + Standard_Integer i, j; + Standard_Real anH = 0.; + for(i = theHeights.Lower(); i <= theHeights.Upper(); ++i) { + anH += theHeights(i); + } + Standard_Real K = (theDiam2 - theDiam1)/anH; + aDiams(1) = theDiam1; + aDiams(aNbParts+1) = theDiam2; + + anH = theHeights(1); + for(i = theHeights.Lower()+1, j = 2; i <= theHeights.Upper(); ++i, ++j) { + aDiams(j) = theDiam1 + K * anH; + anH += theHeights(i); + } + + SetParameters(theAxis, aDiams, theHeights, thePitches, bIsPitches); +} + +//======================================================================= +//function : SetApproxParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetApproxParameters(const Standard_Real aTolerance, + const Standard_Integer aMaxDegree, + const GeomAbs_Shape aCont) +{ + myTolerance=aTolerance; + myMaxDegree=aMaxDegree; + myContinuity=aCont; +} + +//======================================================================= +//function : ToleranceReached +//purpose : +//======================================================================= +Standard_Real HelixBRep_BuilderHelix::ToleranceReached()const +{ + return myTolReached; +} +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::Perform() +{ + + if(myErrorStatus != 0) return; + + Standard_Integer i; + + myTolReached = 0.; + myShape.Nullify(); + BRep_Builder aBB; + //aBB.MakeCompound(TopoDS::Compound(myShape)); + + TopTools_ListOfShape anLst; + + gp_Ax1 anAxis(myAxis3.Axis()); + gp_Pnt aPStart = myAxis3.Location(); + aPStart.Translate(.5*myDiams->Value(1)*myAxis3.XDirection()); + Standard_Boolean bIsClockwise = myAxis3.Direct(); + + Standard_Real aHeight; + Standard_Real aPitch; + Standard_Real aTaperAngle; + + for(i = 1; i <= myNParts; ++i) { + + aHeight = myHeights->Value(i); + + if(myIsPitches->Value(i)) { + aPitch = myPitches->Value(i); + } + else { + aPitch = aHeight/myPitches->Value(i); + } + + aTaperAngle = ATan(.5*(myDiams->Value(i+1) - myDiams->Value(i))/aHeight); + + TopoDS_Wire aPart; + aBB.MakeWire(aPart); + + BuildPart(anAxis, aPStart, aHeight, aPitch, aTaperAngle, bIsClockwise, aPart); + if(myErrorStatus != 0) return; + + TopoDS_Vertex V1, V2; + + TopExp::Vertices(aPart, V1, V2); + + aPStart = BRep_Tool::Pnt(V2); + + anAxis.SetLocation(anAxis.Location().Translated(aHeight*anAxis.Direction())); + + anLst.Append(aPart); + //aBB.Add(myShape, aPart); + } + + Smoothing(anLst); + + TopTools_ListIteratorOfListOfShape anIt(anLst); + BRepBuilderAPI_MakeWire aMkWire(TopoDS::Wire(anLst.First())); + anIt.Next(); + for(; anIt.More(); anIt.Next()) { + aMkWire.Add(TopoDS::Wire(anIt.Value())); + } + + myShape = aMkWire.Shape(); + +} + +//======================================================================= +//function : BuildPart +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::BuildPart(const gp_Ax1& theAxis, + const gp_Pnt& thePStart, + const Standard_Real theHeight, + const Standard_Real thePitch, + const Standard_Real theTaperAngle, + const Standard_Boolean bIsClockwise, + TopoDS_Wire& thePart) +{ + + if(myErrorStatus != 0) return; + + myErrorStatus=0; + myWarningStatus=0; + + // + // 1. check & prepare data + Standard_Real aTolPrec, aDist, aDM, aTwoPI, aC1, aT2, aT1, aT0; + // + aTolPrec=myTolerance; + Standard_Real aTolAng = 1.e-7; + // + + if (theTaperAngle > M_PI/2. - aTolAng) { + myErrorStatus=13; // invalid TaperAngle value + return; + } + if (theHeight 0.) bIsOutWard = Standard_True; + // + const gp_Dir& aDir=theAxis.Direction(); + gp_Vec aVec1 = gp_Vec(aDir); + gp_Pnt aM0 = theAxis.Location(); + gp_Vec aVec(aM0, thePStart); + aDM=aVec1.Dot(aVec); + gp_Pnt aM1= aM0.Translated(aDM*aVec1); + gp_Vec aVecX(aM1, thePStart); + gp_Dir aDirX(aVecX); + gp_Ax2 aAx2(aM1, aDir, aDirX); + // + aTwoPI=2.*M_PI; + aC1=thePitch/aTwoPI; + aT0 = 0.; + aT1=aAngleStart; + + aT2=theHeight/aC1; + // + // 2. compute + Standard_Boolean bIsDone; + Standard_Integer iErr, aNbC, i; + HelixGeom_BuilderHelix aBH; + gp_Pnt aP1, aP2; + BRep_Builder aBB; + BRepBuilderAPI_MakeEdge aBME; + TopoDS_Vertex aV1, aV2; + //TopoDS_Wire aW; + TopoDS_Edge aE; + // + aBH.SetPosition(aAx2); + aBH.SetCurveParameters(aT0, aT2, thePitch, aDist, theTaperAngle, bIsClockwise); + aBH.SetTolerance(myTolerance); + aBH.SetApproxParameters(myContinuity, myMaxDegree, myMaxSegments); + // + aBH.Perform(); + iErr=aBH.ErrorStatus(); + if (iErr) { + myErrorStatus=2; + return; + } + // + aBB.MakeWire(thePart); + // + myTolReached=Max(myTolReached, aBH.ToleranceReached()); + TColGeom_SequenceOfCurve aSC; + aSC.Assign(aBH.Curves()); + if(aT1 < 0.) { + HelixGeom_BuilderHelix aBH1; + aBH1.SetPosition(aAx2); + aBH1.SetCurveParameters(aT1, aT0, thePitch, aDist, theTaperAngle, bIsClockwise); + aBH1.SetTolerance(myTolerance); + aBH1.SetApproxParameters(myContinuity, myMaxDegree, myMaxSegments); + // + aBH1.Perform(); + iErr=aBH1.ErrorStatus(); + if (iErr) { + myErrorStatus=2; + return; + } + + myTolReached = Max(myTolReached, aBH1.ToleranceReached()); + const TColGeom_SequenceOfCurve& aSC1=aBH1.Curves(); + Standard_Integer nbc = aSC1.Length(); + for(i = nbc; i >= 1; i--) { + aSC.Prepend(aSC1.Value(i)); + } + } + + aNbC=aSC.Length(); + for (i=1; i<=aNbC; ++i) { + Handle(Geom_Curve) aC=aSC(i); + // + if (i==1) { + if(aT1 > 0.) { + aT2=aC->LastParameter(); + Handle(Geom_TrimmedCurve) aCT = new Geom_TrimmedCurve(aC, aT1, aT2); + aC = aCT; + } + aT1=aC->FirstParameter(); + aC->D0(aT1, aP1); + aBB.MakeVertex(aV1, aP1, myTolReached); + aV1.Orientation(TopAbs_FORWARD); + } + // + aT2=aC->LastParameter(); + aC->D0(aT2, aP2); + aBB.MakeVertex(aV2, aP2, myTolReached); + aV2.Orientation(TopAbs_REVERSED); + // + aBME.Init(aC, aV1, aV2); + bIsDone=aBME.IsDone(); + if (!bIsDone) { + myErrorStatus=3; + return; + } + aE=aBME.Edge(); + aBB.UpdateEdge(aE, myTolReached); + aBB.Add(thePart, aE); + + // + aV1=aV2; + aV1.Orientation(TopAbs_FORWARD); + } + // + if(myTolReached > myTolerance) myWarningStatus = 1; + +} + +//======================================================================= +//function : Smoothing +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::Smoothing(TopTools_ListOfShape& theParts) +{ + if(theParts.Extent() == 1) return; + + BRepTools_WireExplorer anExpl; + + TopoDS_Wire aPrevWire = TopoDS::Wire(theParts.First()); + anExpl.Init(aPrevWire); + TopoDS_Edge aPrevEdge; + for(; anExpl.More(); anExpl.Next()) { + aPrevEdge = anExpl.Current(); + } + + TopTools_ListIteratorOfListOfShape anIter(theParts); + anIter.Next(); + for(; anIter.More(); anIter.Next()) { + TopoDS_Wire aNextWire = TopoDS::Wire(anIter.Value()); + anExpl.Clear(); + anExpl.Init(aNextWire); + TopoDS_Edge aNextEdge = anExpl.Current(); + + //Smoothing curves + SmoothingEdges(aPrevEdge, aNextEdge); + + for(; anExpl.More(); anExpl.Next()) { + aPrevEdge = anExpl.Current(); + } + } + +} +//======================================================================= +//function : Smoothing +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SmoothingEdges(TopoDS_Edge& thePrev, + TopoDS_Edge& theNext) +{ + + static const Standard_Real EpsAng = 1.e-7; + BRep_Builder aBB; + + Standard_Real f1, l1, f2, l2; + Handle(Geom_BSplineCurve) aCPrev = + Handle(Geom_BSplineCurve)::DownCast(BRep_Tool::Curve(thePrev, f1, l1)); + + Handle(Geom_BSplineCurve) aCNext = + Handle(Geom_BSplineCurve)::DownCast(BRep_Tool::Curve(theNext, f2, l2)); + + gp_Pnt P1, P2; + gp_Vec V1, V2; + + aCPrev->D1(l1, P1, V1); + aCNext->D1(f2, P2, V2); + + + if(V1.Angle(V2) < EpsAng) return; + + V1 = 0.5*(V1 + V2); + V2 = V1; + + Standard_Integer anErrorStatus = 1; + Standard_Integer aDegMax = Geom_BSplineCurve::MaxDegree(); + Standard_Integer aDeg = aCPrev->Degree(); + Standard_Integer i; + Standard_Boolean bPrevOK = Standard_False; + Standard_Boolean bNextOK = Standard_False; + + aCPrev->MovePointAndTangent(l1, P1, V1, myTolerance, 1, -1, anErrorStatus); + if(anErrorStatus != 0) { + for(i = aDeg + 1; i <= aDegMax; ++i) { + aCPrev->IncreaseDegree(i); + aCPrev->MovePointAndTangent(l1, P1, V1, myTolerance, 1, -1, anErrorStatus); + if(anErrorStatus == 0) { + bPrevOK = Standard_True; + break; + } + } + + } + else { + bPrevOK = Standard_True; + } + + if(bPrevOK) { + aBB.UpdateEdge(thePrev, aCPrev, BRep_Tool::Tolerance(thePrev)); + } + + aDeg = aCNext->Degree(); + aCNext->MovePointAndTangent(f2, P2, V2, myTolerance, -1, 1, anErrorStatus); + if(anErrorStatus != 0) { + for(i = aDeg + 1; i <= aDegMax; ++i) { + aCNext->IncreaseDegree(i); + aCNext->MovePointAndTangent(f2, P2, V2, myTolerance, -1, 1, anErrorStatus); + if(anErrorStatus == 0) { + bNextOK = Standard_True; + break; + } + } + + } + else { + bNextOK = Standard_True; + } + + if(bNextOK) { + aBB.UpdateEdge(theNext, aCNext, BRep_Tool::Tolerance(theNext)); + } + +} +//======================================================================= +//function : ErrorStatus +//purpose : +//======================================================================= +Standard_Integer HelixBRep_BuilderHelix::ErrorStatus()const +{ + return myErrorStatus; +} + +//======================================================================= +//function : WarningStatus +//purpose : +//======================================================================= +Standard_Integer HelixBRep_BuilderHelix::WarningStatus()const +{ + return myWarningStatus; +} + +//======================================================================= +//function : Shape +//purpose : +//======================================================================= +const TopoDS_Shape& HelixBRep_BuilderHelix::Shape() const +{ + return myShape; +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const TColStd_Array1OfReal& theDiams, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfReal& theNbTurns) + +{ + Standard_Integer aNbParts = theDiams.Length() - 1; + + if(aNbParts != thePitches.Length() || aNbParts != theNbTurns.Length()) { + Standard_ConstructionError:: + Raise("HelixBRep_BuilderHelix::SetParameters: wrong array dimension"); + } + + TColStd_Array1OfReal aHeights(1, aNbParts); + TColStd_Array1OfBoolean bIsPitches(1, aNbParts); + bIsPitches.Init(Standard_True); + Standard_Integer i, ip, in; + for(i = 1, ip = thePitches.Lower(), in = theNbTurns.Lower(); i <= thePitches.Length(); ++i, ip++, in++) { + aHeights(i) = thePitches(ip)*theNbTurns(in); + } + + SetParameters(theAxis, theDiams, aHeights, thePitches, bIsPitches); +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const Standard_Real theDiam, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfReal& theNbTurns) +{ + Standard_Integer aNbParts = thePitches.Length(); + + if(aNbParts != theNbTurns.Length()) { + Standard_ConstructionError:: + Raise("HelixBRep_BuilderHelix::SetParameters: wrong array dimension"); + } + + TColStd_Array1OfReal aHeights(1, aNbParts); + TColStd_Array1OfBoolean bIsPitches(1, aNbParts); + bIsPitches.Init(Standard_True); + Standard_Integer i, ip, in; + for(i = 1, ip = thePitches.Lower(), in = theNbTurns.Lower(); i <= thePitches.Length(); ++i, ip++, in++) { + aHeights(i) = thePitches(ip)*theNbTurns(in); + } + + SetParameters(theAxis, theDiam, aHeights, thePitches, bIsPitches); +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= +void HelixBRep_BuilderHelix::SetParameters(const gp_Ax3& theAxis, + const Standard_Real theDiam1, + const Standard_Real theDiam2, + const TColStd_Array1OfReal& thePitches, + const TColStd_Array1OfReal& theNbTurns) +{ + Standard_Integer aNbParts = thePitches.Length(); + + if(aNbParts != theNbTurns.Length()) { + Standard_ConstructionError:: + Raise("HelixBRep_BuilderHelix::SetParameters: wrong array dimension"); + } + + TColStd_Array1OfReal aHeights(1, aNbParts); + TColStd_Array1OfBoolean bIsPitches(1, aNbParts); + bIsPitches.Init(Standard_True); + Standard_Integer i, ip, in; + for(i = 1, ip = thePitches.Lower(), in = theNbTurns.Lower(); i <= thePitches.Length(); ++i, ip++, in++) { + aHeights(i) = thePitches(ip)*theNbTurns(in); + } + + SetParameters(theAxis, theDiam1, theDiam2, aHeights, thePitches, bIsPitches); +} diff --git a/src/HelixGeom/HelixGeom.cdl b/src/HelixGeom/HelixGeom.cdl new file mode 100644 index 0000000000..62d0ac4480 --- /dev/null +++ b/src/HelixGeom/HelixGeom.cdl @@ -0,0 +1,35 @@ +-- File: HelixGeom.cdl + + +package HelixGeom + + ---Purpose: + +uses + MMgt, + gp, + TColStd, + GeomAbs, + Geom, + TColGeom, + GeomAdaptor, + Adaptor3d, + GeomFill + +is + + deferred class BuilderApproxCurve; + deferred class BuilderHelixGen; + + class HelixCurve; + class HHelixCurve; + class BuilderHelixCoil; + class BuilderHelix; + class Tools; + + -- + private class GHHelixCurve instantiates GenHCurve from Adaptor3d + (HelixCurve from HelixGeom); + +end HelixGeom; + diff --git a/src/HelixGeom/HelixGeom_BuilderApproxCurve.cdl b/src/HelixGeom/HelixGeom_BuilderApproxCurve.cdl new file mode 100644 index 0000000000..b2292eedee --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderApproxCurve.cdl @@ -0,0 +1,72 @@ +-- File: HelixGeom_BuilderApproxCurve.cdl + + +deferred class BuilderApproxCurve from HelixGeom + + ---Purpose: Root class for algorithm of building helix curves + +uses + Shape from GeomAbs, + SequenceOfCurve from TColGeom + +--raises + +is + Initialize + ---Purpose: Sets default values of aprroximation parameters + returns BuilderApproxCurve from HelixGeom; + ---C++: alias "Standard_EXPORT virtual ~HelixGeom_BuilderApproxCurve();" + + SetApproxParameters(me:out; + aCont : Shape from GeomAbs; + aMaxDegree: Integer from Standard; + aMaxSeg : Integer from Standard); + ---Purpose: Sets aprroximation parameters + + ApproxParameters(me; + aCont :out Shape from GeomAbs; + aMaxDegree:out Integer from Standard; + aMaxSeg :out Integer from Standard); + ---Purpose: Gets aprroximation parameters + + SetTolerance(me:out; + aTolerance: Real from Standard); + ---Purpose: Sets aprroximation tolerance + + Tolerance(me) + returns Real from Standard; + ---Purpose: Gets aprroximation tolerance + + ToleranceReached(me) + ---Purpose: Gets actual tolerance reached by approximation algorithm + returns Real from Standard; + + Curves(me) + ---Purpose: Gets sequence of Bspline curves representing helix coins. + returns SequenceOfCurve from TColGeom; + ---C++: return const & + + ErrorStatus(me) + ---Purpose: Returns error status of algorithm + returns Integer from Standard; + + WarningStatus(me) + ---Purpose: Returns warning status of algorithm + returns Integer from Standard; + + Perform(me:out) + ---Purpose: Performs calculations. + -- Must be redefined. + is deferred; +fields + myErrorStatus : Integer from Standard is protected; + myWarningStatus : Integer from Standard is protected; + myTolerance : Real from Standard is protected; + myCont : Shape from GeomAbs is protected; + myMaxDegree : Integer from Standard is protected; + myMaxSeg : Integer from Standard is protected; + -- + myTolReached : Real from Standard is protected; + myCurves : SequenceOfCurve from TColGeom is protected; + +end BuilderApproxCurve; diff --git a/src/HelixGeom/HelixGeom_BuilderApproxCurve.cxx b/src/HelixGeom/HelixGeom_BuilderApproxCurve.cxx new file mode 100644 index 0000000000..925d4d6512 --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderApproxCurve.cxx @@ -0,0 +1,100 @@ +// File: HelixGeom_BuilderApproxCurve.cxx + +#include + +//======================================================================= +//function : +//purpose : +//======================================================================= +HelixGeom_BuilderApproxCurve::HelixGeom_BuilderApproxCurve() +{ + myTolerance=0.0001; + myCont=GeomAbs_C2; + myMaxDegree=8; + myMaxSeg=150; + // + myTolReached=99.; +} +//======================================================================= +//function : ~ +//purpose : +//======================================================================= +HelixGeom_BuilderApproxCurve::~HelixGeom_BuilderApproxCurve() +{ +} +//======================================================================= +//function : SetApproxParameters +//purpose : +//======================================================================= +void HelixGeom_BuilderApproxCurve::SetApproxParameters(const GeomAbs_Shape aCont, + const Standard_Integer aMaxDegree, + const Standard_Integer aMaxSeg) +{ + + myCont=aCont; + myMaxDegree=aMaxDegree; + myMaxSeg=aMaxSeg; +} +//======================================================================= +//function : ApproxParameters +//purpose : +//======================================================================= +void HelixGeom_BuilderApproxCurve::ApproxParameters(GeomAbs_Shape& aCont, + Standard_Integer& aMaxDegree, + Standard_Integer& aMaxSeg)const +{ + aCont=myCont; + aMaxDegree=myMaxDegree; + aMaxSeg=myMaxSeg; +} +//======================================================================= +//function : SetTolerance +//purpose : +//======================================================================= +void HelixGeom_BuilderApproxCurve::SetTolerance(const Standard_Real aTolerance) +{ + myTolerance=aTolerance; +} +//======================================================================= +//function : Tolerance +//purpose : +//======================================================================= +Standard_Real HelixGeom_BuilderApproxCurve::Tolerance()const +{ + return myTolerance; +} +//======================================================================= +//function : ToleranceReached +//purpose : +//======================================================================= +Standard_Real HelixGeom_BuilderApproxCurve::ToleranceReached()const +{ + return myTolReached; +} + +//======================================================================= +//function : Curves +//purpose : +//======================================================================= +const TColGeom_SequenceOfCurve& HelixGeom_BuilderApproxCurve::Curves()const +{ + return myCurves; +} + +//======================================================================= +//function : ErrorStatus +//purpose : +//======================================================================= +Standard_Integer HelixGeom_BuilderApproxCurve::ErrorStatus()const +{ + return myErrorStatus; +} + +//======================================================================= +//function : WarningStatus +//purpose : +//======================================================================= +Standard_Integer HelixGeom_BuilderApproxCurve::WarningStatus()const +{ + return myWarningStatus; +} diff --git a/src/HelixGeom/HelixGeom_BuilderHelix.cdl b/src/HelixGeom/HelixGeom_BuilderHelix.cdl new file mode 100644 index 0000000000..1ea1958af7 --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelix.cdl @@ -0,0 +1,38 @@ +-- File: HelixGeom_BuilderHelix.cdl + + +class BuilderHelix from HelixGeom + inherits BuilderHelixGen from HelixGeom + + ---Purpose: Upper level class for geometrical algorithm of building + -- helix curves using arbitrary axis + +uses + Ax2 from gp + +--raises + +is + Create + ---Purpose: Empty constructor + returns BuilderHelix from HelixGeom; + ---C++: alias "Standard_EXPORT virtual ~HelixGeom_BuilderHelix();" + + SetPosition (me:out; + ---Purpose: Sets coordinate axes for helix + aAx2 : Ax2 from gp); + + Position (me) + ---Purpose: Gets coordinate axes for helix + returns Ax2 from gp; + ---C++: return const & + + Perform(me:out) + ---Purpose: Performs calculations + is redefined; + +fields + myPosition: Ax2 from gp is protected; + +end BuilderHelix; + diff --git a/src/HelixGeom/HelixGeom_BuilderHelix.cxx b/src/HelixGeom/HelixGeom_BuilderHelix.cxx new file mode 100644 index 0000000000..732998e378 --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelix.cxx @@ -0,0 +1,165 @@ +// File: HelixGeom_BuilderHelix.cxx + + +#include +#include +#include +#include +#include +#include + + +//======================================================================= +//function : +//purpose : +//======================================================================= +HelixGeom_BuilderHelix::HelixGeom_BuilderHelix() +: + HelixGeom_BuilderHelixGen() +{ +} +//======================================================================= +//function : ~ +//purpose : +//======================================================================= +HelixGeom_BuilderHelix::~HelixGeom_BuilderHelix() +{ +} +//======================================================================= +//function : SetPosition +//purpose : +//======================================================================= +void HelixGeom_BuilderHelix::SetPosition(const gp_Ax2& aAx2) +{ + myPosition=aAx2; +} +//======================================================================= +//function : Position +//purpose : +//======================================================================= +const gp_Ax2& HelixGeom_BuilderHelix::Position()const +{ + return myPosition; +} +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void HelixGeom_BuilderHelix::Perform() +{ + myErrorStatus=0; + myWarningStatus=0; + // + Standard_Integer iErr, aN, i, aNbC; + Standard_Real aTwoPI, dT, aT1x, aT2x, aTR; + //HelixGeom_HelixCurve aHC; + HelixGeom_BuilderHelixCoil aBHC; + // + myCurves.Clear(); + myTolReached=-1.; + aTwoPI=2.*M_PI; + // + aBHC.SetTolerance(myTolerance); + aBHC.SetApproxParameters(myCont, myMaxDegree, myMaxSeg); + // + dT=myT2-myT1; + aN=(Standard_Integer)(dT/aTwoPI); + // + if (!aN) { + aBHC.SetCurveParameters(myT1, myT2, myPitch, myRStart, myTaperAngle, myIsClockWise); + aBHC.Perform(); + iErr=aBHC.ErrorStatus(); + if (iErr) { + myErrorStatus=2; + return; + } + const TColGeom_SequenceOfCurve& aSC=aBHC.Curves(); + const Handle(Geom_Curve)& aC=aSC(1); + myCurves.Append(aC); + myTolReached=aBHC.ToleranceReached(); + } + // + else { + Standard_Boolean bIsCylindrical; + Standard_Real aTolAngle; + // + aTolAngle=1.e-4; + bIsCylindrical=fabs(myTaperAngle)1 && bIsCylindrical) { + Handle(Geom_Curve) aCi; + gp_Pnt aP1, aPi; + // + const Handle(Geom_Curve)& aC1=myCurves(1); + aC1->D0(aC1->FirstParameter(), aP1); + aPi.SetCoord(aP1.X(), aP1.Y(), aP1.Z()+(i-1)*myPitch); + aCi=Handle(Geom_Curve)::DownCast(aC1->Translated(aP1, aPi)); + // + myCurves.Append(aCi); + // + aT1x=aT2x; + aT2x=aT1x+aTwoPI; + // + continue; + } + + aBHC.SetCurveParameters(aT1x, aT2x, myPitch, myRStart, myTaperAngle, myIsClockWise); + // + aBHC.Perform(); + iErr=aBHC.ErrorStatus(); + if (iErr) { + myErrorStatus=2; + return; + } + // + const TColGeom_SequenceOfCurve& aSC=aBHC.Curves(); + const Handle(Geom_Curve)& aC=aSC(1); + myCurves.Append(aC); + aTR=aBHC.ToleranceReached(); + if(aTR>myTolReached) { + myTolReached=aTR; + } + // + aT1x=aT2x; + aT2x=aT1x+aTwoPI; + } // for (i=1; i<=aN; ++i) { + // + aT2x=myT2; + Standard_Real eps = 1.e-7*aTwoPI; + if (fabs (aT2x-aT1x)>eps) { + aBHC.SetCurveParameters(aT1x, aT2x, myPitch, myRStart, myTaperAngle, myIsClockWise); + aBHC.Perform(); + iErr=aBHC.ErrorStatus(); + if (iErr) { + myErrorStatus=2; + return; + } + // + const TColGeom_SequenceOfCurve& aSC=aBHC.Curves(); + const Handle(Geom_Curve)& aC=aSC(1); + myCurves.Append(aC); + aTR=aBHC.ToleranceReached(); + if(aTR>myTolReached) { + myTolReached=aTR; + } + } + } + // + // Transformation + gp_Trsf aTrsf; + gp_Ax3 aAx3, aAx3x(myPosition); + // + aTrsf.SetDisplacement(aAx3, aAx3x); + // + aNbC=myCurves.Length(); + for (i=1; i<=aNbC; ++i) { + Handle(Geom_Curve)& aC=myCurves(i); + aC->Transform(aTrsf); + } + // +} + diff --git a/src/HelixGeom/HelixGeom_BuilderHelixCoil.cdl b/src/HelixGeom/HelixGeom_BuilderHelixCoil.cdl new file mode 100644 index 0000000000..175dbed1da --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelixCoil.cdl @@ -0,0 +1,24 @@ +-- File: HelixGeom_BuilderHelixCoil.cdl + +class BuilderHelixCoil from HelixGeom + inherits BuilderHelixGen from HelixGeom + + ---Purpose: Implementation of algorithm for building helix coil with + -- axis OZ + +--uses +--raises + +is + Create + ---Purpose: Empty constructor + returns BuilderHelixCoil from HelixGeom; + ---C++: alias "Standard_EXPORT virtual ~HelixGeom_BuilderHelixCoil();" + + Perform(me:out) + ---Purpose: Performs calculations + is redefined; + +end BuilderHelixCoil; + + diff --git a/src/HelixGeom/HelixGeom_BuilderHelixCoil.cxx b/src/HelixGeom/HelixGeom_BuilderHelixCoil.cxx new file mode 100644 index 0000000000..2021fc4061 --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelixCoil.cxx @@ -0,0 +1,63 @@ +// File: HelixGeom_BuilderHelixCoil.cxx + + +#include +#include +#include +#include +#include + +//======================================================================= +//function : HelixGeom_BuilderHelixCoil +//purpose : +//======================================================================= +HelixGeom_BuilderHelixCoil::HelixGeom_BuilderHelixCoil() +: + HelixGeom_BuilderHelixGen() +{ + myT1=0.; + myT2=2.*M_PI; + myPitch=1.; + myRStart=1.; + myTaperAngle=0.; + myIsClockWise=Standard_True; +} +//======================================================================= +//function : ~ +//purpose : +//======================================================================= +HelixGeom_BuilderHelixCoil::~HelixGeom_BuilderHelixCoil() +{ +} +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void HelixGeom_BuilderHelixCoil::Perform() +{ + myErrorStatus=0; + myWarningStatus=0; + // + Standard_Integer iErr; + HelixGeom_HelixCurve aAdaptor; + Handle(HelixGeom_HHelixCurve) aHAdaptor; + Handle(Geom_BSplineCurve)aBC; + // + myCurves.Clear(); + // + aAdaptor.Load(myT1, myT2, myPitch, myRStart, myTaperAngle, myIsClockWise); + aHAdaptor=new HelixGeom_HHelixCurve(aAdaptor); + // + iErr=HelixGeom_Tools::ApprCurve3D(aHAdaptor, + myTolerance, myCont, myMaxSeg, myMaxDegree, + aBC, myTolReached); + if(iErr) { + myErrorStatus=2; + } + else { + myCurves.Append(aBC); + } +} + + + diff --git a/src/HelixGeom/HelixGeom_BuilderHelixGen.cdl b/src/HelixGeom/HelixGeom_BuilderHelixGen.cdl new file mode 100644 index 0000000000..e5f82b9941 --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelixGen.cdl @@ -0,0 +1,45 @@ +-- File: HelixGeom_BuilderHelixGen.cdl + +deferred class BuilderHelixGen from HelixGeom + inherits BuilderApproxCurve from HelixGeom + + ---Purpose: Root class for algorithms of building helix curves + + +--uses +--raises + +is + Initialize + ---Purpose: Sets default parameters + returns BuilderHelixGen from HelixGeom; + ---C++: alias "Standard_EXPORT virtual ~HelixGeom_BuilderHelixGen();" + + SetCurveParameters(me:out; + aT1 :Real from Standard; + aT2 :Real from Standard; + aPitch :Real from Standard; + aRStart :Real from Standard; + aTaperAngle :Real from Standard; + bIsClockwise :Boolean from Standard); + ---Purpose: Sets parameters for building helix curves + + CurveParameters(me; + aT1 :out Real from Standard; + aT2 :out Real from Standard; + aPitch :out Real from Standard; + aRStart :out Real from Standard; + aTaperAngle :out Real from Standard; + bIsClockwise :out Boolean from Standard); + ---Purpose: Gets parameters for building helix curves + +fields + myT1 : Real from Standard is protected; + myT2 : Real from Standard is protected; + myPitch : Real from Standard is protected; + myRStart : Real from Standard is protected; + myTaperAngle : Real from Standard is protected; + myIsClockWise: Boolean from Standard is protected; + +end BuilderHelixGen; + diff --git a/src/HelixGeom/HelixGeom_BuilderHelixGen.cxx b/src/HelixGeom/HelixGeom_BuilderHelixGen.cxx new file mode 100644 index 0000000000..fd0117ceda --- /dev/null +++ b/src/HelixGeom/HelixGeom_BuilderHelixGen.cxx @@ -0,0 +1,58 @@ +// File: HelixGeom_BuilderHelixGen.cxx + +#include + +//======================================================================= +//function : +//purpose : +//======================================================================= +HelixGeom_BuilderHelixGen::HelixGeom_BuilderHelixGen() +: + HelixGeom_BuilderApproxCurve() +{ +} +//======================================================================= +//function : ~ +//purpose : +//======================================================================= +HelixGeom_BuilderHelixGen::~HelixGeom_BuilderHelixGen() +{ +} +//======================================================================= +//function : SetCurveParameters +//purpose : +//======================================================================= +void HelixGeom_BuilderHelixGen::SetCurveParameters(const Standard_Real aT1, + const Standard_Real aT2, + const Standard_Real aPitch, + const Standard_Real aRStart, + const Standard_Real aTaperAngle, + const Standard_Boolean aIsCW) +{ + myT1=aT1; + myT2=aT2; + myPitch=aPitch; + myRStart=aRStart; + myTaperAngle=aTaperAngle; + myIsClockWise=aIsCW; +} +//======================================================================= +//function : CurveParameters +//purpose : +//======================================================================= +void HelixGeom_BuilderHelixGen::CurveParameters(Standard_Real& aT1, + Standard_Real& aT2, + Standard_Real& aPitch, + Standard_Real& aRStart, + Standard_Real& aTaperAngle, + Standard_Boolean& aIsClockWise)const +{ + aT1=myT1; + aT2=myT2; + aPitch=myPitch; + aRStart=myRStart; + aTaperAngle=myTaperAngle; + aIsClockWise=myIsClockWise; +} + + diff --git a/src/HelixGeom/HelixGeom_HHelixCurve.cdl b/src/HelixGeom/HelixGeom_HHelixCurve.cdl new file mode 100644 index 0000000000..1750654637 --- /dev/null +++ b/src/HelixGeom/HelixGeom_HHelixCurve.cdl @@ -0,0 +1,35 @@ +-- File: HelixGeom_HHelixCurve.cdl + +class HHelixCurve from HelixGeom + inherits GHHelixCurve from HelixGeom + + ---Purpose: HAdaptor class for helix curve + +uses + HelixCurve from HelixGeom + +--raises + +is + Create + ---Purpose: Empty constructor + returns HHelixCurve from HelixGeom; + + Create(aC: HelixCurve from HelixGeom) + ---Purpose: Constructor by corresponding adaptor curve + returns HHelixCurve from HelixGeom; + + Create(aT1:Real from Standard; + aT2:Real from Standard; + aPitch:Real from Standard; + aRStart:Real from Standard; + aTaperAngle:Real from Standard; + aIsCW:Boolean from Standard) + ---Purpose: Constructor by parameters + returns HHelixCurve from HelixGeom; + +--fields + +end HHelixCurve; + + diff --git a/src/HelixGeom/HelixGeom_HHelixCurve.cxx b/src/HelixGeom/HelixGeom_HHelixCurve.cxx new file mode 100644 index 0000000000..afb2dc3530 --- /dev/null +++ b/src/HelixGeom/HelixGeom_HHelixCurve.cxx @@ -0,0 +1,39 @@ +// File: HelixGeom_HHelixCurve.cxx + +#include + +//======================================================================= +//function : HelixGeom_HHelixCurve +//purpose : +//======================================================================= +HelixGeom_HHelixCurve::HelixGeom_HHelixCurve() +{ +} +//======================================================================= +//function : HelixGeom_HHelixCurve// Lastly modified by : +// +---------------------------------------------------------------------------+ +// ! ifv ! Creation !$Date: 2007-10-19 18:21:42 $! %V%-%L%! +// +---------------------------------------------------------------------------+ + + +//purpose : +//======================================================================= +HelixGeom_HHelixCurve::HelixGeom_HHelixCurve(const HelixGeom_HelixCurve& aC) +: HelixGeom_GHHelixCurve(aC) +{ +} +//======================================================================= +//function : HelixGeom_HHelixCurve +//purpose : +//======================================================================= +HelixGeom_HHelixCurve::HelixGeom_HHelixCurve(const Standard_Real aT1, + const Standard_Real aT2, + const Standard_Real aPitch, + const Standard_Real aRStart, + const Standard_Real aTaperAngle, + const Standard_Boolean aIsCW) +{ + ChangeCurve().Load(aT1, aT2, aPitch, aRStart, aTaperAngle, aIsCW); +} + + diff --git a/src/HelixGeom/HelixGeom_HelixCurve.cdl b/src/HelixGeom/HelixGeom_HelixCurve.cdl new file mode 100644 index 0000000000..6be35288e5 --- /dev/null +++ b/src/HelixGeom/HelixGeom_HelixCurve.cdl @@ -0,0 +1,140 @@ +-- File: HelixGeom_HelixCurve.cdl + +class HelixCurve from HelixGeom + inherits Curve from Adaptor3d + + ---Purpose: Adaptor class for calculation helix curve + +uses + Shape from GeomAbs, + Pnt from gp, + Vec from gp, + Array1OfReal from TColStd + +raises + ConstructionError from Standard, + OutOfRange from Standard, + DomainError from Standard +is + Create + ---Purpose: Adaptor class for calculation helix curve + -- implementation of analytical expressions + returns HelixCurve from HelixGeom; + + Load(me:out); + ---Purpose: Sets default values for parameters + + Load(me:out; + aT1:Real from Standard; + aT2:Real from Standard; + aPitch:Real from Standard; + aRStart:Real from Standard; + aTaperAngle:Real from Standard; + aIsCW:Boolean from Standard) + ---Purpose: Sets helix parameters + raises ConstructionError from Standard; + + FirstParameter(me) + ---Purpose: Gets first parameter + returns Real from Standard + is redefined; + + LastParameter(me) + ---Purpose: Gets last parameter + returns Real from Standard + is redefined; + + Continuity(me) + ---Purpose: Gets continuity + returns Shape from GeomAbs + is redefined; + + NbIntervals(me; + S : Shape from GeomAbs) + ---Purpose: Gets number of intervals + returns Integer from Standard + is redefined; + + Intervals(me; + T :out Array1OfReal from TColStd; + S : Shape from GeomAbs) + ---Purpose: Gets parametric intervals + is redefined; + + Resolution(me; R3d :Real from Standard) + ---Purpose: Gets parametric resolution + returns Real from Standard + is redefined; + + IsClosed(me) + ---Purpose: Returns False + returns Boolean from Standard + is redefined; + + IsPeriodic(me) + ---Purpose: Returns False + returns Boolean from Standard + is redefined; + + Period(me) + ---Purpose: Returns 2*PI + returns Real from Standard + raises DomainError from Standard + is redefined; + + Value(me; + U : Real from Standard) + ---Purpose: Gets curve point for parameter U + returns Pnt from gp + is redefined; + + D0 (me; + U : Real from Standard; + P : out Pnt from gp) + ---Purpose: Gets curve point for parameter U + is redefined; + + D1 (me; + U : Real from Standard; + P : out Pnt from gp; + V1: out Vec from gp) + ---Purpose: Gets curve point and first derivatives + -- for parameter U + is redefined; + + + D2 (me; + U : Real from Standard; + P : out Pnt from gp; + V1 : out Vec from gp; + V2 : out Vec from gp) + ---Purpose: Gets curve point, first and second derivatives + -- for parameter U + is redefined; + + + DN (me; + U : Real from Standard; + N : Integer from Standard) + ---Purpose: Gets curve derivative of demanded order + -- for parameter U + returns Vec from gp + raises OutOfRange from Standard + is redefined; + +fields + myFirst : Real from Standard is protected; + myLast : Real from Standard is protected; + myPitch : Real from Standard is protected; + myRStart : Real from Standard is protected; + myTaperAngle : Real from Standard is protected; + myIsClockWise: Boolean from Standard is protected; + -- + -- private + myC1 : Real from Standard is protected; + myTgBeta : Real from Standard is protected; + myTolAngle : Real from Standard is protected; + +end HelixCurve; + + diff --git a/src/HelixGeom/HelixGeom_HelixCurve.cxx b/src/HelixGeom/HelixGeom_HelixCurve.cxx new file mode 100644 index 0000000000..48f8e08d2c --- /dev/null +++ b/src/HelixGeom/HelixGeom_HelixCurve.cxx @@ -0,0 +1,288 @@ +// File: HelixGeom_HelixCurve.cxx + +#include +#include +#include +#include +#include +#include + +//======================================================================= +//function : HelixGeom_HelixCurve +//purpose : +//======================================================================= +HelixGeom_HelixCurve::HelixGeom_HelixCurve() +{ + myFirst=0.; + myLast=2.*M_PI; + myPitch=1.; + myRStart=1.; + myTaperAngle=0.; + myIsClockWise=Standard_True; + // + myC1=myPitch/myLast; + myTgBeta=0.; + myTolAngle=1.e-4; +} +//======================================================================= +//function : Load +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::Load() +{ + Load(myFirst, myLast, myPitch, myRStart, myTaperAngle, myIsClockWise); +} +//======================================================================= +//function : Load +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::Load(const Standard_Real aT1, + const Standard_Real aT2, + const Standard_Real aPitch, + const Standard_Real aRStart, + const Standard_Real aTaperAngle, + const Standard_Boolean aIsCW) +{ + char buf[]={"HelixGeom_HelixCurve::Load"}; + Standard_Real aTwoPI, aHalfPI; + // + aTwoPI=2.*M_PI; + aHalfPI=0.5*M_PI; + // + myFirst=aT1; + myLast=aT2; + myPitch=aPitch; + myRStart=aRStart; + myTaperAngle=aTaperAngle; + myIsClockWise=aIsCW; + // + if (aT1>=aT2) { + Standard_ConstructionError::Raise(buf); + } + if (myPitch<0.) { + Standard_ConstructionError::Raise(buf); + } + if (myRStart<0.) { + Standard_ConstructionError::Raise(buf); + } + if (myTaperAngle<=-aHalfPI || + myTaperAngle>=aHalfPI) { + Standard_ConstructionError::Raise(buf); + } + // + myC1=myPitch/aTwoPI; + if (fabs(myTaperAngle)>myTolAngle) { + myTgBeta=tan(myTaperAngle); + } +} +//======================================================================= +//function : FirstParameter +//purpose : +//======================================================================= +Standard_Real HelixGeom_HelixCurve::FirstParameter() const +{ + return myFirst; +} +//======================================================================= +//function : LastParameter +//purpose : +//======================================================================= +Standard_Real HelixGeom_HelixCurve::LastParameter() const +{ + return myLast; +} +//======================================================================= +//function : Continuity +//purpose : +//======================================================================= +GeomAbs_Shape HelixGeom_HelixCurve::Continuity() const +{ + return GeomAbs_CN; +} +//======================================================================= +//function : NbIntervals +//purpose : +//======================================================================= +Standard_Integer HelixGeom_HelixCurve::NbIntervals(const GeomAbs_Shape ) const +{ + return 1; +} +//======================================================================= +//function : Intervals +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::Intervals(TColStd_Array1OfReal& T, + const GeomAbs_Shape) const +{ + T(1)=myFirst; + T(2)=myLast; +} +//======================================================================= +//function : Resolution +//purpose : +//======================================================================= +Standard_Real HelixGeom_HelixCurve::Resolution(const Standard_Real) const +{ + Standard_NotImplemented::Raise("HelixGeom_HelixCurve::Resolution"); + return 0.; +} +//======================================================================= +//function : IsClosed +//purpose : +//======================================================================= +Standard_Boolean HelixGeom_HelixCurve::IsClosed() const +{ + Standard_NotImplemented::Raise("HelixGeom_HelixCurve::IsClosed"); + return Standard_False; +} +//======================================================================= +//function : IsPeriodic +//purpose : +//======================================================================= +Standard_Boolean HelixGeom_HelixCurve::IsPeriodic() const +{ + Standard_NotImplemented::Raise("HelixGeom_HelixCurve::IsPeriodic"); + return Standard_False; +} +//======================================================================= +//function : Period +//purpose : +//======================================================================= +Standard_Real HelixGeom_HelixCurve::Period()const +{ + Standard_DomainError::Raise("HelixGeom_HelixCurve::Periodic"); + return 0.; +} +//======================================================================= +//function : Value +//purpose : +//======================================================================= +gp_Pnt HelixGeom_HelixCurve::Value(const Standard_Real aT) const +{ + Standard_Real aST, aCT, aX, aY, aZ, a1; + // + aCT=cos(aT); + aST=sin(aT); + a1=myRStart+myC1*myTgBeta*aT; + // + aX=a1*aCT; + aY=a1*aST; + if (!myIsClockWise) { + aY=-aY; + } + aZ=myC1*aT; + return gp_Pnt(aX, aY, aZ); +} +//======================================================================= +//function : D0 +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::D0(const Standard_Real aT, + gp_Pnt& aP) const +{ + aP=Value(aT); +} +//======================================================================= +//function : D1 +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::D1(const Standard_Real aT, + gp_Pnt& aP, + gp_Vec& aV1) const +{ + Standard_Real aST, aCT, aX, aY, aZ, a1, a2; + // + aCT=cos(aT); + aST=sin(aT); + // + a1=myRStart+myC1*myTgBeta*aT; + // + aX=a1*aCT; + aY=a1*aST; + if (!myIsClockWise) { + aY=-aY; + } + aZ=myC1*aT; + aP.SetCoord(aX, aY, aZ); + // + a1=myC1*myTgBeta; + a2=myRStart+a1*aT; + // + aX=a1*aCT-a2*aST; + aY=a1*aST+a2*aCT; + if (!myIsClockWise) { + aY=-aY; + } + aZ=myC1; + aV1.SetCoord(aX, aY, aZ); +} +//======================================================================= +//function : D2 +//purpose : +//======================================================================= +void HelixGeom_HelixCurve::D2(const Standard_Real aT, + gp_Pnt& aP, + gp_Vec& aV1, + gp_Vec& aV2) const +{ + Standard_Real aST, aCT, aX, aY, aZ, a1, a2; + // + aCT=cos(aT); + aST=sin(aT); + // + a1=myRStart+myC1*myTgBeta*aT; + // + aX=a1*aCT; + aY=a1*aST; + if (!myIsClockWise) { + aY=-aY; + } + aZ=myC1*aT; + aP.SetCoord(aX, aY, aZ); + // + a1=myC1*myTgBeta; + a2=myRStart+a1*aT; + // + aX=a1*aCT-a2*aST; + aY=a1*aST+a2*aCT; + if (!myIsClockWise) { + aY=-aY; + } + aZ=myC1; + aV1.SetCoord(aX, aY, aZ); + // + a1=2.*a1; + aX=-a2*aCT-a1*aST; + aY=-a2*aST-a1*aCT; + if (!myIsClockWise) { + aY=-aY; + } + aZ=0.; + aV2.SetCoord(aX, aY, aZ); +} + +//======================================================================= +//function : DN +//purpose : +//======================================================================= +gp_Vec HelixGeom_HelixCurve::DN(const Standard_Real aT, + const Standard_Integer aN) const +{ + gp_Pnt aP; + gp_Vec aV1, aV2; + // + switch (aN) { + case 1: + D1(aT, aP, aV1); + break; + case 2: + D2(aT, aP, aV1, aV2); + break; + default: + Standard_NotImplemented::Raise("HelixGeom_HelixCurve::DN"); + break; + } + return gp_Vec(aV1); +} + + diff --git a/src/HelixGeom/HelixGeom_Tools.cdl b/src/HelixGeom/HelixGeom_Tools.cdl new file mode 100644 index 0000000000..6c0aed68fa --- /dev/null +++ b/src/HelixGeom/HelixGeom_Tools.cdl @@ -0,0 +1,42 @@ +-- File: HelixGeom_Tools.cdl + + +class Tools from HelixGeom + + ---Purpose: Approximation algorithms for bulding helix curves + +uses + HCurve from Adaptor3d, + BSplineCurve from Geom, + Shape from GeomAbs +--raises + +is + ApprHelix(myclass; + aT1 :Real from Standard; + aT2 :Real from Standard; + aPitch :Real from Standard; + aRStart :Real from Standard; + aTaperAngle:Real from Standard; + aIsCW :Boolean from Standard; + aTol :Real from Standard; + theBSpl :out BSplineCurve from Geom; + theMaxError:out Real from Standard) + ---Purpose: Bulding helix curves + returns Integer from Standard; + + ApprCurve3D(myclass; + theHC :out HCurve from Adaptor3d; + theTol : Real from Standard; + theCont : Shape from GeomAbs; + theMaxSeg : Integer from Standard; + theMaxDeg : Integer from Standard; + theBSpl :out BSplineCurve from Geom; + theMaxError:out Real from Standard) + ---Purpose: Reaprroximation of adaptor curve + returns Integer from Standard; +--fields + +end Tools; + + diff --git a/src/HelixGeom/HelixGeom_Tools.cxx b/src/HelixGeom/HelixGeom_Tools.cxx new file mode 100644 index 0000000000..c0d655cca2 --- /dev/null +++ b/src/HelixGeom/HelixGeom_Tools.cxx @@ -0,0 +1,168 @@ +// File: HelixGeom_Tools.cxx + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//======================================================================= +//class : HelixGeom_Tools_Eval +//purpose: evaluator class for approximation +//======================================================================= + +class HelixGeom_Tools_Eval : public AdvApprox_EvaluatorFunction +{ + public: + HelixGeom_Tools_Eval (const Handle(Adaptor3d_HCurve)& theFunc) + : fonct(theFunc) {} + + virtual void Evaluate (Standard_Integer *Dimension, + Standard_Real StartEnd[2], + Standard_Real *Parameter, + Standard_Integer *DerivativeRequest, + Standard_Real *Result, // [Dimension] + Standard_Integer *ErrorCode); + + private: + Handle(Adaptor3d_HCurve) fonct; +}; + +void HelixGeom_Tools_Eval::Evaluate (Standard_Integer *Dimension, + Standard_Real /*StartEnd*/[2], + Standard_Real *Param, // Parameter at which evaluation + Standard_Integer *Order, // Derivative Request + Standard_Real *Result,// [Dimension] + Standard_Integer *ErrorCode) +{ + *ErrorCode = 0; + Standard_Real par = *Param; + +// Dimension is incorrect + if (*Dimension!=3) { + *ErrorCode = 1; + } + gp_Pnt pnt; + gp_Vec v1, v2; + + switch (*Order) { + case 0: + pnt = fonct->Value(par); + Result[0] = pnt.X(); + Result[1] = pnt.Y(); + Result[2] = pnt.Z(); + break; + case 1: + fonct->D1(par, pnt, v1); + Result[0] = v1.X(); + Result[1] = v1.Y(); + Result[2] = v1.Z(); + break; + case 2: + fonct->D2(par, pnt, v1, v2); + Result[0] = v2.X(); + Result[1] = v2.Y(); + Result[2] = v2.Z(); + break; + default: + Result[0] = Result[1] = Result[2] = 0.; + *ErrorCode = 3; + break; + } +} + +//======================================================================= +//function : ApprCurve3D +//purpose : +//======================================================================= +Standard_Integer HelixGeom_Tools::ApprCurve3D(Handle(Adaptor3d_HCurve)& theHC, + const Standard_Real theTol, + const GeomAbs_Shape theCont, + const Standard_Integer theMaxSeg, + const Standard_Integer theMaxDeg, + Handle(Geom_BSplineCurve)& theBSpl, + Standard_Real& theMaxError) +{ + Standard_Boolean anIsDone, aHasResult; + Standard_Integer Num1DSS, Num2DSS, Num3DSS; + Standard_Real First, Last; + Handle(TColStd_HArray1OfReal) OneDTolNul, TwoDTolNul, ThreeDTol; + AdvApprox_DichoCutting aCutTool; + // + Num1DSS=0; + Num2DSS=0; + Num3DSS=1; + ThreeDTol = new TColStd_HArray1OfReal(1,Num3DSS); + ThreeDTol->Init(theTol); + // + First = theHC->FirstParameter(); + Last = theHC->LastParameter(); + // + HelixGeom_Tools_Eval ev (theHC); + AdvApprox_ApproxAFunction aApprox (Num1DSS, Num2DSS, Num3DSS, + OneDTolNul, TwoDTolNul, ThreeDTol, + First, Last, theCont, + theMaxDeg, theMaxSeg, + ev, aCutTool); + // + anIsDone = aApprox.IsDone(); + if(!anIsDone) { + return 1; + } + // + theMaxError = 0.; + // + aHasResult = aApprox.HasResult(); + if (!aHasResult) { + return 2; + } + // + TColgp_Array1OfPnt Poles(1,aApprox.NbPoles()); + aApprox.Poles(1,Poles); + Handle(TColStd_HArray1OfReal) Knots = aApprox.Knots(); + Handle(TColStd_HArray1OfInteger) Mults = aApprox.Multiplicities(); + Standard_Integer Degree = aApprox.Degree(); + theBSpl = new Geom_BSplineCurve(Poles, Knots->Array1(), Mults->Array1(), Degree); + theMaxError = aApprox.MaxError(3, 1); + // + return 0; +} +//======================================================================= +//function : ApprHelix +//purpose : +//======================================================================= +Standard_Integer HelixGeom_Tools::ApprHelix(const Standard_Real aT1, + const Standard_Real aT2, + const Standard_Real aPitch, + const Standard_Real aRStart, + const Standard_Real aTaperAngle, + const Standard_Boolean aIsCW, + const Standard_Real theTol, + Handle(Geom_BSplineCurve)& theBSpl, + Standard_Real& theMaxError) +{ + Standard_Integer iErr, aMaxDegree, aMaxSeg; + GeomAbs_Shape aCont; + HelixGeom_HelixCurve aAdaptor; + Handle(HelixGeom_HHelixCurve) aHAdaptor; + // + aAdaptor.Load(aT1, aT2, aPitch, aRStart, aTaperAngle, aIsCW); + aHAdaptor=new HelixGeom_HHelixCurve(aAdaptor); + // + aCont=GeomAbs_C2; + aMaxDegree = 8; + aMaxSeg=150; + // + iErr=HelixGeom_Tools::ApprCurve3D(aHAdaptor, + theTol, aCont, aMaxSeg, aMaxDegree, + theBSpl, theMaxError); + return iErr; +} + diff --git a/src/HelixTest/FILES b/src/HelixTest/FILES new file mode 100644 index 0000000000..855ee4beca --- /dev/null +++ b/src/HelixTest/FILES @@ -0,0 +1,2 @@ +HelixTest.cxx +HelixTest_HelixCommands.cxx diff --git a/src/HelixTest/HelixTest.cdl b/src/HelixTest/HelixTest.cdl new file mode 100644 index 0000000000..667a8559f1 --- /dev/null +++ b/src/HelixTest/HelixTest.cdl @@ -0,0 +1,19 @@ +-- File: HelixTest.cdl + + +package HelixTest + + ---Purpose: + +uses + Draw, + DBRep, + TopoDS, + gp +is + AllCommands (aDI:out Interpretor from Draw); + HelixCommands (aDI:out Interpretor from Draw); + Factory (aDI:out Interpretor from Draw); + +end HelixTest; + diff --git a/src/HelixTest/HelixTest.cxx b/src/HelixTest/HelixTest.cxx new file mode 100644 index 0000000000..210149d5a0 --- /dev/null +++ b/src/HelixTest/HelixTest.cxx @@ -0,0 +1,35 @@ +// File: HelixTest.cxx + +#include +#include + +//======================================================================= +//function : AllCommands +//purpose : +//======================================================================= + void HelixTest::AllCommands(Draw_Interpretor& theCommands) +{ + static Standard_Boolean done = Standard_False; + if (done) return; + done = Standard_True; + // + HelixTest::HelixCommands (theCommands); +} +//======================================================================= +//function : Factory +//purpose : +//======================================================================= + void HelixTest::Factory(Draw_Interpretor& theCommands) +{ + static Standard_Boolean FactoryDone = Standard_False; + if (FactoryDone) return; + + FactoryDone = Standard_True; + + HelixTest::AllCommands(theCommands); + Printf(" Helix Plugin is loaded\n"); +} +#include +DPLUGIN(HelixTest) + + diff --git a/src/HelixTest/HelixTest_HelixCommands.cxx b/src/HelixTest/HelixTest_HelixCommands.cxx new file mode 100644 index 0000000000..0f151c846e --- /dev/null +++ b/src/HelixTest/HelixTest_HelixCommands.cxx @@ -0,0 +1,559 @@ +// File: HelixTest_HelixCommands.cxx + +#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 + + +// +Standard_IMPORT Draw_Viewer dout; +// +static gp_Ax3 theHelixAxis(gp_Pnt(0., 0., 0), gp_Dir(0., 0., 1.), gp_Dir(1., 0., 0.)); + +static Standard_Integer comphelix (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer helix (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer spiral (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer setaxis (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer comphelix2 (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer helix2 (Draw_Interpretor& , Standard_Integer , const char ** ); +static Standard_Integer spiral2 (Draw_Interpretor& , Standard_Integer , const char ** ); +//======================================================================= +//function : HelixTest::HelixCommands +//purpose : +//======================================================================= + void HelixTest::HelixCommands(Draw_Interpretor& theCommands) +{ + static Standard_Boolean done = Standard_False; + if (done) return; + done = Standard_True; + // Chapters name + const char* g = "Helix commands"; + // Commands + theCommands.Add("setaxis", "setaxis x y z Nx Ny Nz Xx Xy Xz", + __FILE__, setaxis, g); + theCommands.Add("comphelix", "comphelix name np D1 [Di...] H1 [Hi...] P1 [Pi...] PF1 [PFi...]", + __FILE__, comphelix, g); + theCommands.Add("helix", "helix name np D1 H1 [Hi...] P1 [Pi...] PF1 [PFi...]", + __FILE__, helix, g); + theCommands.Add("spiral", "spiral name np D1 D2 H1 [Hi...] P1 [Pi...] PF1 [PFi...]", + __FILE__, spiral, g); + theCommands.Add("comphelix2", "comphelix2 name np D1 [Di...] P1 [Pi...] N1 [Ni...]", + __FILE__, comphelix2, g); + theCommands.Add("helix2", "helix2 name np D1 P1 [Pi...] N1 [Ni...]", + __FILE__, helix2, g); + theCommands.Add("spiral2", "spiral2 name np D1 D2 P1 [Pi...] N1 [Ni...]", + __FILE__, spiral2, g); +} + +//======================================================================= +//function : setaxis +//purpose : +//======================================================================= + Standard_Integer setaxis(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 10) { + di << "Usage : " << a[0] << " x y z Nx Ny Nz Xx Xy Xz" <<"\n"; + di << " " << "x y z - location" <<"\n"; + di << " " << "Nx Ny Nz - direction" <<"\n"; + di << " " << "Xx Xy Xz - X direction" <<"\n"; + return 1; + } + Standard_Real xx[9]; + Standard_Integer i; + for(i = 0; i < 9; ++i) { + xx[i] = Draw::Atof(a[i+1]); + } + + theHelixAxis.SetLocation(gp_Pnt(xx[0], xx[1], xx[2])); + theHelixAxis.SetDirection(gp_Dir(xx[3], xx[4], xx[5])); + theHelixAxis.SetXDirection(gp_Dir(xx[6], xx[7], xx[8])); + + return 0; +} +// +//======================================================================= +//function : comphelix +//purpose : +//======================================================================= + Standard_Integer comphelix(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 8) { + di << "Usage : " << a[0] << " name np D1 D2 [Di...] H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 ... (must be np+1 values) - diameters" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + (aNb+1) + aNb*3) { + di << "Usage : " << a[0] << " name np D1 D2 [Di...] H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 ... (must be np+1 values) - diameters" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, aNb + 1); + TColStd_Array1OfReal aHeights(1, aNb); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfBoolean bIsPitches(1, aNb); + + ic = 3; + for(i = 1; i <= aNb+1; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aHeights(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + bIsPitches(i) = Draw::Atoi(a[ic]); + ++ic; + } + // + + aBH.SetParameters(theHelixAxis, aDiams, aHeights, aPitches, bIsPitches); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} + +//======================================================================= +//function : helix +//purpose : +//======================================================================= + Standard_Integer helix(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 7) { + di << "Usage : " << a[0] << " name np D1 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 - diameter" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + 1 + aNb*3) { + di << "Usage : " << a[0] << " name np D1 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 - diameter" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, 1); + TColStd_Array1OfReal aHeights(1, aNb); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfBoolean bIsPitches(1, aNb); + + ic = 3; + for(i = 1; i <= 1; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aHeights(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + bIsPitches(i) = Draw::Atoi(a[ic]); + ++ic; + } + // + + aBH.SetParameters(theHelixAxis, aDiams(1), aHeights, aPitches, bIsPitches); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} + +//======================================================================= +//function : spiral +//purpose : +//======================================================================= + Standard_Integer spiral(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 8) { + di << "Usage : " << a[0] << " name np D1 D2 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 - first and last diameters" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + 2 + aNb*3) { + di << "Usage : " << a[0] << " name np D1 D2 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 - first and last diameters" <<"\n"; + di << " " << "H1, H2 ... (must be np values) - heights" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches or numbers of turns" <<"\n"; + di << " " << "PF1, PF2 ... (must be np values) - 0 or 1, if PFi = 1, Pi is pitch, otherwise Pi is number of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, 2); + TColStd_Array1OfReal aHeights(1, aNb); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfBoolean bIsPitches(1, aNb); + + ic = 3; + for(i = 1; i <= 2; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aHeights(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + bIsPitches(i) = Draw::Atoi(a[ic]); + ++ic; + } + // + + aBH.SetParameters(theHelixAxis, aDiams(1), aDiams(2), aHeights, aPitches, bIsPitches); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} + +//======================================================================= +//function : comphelix2 +//purpose : +//======================================================================= + Standard_Integer comphelix2(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 7) { + di << "Usage : " << a[0] << " name np D1 D2 [Di...] P1 [Pi...] N1 [Ni...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2, ... (must be np+1 values) - diameters" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + (aNb+1) + aNb*2) { + di << "Usage : " << a[0] << " name np D1 D2 [Di...] P1 [Pi...] N1 [Ni...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2, ... (must be np+1 values) - diameters" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, aNb + 1); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfReal aNbTurns(1, aNb); + + ic = 3; + for(i = 1; i <= aNb+1; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aNbTurns(i) = Draw::Atof(a[ic]); + ++ic; + } + + // + + aBH.SetParameters(theHelixAxis, aDiams, aPitches, aNbTurns); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} + +//======================================================================= +//function : helix2 +//purpose : +//======================================================================= + Standard_Integer helix2(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 6) { + di << "Usage : " << a[0] << " name np D1 P1 [Pi...] N1 [Ni...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 - diameter" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + 1 + aNb*2) { + di << "Usage : " << a[0] << " name np D1 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 - diameter" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, 1); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfReal aNbTurns(1, aNb); + + ic = 3; + for(i = 1; i <= 1; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aNbTurns(i) = Draw::Atof(a[ic]); + ++ic; + } + // + + aBH.SetParameters(theHelixAxis, aDiams(1), aPitches, aNbTurns); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} + +//======================================================================= +//function : spiral2 +//purpose : +//======================================================================= + Standard_Integer spiral2(Draw_Interpretor& di, Standard_Integer n, const char ** a) +{ + if (n < 7) { + di << "Usage : " << a[0] << " name np D1 D2 P1 [Pi...] N1 [Ni...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 - first and last diameters" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + Standard_Integer i, aNb, ic; + HelixBRep_BuilderHelix aBH; + // + aNb = Draw::Atoi(a[2]); + if (n != 3 + 2 + aNb*2) { + di << "Usage : " << a[0] << " name np D1 D2 H1 [Hi...] P1 [Pi...] PF1 [PFi...]" <<"\n"; + di << " " << "name - name of result" <<"\n"; + di << " " << "np - number of helix parts" <<"\n"; + di << " " << "D1 D2 - first and last diameters" <<"\n"; + di << " " << "P1, P2, ... (must be np values) - pitches" <<"\n"; + di << " " << "N1, N2, ... (must be np values) - numbers of turns" <<"\n"; + return 1; + } + // + + TColStd_Array1OfReal aDiams(1, 2); + TColStd_Array1OfReal aPitches(1, aNb); + TColStd_Array1OfReal aNbTurns(1, aNb); + + ic = 3; + for(i = 1; i <= 2; ++i) { + aDiams(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aPitches(i) = Draw::Atof(a[ic]); + ++ic; + } + + for(i = 1; i <= aNb; ++i) { + aNbTurns(i) = Draw::Atof(a[ic]); + ++ic; + } + // + + aBH.SetParameters(theHelixAxis, aDiams(1), aDiams(2), aPitches, aNbTurns); + + aBH.Perform(); + + if(aBH.ErrorStatus() == 0) { + Standard_Real aMaxError=aBH.ToleranceReached(); + di << "WarningStatus = " << aBH.WarningStatus() <<"\n"; + di << "ToleranceReached = " << aMaxError <<"\n"; + // + const TopoDS_Shape& aW=aBH.Shape(); + DBRep::Set(a[1], aW); + } + else { + di << "ErrorStatus = " << aBH.ErrorStatus() << "\n"; + } + + return 0; +} diff --git a/src/OS/FILES b/src/OS/FILES index 5ad90edc61..7d767e7426 100755 --- a/src/OS/FILES +++ b/src/OS/FILES @@ -6,3 +6,5 @@ srcinc:::ModelingData.tcl srcinc:::Visualization.tcl srcinc:::ApplicationFramework.tcl srcinc:::DataExchange.tcl +srcinc:::Helix.tcl +srcinc:::Unfolding.tcl diff --git a/src/OS/Helix.tcl b/src/OS/Helix.tcl new file mode 100644 index 0000000000..2a48257f38 --- /dev/null +++ b/src/OS/Helix.tcl @@ -0,0 +1,36 @@ +# Definitions for a product: Helix + +# List of toolkits +proc Helix:toolkits { } { + return [list TKHelix] +} + +# List of non-toolkits (resource units, executables etc., with associated info) +proc Helix:ressources { } { + return {} +} + +# Product name +proc Helix:name { } { + return Helix +} + +# And short alias +proc Helix:alias { } { + return Helix +} + +# Dependency on other products +proc Helix:depends { } { + return {} +} + +proc Helix:CompileWith { } { +} + +proc Helix:LinksoWith { } { +} + +proc Helix:Export { } { + return [list source runtime wokadm api] +} diff --git a/src/OS/Modules.tcl b/src/OS/Modules.tcl index 2ca889cc09..3e1ef542cd 100644 --- a/src/OS/Modules.tcl +++ b/src/OS/Modules.tcl @@ -22,6 +22,8 @@ proc OS:Modules { {plat ""} } { ApplicationFramework \ DataExchange \ Draw \ + Helix \ + Unfolding \ ] return $ret } diff --git a/src/OS/Unfolding.tcl b/src/OS/Unfolding.tcl new file mode 100644 index 0000000000..41ef7ee10f --- /dev/null +++ b/src/OS/Unfolding.tcl @@ -0,0 +1,36 @@ +# Definitions for a product: Unfolding + +# List of toolkits +proc Unfolding:toolkits { } { + return [list TKUnfolding TKUnfoldingTest] +} + +# List of non-toolkits (resource units, executables etc., with associated info) +proc Unfolding:ressources { } { + return {} +} + +# Product name +proc Unfolding:name { } { + return Unfolding +} + +# And short alias +proc Unfolding:alias { } { + return Unfolding +} + +# Dependency on other products +proc Unfolding:depends { } { + return {} +} + +proc Unfolding:CompileWith { } { +} + +proc Unfolding:LinksoWith { } { +} + +proc Unfolding:Export { } { + return [list source runtime wokadm api] +} diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 02f24518ed..2d5d613eec 100755 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -3270,47 +3270,6 @@ struct OCC25545_Functor mutable volatile int myIsRaceDetected; }; -//======================================================================= -//function : OCC25545 -//purpose : Tests data race when concurrently accessing TopLoc_Location::Transformation() -//======================================================================= -#ifdef HAVE_TBB -static Standard_Integer OCC25545 (Draw_Interpretor& di, - Standard_Integer, - const char **) -{ - // Place vertices in a vector, giving the i-th vertex the - // transformation that translates it on the vector (i,0,0) from the origin. - size_t n = 1000; - std::vector aShapeVec (n); - std::vector aLocVec (n); - TopoDS_Shape aShape = BRepBuilderAPI_MakeVertex (gp::Origin ()); - aShapeVec[0] = aShape; - for (size_t i = 1; i < n; ++i) { - gp_Trsf aT; - aT.SetTranslation (gp_Vec (1, 0, 0)); - aLocVec[i] = aLocVec[i - 1] * aT; - aShapeVec[i] = aShape.Moved (aLocVec[i]); - } - - // Evaluator function will access vertices geometry - // concurrently - OCC25545_Functor aFunc(aShapeVec); - - //concurrently process - tbb::parallel_for (size_t (0), n, aFunc, tbb::simple_partitioner ()); - QVERIFY (!aFunc.myIsRaceDetected); - return 0; -} -#else -static Standard_Integer OCC25545 (Draw_Interpretor&, - Standard_Integer, - const char **argv) -{ - cout << "Test skipped: command " << argv[0] << " requires TBB library" << endl; - return 0; -} -#endif //======================================================================= //function : OCC25547 @@ -4368,10 +4327,6 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) { theCommands.Add ("OCC25348", "OCC25348", __FILE__, OCC25348, group); theCommands.Add ("OCC25413", "OCC25413 shape", __FILE__, OCC25413, group); theCommands.Add ("OCC25446", "OCC25446 res b1 b2 op", __FILE__, OCC25446, group); - theCommands.Add ("OCC25545", - "no args; tests data race when concurrently accessing \n" - "\t\tTopLoc_Location::Transformation()", - __FILE__, OCC25545, group); theCommands.Add ("OCC25547", "OCC25547", __FILE__, OCC25547, group); theCommands.Add ("OCC24881", "OCC24881 shape", __FILE__, OCC24881, group); theCommands.Add ("OCC26172", "OCC26172", __FILE__, OCC26172, group); diff --git a/src/TKHelix/EXTERNLIB b/src/TKHelix/EXTERNLIB new file mode 100644 index 0000000000..f48ab6c4bc --- /dev/null +++ b/src/TKHelix/EXTERNLIB @@ -0,0 +1,7 @@ +TKBRep +TKMath +TKernel +TKG2d +TKG3d +TKDraw +TKTopAlgo diff --git a/src/TKHelix/FILES b/src/TKHelix/FILES new file mode 100644 index 0000000000..ee6f7057f7 --- /dev/null +++ b/src/TKHelix/FILES @@ -0,0 +1 @@ +EXTERNLIB diff --git a/src/TKHelix/PACKAGES b/src/TKHelix/PACKAGES new file mode 100644 index 0000000000..2be7474caa --- /dev/null +++ b/src/TKHelix/PACKAGES @@ -0,0 +1,3 @@ +HelixGeom +HelixBRep +HelixTest diff --git a/src/TKUnfolding/EXTERNLIB b/src/TKUnfolding/EXTERNLIB new file mode 100644 index 0000000000..aede3a708b --- /dev/null +++ b/src/TKUnfolding/EXTERNLIB @@ -0,0 +1,10 @@ +TKBRep +TKMath +TKernel +TKG2d +TKG3d +TKDraw +TKTopAlgo +TKGeomAlgo +TKShHealing +TKGeomBase diff --git a/src/TKUnfolding/FILES b/src/TKUnfolding/FILES new file mode 100644 index 0000000000..ee6f7057f7 --- /dev/null +++ b/src/TKUnfolding/FILES @@ -0,0 +1 @@ +EXTERNLIB diff --git a/src/TKUnfolding/PACKAGES b/src/TKUnfolding/PACKAGES new file mode 100644 index 0000000000..66fa871b7c --- /dev/null +++ b/src/TKUnfolding/PACKAGES @@ -0,0 +1 @@ +Unfolding diff --git a/src/TKUnfoldingTest/EXTERNLIB b/src/TKUnfoldingTest/EXTERNLIB new file mode 100644 index 0000000000..683e029f62 --- /dev/null +++ b/src/TKUnfoldingTest/EXTERNLIB @@ -0,0 +1,6 @@ +TKBRep +TKMath +TKernel +TKG3d +TKDraw +TKUnfolding \ No newline at end of file diff --git a/src/TKUnfoldingTest/FILES b/src/TKUnfoldingTest/FILES new file mode 100644 index 0000000000..ee6f7057f7 --- /dev/null +++ b/src/TKUnfoldingTest/FILES @@ -0,0 +1 @@ +EXTERNLIB diff --git a/src/TKUnfoldingTest/PACKAGES b/src/TKUnfoldingTest/PACKAGES new file mode 100644 index 0000000000..1626becca8 --- /dev/null +++ b/src/TKUnfoldingTest/PACKAGES @@ -0,0 +1 @@ +UnfoldingTest diff --git a/src/Unfolding/Unfolding.cdl b/src/Unfolding/Unfolding.cdl new file mode 100644 index 0000000000..aa130b1b88 --- /dev/null +++ b/src/Unfolding/Unfolding.cdl @@ -0,0 +1,90 @@ +-- File: Unfolding.cdl +-- Created: Tue Jul 22 12:48:05 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Open CASCADE 2008 + +package Unfolding + ---Purpose: This package contains a tool for unfolding a surface on a plane. + +uses + + TopoDS, + TopTools, + gp, + Standard, + TCollection, + TColgp, + math + +is + + ---Purpose: Enumeration that defines an error status of an operation. + enumeration ErrorStatus + is + Done, + NotDone, + Failure, + InvalidSurface, + InvalidInput, + InvalidShape, + ComplexShape + end; + + class Surface; + + class Point; + + class FunctionWithDerivative; + + class Shell; + + class FaceDataContainer; + + class FaceDataMapHasher; + + class Array2OfPoint + instantiates Array2 from TCollection (Point from Unfolding); + + class HArray2OfPoint + instantiates HArray2 from TCollection (Point from Unfolding, + Array2OfPoint from Unfolding); + + class IndexedMapOfFaceDataContainer + instantiates IndexedMap from TCollection + (FaceDataContainer from Unfolding, + FaceDataMapHasher from Unfolding); + + ToShell(theShape : Shape from TopoDS; + theTolerance : Real from Standard; + theStatus : out ErrorStatus from Unfolding) + ---Purpose: This method converts theShape to a shell. It sewes faces of the + -- shell if it is necessary and possible with the given tolerance. + -- If it is not possible to construct a single shell from theShape, + -- this method returns null shell and the corresponding error + -- status. The status can have the following values: + -- - Unfolding_Done: the operation succeeded + -- - Unfolding_InvalidInput: input shape type is less then + -- TopAbs_SHELL. + -- - Unfolding_Failure: sewing failure. + -- - Unfolding_InvalidShape: the shape after sewing does not + -- contain shells. + -- - Unfolding_ComplexShape: the shape after sewing contains + -- either more then one shell or one shell and other not + -- connected shapes. + returns Shell from TopoDS; + + NbSamples(theEdge : Edge from TopoDS; + theFaces : ListOfShape from TopTools; + theTolerance: Real from Standard) + ---Purpose: This method returns the number of sample points for theEdge. + -- theFaces is a list of faces that contain theEdge. + returns Integer from Standard; + + GetMaxNbSamples + ---Purpose: This method returns the maximal number of points for sampling of + -- edges and/or faces. + ---C++: inline + returns Integer from Standard; + +end Unfolding; diff --git a/src/Unfolding/Unfolding.cxx b/src/Unfolding/Unfolding.cxx new file mode 100644 index 0000000000..2e036d705a --- /dev/null +++ b/src/Unfolding/Unfolding.cxx @@ -0,0 +1,162 @@ +// File: Unfolding.cxx +// Created: Wed Sep 17 09:16:05 2008 +// Author: Sergey KHROMOV +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//======================================================================= +//function : ToShell +//purpose : +//======================================================================= + +TopoDS_Shell Unfolding::ToShell(const TopoDS_Shape &theShape, + const Standard_Real theTolerance, + Unfolding_ErrorStatus &theStatus) +{ + TopoDS_Shell aShell; + TopAbs_ShapeEnum aType = theShape.ShapeType(); + + if (aType != TopAbs_COMPOUND && aType != TopAbs_COMPSOLID && + aType != TopAbs_SOLID && aType != TopAbs_SHELL) { + theStatus = Unfolding_InvalidInput; + return aShell; + } + + if (aType == TopAbs_SHELL) { + // theShape is a shell. Nothing to be done. + theStatus = Unfolding_Done; + aShell = TopoDS::Shell(theShape); + return aShell; + } + + BRepBuilderAPI_Sewing aSewing(theTolerance); + + aSewing.Add(theShape); + aSewing.Perform(); + + const TopoDS_Shape &aShape = aSewing.SewedShape(); + + if (aShape.IsNull()) { + theStatus = Unfolding_Failure; + return aShell; + } + + // Explore shape to extract a shell. + TopExp_Explorer anExp(aShape, TopAbs_SHELL); + + if (!anExp.More()) { + theStatus = Unfolding_InvalidShape; + return aShell; + } + + TopoDS_Shape aSingleShell = anExp.Current(); + + anExp.Next(); + + if (anExp.More()) { + theStatus = Unfolding_ComplexShape; + return aShell; + } + + // Check if there is no other redundant shapes that are not in the shell. + anExp.Init(aShape, TopAbs_VERTEX, TopAbs_SHELL); + + if (anExp.More()) { + theStatus = Unfolding_ComplexShape; + return aShell; + } + + // Get the single shell. + theStatus = Unfolding_Done; + aShell = TopoDS::Shell(aSingleShell); + + return aShell; +} + +//======================================================================= +//function : ToShell +//purpose : +//======================================================================= + +Standard_Integer Unfolding::NbSamples(const TopoDS_Edge &theEdge, + const TopTools_ListOfShape &theFaces, + const Standard_Real theTolerance) +{ + Standard_Integer aNbPointsLimit = Unfolding::GetMaxNbSamples() / 2; + Standard_Integer aMaxNbPoints = 11; + Standard_Integer aNbPoints; + TopTools_ListIteratorOfListOfShape anIt( theFaces ); + + for ( ; anIt.More(); anIt.Next() ) { + TopoDS_Shape aCurShape = anIt.Value(); + TopoDS_Face aFace = TopoDS::Face( aCurShape ); + aFace.Orientation(TopAbs_FORWARD); + + Standard_Integer aNbPnt = 2; + Standard_Real aParam[2]; + Handle(Geom2d_Curve) aCurve = + BRep_Tool::CurveOnSurface(theEdge, aFace, aParam[0], aParam[1]); + Handle(Standard_Type) aType = aCurve->DynamicType(); + + while (aType == STANDARD_TYPE(Geom2d_TrimmedCurve)) { + Handle(Geom2d_TrimmedCurve) aTrCurve = + Handle(Geom2d_TrimmedCurve)::DownCast(aCurve); + aCurve = aTrCurve->BasisCurve(); + aType = aCurve->DynamicType(); + } + + if (aType == STANDARD_TYPE(Geom2d_BezierCurve)) { + Handle(Geom2d_BezierCurve) aBezier = + Handle(Geom2d_BezierCurve)::DownCast(aCurve); + aNbPnt = 3 + aBezier->NbPoles(); + + + if (aNbPnt < 11) + aNbPnt = 11; + } else if (aType == STANDARD_TYPE(Geom2d_BSplineCurve)) { + Handle(Geom2d_BSplineCurve) aBSpline = + Handle(Geom2d_BSplineCurve)::DownCast(aCurve); + aNbPnt = aBSpline->NbKnots()*aBSpline->Degree(); + + if (aNbPnt < 11) + aNbPnt = 11; + } else { + aNbPnt = 11; + } + aMaxNbPoints = ( aMaxNbPoints < aNbPnt ) ? aNbPnt : aMaxNbPoints; + + Geom2dAdaptor_Curve aCurve1(aCurve); + Standard_Real L = GCPnts_AbscissaPoint::Length(aCurve1, aParam[0], aParam[1]) ; + // estimate number of points taking into account the curvature of radius myTolContour * 2. + Standard_Real sizeR = 0.125 * L / theTolerance + 2; + + if ( aNbPointsLimit > sizeR ) + aNbPointsLimit = (Standard_Integer) sizeR; + } + + // Check if the number of points exceeds the maximum number of points. + + if(aMaxNbPoints > aNbPointsLimit) + aMaxNbPoints = aNbPointsLimit; + + aNbPoints = aMaxNbPoints; + + return aNbPoints; +} diff --git a/src/Unfolding/Unfolding.lxx b/src/Unfolding/Unfolding.lxx new file mode 100644 index 0000000000..9116d7ba8a --- /dev/null +++ b/src/Unfolding/Unfolding.lxx @@ -0,0 +1,12 @@ +// File: Unfolding.lxx +// Created: Tue Jul 22 13:12:24 2008 +// Author: Sergey KHROMOV +// + + +inline Standard_Integer Unfolding::GetMaxNbSamples() +{ + static Standard_Integer aMaxNbSamples = 1000; + + return aMaxNbSamples; +} diff --git a/src/Unfolding/Unfolding_FaceDataContainer.cdl b/src/Unfolding/Unfolding_FaceDataContainer.cdl new file mode 100644 index 0000000000..075705b7fa --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataContainer.cdl @@ -0,0 +1,89 @@ +-- File: Unfolding_FaceDataContainer.cdl +-- Created: Fri Sep 19 16:52:05 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Matra Datavision 2008 + +class FaceDataContainer from Unfolding inherits TShared from MMgt + ---Purpose: This class represents a data container for data constructed + -- during unfolding operation. + +uses + + Face from TopoDS, + Edge from TopoDS, + Trsf from gp, + Real from Standard, + ListOfShape from TopTools, + DataMapOfShapeListOfShape from TopTools + +is + + Create + ---Purpose: Empty constructor + ---C++: inline + returns FaceDataContainer from Unfolding; + + SetFace(me: mutable; theFace: Face from TopoDS); + ---Purpose: Sets the original face. + + GetFace(me) + ---Purpose: Returns the original face. + ---C++: inline + ---C++: return const & + returns Face from TopoDS; + + SetUnfoldedFace(me: mutable; theUnfoldedFace: Face from TopoDS); + ---Purpose: Sets the unfolded face for the original one. + ---C++: inline + + GetUnfoldedFace(me) + ---Purpose: Returns the unfolded face for the original one. + ---C++: inline + ---C++: return const & + returns Face from TopoDS; + + SetDistortionArea(me: mutable; theDistortionArea: Real from Standard); + ---Purpose: Sets the distortion area. + ---C++: inline + + GetDistortionArea(me) + ---Purpose: Returns the distortion area. + ---C++: inline + returns Real from Standard; + + SetMaxGaussCurvature(me: mutable; theCurvature: Real from Standard); + ---Purpose: Sets the maximal Gauss curvature. + ---C++: inline + + GetMaxGaussCurvature(me) + ---Purpose: Returns the maximal Gauss curvature. + ---C++: inline + returns Real from Standard; + + Reset(me: mutable); + ---Purpose: Resets the data container. + ---C++: inline + + ApplyTrsf(me: mutable; theTrsf: Trsf from gp); + ---Purpose: Applies the transformation to all unfolded shapes. + + SetEdgesForEdge(me: mutable; + theEdge : Edge from TopoDS; + theUnfoldedEdges: ListOfShape from TopTools); + ---Purpose: Associates unfolded edges with the source edge. + + GetEdgesForEdge(me; theEdge: Edge from TopoDS) + ---Purpose: Returns unfolded edges associated to the source edge. + ---C++: return const & + returns ListOfShape from TopTools; + +fields + + myFace : Face from TopoDS; + myUnfoldedFace : Face from TopoDS; + myEdgeMap : DataMapOfShapeListOfShape from TopTools; + myDistortionArea : Real from Standard; + myCurvature : Real from Standard; + +end; diff --git a/src/Unfolding/Unfolding_FaceDataContainer.cxx b/src/Unfolding/Unfolding_FaceDataContainer.cxx new file mode 100644 index 0000000000..b1d147dd30 --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataContainer.cxx @@ -0,0 +1,111 @@ +// File: Unfolding_FaceDataContainer.cxx +// Created: Tue Jul 22 13:12:24 2008 +// Author: Sergey KHROMOV +// + + +#include +#include +#include +#include +#include +#include + + +//======================================================================= +//function : SetFace +//purpose : +//======================================================================= + +void Unfolding_FaceDataContainer::SetFace(const TopoDS_Face &theFace) +{ + Standard_Boolean isSame = theFace.IsSame(myFace); + myFace = theFace; + + if (!isSame) { + // Update the map myEdgeMap + myEdgeMap.Clear(); + + TopExp_Explorer anExp(myFace, TopAbs_EDGE); + TopTools_ListOfShape anEmptyList; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &anEdge = anExp.Current(); + + myEdgeMap.Bind(anEdge, anEmptyList); + } + } +} + +//======================================================================= +//function : ApplyTrsf +//purpose : +//======================================================================= + +void Unfolding_FaceDataContainer::ApplyTrsf(const gp_Trsf &theTrsf) +{ + BRepBuilderAPI_Transform aTrsf(theTrsf); + + if (!myUnfoldedFace.IsNull()) { + aTrsf.Perform(myUnfoldedFace); + + if (aTrsf.IsDone()) + myUnfoldedFace = TopoDS::Face(aTrsf.Shape()); + } + + TopTools_DataMapIteratorOfDataMapOfShapeListOfShape anEdgeIter(myEdgeMap); + TopTools_ListIteratorOfListOfShape aUEIter; + + for (; anEdgeIter.More(); anEdgeIter.Next()) { + const TopoDS_Shape &anEdge = anEdgeIter.Key(); + TopTools_ListOfShape &anEdges = myEdgeMap.ChangeFind(anEdge); + TopTools_ListOfShape aTrsfEdges; + + for (aUEIter.Initialize(anEdges); aUEIter.More(); aUEIter.Next()) { + const TopoDS_Shape &aUEdge = aUEIter.Value(); + + aTrsf.Perform(aUEdge); + + if (aTrsf.IsDone()) + aTrsfEdges.Append(aTrsf.Shape()); + } + + anEdges.Clear(); + anEdges.Append(aTrsfEdges); + } +} + +//======================================================================= +//function : SetEdgesForEdge +//purpose : +//======================================================================= + +void Unfolding_FaceDataContainer::SetEdgesForEdge + (const TopoDS_Edge &theEdge, + const TopTools_ListOfShape &theUnfoldedEdges) +{ + if (myEdgeMap.IsBound(theEdge)) { + TopTools_ListOfShape &anEdges = myEdgeMap.ChangeFind(theEdge); + + anEdges = theUnfoldedEdges; + } +} + +//======================================================================= +//function : GetEdgesForEdge +//purpose : +//======================================================================= + +const TopTools_ListOfShape &Unfolding_FaceDataContainer::GetEdgesForEdge + (const TopoDS_Edge &theEdge) const +{ + if (myEdgeMap.IsBound(theEdge)) { + const TopTools_ListOfShape &anEdges = myEdgeMap.Find(theEdge); + + return anEdges; + } + + static TopTools_ListOfShape anEmptyList; + + return anEmptyList; +} diff --git a/src/Unfolding/Unfolding_FaceDataContainer.lxx b/src/Unfolding/Unfolding_FaceDataContainer.lxx new file mode 100644 index 0000000000..86f770251c --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataContainer.lxx @@ -0,0 +1,101 @@ +// File: Unfolding_FaceDataContainer.lxx +// Created: Tue Jul 22 13:12:24 2008 +// Author: Sergey KHROMOV +// + + +//======================================================================= +//function : Empty constructor +//purpose : +//======================================================================= + +inline Unfolding_FaceDataContainer::Unfolding_FaceDataContainer() + : myDistortionArea(0.), + myCurvature(0.) +{ +} + +//======================================================================= +//function : GetFace +//purpose : +//======================================================================= + +inline const TopoDS_Face &Unfolding_FaceDataContainer::GetFace() const +{ + return myFace; +} + +//======================================================================= +//function : SetUnfoldedFace +//purpose : +//======================================================================= + +inline void Unfolding_FaceDataContainer::SetUnfoldedFace + (const TopoDS_Face &theUnfoldedFace) +{ + myUnfoldedFace = theUnfoldedFace; +} + +//======================================================================= +//function : GetUnfoldedFace +//purpose : +//======================================================================= + +inline const TopoDS_Face &Unfolding_FaceDataContainer::GetUnfoldedFace() const +{ + return myUnfoldedFace; +} + +//======================================================================= +//function : SetDistortionArea +//purpose : +//======================================================================= + +inline void Unfolding_FaceDataContainer::SetDistortionArea + (const Standard_Real theDistortionArea) +{ + myDistortionArea = theDistortionArea; +} + +//======================================================================= +//function : GetDistortionArea +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_FaceDataContainer::GetDistortionArea() const +{ + return myDistortionArea; +} + +//======================================================================= +//function : SetMaxGaussCurvature +//purpose : +//======================================================================= + +inline void Unfolding_FaceDataContainer::SetMaxGaussCurvature + (const Standard_Real theCurvature) +{ + myCurvature = theCurvature; +} + +//======================================================================= +//function : GetMaxGaussCurvature +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_FaceDataContainer::GetMaxGaussCurvature() const +{ + return myCurvature; +} + +//======================================================================= +//function : Reset +//purpose : +//======================================================================= + +inline void Unfolding_FaceDataContainer::Reset() +{ + myUnfoldedFace.Nullify(); + myDistortionArea = 0.; + myCurvature = 0.; +} diff --git a/src/Unfolding/Unfolding_FaceDataMapHasher.cdl b/src/Unfolding/Unfolding_FaceDataMapHasher.cdl new file mode 100644 index 0000000000..7ee72b47f4 --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataMapHasher.cdl @@ -0,0 +1,32 @@ +-- File: Unfolding_FaceDataMapHasher.cdl +-- Created: Fri Sep 19 16:52:05 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Matra Datavision 2008 + +class FaceDataMapHasher from Unfolding + ---Purpose: Hash tool, used for generating maps of face data containers. + +uses + + FaceDataContainer from Unfolding, + Integer from Standard, + Boolean from Standard + +is + + HashCode(myclass; theKey : FaceDataContainer from Unfolding; + theUpper: Integer from Standard) + ---Purpose: Returns a HasCode value for the Key in the + -- range 0..theUpper. + ---C++: inline + returns Integer from Standard; + + IsEqual(myclass; theKey1, theKey2 : FaceDataContainer from Unfolding) + ---Purpose: Returns True when the two keys are the same. Two + -- same keys must have the same hashcode, the + -- contrary is not necessary. + ---C++: inline + returns Boolean from Standard; + +end; diff --git a/src/Unfolding/Unfolding_FaceDataMapHasher.cxx b/src/Unfolding/Unfolding_FaceDataMapHasher.cxx new file mode 100644 index 0000000000..8357ff58cd --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataMapHasher.cxx @@ -0,0 +1,7 @@ +// File: Unfolding_FaceDataMapHasher.cxx +// Created: Mon Sep 22 09:01:04 2008 +// Author: Sergey KHROMOV +// + + +#include diff --git a/src/Unfolding/Unfolding_FaceDataMapHasher.lxx b/src/Unfolding/Unfolding_FaceDataMapHasher.lxx new file mode 100644 index 0000000000..fd132b7892 --- /dev/null +++ b/src/Unfolding/Unfolding_FaceDataMapHasher.lxx @@ -0,0 +1,30 @@ +// File: Unfolding_FaceDataMapHasher.lxx +// Created: Mon Sep 22 08:54:51 2008 +// Author: Sergey KHROMOV +// + + +//======================================================================= +//function : HashCode +//purpose : +//======================================================================= + +inline Standard_Integer Unfolding_FaceDataMapHasher::HashCode + (const Handle(Unfolding_FaceDataContainer) &theKey, + const Standard_Integer theUpper) +{ + return (theKey.IsNull()) ? 0 : theKey->GetFace().HashCode(theUpper); +} + +//======================================================================= +//function : IsEqual +//purpose : +//======================================================================= + +inline Standard_Boolean Unfolding_FaceDataMapHasher::IsEqual + (const Handle(Unfolding_FaceDataContainer) &theKey1, + const Handle(Unfolding_FaceDataContainer) &theKey2) +{ + return !theKey1.IsNull() && !theKey2.IsNull() && + theKey1->GetFace().IsSame(theKey2->GetFace()); +} diff --git a/src/Unfolding/Unfolding_FunctionWithDerivative.cdl b/src/Unfolding/Unfolding_FunctionWithDerivative.cdl new file mode 100644 index 0000000000..6ca0c19bfd --- /dev/null +++ b/src/Unfolding/Unfolding_FunctionWithDerivative.cdl @@ -0,0 +1,60 @@ +-- File: Unfolding_FunctionWithDerivative.cdl +-- Created: Fri Sep 5 17:44:29 2008 +-- Author: Mikhail KLOKOV +-- +---Copyright: Open CASCADE 2008 + +class FunctionWithDerivative from Unfolding inherits FunctionWithDerivative from math +uses + Array1OfXY from TColgp, + Trsf2d from gp, + Dir2d from gp +is + + Create (theMaster, theSlave: Array1OfXY from TColgp; + theDir: Dir2d from gp; + theTrsf: Trsf2d from gp) + returns FunctionWithDerivative from Unfolding; + ---Purpose: + + Value(me: in out; X: Real; F: out Real) + ---Purpose: Computes the value of the function for the variable . + -- Returns True if the calculation were successfully done, + -- False otherwise. + + returns Boolean + is redefined; + + Derivative(me: in out; X: Real; D: out Real) + ---Purpose: Computes the derivative of the function + -- for the variable . + -- Returns True if the calculation were successfully done, + -- False otherwise. + + returns Boolean + is redefined; + + Values(me: in out; X: Real; F, D: out Real) + ---Purpose: Computes the value and the derivative of the + -- function for the variable . + -- Returns True if the calculation were successfully done, + -- False otherwise. + + returns Boolean + is redefined; + + GetStateNumber (me: in out) returns Integer from Standard + is redefined; + + Area(me) + returns Real from Standard; + +fields + myMasterPolyLine: Array1OfXY from TColgp; + mySlavePolyLine: Array1OfXY from TColgp; + myTrsf: Trsf2d from gp; + myShiftDir: Dir2d from gp; + myShift: Real from Standard; + myArea: Real from Standard; + +end FunctionWithDerivative from Unfolding; diff --git a/src/Unfolding/Unfolding_FunctionWithDerivative.cxx b/src/Unfolding/Unfolding_FunctionWithDerivative.cxx new file mode 100644 index 0000000000..fca468b391 --- /dev/null +++ b/src/Unfolding/Unfolding_FunctionWithDerivative.cxx @@ -0,0 +1,247 @@ +// File: Unfolding_FunctionWithDerivative.cxx +// Created: Fri Sep 5 17:51:58 2008 +// Author: Mikhail KLOKOV +// + + +#include + + +static Standard_Boolean ComputeArea(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const gp_Dir2d& theShiftDir, + const Standard_Real& theShift, + const gp_Trsf2d theTrsf, + Standard_Real& theArea); + + +static Standard_Boolean ComputeAreaDeriv(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const gp_Dir2d& theShiftDir, + const Standard_Real& theShift, + const gp_Trsf2d theTrsf, + Standard_Real& theArea, + Standard_Real& theDeriv); + + +//============================================================================= +// function: Constructor +//============================================================================= +Unfolding_FunctionWithDerivative::Unfolding_FunctionWithDerivative(const TColgp_Array1OfXY& theMaster, + const TColgp_Array1OfXY& theSlave, + const gp_Dir2d& theDir, + const gp_Trsf2d& theTrsf): +myMasterPolyLine(theMaster.Lower(), theMaster.Upper()), +mySlavePolyLine(theSlave.Lower(), theSlave.Upper()) +{ + myMasterPolyLine.Assign(theMaster); + mySlavePolyLine.Assign(theSlave); + myTrsf = theTrsf; + myShiftDir = theDir; + myShift = 0.; + myArea = 0.; +} + + +//============================================================================= +// function: Value +//============================================================================= +Standard_Boolean Unfolding_FunctionWithDerivative::Value(const Standard_Real X,Standard_Real& F) +{ + myShift = X; + F = 0.; + Standard_Real A = 0.; + Standard_Real D = 0.; + if ( !ComputeAreaDeriv(myMasterPolyLine, mySlavePolyLine, myShiftDir, myShift, myTrsf, A, D) ) + return Standard_False; + + myArea = A; + + gp_XY aP1P2(0, A); + gp_XY vecD(1,D); + Standard_Real modD = vecD.Modulus(); + if ( modD < gp::Resolution() ) { + Standard_Real delta = 1.e-7; + if ( !ComputeArea(myMasterPolyLine, mySlavePolyLine, myShiftDir, myShift - delta, myTrsf, A) ) + return Standard_False; + gp_XY P1(0,A); + if ( !ComputeArea(myMasterPolyLine, mySlavePolyLine, myShiftDir, myShift + delta, myTrsf, A) ) + return Standard_False; + gp_XY P2(0,A); + gp_XY V = P2-P1; + modD = V.Modulus(); + if ( modD < gp::Resolution() ) + return Standard_False; + } + F = aP1P2 * vecD; + F /= modD; + + return Standard_True; +} + +//============================================================================= +// function: Derivative +//============================================================================= +Standard_Boolean Unfolding_FunctionWithDerivative::Derivative(const Standard_Real X,Standard_Real& D) +{ + Standard_Real F = 0.; + return Values(X,F,D); +} + +//============================================================================= +// function: Values +//============================================================================= +Standard_Boolean Unfolding_FunctionWithDerivative::Values(const Standard_Real X,Standard_Real& F,Standard_Real& D) +{ + Standard_Real F1 = 0., F2 = 0.; + Standard_Real aDelta = 1.e-05; + if ( fabs(X) > aDelta ) + aDelta = fabs(X) * aDelta; + if ( !Value(X + aDelta, F2) ) + return Standard_False; + + if ( !Value(X, F1) ) + return Standard_False; + + myShift = X; + F = F1; + D = F2 - F1; + D /= aDelta; + + return Standard_True; +} + +//============================================================================= +// function: GetStateNumber +//============================================================================= +Standard_Integer Unfolding_FunctionWithDerivative::GetStateNumber() +{ + ComputeArea(myMasterPolyLine, mySlavePolyLine, myShiftDir, myShift, myTrsf, myArea); + return 0; +} + +//============================================================================= +// function: Area +//============================================================================= +Standard_Real Unfolding_FunctionWithDerivative::Area() const +{ + return myArea; +} + +//----------------------------------------------------------------------------- +// function: ComputeAreaDeriv +//----------------------------------------------------------------------------- +static Standard_Boolean ComputeAreaDeriv(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const gp_Dir2d& theShiftDir, + const Standard_Real& theShift, + const gp_Trsf2d theTrsf, + Standard_Real& theArea, + Standard_Real& theDeriv) +{ + theArea = 0.; + theDeriv = 0.; + Standard_Real X = theShift; + Standard_Real F1 = 0., F2 = 0.; + if ( !ComputeArea(theMasterPolyLine, theSlavePolyLine, theShiftDir, X, theTrsf, F1) ) + return Standard_False; + theArea = F1; + Standard_Real aDelta = 1.e-05; + if ( fabs(X) > aDelta ) + aDelta = fabs(X) * aDelta; + if ( !ComputeArea(theMasterPolyLine, theSlavePolyLine, theShiftDir, X + aDelta, theTrsf, F2) ) + return Standard_False; + + theDeriv = F2 - F1; + theDeriv /= aDelta; + return Standard_True; +} + +//----------------------------------------------------------------------------- +// function: ComputeArea +//----------------------------------------------------------------------------- +static Standard_Boolean ComputeArea(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const gp_Dir2d& theShiftDir, + const Standard_Real& theShift, + const gp_Trsf2d theTrsf, + Standard_Real& theArea) +{ + if ( ( theMasterPolyLine.Length() < 2 ) || ( theSlavePolyLine.Length() < 2 ) || + ( theSlavePolyLine.Length() != theMasterPolyLine.Length() ) ) + return Standard_False; + theArea = 0.; + + gp_Vec2d aTranslation( theShiftDir.XY() * theShift ); + + gp_Trsf2d aTransTrsf; + aTransTrsf.SetTranslation( aTranslation ); + gp_Trsf2d aTrans; + aTrans = aTransTrsf * theTrsf; + + // + TColgp_Array1OfXY aTransformedSlave(theSlavePolyLine.Lower(), theSlavePolyLine.Upper()); + Standard_Integer i = 0; + for ( i = aTransformedSlave.Lower(); i <= aTransformedSlave.Upper(); i++ ) { + gp_Pnt2d aP( theSlavePolyLine.Value( i ) ); + aP.Transform( aTrans ); + aTransformedSlave.SetValue( i, aP.XY() ); + } + // + + // compute area + // This method assumes that the polylines shape is similar + // if the shape is completely different, the compute area will be wrong. + // But it will grow, that can be considered as a condition of distortion. + // So, the method can be acceptable. + gp_XY aFirstPoint = aTransformedSlave( aTransformedSlave.Lower() ); + aFirstPoint += theMasterPolyLine( theMasterPolyLine.Lower() ); + aFirstPoint *= 0.5; + + gp_XY aLastPoint = aTransformedSlave( aTransformedSlave.Upper() ); + aLastPoint += theMasterPolyLine( theMasterPolyLine.Upper() ); + aLastPoint *= 0.5; + Standard_Integer nIndexDif = theMasterPolyLine.Lower() - aTransformedSlave.Lower(); + + gp_XY aP1 = aFirstPoint; + gp_XY aP3 = aFirstPoint; + + for ( i = theMasterPolyLine.Lower() + 1; i <= theMasterPolyLine.Upper(); i++ ) { + gp_XY aP2 = theMasterPolyLine(i); + gp_XY aP4 = aTransformedSlave(i-nIndexDif); + if ( i == theMasterPolyLine.Upper() ) { + aP2 = aLastPoint; + aP4 = aLastPoint; + } + gp_XY aP1P4 = aP4 - aP1; + gp_XY aP1P2 = aP2 - aP1; + gp_XY aP1P3 = aP3 - aP1; + Standard_Real aprod1 = aP1P4 ^ aP1P3; + Standard_Real aprod2 = aP1P4 ^ aP1P2; + if ( aprod1 * aprod2 <= 0. ) { + theArea += 0.5 * ( fabs( aprod1 ) + fabs( aprod2 ) ); + } + else { + gp_XY aP3P2 = aP2 - aP3; + gp_XY aP3P4 = aP4 - aP3; + gp_XY aP3P1 = -aP1P3; + + Standard_Real asum = 0.5 * ( fabs( aprod1 ) + fabs( aprod2 ) ); + aprod1 = aP3P2 ^ aP3P4; + aprod2 = aP3P2 ^ aP3P1; + if ( aprod1 * aprod2 <= 0. ) { + theArea += 0.5 * ( fabs( aprod1 ) + fabs( aprod2 ) ); + } + else { + asum += 0.5 * ( fabs( aprod1 ) + fabs( aprod2 ) ); + asum *= 0.5; + theArea += asum; + } + } + + aP1 = aP2; + aP3 = aP4; + } + + return Standard_True; +} diff --git a/src/Unfolding/Unfolding_Point.cdl b/src/Unfolding/Unfolding_Point.cdl new file mode 100644 index 0000000000..8c62588e8e --- /dev/null +++ b/src/Unfolding/Unfolding_Point.cdl @@ -0,0 +1,82 @@ +-- File: Unfolding_Point.cdl +-- Created: Mon Jul 28 14:56:12 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Matra Datavision 2008 + + +class Point from Unfolding + ---Purpose: This class represents a data container for a point. It contains + -- a point on a surface, its U and V parameters on a surface, + -- corresponding point on an unfolding plane. + +uses + + XY from gp, + XYZ from gp, + Real from Standard + +is + + Create + ---Purpose: Empty constructor. + ---C++: inline + returns Point from Unfolding; + + SetPointOnSurface(me: in out; thePOnSurface: XYZ from gp); + ---Purpose: Sets the point on a surface. + ---C++: inline + + GetPointOnSurface(me) + ---Purpose: Returns the point on a surface. + ---C++: return const & + ---C++: inline + returns XYZ from gp; + + SetParameters(me: in out; theU: Real from Standard; + theV: Real from Standard); + ---Purpose: Sets the U and V parameters of the point on a surface. + ---C++: inline + + GetParameters(me; theU: out Real from Standard; + theV: out Real from Standard); + ---Purpose: Returns the U and V parameters of the point on a surface. + ---C++: inline + + GetU(me) + ---Purpose: Returns the U parameter of the point on a surface. + ---C++: inline + returns Real from Standard; + + GetV(me) + ---Purpose: Returns the V parameter of the point on a surface. + ---C++: inline + returns Real from Standard; + + SetAngle(me: in out; theAngle: Real from Standard); + ---Purpose: Sets the angle between DU and DV directions. + ---C++: inline + + GetAngle(me) + ---Purpose: Returns the angle between DU and DV directions. + ---C++: inline + returns Real from Standard; + + SetPointOnPlane(me: in out; thePOnPlane: XY from gp); + ---Purpose: Sets the point on an unfolding plane. + ---C++: inline + + GetPointOnPlane(me) + ---Purpose: Returns the point on an unfolding plane. + ---C++: return const & + ---C++: inline + returns XY from gp; + +fields + + myPoint2d : XY from gp; + myPOnSurface : XYZ from gp; + myPOnPlane : XY from gp; + myAngle : Real from Standard; + +end; diff --git a/src/Unfolding/Unfolding_Point.cxx b/src/Unfolding/Unfolding_Point.cxx new file mode 100644 index 0000000000..d5f08731a8 --- /dev/null +++ b/src/Unfolding/Unfolding_Point.cxx @@ -0,0 +1,8 @@ +// File: Unfolding_Point.cxx +// Created: Mon Jul 28 15:27:34 2008 +// Author: Sergey KHROMOV +// + + +#include + diff --git a/src/Unfolding/Unfolding_Point.lxx b/src/Unfolding/Unfolding_Point.lxx new file mode 100644 index 0000000000..566b2a0437 --- /dev/null +++ b/src/Unfolding/Unfolding_Point.lxx @@ -0,0 +1,116 @@ +// File: Unfolding_Point.lxx +// Created: Mon Jul 28 15:18:15 2008 +// Author: Sergey KHROMOV +// + + +//======================================================================= +//function : Empty constructor +//purpose : +//======================================================================= + +inline Unfolding_Point::Unfolding_Point() + : myAngle(-1.) +{ +} + +//======================================================================= +//function : SetPointOnSurface +//purpose : +//======================================================================= + +inline void Unfolding_Point::SetPointOnSurface(const gp_XYZ &thePOnSurface) +{ + myPOnSurface = thePOnSurface; +} +//======================================================================= +//function : GetPointOnSurface +//purpose : +//======================================================================= + +inline const gp_XYZ &Unfolding_Point::GetPointOnSurface() const +{ + return myPOnSurface; +} + +//======================================================================= +//function : SetParameters +//purpose : +//======================================================================= + +inline void Unfolding_Point::SetParameters(const Standard_Real theU, + const Standard_Real theV) +{ + myPoint2d.SetCoord(theU, theV); +} + +//======================================================================= +//function : GetParameters +//purpose : +//======================================================================= + +inline void Unfolding_Point::GetParameters(Standard_Real &theU, + Standard_Real &theV) const +{ + myPoint2d.Coord(theU, theV); +} + +//======================================================================= +//function : GetU +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_Point::GetU() const +{ + return myPoint2d.X(); +} + +//======================================================================= +//function : GetV +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_Point::GetV() const +{ + return myPoint2d.Y(); +} + +//======================================================================= +//function : GetAngle +//purpose : +//======================================================================= + +inline void Unfolding_Point::SetAngle(const Standard_Real theAngle) +{ + myAngle = theAngle; +} + +//======================================================================= +//function : GetAngle +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_Point::GetAngle() const +{ + return myAngle; +} + +//======================================================================= +//function : SetPointOnPlane +//purpose : +//======================================================================= + +inline void Unfolding_Point::SetPointOnPlane(const gp_XY &thePOnPlane) +{ + myPOnPlane = thePOnPlane; +} + +//======================================================================= +//function : GetPointOnPlane +//purpose : +//======================================================================= + +inline const gp_XY &Unfolding_Point::GetPointOnPlane() const +{ + return myPOnPlane; +} diff --git a/src/Unfolding/Unfolding_Shell.cdl b/src/Unfolding/Unfolding_Shell.cdl new file mode 100644 index 0000000000..403ecf1a2d --- /dev/null +++ b/src/Unfolding/Unfolding_Shell.cdl @@ -0,0 +1,167 @@ +-- File: Unfolding_Shell.cdl +-- Created: Tue Sep 9 16:56:09 2008 +-- Author: Mikhail KLOKOV +-- +---Copyright: Open CASCADE 2008 + +class Shell from Unfolding + + ---Purpose: This class is used to perform unfolding of a shell onto a plane. + -- To perform this operation it is necessary to initialize the + -- object by a shell to be unfolded, a plane and a tolerance for + -- operation. Then to call the method Perform. The result planar + -- shell can be obtained using the method GetResult. Error status + -- can be obtained by the method ErrorStatus. + +uses + + ErrorStatus from Unfolding, + Shell from TopoDS, + Face from TopoDS, + ListOfShape from TopTools, + Pln from gp, + Real from Standard, + IndexedMapOfFaceDataContainer from Unfolding, + FaceDataContainer from Unfolding + +is + + Create + ---Purpose: Empty constructor + returns Shell from Unfolding; + + Create (theShell : Shell from TopoDS; + thePlane : Pln from gp; + theContourTolerance: Real from Standard; + theCurvatureTolerance: Real from Standard = 0.001; + theDeflection: Real from Standard = 0.001) + ---Purpose: Constructor. Initializes the object with the shell, the plane and + -- the tolerances for operation. + returns Shell from Unfolding; + + SetShell (me: in out; theShell: Shell from TopoDS); + ---Purpose: Sets the face. + ---C++: inline + + GetShell (me) + ---Purpose: Returns the shell. + ---C++: inline + ---C++: return const & + returns Shell from TopoDS; + + SetPlane (me: in out; thePlane: Pln from gp); + ---Purpose: Sets the plane. + ---C++: inline + + GetPlane (me) + ---Purpose: Returns the plane. + ---C++: inline + ---C++: return const & + returns Pln from gp; + + SetCurvatureTolerance (me: in out; theTolerance: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetCurvatureTolerance (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + SetContourTolerance (me: in out; theTolerance: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetContourTolerance (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + SetDeflection (me: in out; theDeflection: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetDeflection (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + Perform (me: in out) + ---Purpose: Performs computation of the unfolded surface. It returns + -- Standard_True if the operation succeeds otherwise returns + -- Standard_False. It is possible to get the error status of + -- the performed operation using the method ErrorStatus(). + returns Boolean from Standard; + + ErrorStatus (me) + ---Purpose: Returns error status of the operation. The error status can have + -- one of the following values: + -- - Unfolding_Done: operation is succeeded; + -- - Unfolding_NotDone: the method Perform() is not called yet; + -- - Unfolding_Failure: the operation is failed; + -- - Unfolding_InvalidSurface: the surface cannot be unfolded + -- without distortion; + -- - Unfolding_InvalidInput: invalid input for the operation; + -- - Unfolding_InvalidShape: can be returned by + -- Unfolding::ToShape method; + -- - Unfolding_ComplexShape: can be returned by + -- Unfolding::ToShape method; + ---C++: inline + returns ErrorStatus from Unfolding; + + GetResult (me) + ---Purpose: Returns the result of the operation. If the operation is failed, + -- it returns a null shape. + ---C++: inline + ---C++: return const & + returns Face from TopoDS; + + + GetAreaError(me) + ---Purpose: Returns the area cumulated during primitive patches mergin. + -- It shows computed distortion. + ---C++: inline + returns Real from Standard; + + GetMaxGaussCurvature(me) + ---Purpose: Returns the gauss curvature computed in the mesh points. + ---C++: inline + returns Real from Standard; + + + + --protected + Reset(me: in out) + ---Purpose: Resets data to the initial state. + ---C++: inline + is protected; + + --private + ComputeTransformed(me: in out; theResult: in out ListOfShape from TopTools) + returns Boolean from Standard + is private; + + MoveFace2ToFace1(me: in out; theFaceData1 : FaceDataContainer from Unfolding; + theFaceData2 : FaceDataContainer from Unfolding; + theCommonEdges: ListOfShape from TopTools; + theIsFixed : Boolean from Standard) + ---Purpose: Perform transformation of unfolded face2 to glue with unfolded + -- face1. If theIsFixed is Standard_True, the face 2 is not + -- transformed only estimations of distortions are performed. + returns Boolean from Standard + is private; + +fields + + myShell : Shell from TopoDS; + myPlane : Pln from gp; + myTolContour : Real from Standard; + myTolCurvature : Real from Standard; + myDeflection : Real from Standard; + myMapFaceData : IndexedMapOfFaceDataContainer from Unfolding; + myResult : Face from TopoDS; + myErrorStatus : ErrorStatus from Unfolding; + myDistortionArea : Real from Standard; + myCurvature : Real from Standard; + +end Shell from Unfolding; diff --git a/src/Unfolding/Unfolding_Shell.cxx b/src/Unfolding/Unfolding_Shell.cxx new file mode 100644 index 0000000000..f6430e17ab --- /dev/null +++ b/src/Unfolding/Unfolding_Shell.cxx @@ -0,0 +1,777 @@ +// File: Unfolding_Shell.cxx +// Created: Tue Sep 9 17:14:33 2008 +// Author: Mikhail KLOKOV +// + + +#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 + + +static Standard_Boolean CombineCurves(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const Standard_Boolean IsFixed, + const Standard_Real theConfTolerance, + const Standard_Real theAreaTolerance, + gp_Trsf2d& theTransformation, + Standard_Real& theDistortionArea); + +// ============================================================================== +// function: GetCommonEdges +// purpose : This function returns the list of common edges of two faces. +// ============================================================================== +static void GetCommonEdges(const TopoDS_Face &theFace1, + const TopoDS_Face &theFace2, + TopTools_ListOfShape &theCommonEdges) +{ + TopTools_IndexedMapOfShape aMapEdges1; + TopExp_Explorer anExp2(theFace2, TopAbs_EDGE); + + TopExp::MapShapes(theFace1, TopAbs_EDGE, aMapEdges1); + theCommonEdges.Clear(); + + for (; anExp2.More(); anExp2.Next()) { + const TopoDS_Shape &anEdge2 = anExp2.Current(); + + if (aMapEdges1.Contains(anEdge2)) + theCommonEdges.Append(anEdge2); + } +} + +// ============================================================================== +// function: GetWires +// purpose : This function returns a list of wires edges composed from theEdges. +// ============================================================================== +static Standard_Boolean GetWires(const TopTools_ListOfShape &theEdges, + TopTools_ListOfShape &theWires) +{ + TopTools_ListIteratorOfListOfShape anEdgeIter(theEdges); + TopTools_DataMapOfShapeListOfShape aMapVE; + TopExp_Explorer anExp; + TopTools_MapOfShape aMapUsed; + + for (; anEdgeIter.More(); anEdgeIter.Next()) { + const TopoDS_Shape &anEdge = anEdgeIter.Value(); + + if (!aMapUsed.Add(anEdge) || BRep_Tool::Degenerated(TopoDS::Edge(anEdge))) + continue; + + for (anExp.Init(anEdge, TopAbs_VERTEX); anExp.More(); anExp.Next()) { + const TopoDS_Shape &aVertex = anExp.Current(); + + if (!aMapVE.IsBound(aVertex)) { + TopTools_ListOfShape aList; + aMapVE.Bind(aVertex, aList); + } + + TopTools_ListOfShape &aListAncEdges = aMapVE.ChangeFind(aVertex); + + aListAncEdges.Append(anEdge); + } + } + + // Construct wires as chains of edges. + Standard_Boolean isToTreat = Standard_True; + TopoDS_Vertex aFirstVtx; + TopoDS_Edge aCurEdge; + TopoDS_Vertex aV[2]; + BRep_Builder aBuilder; + + for(;;) { + isToTreat = Standard_False; + + // Get the bounding vertex, i.e. the vertex that contains only one edge in + // the list of ancestors. + TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aMapIter(aMapVE); + + for (; aMapIter.More(); aMapIter.Next()) { + const TopTools_ListOfShape &anEdges = aMapIter.Value(); + + if (anEdges.Extent() == 1) { + isToTreat = Standard_True; + break; + } + } + + if (!isToTreat) { + // Get a closed loop. + for (aMapIter.Initialize(aMapVE); aMapIter.More(); aMapIter.Next()) { + const TopTools_ListOfShape &anEdges = aMapIter.Value(); + + if (anEdges.Extent() == 1) { + isToTreat = Standard_True; + break; + } + } + } + + // Stop treatment if there is no more edges. + if (!isToTreat) + break; + + // Treat the list of edges starting from the current iterator. + TopoDS_Wire aWire; + + aBuilder.MakeWire(aWire); + aFirstVtx = TopoDS::Vertex(aMapIter.Key()); + + while (!aFirstVtx.IsNull()) { + const TopTools_ListOfShape &anEdges = aMapVE.ChangeFind(aFirstVtx); + + aCurEdge = TopoDS::Edge(anEdges.First()); + TopExp::Vertices(aCurEdge, aV[0], aV[1], Standard_True); + + if (aFirstVtx.IsSame(aV[1])) { + aV[1] = aV[0]; + aV[0] = aFirstVtx; + aCurEdge.Reverse(); + } + + aBuilder.Add(aWire, aCurEdge); + + TopTools_ListOfShape &anEdges1 = aMapVE.ChangeFind(aV[0]); + TopTools_ListOfShape &anEdges2 = aMapVE.ChangeFind(aV[1]); + + // Remove the current edge from aMapVE. + anEdges1.RemoveFirst(); + + if (anEdges1.IsEmpty()) + aMapVE.UnBind(aV[0]); + + if (anEdges2.IsEmpty() || anEdges2.Extent() > 2) + return Standard_False; + + if (aCurEdge.IsSame(anEdges2.First())) { + // Remove first element. + anEdges2.RemoveFirst(); + } else if (aCurEdge.IsSame(anEdges2.Last())) { + // Remove last element. + TopTools_ListIteratorOfListOfShape anEdgeIt(anEdges2); + + anEdgeIt.Next(); + anEdges2.Remove(anEdgeIt); + } else { + return Standard_False; + } + + if (anEdges2.IsEmpty()) { + aMapVE.UnBind(aV[1]); + aFirstVtx.Nullify(); + } else { + aFirstVtx = aV[1]; + } + } + + theWires.Append(aWire); + } + + return Standard_True; +} + +// ============================================================================== +// function: Constructor +// ============================================================================== +Unfolding_Shell::Unfolding_Shell() + : myTolContour(0.001), + myTolCurvature(0.001), + myDeflection(0.001), + myDistortionArea(0.), + myCurvature(0.) +{ + Reset(); +} + +// ============================================================================== +// function: Constructor +// ============================================================================== +Unfolding_Shell::Unfolding_Shell(const TopoDS_Shell& theShell, + const gp_Pln& thePlane, + const Standard_Real theContourTolerance, + const Standard_Real theCurvatureTolerance, + const Standard_Real theDeflection) + : myShell(theShell), + myPlane(thePlane), + myTolContour(theContourTolerance), + myTolCurvature(theCurvatureTolerance), + myDeflection(theDeflection), + myDistortionArea(0.), + myCurvature(0.) +{ + Reset(); +} + +// ============================================================================== +// function: Perform +// ============================================================================== +Standard_Boolean Unfolding_Shell::Perform() +{ + // Check if the operation is already performed and there is nothing to do. + if (myErrorStatus != Unfolding_NotDone) + return (myErrorStatus == Unfolding_Done); + + // Check input data validity. + if (myShell.IsNull() || + ( myTolContour <= RealEpsilon() ) || + ( myTolCurvature <= RealEpsilon() ) || + ( myDeflection <= RealEpsilon() ) ) { + myErrorStatus = Unfolding_InvalidInput; + return Standard_False; + } + + // Compute number of samples for each edge of the shell. + TopTools_DataMapOfShapeInteger aMapEdgeNbSamples; + TopTools_IndexedDataMapOfShapeListOfShape aMapEF; + Standard_Integer i; + Standard_Integer aNbEdges; + + + TopExp::MapShapesAndAncestors(myShell, TopAbs_EDGE, TopAbs_FACE, aMapEF); + aNbEdges = aMapEF.Extent(); + + for (i = 1; i <= aNbEdges; i++) { + TopoDS_Edge anEdge = TopoDS::Edge(aMapEF.FindKey(i)); + const TopTools_ListOfShape &aFaces = aMapEF.FindFromIndex(i); + Standard_Integer aNbPoints = Unfolding::NbSamples(anEdge, aFaces, + myTolContour); + + aMapEdgeNbSamples.Bind(anEdge, aNbPoints); + } + + // Perform unfolding of each face. + TopTools_ListOfShape aList2Sew; + myDistortionArea = 0.; + myCurvature = 0.; + TopExp_Explorer anExp( myShell, TopAbs_FACE ); + Standard_Boolean isFirstReversed = Standard_False; + + for ( ; anExp.More(); anExp.Next() ) { + TopoDS_Face aFaceOriginal = TopoDS::Face( anExp.Current() ); + TopoDS_Face aFace = aFaceOriginal; + aFace.Orientation( TopAbs_FORWARD ); + + Unfolding_Surface anUnfoldFace(aFace, myPlane, myTolContour, + myTolCurvature, myDeflection); + + Standard_Boolean isDone = + anUnfoldFace.Perform(aMapEdgeNbSamples); + Handle(Unfolding_FaceDataContainer) aFaceData = anUnfoldFace.GetDataContainer(); + + // Keep the original orientation of unfolding data container. + aFaceData->SetFace(aFaceOriginal); + + if ( myCurvature < aFaceData->GetMaxGaussCurvature() ) + myCurvature = aFaceData->GetMaxGaussCurvature(); + myDistortionArea += aFaceData->GetDistortionArea(); + + if ( !isDone ) { + myErrorStatus = anUnfoldFace.ErrorStatus(); + return Standard_False; + } + if ( myMapFaceData.IsEmpty() ) { + isFirstReversed = ( aFaceOriginal.Orientation() == TopAbs_REVERSED ); + } + + TopoDS_Face aNewFace = aFaceData->GetUnfoldedFace(); + + Standard_Boolean toReverse = ( aFaceOriginal.Orientation() == TopAbs_REVERSED ); + if ( isFirstReversed ) + toReverse = !toReverse; + gp_Trsf aTrsfPln; + + if ( toReverse ) { + // Take into account the faces of different orientation are unfolded + // as mirror compared to the first unfolded face representation + aTrsfPln.SetMirror( gp_Ax1( myPlane.Location(), myPlane.Position().XDirection() ) ); + aFaceData->ApplyTrsf(aTrsfPln); + } + + myMapFaceData.Add(aFaceData); + } + // + + if ( !ComputeTransformed( aList2Sew ) ) { + return Standard_False; + } + + // + BRep_Builder aBuilder; + TopoDS_Compound aCompound; + TopTools_ListIteratorOfListOfShape anIt( aList2Sew ); + + aBuilder.MakeCompound(aCompound); + + for ( ; anIt.More(); anIt.Next() ) + aBuilder.Add(aCompound, anIt.Value()); + + Unfolding_ErrorStatus aStatus; + TopoDS_Shell aShell = Unfolding::ToShell(aCompound, + myTolContour, aStatus); + + if (aShell.IsNull()) { + switch (aStatus) { + case Unfolding_ComplexShape: + myErrorStatus = Unfolding_ComplexShape; + break; + case Unfolding_InvalidShape: + myErrorStatus = Unfolding_InvalidShape; + break; + default: + myErrorStatus = Unfolding_Failure; + break; + } + return Standard_False; + } + + ShapeAnalysis_FreeBoundsProperties aFreeBoundAlgo(aShell); + + if ( !aFreeBoundAlgo.Perform() ) { + myErrorStatus = Unfolding_Failure; + return Standard_False; + } + + Handle(ShapeAnalysis_HSequenceOfFreeBounds) aSeqWire; + aSeqWire = aFreeBoundAlgo.ClosedFreeBounds(); + + BRepBuilderAPI_MakeFace aFaceMaker(myPlane); + + if ( !aSeqWire.IsNull() ) { + for ( Standard_Integer w = 1; w <= aSeqWire->Length(); w++ ) { + aFaceMaker.Add( aSeqWire->Value(w)->FreeBound() ); + } + } + myResult = aFaceMaker.Face(); + +#ifdef DEB + cout << "Checking the result..." << endl; +#endif + BRepCheck_Analyzer aChecker( myResult, Standard_True ); + if ( !aChecker.IsValid() ) { + myErrorStatus = Unfolding_ComplexShape; + return Standard_False; + } + return Standard_True; +} + +// ============================================================================== +// function: ComputeTransformed +// ============================================================================== +Standard_Boolean Unfolding_Shell::ComputeTransformed(TopTools_ListOfShape& theResult) +{ + theResult.Clear(); + + // If the map of face data is empty, nothing to do. + if (myMapFaceData.IsEmpty()) + return Standard_True; + + TopTools_MapOfShape aMapTreated; + TColStd_MapOfInteger aMapTreatedIndices; + TopTools_IndexedDataMapOfShapeListOfShape aMapEF; + Standard_Integer i; + Standard_Integer aNbFaces = myMapFaceData.Extent(); + TColStd_ListOfInteger aListToTreat; + Handle(Unfolding_FaceDataContainer) aDummyFaceData; + + aDummyFaceData = new Unfolding_FaceDataContainer; + TopExp::MapShapesAndAncestors( myShell, TopAbs_EDGE, TopAbs_FACE, aMapEF ); + + for (i = 1; i <= aNbFaces; i++) { + // Skip index already treated. + if (aMapTreatedIndices.Contains(i)) + continue; + + aListToTreat.Append(i); + + while (!aListToTreat.IsEmpty()) { + Standard_Integer anIndex = aListToTreat.First(); + + if (!aMapTreatedIndices.Add(anIndex)) + continue; + + aListToTreat.RemoveFirst(); + + const Handle(Unfolding_FaceDataContainer) &aFaceData = + myMapFaceData.FindKey(anIndex); + const TopoDS_Face &aFace = + aFaceData->GetFace(); + + aMapTreated.Add(aFace); + + TopExp_Explorer anEdgeExp(aFace, TopAbs_EDGE); + + for ( ; anEdgeExp.More(); anEdgeExp.Next() ) { + const TopoDS_Shape &anEdge = anEdgeExp.Current(); + + if (!aMapTreated.Add(anEdge) || !aMapEF.Contains(anEdge)) { + // This edge is already treated or it is absent in aMapEF. Skip it. + continue; + } + + // Treat faces share the edge anEdge with the face aFace. + const TopTools_ListOfShape &aFaces = aMapEF.FindFromKey(anEdge); + TopTools_ListIteratorOfListOfShape aFaceIter(aFaces); + + for (; aFaceIter.More(); aFaceIter.Next()) { + const TopoDS_Shape &aNeighborFace = aFaceIter.Value(); + + // Skip aFace + if (aFace.IsSame(aNeighborFace)) + continue; + + aDummyFaceData->SetFace(TopoDS::Face(aNeighborFace)); + + Standard_Boolean isFixed = !aMapTreated.Add(aNeighborFace); + Standard_Integer aNeighborIndex = myMapFaceData.FindIndex(aDummyFaceData); + + if (aNeighborIndex == 0) { + myErrorStatus = Unfolding_Failure; + + return Standard_False; // This is an invalid case. + } + + const Handle(Unfolding_FaceDataContainer) &aNeighborFaceData = + myMapFaceData.FindKey(aNeighborIndex); + TopTools_ListOfShape aCommonEdges; + + GetCommonEdges(aFace, aNeighborFaceData->GetFace(), aCommonEdges); + + if (!MoveFace2ToFace1(aFaceData, aNeighborFaceData, + aCommonEdges, isFixed)) + return Standard_False; + + // Add common edge to the map of treated shapes. + TopTools_ListIteratorOfListOfShape anEdgeIter(aCommonEdges); + + for (; anEdgeIter.More(); anEdgeIter.Next()) + aMapTreated.Add(anEdgeIter.Value()); + + if (!isFixed) + aListToTreat.Append(aNeighborIndex); + } + } + + theResult.Append(aFaceData->GetUnfoldedFace()); + } + } + + return Standard_True; +} + + +// ============================================================================== +// function: MoveFace2ToFace1 +// ============================================================================== +Standard_Boolean Unfolding_Shell::MoveFace2ToFace1 + (const Handle(Unfolding_FaceDataContainer) &theFaceData1, + const Handle(Unfolding_FaceDataContainer) &theFaceData2, + const TopTools_ListOfShape &theCommonEdges, + const Standard_Boolean theIsFixed) +{ + TopTools_ListOfShape aWires; + + if (!GetWires(theCommonEdges, aWires)) { + myErrorStatus = Unfolding_Failure; + + return Standard_False; + } + + // Get a wire with the greatest distance between first and last vertices. + TopoDS_Wire aRefWire; + TopoDS_Wire aWire; + TopTools_ListIteratorOfListOfShape anIter(aWires); + Standard_Real aMaxDist = -1; + Standard_Real aDist; + TopoDS_Vertex aV[2]; + + for (; anIter.More(); anIter.Next()) { + aWire = TopoDS::Wire(anIter.Value()); + TopExp::Vertices(aWire, aV[0], aV[1]); + + gp_Pnt aP1 = BRep_Tool::Pnt(aV[0]); + gp_Pnt aP2 = BRep_Tool::Pnt(aV[1]); + + aDist = aP1.Distance(aP2); + + if (aDist > aMaxDist) { + aMaxDist = aDist; + aRefWire = aWire; + } + } + + if (aRefWire.IsNull()) { + myErrorStatus = Unfolding_Failure; + + return Standard_False; + } + + // Compute points. + Standard_Boolean isReversedOn1 = Standard_False; + Standard_Boolean isReversedOn2 = Standard_False; + TopExp_Explorer anExp(aRefWire, TopAbs_EDGE); + + if (anExp.More()) { + TopoDS_Edge aFirstEdge = TopoDS::Edge(anExp.Current()); + TopoDS_Face aFace1 = theFaceData1->GetFace(); + TopoDS_Face aFace2 = theFaceData2->GetFace(); + + TopExp_Explorer aFaceExp(aFace1, TopAbs_EDGE); + + for (; aFaceExp.More(); aFaceExp.Next()) { + const TopoDS_Shape &anEdgeOnF1 = aFaceExp.Current(); + + if (aFirstEdge.IsSame(anEdgeOnF1)) { + if (aFirstEdge.Orientation() != anEdgeOnF1.Orientation()) + isReversedOn1 = Standard_True; + + break; + } + } + + // If aFirstEdge is not found on the face1. It is not possible by construction. + // Return with error status. + if (!aFaceExp.More()) { + myErrorStatus = Unfolding_Failure; + + return Standard_False; + } + + if (aFace1.Orientation() == aFace2.Orientation()) + isReversedOn2 = !isReversedOn1; + else + isReversedOn2 = isReversedOn1; + } + + // Collect points. + TopoDS_Shape aFace1 = theFaceData1->GetUnfoldedFace(); + TopoDS_Shape aFace2 = theFaceData2->GetUnfoldedFace(); + TColgp_SequenceOfXY aMasterPoints; + TColgp_SequenceOfXY aSlavePoints; + gp_Pnt2d aUV[2]; + Handle(Geom_Surface) aSurface = new Geom_Plane(myPlane); + TopLoc_Location aLoc; + + for (; anExp.More(); anExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current()); + const TopTools_ListOfShape &anUnfld1 = theFaceData1->GetEdgesForEdge(anEdge); + const TopTools_ListOfShape &anUnfld2 = theFaceData2->GetEdgesForEdge(anEdge); + + // Fill aMasterPoints. + for (anIter.Initialize(anUnfld1); anIter.More(); anIter.Next()) { + TopoDS_Edge anUnfoldEdge = TopoDS::Edge(anIter.Value()); + + if (isReversedOn1) + BRep_Tool::UVPoints(anUnfoldEdge, aSurface, aLoc, aUV[1], aUV[0]); + else + BRep_Tool::UVPoints(anUnfoldEdge, aSurface, aLoc, aUV[0], aUV[1]); + + // Add the first point if the collection is empty. + if (aMasterPoints.IsEmpty()) + aMasterPoints.Append(aUV[0].XY()); + + // Add the last point. + if (isReversedOn1) + aMasterPoints.Prepend(aUV[1].XY()); + else + aMasterPoints.Append(aUV[1].XY()); + } + + // Fill aSlavePoints. + for (anIter.Initialize(anUnfld2); anIter.More(); anIter.Next()) { + TopoDS_Edge anUnfoldEdge = TopoDS::Edge(anIter.Value()); + + if (isReversedOn2) + BRep_Tool::UVPoints(anUnfoldEdge, aSurface, aLoc, aUV[1], aUV[0]); + else + BRep_Tool::UVPoints(anUnfoldEdge, aSurface, aLoc, aUV[0], aUV[1]); + + // Add the first point if the collection is empty. + if (aSlavePoints.IsEmpty()) + aSlavePoints.Append(aUV[0].XY()); + + // Add the last point. + if (isReversedOn2) + aSlavePoints.Prepend(aUV[1].XY()); + else + aSlavePoints.Append(aUV[1].XY()); + } + } + + // Construct array of points. + Handle(TColgp_HArray1OfXY) aMasterPolyLine; + Handle(TColgp_HArray1OfXY) aSlavePolyLine; + Standard_Integer i = 0; + + aMasterPolyLine = new TColgp_HArray1OfXY( 1, aMasterPoints.Length() ); + aSlavePolyLine = new TColgp_HArray1OfXY( 1, aSlavePoints.Length() ); + + for ( i = aMasterPolyLine->Lower(); i <= aMasterPolyLine->Upper(); i++ ) + aMasterPolyLine->SetValue( i, aMasterPoints(i) ); + + for ( i = aSlavePolyLine->Lower(); i <= aSlavePolyLine->Upper(); i++ ) + aSlavePolyLine->SetValue( i, aSlavePoints(i) ); + + // Compute transformation + gp_Trsf2d aTransformation2d; + Standard_Real aDistortionArea; + + if ( !CombineCurves(aMasterPolyLine->Array1(), aSlavePolyLine->Array1(), + theIsFixed, myTolContour, myTolContour*myTolContour, + aTransformation2d, aDistortionArea) ) { + myDistortionArea += aDistortionArea; + myErrorStatus = Unfolding_InvalidSurface; + + return Standard_False; + } + + myDistortionArea += aDistortionArea; + + // Trasform face + if (!theIsFixed) { + gp_Trsf aTrsf2dTo3d( aTransformation2d ); + gp_Trsf aTrsfPln1, aTrsfPln2; + gp_Ax3 anAx3( gp_Pnt(0,0,0), gp_Dir(0,0,1), gp_Dir(1,0,0)); + + aTrsfPln1.SetDisplacement( myPlane.Position(), anAx3 ); + aTrsfPln2.SetDisplacement( anAx3, myPlane.Position() ); + + gp_Trsf aTransformation = aTrsf2dTo3d * aTrsfPln1; + + aTransformation = aTrsfPln2 * aTransformation; + theFaceData2->ApplyTrsf(aTransformation); + } + + return Standard_True; +} + +//----------------------------------------------------------------------- +//function : CombineCurves +//purpose : +//----------------------------------------------------------------------- +static Standard_Boolean CombineCurves(const TColgp_Array1OfXY& theMasterPolyLine, + const TColgp_Array1OfXY& theSlavePolyLine, + const Standard_Boolean IsFixed, + const Standard_Real theConfTolerance, + const Standard_Real theAreaTolerance, + gp_Trsf2d& theTransformation, + Standard_Real& theDistortionArea) +{ + theDistortionArea = 0.; + + if ( ( theMasterPolyLine.Length() < 2 ) || ( theSlavePolyLine.Length() < 2 ) ) + return Standard_False; + + gp_XY aPMasterFirst = theMasterPolyLine.Value(theMasterPolyLine.Lower()); + gp_XY aPMasterLast = theMasterPolyLine.Value(theMasterPolyLine.Upper()); + gp_XY aPSlaveFirst = theSlavePolyLine.Value(theSlavePolyLine.Lower()); + gp_XY aPSlaveLast = theSlavePolyLine.Value(theSlavePolyLine.Upper()); + + if (aPMasterFirst.IsEqual(aPMasterLast, theConfTolerance) || + aPSlaveFirst.IsEqual(aPSlaveLast, theConfTolerance)) { + // One of polylines is closed. Get the points previous to the last ones. + aPMasterLast = theMasterPolyLine.Value(theMasterPolyLine.Upper() - 1); + aPSlaveLast = theSlavePolyLine.Value(theSlavePolyLine.Upper() - 1); + + if (aPMasterFirst.IsEqual(aPMasterLast, theConfTolerance) || + aPSlaveFirst.IsEqual(aPSlaveLast, theConfTolerance)) + return Standard_False; + } + + Standard_Real aRotation = 0.; + gp_XY aTranslation; + + gp_Vec2d aLineDir1(aPMasterLast - aPMasterFirst); + gp_Vec2d aLineDir2(aPSlaveLast - aPSlaveFirst); + + aTranslation = aPMasterFirst - aPSlaveFirst; + Standard_Real aLen1 = aLineDir1.Magnitude(); + Standard_Real aLen2 = aLineDir2.Magnitude(); + Standard_Real aShift = ( aLen2 - aLen1 ) * 0.5; + if ( aLen1 > gp::Resolution() ) { + aTranslation = aTranslation - aLineDir1.XY() * (aShift / aLen1); + if ( aLen2 > gp::Resolution() ) + aRotation = aLineDir1.Angle( aLineDir2 ); + } + + // compute base transformation + gp_Trsf2d aRotTrsf; + aRotTrsf.SetRotation(aPSlaveFirst, -aRotation); + + gp_Trsf2d aTransTrsf; + aTransTrsf.SetTranslation( gp_Vec2d(aTranslation) ); + + theTransformation = aTransTrsf * aRotTrsf; + // + + // Compute transformation of shift to minimize the area of + // poly-lines difference + gp_Dir2d aDir(1,0); + if ( aLen1 > gp::Resolution() ) + aDir = gp_Dir2d( gp_XY(-aLineDir1.Y(), aLineDir1.X() ) ) ; + Unfolding_FunctionWithDerivative aFunc( theMasterPolyLine, theSlavePolyLine, aDir, theTransformation ); + + if (IsFixed) { + Standard_Real aVal; + + aFunc.Value(0, aVal); + theDistortionArea = aFunc.Area(); + + return Standard_True; + } else { + Standard_Real aBoundary = aShift * 20.; + const Standard_Real aTolX = 1.e-05; + if ( fabs(aBoundary) < aTolX * 2. ) { + Standard_Real aVal = 0.; + aFunc.Value(0, aVal); + theDistortionArea = aFunc.Area(); + return Standard_True; + } + const Standard_Real aTolF = ( theAreaTolerance < 1.e-06 ) ? 1.e-06 : theAreaTolerance; + + math_NewtonFunctionRoot R( aFunc, 0., aTolX, aTolF, -aBoundary, aBoundary, 10 ); + + if ( R.IsDone() ) { + gp_Trsf2d aTransTrsfAdd; + aTransTrsfAdd.SetTranslation( gp_Vec2d(aDir.XY() * R.Root() ) ); + theTransformation = aTransTrsfAdd * theTransformation; + theDistortionArea = aFunc.Area(); + } + else { + math_FunctionRoot R2( aFunc, 0., aTolX, -aBoundary, aBoundary ); + if ( R2.IsDone() ) { + gp_Trsf2d aTransTrsfAdd; + aTransTrsfAdd.SetTranslation( gp_Vec2d(aDir.XY() * R2.Root() ) ); + theTransformation = aTransTrsfAdd * theTransformation; + theDistortionArea = aFunc.Area(); + } + } + } + + return Standard_True; +} diff --git a/src/Unfolding/Unfolding_Shell.lxx b/src/Unfolding/Unfolding_Shell.lxx new file mode 100644 index 0000000000..5a3cc7a69e --- /dev/null +++ b/src/Unfolding/Unfolding_Shell.lxx @@ -0,0 +1,99 @@ +// File: Unfolding_Shell.lxx +// Created: Tue Sep 9 17:14:56 2008 +// Author: Mikhail KLOKOV +// + + +inline void Unfolding_Shell::SetShell(const TopoDS_Shell& theShell) +{ + myShell = theShell; +} + + +inline const TopoDS_Shell& Unfolding_Shell::GetShell() const +{ + return myShell; +} + + +inline void Unfolding_Shell::SetPlane(const gp_Pln& thePlane) +{ + myPlane = thePlane; +} + + +inline const gp_Pln& Unfolding_Shell::GetPlane() const +{ + return myPlane; +} + + +inline void Unfolding_Shell::SetCurvatureTolerance(const Standard_Real theTolerance) +{ + myTolCurvature = theTolerance; +} + + +inline Standard_Real Unfolding_Shell::GetCurvatureTolerance() const +{ + return myTolCurvature; +} + + +inline void Unfolding_Shell::SetContourTolerance(const Standard_Real theTolerance) +{ + myTolContour = theTolerance; +} + + +inline Standard_Real Unfolding_Shell::GetContourTolerance() const +{ + return myTolContour; +} + + +inline void Unfolding_Shell::SetDeflection(const Standard_Real theDeflection) +{ + myDeflection = theDeflection; +} + + +inline Standard_Real Unfolding_Shell::GetDeflection() const +{ + return myDeflection; +} + + +inline Unfolding_ErrorStatus Unfolding_Shell::ErrorStatus() const +{ + return myErrorStatus; +} + + +inline const TopoDS_Face& Unfolding_Shell::GetResult() const +{ + return myResult; +} + + +inline Standard_Real Unfolding_Shell::GetAreaError() const +{ + return myDistortionArea; +} + + +inline Standard_Real Unfolding_Shell::GetMaxGaussCurvature() const +{ + return myCurvature; +} + + +inline void Unfolding_Shell::Reset() +{ + myDistortionArea = 0.; + myCurvature = 0.; + myErrorStatus = Unfolding_NotDone; + + myMapFaceData.Clear(); + myResult.Nullify(); +} diff --git a/src/Unfolding/Unfolding_Surface.cdl b/src/Unfolding/Unfolding_Surface.cdl new file mode 100644 index 0000000000..dfc5a25930 --- /dev/null +++ b/src/Unfolding/Unfolding_Surface.cdl @@ -0,0 +1,200 @@ +-- File: Unfolding_Surface.cdl +-- Created: Tue Jul 22 12:50:10 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Open CASCADE 2008 + + +class Surface from Unfolding + ---Purpose: This class is used to perform unfolding of a face onto a plane. + -- To perform this operation it is necessary to initialize the + -- object by a face to be unfolded, a plane and a tolerance for + -- operation. Then to call the method Perform. The result planar + -- face can be obtained using the method GetResult. Error status + -- can be obtained by the method ErrorStatus. + +uses + + ErrorStatus from Unfolding, + HArray2OfPoint from Unfolding, + FaceDataContainer from Unfolding, + Face from TopoDS, + Wire from TopoDS, + Edge from TopoDS, + Vertex from TopoDS, + ListOfShape from TopTools, + Pln from gp, + XY from gp, + Real from Standard, + DataMapOfShapeInteger from TopTools + +is + + Create + ---Purpose: Empty constructor + ---C++: inline + returns Surface from Unfolding; + + Create (theFace : Face from TopoDS; + thePlane : Pln from gp; + theContourTolerance : Real from Standard; + theCurvatureTolerance: Real from Standard = 0.001; + theDeflection : Real from Standard = 0.001) + ---Purpose: Constructor. Initializes the object with the face, the plane and + -- the tolerance for operation. + returns Surface from Unfolding; + + SetFace (me: in out; theFace: Face from TopoDS); + ---Purpose: Sets the face. + ---C++: inline + + GetFace (me) + ---Purpose: Returns the face. + ---C++: inline + ---C++: return const & + returns Face from TopoDS; + + SetPlane (me: in out; thePlane: Pln from gp); + ---Purpose: Sets the plane. + ---C++: inline + + GetPlane (me) + ---Purpose: Returns the plane. + ---C++: inline + ---C++: return const & + returns Pln from gp; + + SetCurvatureTolerance (me: in out; theTolerance: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetCurvatureTolerance (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + SetContourTolerance (me: in out; theTolerance: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetContourTolerance (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + SetDeflection (me: in out; theDeflection: Real from Standard); + ---Purpose: Sets the tolerance for the operation. + ---C++: inline + + GetDeflection (me) + ---Purpose: Returns the tolerance for the operation. + ---C++: inline + returns Real from Standard; + + Perform (me: in out; theMapEdgeNbSamples: DataMapOfShapeInteger from TopTools) + ---Purpose: Performs computation of the unfolded surface. It returns + -- Standard_True if the operation succeeds otherwise returns + -- Standard_False. It is possible to get the error status of + -- the performed operation using the method ErrorStatus(). + -- theMapEdgeNbSamples is the map of edges as keys and + -- number of samples for this edge as item. It is required + -- for predefined sampling of edges of a face. If an edge is + -- absent in this map its sampling is automatically computed. + -- This feature is used to get same sampling for shared edges + -- on different faces. + returns Boolean from Standard; + + ErrorStatus (me) + ---Purpose: Returns error status of the operation. The error status can have + -- one of the following values: + -- - Unfolding_Done: operation is succeeded; + -- - Unfolding_NotDone: the method Perform() is not called yet; + -- - Unfolding_Failure: the operation is failed; + -- - Unfolding_InvalidSurface: the surface cannot be unfolded + -- without distortion; + -- - Unfolding_InvalidInput: invalid input for the operation. + ---C++: inline + returns ErrorStatus from Unfolding; + + GetDataContainer(me) + ---Purpose: Returns data container. That stores all results of the operation. + ---C++: inline + returns FaceDataContainer from Unfolding; + + --protected + Reset(me: in out) + ---Purpose: Resets data to the initial state. + ---C++: inline + is protected; + + --private + InitGrid(me: in out) + ---Purpose: Initializes the grid on surface. Computes a rectangular grid in + -- the parametric space of the face and computes the corresponding + -- 3d points on the surface. + returns Boolean from Standard + is private; + + NbPoints(me; theUMin : Real from Standard; + theUMax : Real from Standard; + theVMin : Real from Standard; + theVMax : Real from Standard; + theNbPointsU: out Integer from Standard; + theNbPointsV: out Integer from Standard) + ---Purpose: Computes and returns the numbers of sampling points + -- for U and V directions. + is private; + + Unfolding(me: in out) + ---Purpose: Performs unfolding of the grid of points onto the plane. Returns + -- Standard_True in case of success and Standard_False otherwise. + -- Initializes the error status of the operation. + returns Boolean from Standard + is private; + + BuildPlanarFace(me: in out; + theMapEdgeNbSamples: DataMapOfShapeInteger from TopTools) + ---Purpose: Constructs and returns a planar face. + returns Boolean from Standard + is private; + + BuildPlanarWire(me: in out; + theWire : Wire from TopoDS; + theMapEdgeNbSamples: DataMapOfShapeInteger from TopTools; + thePlanarWire : out Wire from TopoDS) + ---Purpose: Constructs and returns planar unfolded wire from original one. + returns Boolean from Standard + is private; + + UnfoldEdge(me; + theEdge : Edge from TopoDS; + theStartVtx : Vertex from TopoDS; + theEndVtx : Vertex from TopoDS; + theMapEdgeNbSamples: DataMapOfShapeInteger from TopTools; + theStartPnt : in out XY from gp; + theEndPnt : out XY from gp; + thePlnEdges : out ListOfShape from TopTools) + ---Purpose: Constructs and returns a set of planar unfolded edges + -- from theEdge. + returns Boolean from Standard + is private; + + ComputePointOnPlane(me; thePoint : XY from gp; + theEdgeTol : Real from Standard; + thePointOnPlane: out XY from gp) + ---Purpose: Computes and returns a point on plane that corresponds + -- to a point on a surface. + returns Boolean from Standard + is private; + +fields + + myDataContainer : FaceDataContainer from Unfolding; + myPlane : Pln from gp; + myTolContour : Real from Standard; + myTolCurvature : Real from Standard; + myDeflection : Real from Standard; + myGrid : HArray2OfPoint from Unfolding; + myErrorStatus : ErrorStatus from Unfolding; + +end; diff --git a/src/Unfolding/Unfolding_Surface.cxx b/src/Unfolding/Unfolding_Surface.cxx new file mode 100644 index 0000000000..2de862ab1d --- /dev/null +++ b/src/Unfolding/Unfolding_Surface.cxx @@ -0,0 +1,1543 @@ +// File: Unfolding_Surface.cxx +// Created: Tue Jul 22 13:12:24 2008 +// Author: Sergey KHROMOV +// + + +#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 + + +static Standard_Integer aLimitNumber = 1000; + +static void AdjustToDeflection( Standard_Integer &theNbPointsU, + Standard_Integer &theNbPointsV, + const Handle(Geom_Surface) &theSurface, + const Standard_Real theUMin, + const Standard_Real theUMax, + const Standard_Real theVMin, + const Standard_Real theVMax, + const Standard_Real theDeflection); + +//======================================================================= +//function : MakeCirc +//purpose : This method constructs a circle that passes through 3 points. +// theNorm is a normal to the plane that is formed by theP1, theP2 +// and theP3. Three points should not be on the same line and should +// not coincide. All these conditions are not checked. Their respect +// is under responsibility of the caller. +//======================================================================= + +static Standard_Boolean MakeCirc(const gp_Pnt &theP1, + const gp_Pnt &theP2, + const gp_Pnt &theP3, + const gp_Dir &theNorm, + gp_Circ &theCircle) +{ + gp_Dir aX(theP3.XYZ().Subtracted(theP1.XYZ())); + gp_Ax3 aPlnAxis(theP1, theNorm, aX); + Standard_Real aU; + Standard_Real aV; + gp_Pnt2d aP1(0., 0.); + + ElSLib::PlaneParameters(aPlnAxis, theP2, aU, aV); + + gp_Pnt2d aP2(aU, aV); + + ElSLib::PlaneParameters(aPlnAxis, theP3, aU, aV); + + gp_Pnt2d aP3(aU, aV); + + GccAna_Circ2d3Tan aCircTan(aP1, aP2, aP3, Precision::Confusion()); + + if (!aCircTan.IsDone() || aCircTan.NbSolutions() != 1) + return Standard_False; + + gp_Circ2d aCirc2d = aCircTan.ThisSolution(1); + + // Convert 2d circle to 3d. + const gp_Pnt2d &a2dLoc = aCirc2d.Location(); + gp_Pnt a3dLoc = ElSLib::PlaneValue(a2dLoc.X(), a2dLoc.Y(), aPlnAxis); + gp_Dir a3dX(theP1.XYZ().Subtracted(a3dLoc.XYZ())); + gp_Ax2 aCircAxis(a3dLoc, theNorm, a3dX); + Standard_Real aRadius = aCirc2d.Radius(); + + theCircle.SetPosition(aCircAxis); + theCircle.SetRadius(aRadius); + + return Standard_True; +} + +//======================================================================= +//function : CrvDistance +//purpose : Returns the approximate curvelinear distance between two +// points on surface. The distance is approximated by length of +// the circular arc started at thePoint1 and ended at thePoint2 +// that is passed through the middle in UV space point. +//======================================================================= + +static Standard_Real CrvDistance(const Unfolding_Point &thePoint1, + const Unfolding_Point &thePoint2, + const Handle(Geom_Surface) &theSurface, + const Standard_Real &theTolerance) +{ + const gp_XYZ &aP1 = thePoint1.GetPointOnSurface(); + const gp_XYZ &aP2 = thePoint2.GetPointOnSurface(); + gp_XYZ aP12 = aP2.Subtracted(aP1); + Standard_Real aLinDist = aP12.Modulus(); + + if (aLinDist <= theTolerance) + return aLinDist; + + // Get middle point. + Standard_Real aUMid; + Standard_Real aVMid; + Standard_Real aU; + Standard_Real aV; + gp_Pnt aPntMid; + + thePoint1.GetParameters(aUMid, aVMid); + thePoint2.GetParameters(aU, aV); + + aUMid = 0.5*(aUMid + aU); + aVMid = 0.5*(aVMid + aV); + + theSurface->D0(aUMid, aVMid, aPntMid); + + const gp_XYZ &aPMid = aPntMid.XYZ(); + + // Compute distance from aPMid to aP12. + aP12.Divide(aLinDist); + + gp_XYZ aDistCoord(aPMid.Subtracted(aP1)); + + aDistCoord.Cross(aP12); + + Standard_Real aDist = aDistCoord.Modulus(); + + if (aDist < 0.01*theTolerance) + return aLinDist; + + // Find a distance along an arc. + gp_Pnt aPnt1(aP1); + gp_Pnt aPnt2(aP2); + gp_Dir aNorm(aDistCoord); + gp_Circ aCirc; + + if (!MakeCirc(aPnt1, aPntMid, aPnt2, aNorm, aCirc)) + return 0.; + + const gp_Ax2 &anAxis = aCirc.Position(); + Standard_Real anAngle = ElCLib::CircleParameter(anAxis, aPnt2); + Standard_Real aCircParMid = ElCLib::CircleParameter(anAxis, aPntMid); + Standard_Real aRadius = aCirc.Radius(); + + if (anAngle < aCircParMid) + anAngle = 2.*M_PI - anAngle; + + Standard_Real aCrvDist = anAngle*aRadius; + + return aCrvDist; +} + +//======================================================================= +//function : GetCell +//purpose : Returns the indices of a cell thePoint belongs to. The cell (i, j) +// is defined between grid's points (i, j) - (i + 1, j) - +// (i + 1, j + 1) - (i, j + 1). If the point is outside the grid, +// its index is equal to 0 in case if corresponding index is lower +// then the lower bound or NbPoints if it is greater then the upper +// bound. +//======================================================================= + +static void GetCell(const gp_XY &thePoint, + const Handle(Unfolding_HArray2OfPoint) &theGrid, + const Standard_Real &theTolerance, + Standard_Integer &theI, + Standard_Integer &theJ) +{ + Standard_Integer iStart = theGrid->LowerRow(); + Standard_Integer jStart = theGrid->LowerCol(); + Standard_Integer iEnd = theGrid->UpperRow(); + Standard_Integer jEnd = theGrid->UpperCol(); + const Unfolding_Point &aPff = theGrid->Value(iStart, jStart); + const Unfolding_Point &aPll = theGrid->Value(iEnd, jEnd); + Standard_Real aU = thePoint.X(); + + // Compute theI. + if (aU < aPff.GetU() - theTolerance) + theI = iStart - 1; + else if (aU >= aPll.GetU() - theTolerance) + theI = iEnd; + else { + Standard_Real aStep = (aPll.GetU() - aPff.GetU())/(iEnd - iStart + 1); + + theI = Standard_Integer(Round((aU - aPff.GetU())/aStep)) + iStart; + + if (theI < iStart) + theI = iStart; + + if (theI > iEnd) + theI = iEnd; + + while (theI >= iStart && + aU < theGrid->Value(theI, jStart).GetU() - theTolerance) + theI--; + + while (theI < iEnd && + aU >= theGrid->Value(theI + 1, jStart).GetU() - theTolerance) + theI++; + } + + // Compute theI. + Standard_Real aV = thePoint.Y(); + + if (aV < aPff.GetV() - theTolerance) + theJ = jStart - 1; + else if (aV >= aPll.GetV() - theTolerance) + theJ = jEnd; + else { + Standard_Real aStep = (aPll.GetV() - aPff.GetV())/(jEnd - jStart + 1); + + theJ = Standard_Integer(Round((aV - aPff.GetV())/aStep)) + jStart; + + if (theJ < jStart) + theJ = jStart; + + if (theJ > jEnd) + theJ = jEnd; + + while (theJ >= jStart && + aV < theGrid->Value(iStart, theJ).GetV() - theTolerance) + theJ--; + + while (theJ < jEnd && + aV >= theGrid->Value(iStart, theJ + 1).GetV() - theTolerance) + theJ++; + } +} + +//======================================================================= +//function : Empty constructor +//purpose : This method constructs and returns the curve that is passed +// through three points. It can be either a line if these three +// points lie on the same line or a circle. In case of failure +// it returns a null handle. +//======================================================================= + +static Handle(Geom_Curve) MakeCurve(const gp_Pnt &thePFirst, + const gp_Pnt &thePMid, + const gp_Pnt &thePLast, + const gp_Pln &thePlane, + const Standard_Real theTolerance) +{ + Handle(Geom_Curve) aCurve; + gp_Vec aDFL(thePLast.XYZ().Subtracted(thePFirst.XYZ())); + Standard_Real aLinDist = aDFL.Magnitude(); + + if (aLinDist > theTolerance) { + // compute distance between thePMid and the segment [thePFirst, thePLast]. + gp_XYZ aDPMidFirst = thePMid.XYZ(); + + aDFL.Divide(aLinDist); + aDPMidFirst.Subtract(thePFirst.XYZ()); + aDPMidFirst.Cross(aDFL.XYZ()); + + Standard_Real aDist = aDPMidFirst.Modulus(); + + // Line criteria like in the CrvDistance function. + if (aDist < 0.01*theTolerance) { + aCurve = new Geom_Line(thePFirst, gp_Dir(aDFL)); + } else { + // Compute a circle + gp_Circ aCirc; + + if (!MakeCirc(thePFirst, thePMid, thePLast, + thePlane.Position().Direction(), aCirc)) + return aCurve; + + aCurve = new Geom_Circle(aCirc); + + // Trim the curve by the circle parameters. + const gp_Ax2 &anAxis = aCirc.Position(); + Standard_Real aCircPar1 = 0.; // By construction + Standard_Real aCircPar2 = ElCLib::CircleParameter(anAxis, thePLast); + Standard_Real aCircParMid = ElCLib::CircleParameter(anAxis, thePMid); + + if (aCircParMid > aCircPar2) + aCurve = new Geom_TrimmedCurve(aCurve, aCircPar1, + aCircPar2, Standard_False); + else + aCurve = new Geom_TrimmedCurve(aCurve, aCircPar1, aCircPar2); + } + } + + return aCurve; +} + +//======================================================================= +// function : Analyse +// purpose : Computes the numbers of samples along U and V direction using +// the array of poles. +//======================================================================= + +static void Analyse(const TColgp_Array2OfPnt &array2, + Standard_Integer &theNbSamplesU, + Standard_Integer &theNbSamplesV) +{ + gp_Vec Vi,Vip1; + Standard_Integer sh,nbch,i,j; + const Standard_Integer nbup = array2.UpperRow() - array2.LowerRow() + 1; + const Standard_Integer nbvp = array2.UpperCol() - array2.LowerCol() + 1; + + sh = 1; + nbch = 0; + if(nbvp>2) { + + for(i = array2.LowerRow(); i <= array2.UpperRow(); i++) { + const gp_Pnt& A=array2.Value(i,1); + const gp_Pnt& B=array2.Value(i,2); + const gp_Pnt& C=array2.Value(i,3); + Vi.SetCoord(C.X()-B.X()-B.X()+A.X(), + C.Y()-B.Y()-B.Y()+A.Y(), + C.Z()-B.Z()-B.Z()+A.Z()); + Standard_Integer locnbch=0; + + for(j = array2.LowerCol() + 2; j < array2.UpperCol();j++) { //-- essai + const gp_Pnt& Ax=array2.Value(i,j-1); + const gp_Pnt& Bx=array2.Value(i,j); + const gp_Pnt& Cx=array2.Value(i,j+1); + Vip1.SetCoord(Cx.X()-Bx.X()-Bx.X()+Ax.X(), + Cx.Y()-Bx.Y()-Bx.Y()+Ax.Y(), + Cx.Z()-Bx.Z()-Bx.Z()+Ax.Z()); + Standard_Real pd = Vi.Dot(Vip1); + Vi=Vip1; + if(pd>1.0e-7 || pd<-1.0e-7) { + if(pd>0) { if(sh==-1) { sh=1; locnbch++; } } + else { if(sh==1) { sh=-1; locnbch++; } } + } + } + if(locnbch>nbch) { + nbch=locnbch; + } + } + } + theNbSamplesV = nbch+5; + + + nbch=0; + if(nbup > 2) { + for(j = array2.LowerCol(); j <= array2.UpperCol(); j++) { + const gp_Pnt& A=array2.Value(array2.LowerRow(), j); + const gp_Pnt& B=array2.Value(array2.LowerRow() + 1, j); + const gp_Pnt& C=array2.Value(array2.LowerRow() + 2, j); + Vi.SetCoord(C.X()-B.X()-B.X()+A.X(), + C.Y()-B.Y()-B.Y()+A.Y(), + C.Z()-B.Z()-B.Z()+A.Z()); + Standard_Integer locnbch=0; + + for(i = array2.LowerRow() + 2; i < array2.UpperRow(); i++) { //-- essai + const gp_Pnt& Ax=array2.Value(i-1,j); + const gp_Pnt& Bx=array2.Value(i,j); + const gp_Pnt& Cx=array2.Value(i+1,j); + Vip1.SetCoord(Cx.X()-Bx.X()-Bx.X()+Ax.X(), + Cx.Y()-Bx.Y()-Bx.Y()+Ax.Y(), + Cx.Z()-Bx.Z()-Bx.Z()+Ax.Z()); + Standard_Real pd = Vi.Dot(Vip1); + Vi=Vip1; + if(pd>1.0e-7 || pd<-1.0e-7) { + if(pd>0) { if(sh==-1) { sh=1; locnbch++; } } + else { if(sh==1) { sh=-1; locnbch++; } } + } + } + if(locnbch>nbch) nbch=locnbch; + } + } + theNbSamplesU = nbch+5; +} + +//======================================================================= +//function : Empty constructor +//purpose : +//======================================================================= + +Unfolding_Surface::Unfolding_Surface() + : myTolContour(0.001), + myTolCurvature(0.001), + myDeflection(0.001) +{ + myDataContainer = new Unfolding_FaceDataContainer; + Reset(); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= + +Unfolding_Surface::Unfolding_Surface(const TopoDS_Face &theFace, + const gp_Pln &thePlane, + const Standard_Real theContourTolerance, + const Standard_Real theCurvatureTolerance, + const Standard_Real theDeflection) + : myPlane(thePlane), + myTolContour(theContourTolerance), + myTolCurvature(theCurvatureTolerance), + myDeflection(theDeflection) +{ + myDataContainer = new Unfolding_FaceDataContainer; + myDataContainer->SetFace(theFace); + Reset(); +} + +//======================================================================= +//function : Perform +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::Perform + (const TopTools_DataMapOfShapeInteger &theMapEdgeNbSamples) +{ + // Check if the operation is already performed and there is nothing to do. + if (myErrorStatus != Unfolding_NotDone) + return (myErrorStatus == Unfolding_Done); + + // Check input data validity. + if (myDataContainer->GetFace().IsNull() || + ( myTolContour <= RealEpsilon() ) || + ( myTolCurvature <= RealEpsilon() ) || + ( myDeflection <= RealEpsilon() ) ) { + myErrorStatus = Unfolding_InvalidInput; + return Standard_False; + } + + // Initialize the grid on the surface. + Standard_Boolean isOK = InitGrid(); + + if (isOK) { + // Perform unfolding + isOK = Unfolding(); + + if (isOK) { + // Construct a planar face. + isOK = BuildPlanarFace(theMapEdgeNbSamples); + } + } + + return isOK; +} + +//======================================================================= +//function : InitGrid +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::InitGrid() +{ + // Get Bounding box of the face. + Standard_Real aUMin; + Standard_Real aUMax; + Standard_Real aVMin; + Standard_Real aVMax; + const TopoDS_Face &aFace = myDataContainer->GetFace(); + + BRepTools::UVBounds(aFace, aUMin, aUMax, aVMin, aVMax); + + // Compute number of samples. + Standard_Integer aNbPntsU; + Standard_Integer aNbPntsV; + + NbPoints(aUMin, aUMax, aVMin, aVMax, aNbPntsU, aNbPntsV); + + + // Construct a grid. + myGrid = new Unfolding_HArray2OfPoint(1, aNbPntsU, 1, aNbPntsV); + + // Fill in the grid. + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace); + Standard_Real aUStep = (aUMax - aUMin)/(aNbPntsU - 1); + Standard_Real aVStep = (aVMax - aVMin)/(aNbPntsV - 1); + Standard_Real aUPar; + Standard_Real aVPar; + Standard_Integer i; + Standard_Integer j; + gp_Pnt aPnt; + gp_Vec aD1U; + gp_Vec aD1V; + gp_Vec aD2U; + gp_Vec aD2V; + gp_Vec aD2UV; + gp_Vec aNorm; + Standard_Real aL; + Standard_Real aM; + Standard_Real aN; + Standard_Real aMaxCurvature = 0.; + + for (aUPar = aUMin, i = 1; i <= aNbPntsU; i++) { + for (aVPar = aVMin, j = 1; j <= aNbPntsV; j++) { + aSurface->D2(aUPar, aVPar, aPnt, aD1U, aD1V, aD2U, aD2V, aD2UV); + + // Check Gauss curvature + aNorm = aD1U.Crossed(aD1V); + aNorm.Normalize(); + aL = aD2U.Dot(aNorm); + aN = aD2V.Dot(aNorm); + aM = aD2UV.Dot(aNorm); + const Standard_Real aCurvature = Abs(aL*aN - aM*aM); + aMaxCurvature = ( aMaxCurvature < aCurvature ) ? aCurvature : aMaxCurvature; + + if (aCurvature > myTolCurvature) { + myDataContainer->SetMaxGaussCurvature(aMaxCurvature); + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + // Initialize the point. + Unfolding_Point &aPoint = myGrid->ChangeValue(i, j); + + aPoint.SetParameters(aUPar, aVPar); + aPoint.SetPointOnSurface(aPnt.XYZ()); + + aVPar = (j == aNbPntsV - 1) ? aVMax : aVPar + aVStep; + } + + aUPar = (i == aNbPntsU - 1) ? aUMax : aUPar + aUStep; + } + + myDataContainer->SetMaxGaussCurvature(aMaxCurvature); + + // Initialize points by angles in DU and DV directions. + Standard_Real aTolConf = 0.01*Max(myTolContour,myDeflection); + gp_XYZ aDX; + gp_XYZ aDY; + + for (i = 1; i <= aNbPntsU; i++) { + for (j = 1; j <= aNbPntsV; j++) { + Unfolding_Point &aP = myGrid->ChangeValue(i, j); + + if (i == aNbPntsU || j == aNbPntsV) { + aP.SetAngle(0.); + } else { + const Unfolding_Point &aPX = myGrid->Value(i + 1, j); + + aDX = aPX.GetPointOnSurface(); + aDX.Subtract(aP.GetPointOnSurface()); + + if (aDX.Modulus() <= aTolConf) { + aP.SetAngle(0.); + } else { + const Unfolding_Point &aPY = myGrid->Value(i, j + 1); + + aDY = aPY.GetPointOnSurface(); + aDY.Subtract(aP.GetPointOnSurface()); + + if (aDY.Modulus() <= aTolConf) { + aP.SetAngle(0.); + } else { + aP.SetAngle(gp_Vec(aDX).Angle(gp_Vec(aDY))); + } + } + } + } + } + + return Standard_True; +} + +//======================================================================= +//function : NbPoints +//purpose : +//======================================================================= + +void Unfolding_Surface::NbPoints(const Standard_Real theUMin, + const Standard_Real theUMax, + const Standard_Real theVMin, + const Standard_Real theVMax, + Standard_Integer &theNbPointsU, + Standard_Integer &theNbPointsV) const +{ + Handle(Geom_Surface) aSurface = + BRep_Tool::Surface(myDataContainer->GetFace()); + Handle(Standard_Type) aType = aSurface->DynamicType(); + + while (aType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { + Handle(Geom_RectangularTrimmedSurface) aTrSurf = + Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); + aSurface = aTrSurf->BasisSurface(); + aType = aSurface->DynamicType(); + } + + if (aType == STANDARD_TYPE(Geom_Plane)) { + // PLANE + theNbPointsU = 11; + theNbPointsV = 11; + } else if (aType == STANDARD_TYPE(Geom_CylindricalSurface)) { + // CYLINDER + Handle(Geom_CylindricalSurface) aCyl = + Handle(Geom_CylindricalSurface)::DownCast(aSurface); + Standard_Real aRadius = aCyl->Radius(); + Standard_Real aMaxAngle = M_PI *0.5; + + if(aRadius > myDeflection) { + aMaxAngle = ACos(1. - myDeflection/aRadius)*2.; + } + if(aMaxAngle > Precision::Angular()) + theNbPointsU = Standard_Integer((theUMax - theUMin)/aMaxAngle); + else + theNbPointsU = (Standard_Integer)(theUMax - theUMin); + + theNbPointsV = (Standard_Integer)(theVMax - theVMin); + theNbPointsV /= 10; + + if (theNbPointsU < 3) + theNbPointsU = 3; + + if (theNbPointsV < 3) + theNbPointsV = 3; + } else if (aType == STANDARD_TYPE(Geom_ConicalSurface)) { + // CONE + Handle(Geom_ConicalSurface) aConeSurf = + Handle(Geom_ConicalSurface)::DownCast(aSurface); + gp_Cone aCone = aConeSurf->Cone(); + gp_Circ aCircle = ElSLib::ConeVIso(aCone.Position(), + aCone.RefRadius(), + aCone.SemiAngle(), + theVMin); + Standard_Real aRadius = aCircle.Radius(); + aCircle = ElSLib::ConeVIso(aCone.Position(), aCone.RefRadius(), + aCone.SemiAngle(), theVMax); + + if(aRadius < aCircle.Radius()) + aRadius = aCircle.Radius(); + + Standard_Real aMaxAngle = M_PI*0.5; + + if(aRadius > myDeflection) + aMaxAngle = ACos(1. - myDeflection/aRadius)*2.; + + if(aMaxAngle > Precision::Angular()) + theNbPointsU = Standard_Integer((theUMax - theUMin)/aMaxAngle); + else + theNbPointsU = (Standard_Integer)(theUMax - theUMin); + + theNbPointsV = (Standard_Integer)(theVMax - theVMin); + theNbPointsV /= 10; + + if (theNbPointsU < 11) + theNbPointsU = 11; + + if (theNbPointsV < 11) + theNbPointsV = 11; + } else if (aType == STANDARD_TYPE(Geom_SphericalSurface) || + aType == STANDARD_TYPE(Geom_ToroidalSurface)) { + // SPHERE or TORUS + gp_Circ aCircle; + Standard_Real aRadius1; + Standard_Real aRadius2; + + if (aType == STANDARD_TYPE(Geom_SphericalSurface)) { + // SPHERE + Handle(Geom_SphericalSurface) aSphSurf = + Handle(Geom_SphericalSurface)::DownCast(aSurface); + gp_Sphere aSphere = aSphSurf->Sphere(); + + aRadius1 = aSphere.Radius(); + aRadius2 = aSphere.Radius(); + } else { + Handle(Geom_ToroidalSurface) aTorusSurf = + Handle(Geom_ToroidalSurface)::DownCast(aSurface); + // TORUS + gp_Torus aTorus = aTorusSurf->Torus(); + + aCircle = ElSLib::TorusUIso(aTorus.Position(), aTorus.MajorRadius(), + aTorus.MinorRadius(), theUMin); + aRadius2 = aCircle.Radius(); + aCircle = ElSLib::TorusUIso(aTorus.Position(), aTorus.MajorRadius(), + aTorus.MinorRadius(), theUMax); + aRadius2 = (aRadius2 < aCircle.Radius()) ? aCircle.Radius() : aRadius2; + aCircle = ElSLib::TorusVIso(aTorus.Position(), aTorus.MajorRadius(), + aTorus.MinorRadius(), theVMin); + aRadius1 = aCircle.Radius(); + aCircle = ElSLib::TorusVIso(aTorus.Position(), aTorus.MajorRadius(), + aTorus.MinorRadius(), theVMax); + aRadius1 = (aRadius1 < aCircle.Radius()) ? aCircle.Radius() : aRadius1; + } + + Standard_Real aMaxAngle = M_PI*0.5; + + if(aRadius1 > myDeflection) + aMaxAngle = ACos(1. - myDeflection/aRadius1)*2.; + + if(aMaxAngle > Precision::Angular()) + theNbPointsU = Standard_Integer((theUMax - theUMin)/aMaxAngle); + else + theNbPointsU = (Standard_Integer)(theUMax - theUMin); + + aMaxAngle = M_PI*0.5; + + if(aRadius2 > myDeflection) + aMaxAngle = ACos(1. - myDeflection/aRadius2)*2.; + + if(aMaxAngle > Precision::Angular()) + theNbPointsV = Standard_Integer((theVMax - theVMin)/aMaxAngle); + else + theNbPointsV = (Standard_Integer)(theVMax - theVMin); + + if (theNbPointsU < 11) + theNbPointsU = 11; + + if (theNbPointsV < 11) + theNbPointsV = 11; + } else if (aType == STANDARD_TYPE(Geom_BezierSurface)) { + Handle(Geom_BezierSurface) aBezier = + Handle(Geom_BezierSurface)::DownCast(aSurface); + // BEZIER + theNbPointsU = 3 + aBezier->NbUPoles(); + theNbPointsV = 3 + aBezier->NbVPoles(); + + if(theNbPointsU > 11 || theNbPointsV > 11) { + TColgp_Array2OfPnt array2(1, aBezier->NbUPoles(), 1, aBezier->NbVPoles()); + aBezier->Poles(array2); + Analyse(array2, theNbPointsU, theNbPointsV); + } + AdjustToDeflection( theNbPointsU, theNbPointsV, aSurface, + theUMin, theUMax, theVMin, theVMax, myDeflection ); + + if(theNbPointsU < 11) + theNbPointsU = 11; + + if(theNbPointsV < 11) + theNbPointsV = 11; + } else if (aType == STANDARD_TYPE(Geom_BSplineSurface)) { + // BSPLINE + Handle(Geom_BSplineSurface) aBSpline = + Handle(Geom_BSplineSurface)::DownCast(aSurface); + + theNbPointsU = aBSpline->NbUKnots(); + theNbPointsU *= aBSpline->UDegree(); + theNbPointsV = aBSpline->NbVKnots(); + theNbPointsV *= aBSpline->VDegree(); + + if(theNbPointsU > 11 || theNbPointsU > 11) { + TColgp_Array2OfPnt array2(1, aBSpline->NbUPoles(), + 1, aBSpline->NbVPoles()); + aBSpline->Poles(array2); + Analyse(array2, theNbPointsU, theNbPointsV); + } + AdjustToDeflection( theNbPointsU, theNbPointsV, aSurface, + theUMin, theUMax, theVMin, theVMax, myDeflection ); + + if(theNbPointsU < 11) + theNbPointsU = 11; + + if(theNbPointsV < 11) + theNbPointsV = 11; + } else if (aType == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)) { + // EXTRUSION + theNbPointsU = 15; + theNbPointsV = (Standard_Integer)(theVMax - theVMin); + theNbPointsV /= 10; + + AdjustToDeflection( theNbPointsU, theNbPointsV, aSurface, + theUMin, theUMax, theVMin, theVMax, myDeflection ); + + if(theNbPointsV < 15) + theNbPointsV = 15; + } else if (aType == STANDARD_TYPE(Geom_SurfaceOfRevolution)) { + // REVOLUTION + theNbPointsU = 15; + theNbPointsV = 15; + + AdjustToDeflection( theNbPointsU, theNbPointsV, aSurface, + theUMin, theUMax, theVMin, theVMax, myDeflection ); + } else { + // OTHER + theNbPointsU = 11; + theNbPointsV = 11; + AdjustToDeflection( theNbPointsU, theNbPointsV, aSurface, + theUMin, theUMax, theVMin, theVMax, myDeflection ); + } + + // Check if the number of points exceeds the maximum number of points. + const Standard_Integer aMaxNbPoints = aLimitNumber; + + if(theNbPointsU > aMaxNbPoints) { + if ( theNbPointsU < theNbPointsV ) { + theNbPointsU = aMaxNbPoints; + } + else { + Standard_Integer alim = aMaxNbPoints * aMaxNbPoints / theNbPointsV; + theNbPointsU = ( theNbPointsU > alim ) ? alim : theNbPointsU; + } + } + + if(theNbPointsV > aMaxNbPoints) { + if ( theNbPointsV < theNbPointsU ) { + theNbPointsV = aMaxNbPoints; + } + else { + Standard_Integer alim = aMaxNbPoints * aMaxNbPoints / theNbPointsU; + theNbPointsV = ( theNbPointsV > alim ) ? alim : theNbPointsV; + } + } +} + +//======================================================================= +//function : Unfolding +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::Unfolding() +{ + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myDataContainer->GetFace()); + Standard_Integer iStart = myGrid->LowerRow(); + Standard_Integer jStart = myGrid->LowerCol(); + Standard_Integer iEnd = myGrid->UpperRow(); + Standard_Integer jEnd = myGrid->UpperCol(); + Standard_Integer i; + Standard_Integer j; + + // Initialize the array of 4 points on a plane. For a couple of indices (i, j) + // the points on a plane are initialized as follows: + // aPonPln[0] -> (i, j + 1) + // aPonPln[1] -> (i, j) + // aPonPln[2] -> (i + 1, j) + // aPonPln[3] -> (i + 1, j + 1) + gp_XY aPonPln[4]; + Standard_Real aCrvDist; + Standard_Real aCrvDist2; + gp_XY aDirX; + gp_XY aDirY; + Standard_Real aTolConf = 0.01*Max(myTolContour, myDeflection); + Standard_Real aNorm; + Standard_Real aDistortionArea = 0.; + + for (j = jStart; j < jEnd; j++) { + // Step 1: Get or compute aPonPln[1]. + Unfolding_Point &aP1 = myGrid->ChangeValue(iStart, j); + + // Add the first point aPonPln[1]. + if (j == jStart) + aP1.SetPointOnPlane(gp_XY(0., 0.)); + + // Get aPonPln[1]. + aPonPln[1] = aP1.GetPointOnPlane(); + + // Step 2: Compute aPonPln[0]. + Unfolding_Point &aP2 = myGrid->ChangeValue(iStart, j + 1); + + // Compute a curvelinear distance. + aCrvDist = CrvDistance(aP1, aP2, aSurface, myTolContour); + + if (aCrvDist <= aTolConf) { + aPonPln[0] = aPonPln[1]; + } else { + // Compute the Y direction. + if (j == jStart) { + aDirY.SetCoord(0., 1.); + } else { + Unfolding_Point &aP21 = myGrid->ChangeValue(iStart + 1, j); + + aDirX = aP21.GetPointOnPlane().Subtracted(aPonPln[1]); + aNorm = aDirX.Modulus(); + + if (aNorm <= aTolConf) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + // Compute the Y direction. + aDirX.Divide(aNorm); + + gp_Vec2d aVecX(aDirX); + aVecX.Rotate(aP1.GetAngle()); + aDirY = aVecX.XY(); + } + + // Compute point on plane. + aPonPln[0] = aPonPln[1].Added(aDirY.Multiplied(aCrvDist)); + } + + aP2.SetPointOnPlane(aPonPln[0]); + + for (i = iStart; i < iEnd; i++) { + Unfolding_Point &aP11 = myGrid->ChangeValue(i, j); + Unfolding_Point &aP21 = myGrid->ChangeValue(i + 1, j); + Unfolding_Point &aP22 = myGrid->ChangeValue(i + 1, j + 1); + Unfolding_Point &aP12 = myGrid->ChangeValue(i, j + 1); + + // Step 3: Compute aPonPln[2]. + aCrvDist = CrvDistance(aP11, aP21, aSurface, myTolContour); + + if (aCrvDist <= aTolConf) { + if (j > jStart) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + aPonPln[2] = aPonPln[1]; + } else { + aDirY = aPonPln[0].Subtracted(aPonPln[1]); + aNorm = aDirY.Modulus(); + + if (aNorm <= aTolConf) { + if (i == iStart) { + aDirX.SetCoord(1., 0.); + } else { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + } else { + // Compute the X direction. + aDirY.Divide(aNorm); + + gp_Vec2d aVecY(aDirY); + + aVecY.Rotate(-aP11.GetAngle()); + aDirX = aVecY.XY(); + } + + aPonPln[2] = aPonPln[1].Added(aDirX.Multiplied(aCrvDist)); + } + + if (j == jStart) { + aP21.SetPointOnPlane(aPonPln[2]); + aCrvDist2 = CrvDistance(aP21, aP22, aSurface, myTolContour); + } else { + aCrvDist2 = CrvDistance(aP21, aP22, aSurface, myTolContour); + Standard_Real aDif = aPonPln[2].Subtracted(aP21.GetPointOnPlane()).Modulus(); +// aDistortionArea += aDif * aCrvDist * 0.5; + Standard_Real area = aDif * aCrvDist * 0.5; + if ( aCrvDist > gp::Resolution() ) { + Standard_Real aSinVal = 1. - (0.25*aDif*aDif / (aCrvDist*aCrvDist)); + if ( aSinVal > 0. ) + aSinVal = sqrt( aSinVal ); + area *= aSinVal; + } + aDistortionArea += area; +// if (!aPonPln[2].IsEqual(aP21.GetPointOnPlane(), myTolContour)) { + if ( aDif > ( aCrvDist2 + aCrvDist ) ) { + // The surface cannot be unfolded. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + // Keep old point + aPonPln[2] = aP21.GetPointOnPlane(); + } + + // Step 4: Compute aPonPln[3]. + gp_XY aDiag = aPonPln[2].Subtracted(aPonPln[0]); + Standard_Real aDDiag = aDiag.Modulus(); + + if (aDDiag <= aTolConf) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + aCrvDist = CrvDistance(aP12, aP22, aSurface, myTolContour); + + if (aCrvDist <= aTolConf) { + if (j < jEnd - 1) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + aPonPln[3] = aPonPln[0]; + } else { + + if (aCrvDist2 <= aTolConf) { + if (i < iEnd - 1) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + aPonPln[3] = aPonPln[2]; + } else { + if (aCrvDist + aCrvDist2 <= aDDiag + aTolConf) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + // Construct two circles + gp_Dir2d aX(1., 0.); + gp_Ax22d aCirc1Axis = gp_Ax22d(gp_Pnt2d(aPonPln[0]), aX); + gp_Ax22d aCirc2Axis = gp_Ax22d(gp_Pnt2d(aPonPln[2]), aX); + gp_Circ2d aCirc1(aCirc1Axis, aCrvDist); + gp_Circ2d aCirc2(aCirc2Axis, aCrvDist2); + + // Analytic intersection of two circles. + IntAna2d_AnaIntersection anInter(aCirc1, aCirc2); + + if (!anInter.IsDone() || anInter.NbPoints() != 2) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + + gp_Pnt2d anIntP = anInter.Point(1).Value(); + gp_XY aD30(anIntP.XY().Subtracted(aPonPln[0])); + + if (aD30.Crossed(aDiag) > 0.) { + anIntP = anInter.Point(2).Value(); + aD30 = anIntP.XY().Subtracted(aPonPln[0]); + + if (aD30.Crossed(aDiag) > 0.) { + // Invalid case. + myErrorStatus = Unfolding_InvalidSurface; + return Standard_False; + } + } + + aPonPln[3] = anIntP.XY(); + } + } + + aP22.SetPointOnPlane(aPonPln[3]); + + // Prepare points for next iterations. + aPonPln[0] = aPonPln[3]; + aPonPln[1] = aPonPln[2]; + } + } + + myDataContainer->SetDistortionArea(aDistortionArea); + + return Standard_True; +} + +//======================================================================= +//function : BuildPlanarFace +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::BuildPlanarFace + (const TopTools_DataMapOfShapeInteger &theMapEdgeNbSamples) +{ + Handle(Geom_Surface) aPlane = new Geom_Plane(myPlane); + BRep_Builder aBuilder; + TopoDS_Face aPlanarFace; + Standard_Real aTopoTol = Precision::Confusion(); + + aBuilder.MakeFace(aPlanarFace, aPlane, aTopoTol); + + // Build wires. + TopExp_Explorer anExp(myDataContainer->GetFace(), TopAbs_WIRE); + TopoDS_Wire aWire; + + for (; anExp.More(); anExp.Next()) { + TopoDS_Wire aPlanarWire; + + aWire = TopoDS::Wire(anExp.Current()); + + if (!BuildPlanarWire(aWire, theMapEdgeNbSamples, aPlanarWire)) { + myErrorStatus = Unfolding_Failure; + + return Standard_False; + } + + aBuilder.Add(aPlanarFace, aPlanarWire); + } + + myDataContainer->SetUnfoldedFace(aPlanarFace); + myErrorStatus = Unfolding_Done; + + return Standard_True; +} + +//======================================================================= +//function : BuildPlanarWire +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::BuildPlanarWire + (const TopoDS_Wire &theWire, + const TopTools_DataMapOfShapeInteger &theMapEdgeNbSamples, + TopoDS_Wire &thePlanarWire) +{ + BRep_Builder aBuilder; + BRepTools_WireExplorer aWExp(theWire, myDataContainer->GetFace()); + TopoDS_Vertex aV[2]; + TopoDS_Vertex aVEmpty; + TopoDS_Vertex aVFirst[2]; + gp_XY aBndPnt[2] = { gp_XY(0., 0.), gp_XY(0., 0.) }; + gp_XY aPntFirst; + + aBuilder.MakeWire(thePlanarWire); + + for (; aWExp.More();) { + TopoDS_Edge anEdge = aWExp.Current(); + + aWExp.Next(); + // Skip degenerated edges as they cannot be unfolded. + if (BRep_Tool::Degenerated(anEdge)) + continue; + + aV[0] = TopExp::LastVertex(anEdge, Standard_True); + + if (!aVFirst[0].IsNull() && !aWExp.More() && aVFirst[0].IsSame(aV[0])) { + // Close the edge + aVEmpty = aVFirst[1]; + aBndPnt[1] = aPntFirst; + } + + // Perform unfolding + TopTools_ListOfShape anEdges; + + if (!UnfoldEdge(anEdge, aV[1], aVEmpty, theMapEdgeNbSamples, + aBndPnt[0], aBndPnt[1], anEdges)) + return Standard_False; + myDataContainer->SetEdgesForEdge(anEdge, anEdges); + + if (anEdges.IsEmpty()) + return Standard_False; + + // Build result. + TopTools_ListIteratorOfListOfShape anIter(anEdges); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aPlnEdge = anIter.Value(); + + aBuilder.Add(thePlanarWire, aPlnEdge); + } + + if (aVFirst[1].IsNull()) { + aVFirst[0] = TopExp::FirstVertex(anEdge, Standard_True); + aVFirst[1] = TopExp::FirstVertex(TopoDS::Edge(anEdges.First())); + aPntFirst = aBndPnt[0]; + } + + aV[1] = TopExp::LastVertex(TopoDS::Edge(anEdges.Last())); + aBndPnt[0] = aBndPnt[1]; + } + + thePlanarWire.Closed(Standard_True); + + return Standard_True; +} + +//======================================================================= +//function : UnfoldEdge +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::UnfoldEdge + (const TopoDS_Edge &theEdge, + const TopoDS_Vertex &theStartVtx, + const TopoDS_Vertex &theEndVtx, + const TopTools_DataMapOfShapeInteger &theMapEdgeNbSamples, + gp_XY &theStartPnt, + gp_XY &theEndPnt, + TopTools_ListOfShape &thePlnEdges) const +{ + Standard_Boolean isReversed = theEdge.Orientation() == TopAbs_REVERSED; + Standard_Real aTol = BRep_Tool::Tolerance(theEdge); + Standard_Real aParam[2]; + const TopoDS_Face &aFace = myDataContainer->GetFace(); + Handle(Geom2d_Curve) a2dCurve = BRep_Tool::CurveOnSurface + (theEdge, aFace, aParam[0], aParam[1]); + Standard_Integer aNbPoints; + + if (theMapEdgeNbSamples.IsBound(theEdge)) { + // Get already computed sampling. + aNbPoints = theMapEdgeNbSamples.Find(theEdge); + } else { + // Compute sampling + TopTools_ListOfShape aFaces; + + aFaces.Append(aFace); + aNbPoints = Unfolding::NbSamples(theEdge, aFaces, myTolContour); + } + + // Make sampling with middle points. + aNbPoints *= 2; + aNbPoints--; + + Standard_Real aCurPar = aParam[0]; + Standard_Real aStep = (aParam[1] - aParam[0])/(aNbPoints - 1); + Standard_Integer i = 1; + gp_Pnt2d aPUV; + gp_XY aPOnP; + TColgp_SequenceOfXY aSeqPnts; + Standard_Integer aNbIter = aNbPoints; + + if (!theStartVtx.IsNull()) { + // Do not compute the first point. + if (isReversed) + aNbIter--; + else { + aCurPar += aStep; + i++; + } + } + + if (!theEndVtx.IsNull()) { + // Do not compute the last point. + if (isReversed) { + aCurPar += aStep; + i++; + } else + aNbIter--; + } + + for (; i <= aNbIter; i++) { + a2dCurve->D0(aCurPar, aPUV); + + if (!ComputePointOnPlane(aPUV.XY(), aTol, aPOnP)) + return Standard_False; + + if (isReversed) + aSeqPnts.Prepend(aPOnP); + else + aSeqPnts.Append(aPOnP); + + aCurPar = (i == aNbPoints - 1) ? aParam[1] : aCurPar + aStep; + } + + // Prepend theStartPnt to the sequence of points if it was computed before. + if (!theStartVtx.IsNull()) + aSeqPnts.Prepend(theStartPnt); + else + theStartPnt = aSeqPnts.First(); + + // Append theEndPoint to the sequence of points if it was computed before. + if (!theEndVtx.IsNull()) + aSeqPnts.Append(theEndPnt); + else + theEndPnt = aSeqPnts.Last(); + + // Compute edges. + if (aSeqPnts.IsEmpty()) + return Standard_False; + + TopoDS_Vertex aV[2]; + Standard_Boolean isClosed = Standard_False; + + TopExp::Vertices(theEdge, aV[0], aV[1], Standard_True); + + if (aV[0].IsSame(aV[1])) { + gp_Pnt2d aP2d[2]; + + a2dCurve->D0(aParam[0], aP2d[0]); + a2dCurve->D0(aParam[1], aP2d[1]); + isClosed = aP2d[0].IsEqual(aP2d[1], aTol); + } + + // Check if the first point coincides with theStartVtx. + Handle(Geom_Surface) aPlane = new Geom_Plane(myPlane); + const gp_XY &aFirst = aSeqPnts.First(); + const gp_XY &aLast = aSeqPnts.Last(); + gp_Pnt aPFirst; + gp_Pnt aPLast; + + aPlane->D0(aFirst.X(), aFirst.Y(), aPFirst); + aPlane->D0(aLast.X(), aLast.Y(), aPLast); + + if (!theStartVtx.IsNull()) { + gp_Pnt aPStartVtx = BRep_Tool::Pnt(theStartVtx); + Standard_Real aVtxTol = BRep_Tool::Tolerance(theStartVtx); + Standard_Real aTolConf = Max(aVtxTol, myTolContour); + + if (!aPFirst.IsEqual(aPStartVtx, aTolConf)) + return Standard_False; + + if (isClosed && !aPLast.IsEqual(aPStartVtx, aTolConf)) + return Standard_False; + } + + // Check if the last point coincides with theEndVtx. + if (!theEndVtx.IsNull()) { + gp_Pnt aPEndVtx = BRep_Tool::Pnt(theEndVtx); + Standard_Real aVtxTol = BRep_Tool::Tolerance(theEndVtx); + Standard_Real aTolConf = Max(aVtxTol, myTolContour); + + if (!aPLast.IsEqual(aPEndVtx, aTolConf)) + return Standard_False; + } + + // Construct edges. + gp_Pnt aPOnPln[2]; + gp_Pnt aPMid; + Standard_Real aTopoTol = Precision::Confusion(); + BRep_Builder aBuilder; + Handle(Geom_Curve) aCurve; + + for (i = 1; i <= aNbPoints; i += 2) { + const gp_XY &aP = aSeqPnts.Value(i); + + aPlane->D0(aP.X(), aP.Y(), aPOnPln[1]); + + // Get or compute aV[1]. + if (i == 1 && !theStartVtx.IsNull()) { + aV[1] = theStartVtx; + } else if (i == aNbPoints) { + if (isClosed && !theStartVtx.IsNull()) + aV[1] = theStartVtx; + else if(!theEndVtx.IsNull()) + aV[1] = theEndVtx; + else + aBuilder.MakeVertex(aV[1], aPOnPln[1], aTopoTol); + } else + aBuilder.MakeVertex(aV[1], aPOnPln[1], aTopoTol); + + if (i == 1) { + aV[0] = aV[1]; + continue; + } + + // Compute a curve + const gp_XY &aPm1 = aSeqPnts.Value(i - 1); + + aPOnPln[0] = BRep_Tool::Pnt(aV[0]); + aPlane->D0(aPm1.X(), aPm1.Y(), aPMid); + + aCurve = MakeCurve(aPOnPln[0], aPMid, aPOnPln[1], myPlane, myTolContour); + + if (aCurve.IsNull()) + return Standard_False; + + // Construct the edge. + BRepBuilderAPI_MakeEdge aMkEdge(aCurve, aV[0], aV[1]); + + if (!aMkEdge.IsDone()) + return Standard_False; + + const TopoDS_Edge &anEdge = aMkEdge.Edge(); + + thePlnEdges.Append(anEdge); + aV[0] = aV[1]; + } + + return Standard_True; +} + +//======================================================================= +//function : ComputePointOnPlane +//purpose : +//======================================================================= + +Standard_Boolean Unfolding_Surface::ComputePointOnPlane + (const gp_XY &thePoint, + const Standard_Real theEdgeTol, + gp_XY &thePointOnPlane) const +{ + Standard_Integer i; + Standard_Integer j; + Standard_Integer iStart = myGrid->LowerRow(); + Standard_Integer jStart = myGrid->LowerCol(); + Standard_Integer iEnd = myGrid->UpperRow(); + Standard_Integer jEnd = myGrid->UpperCol(); + + GetCell(thePoint, myGrid, theEdgeTol, i, j); + + if (i < iStart) + i++; + + if (j < jStart) + j++; + + const Unfolding_Point &aP11 = myGrid->Value(i, j); + gp_Pnt aPOnSurf; + gp_XYZ aDP; + Handle(Geom_Surface) aSurface = + BRep_Tool::Surface(myDataContainer->GetFace()); + + aSurface->D0(thePoint.X(), thePoint.Y(), aPOnSurf); + aDP = aPOnSurf.XYZ(); + aDP.Subtract(aP11.GetPointOnSurface()); + + if (aDP.Modulus() < myTolContour) { + thePointOnPlane = aP11.GetPointOnPlane(); + return Standard_True; + } + + gp_XY aDP2d = thePoint.Subtracted(gp_XY(aP11.GetU(), aP11.GetV())); + gp_XYZ aDIso; + gp_XY aDIso2d; + gp_XY aDIsoSurf; + + // Get direction along V. + if (j == jEnd) { + const Unfolding_Point &aP1M1 = myGrid->Value(i, j - 1); + aDIso = aP11.GetPointOnSurface() - aP1M1.GetPointOnSurface(); + aDIso2d = aP11.GetPointOnPlane() - aP1M1.GetPointOnPlane(); + aDIsoSurf.SetCoord(aP11.GetU() - aP1M1.GetU(), aP11.GetV() - aP1M1.GetV()); + } else { + const Unfolding_Point &aP12 = myGrid->Value(i, j + 1); + aDIso = aP12.GetPointOnSurface() - aP11.GetPointOnSurface(); + aDIso2d = aP12.GetPointOnPlane() - aP11.GetPointOnPlane(); + aDIsoSurf.SetCoord(aP12.GetU() - aP11.GetU(), aP12.GetV() - aP11.GetV()); + } + + if (aDIso.Modulus() <= myTolContour) { + // Get direction along U. + if (i == iEnd) { + const Unfolding_Point &aPM11 = myGrid->Value(i - 1, j); + aDIso = aP11.GetPointOnSurface() - aPM11.GetPointOnSurface(); + aDIso2d = aP11.GetPointOnPlane() - aPM11.GetPointOnPlane(); + aDIsoSurf.SetCoord(aP11.GetU() - aPM11.GetU(), aP11.GetV() - aPM11.GetV()); + } else { + const Unfolding_Point &aP21 = myGrid->Value(i + 1, j); + aDIso = aP21.GetPointOnSurface() - aP11.GetPointOnSurface(); + aDIso2d = aP21.GetPointOnPlane() - aP11.GetPointOnPlane(); + aDIsoSurf.SetCoord(aP21.GetU() - aP11.GetU(), aP21.GetV() - aP11.GetV()); + } + } + + if (aDIso.Modulus() <= myTolContour) + return Standard_False; + + // Compute angle between aDP and aDIso + gp_Vec aVecIso(aDIso); + Standard_Real anAngle = aVecIso.Angle(gp_Vec(aDP)); + + if (aDP2d.Crossed(aDIsoSurf) < 0.) + anAngle = -anAngle; + + // Rotate DIso2d by anAngle. + gp_Dir2d aPDir(aDIso2d); + + aPDir.Rotate(-anAngle); + + Unfolding_Point aPoint; + Standard_Real aCrvDist; + + aPoint.SetPointOnSurface(aPOnSurf.XYZ()); + aPoint.SetParameters(thePoint.X(), thePoint.Y()); + aCrvDist = CrvDistance(aP11, aPoint, aSurface, myTolContour); + + // Compute point on plane + thePointOnPlane = aP11.GetPointOnPlane(); + thePointOnPlane += aPDir.XY().Multiplied(aCrvDist); + + return Standard_True; +} + +static void AdjustToDeflection( Standard_Integer &theNbPointsU, + Standard_Integer &theNbPointsV, + const Handle(Geom_Surface) &theSurface, + const Standard_Real theUMin, + const Standard_Real theUMax, + const Standard_Real theVMin, + const Standard_Real theVMax, + const Standard_Real theDeflection) +{ + if ( theNbPointsU < 2 ) + theNbPointsU = 2; + + if ( theNbPointsV < 2 ) + theNbPointsV = 2; + Standard_Real aUStep = (theUMax - theUMin)/(theNbPointsU - 1); + Standard_Real aVStep = (theVMax - theVMin)/(theNbPointsV - 1); + Standard_Real aUPar; + Standard_Real aVPar; + Standard_Integer i; + Standard_Integer j; + TColgp_Array2OfPnt aMesh(1, theNbPointsU, 1, theNbPointsV); + gp_Pnt aPnt; + + + for (aUPar = theUMin, i = 1; i <= theNbPointsU; i++) { + for (aVPar = theVMin, j = 1; j <= theNbPointsV; j++) { + aPnt = theSurface->Value(aUPar, aVPar); + aMesh.SetValue(i, j, aPnt); + aVPar = (j == theNbPointsV - 1) ? theVMax : aVPar + aVStep; + } + aUPar = (i == theNbPointsU - 1) ? theUMax : aUPar + aUStep; + } + Standard_Real aMaxDist = 0.; + Standard_Real aMaxDifU = 0.; + Standard_Real aMaxDifV = 0.; + + for (aUPar = theUMin + aUStep, i = 2; i <= theNbPointsU; i++) { + for (aVPar = theVMin + aVStep, j = 2; j <= theNbPointsV; j++) { + aPnt = theSurface->Value(aUPar-aUStep*0.5, aVPar-aVStep*0.5); + gp_XYZ xyz = aMesh.Value(i,j).XYZ(); + xyz += aMesh.Value(i-1,j).XYZ(); + xyz += aMesh.Value(i,j-1).XYZ(); + xyz += aMesh.Value(i-1,j-1).XYZ(); + xyz /= 4.; + Standard_Real aVal = aMesh.Value(i,j).SquareDistance(aMesh.Value(i-1,j)); + if ( aMaxDifU < aVal ) + aMaxDifU = aVal; + + aVal = aMesh.Value(i,j-1).SquareDistance(aMesh.Value(i-1,j-1)); + if ( aMaxDifU < aVal ) + aMaxDifU = aVal; + + aVal = aMesh.Value(i,j).SquareDistance(aMesh.Value(i,j-1)); + if ( aMaxDifV < aVal ) + aMaxDifV = aVal; + + aVal = aMesh.Value(i-1,j).SquareDistance(aMesh.Value(i-1,j-1)); + if ( aMaxDifV < aVal ) + aMaxDifV = aVal; + + Standard_Real aDist = aPnt.SquareDistance(gp_Pnt(xyz)); + if ( aMaxDist < aDist ) + aMaxDist = aDist; + + aVPar = (j == theNbPointsV - 1) ? theVMax : aVPar + aVStep; + } + aUPar = (i == theNbPointsU - 1) ? theUMax : aUPar + aUStep; + } + aMaxDist = sqrt( aMaxDist ); + + if ( aMaxDist > theDeflection ) { + aMaxDifU = sqrt( aMaxDifU ); + aMaxDifV = sqrt( aMaxDifV ); + + Standard_Real anewdifu = theDeflection * aMaxDifU / aMaxDist; + Standard_Real anewdifv = theDeflection * aMaxDifV / aMaxDist; + + Standard_Real aVal = ( theUMax - theUMin ) / anewdifu; + if ( aVal > aLimitNumber ) + aVal = aLimitNumber; + theNbPointsU = ( theNbPointsU < aVal ) ? Standard_Integer (aVal) : theNbPointsU; + + aVal = ( theVMax - theVMin ) / anewdifv; + if ( aVal > aLimitNumber ) + aVal = aLimitNumber; + theNbPointsV = ( theNbPointsV < aVal ) ? Standard_Integer (aVal) : theNbPointsV; + } +} diff --git a/src/Unfolding/Unfolding_Surface.lxx b/src/Unfolding/Unfolding_Surface.lxx new file mode 100644 index 0000000000..ff7ff984d4 --- /dev/null +++ b/src/Unfolding/Unfolding_Surface.lxx @@ -0,0 +1,132 @@ +// File: Unfolding_Surface.lxx +// Created: Tue Jul 22 16:13:39 2008 +// Author: Sergey KHROMOV +// + + +#include + + +//======================================================================= +//function : SetFace +//purpose : +//======================================================================= + +inline void Unfolding_Surface::SetFace (const TopoDS_Face &theFace) +{ + myDataContainer->SetFace(theFace); + Reset(); +} + +//======================================================================= +//function : GetFace +//purpose : +//======================================================================= + +inline const TopoDS_Face &Unfolding_Surface::GetFace () const +{ + return myDataContainer->GetFace(); +} + +//======================================================================= +//function : SetPlane +//purpose : +//======================================================================= + +inline void Unfolding_Surface::SetPlane (const gp_Pln &thePlane) +{ + myPlane = thePlane; + Reset(); +} + +//======================================================================= +//function : GetPlane +//purpose : +//======================================================================= + +inline const gp_Pln &Unfolding_Surface::GetPlane () const +{ + return myPlane; +} + +//======================================================================= +//function : SetTolerance +//purpose : +//======================================================================= + +inline void Unfolding_Surface::SetContourTolerance (const Standard_Real theTolerance) +{ + myTolContour = theTolerance; + Reset(); +} + +//======================================================================= +//function : GetTolerance +//purpose : +//======================================================================= + +inline Standard_Real Unfolding_Surface::GetContourTolerance () const +{ + return myTolContour; +} + + +inline void Unfolding_Surface::SetCurvatureTolerance(const Standard_Real theTolerance) +{ + myTolCurvature = theTolerance; + Reset(); +} + + +inline Standard_Real Unfolding_Surface::GetCurvatureTolerance() const +{ + return myTolCurvature; +} + +inline void Unfolding_Surface::SetDeflection(const Standard_Real theDeflection) +{ + myDeflection = theDeflection; + Reset(); +} + + +inline Standard_Real Unfolding_Surface::GetDeflection() const +{ + return myDeflection; +} + + +//======================================================================= +//function : ErrorStatus +//purpose : +//======================================================================= + +inline Unfolding_ErrorStatus Unfolding_Surface::ErrorStatus () const +{ + return myErrorStatus; +} + +//======================================================================= +//function : GetDataContainer +//purpose : +//======================================================================= + +inline Handle(Unfolding_FaceDataContainer) + Unfolding_Surface::GetDataContainer() const +{ + return myDataContainer; +} + +//======================================================================= +//function : Reset +//purpose : +//======================================================================= + +inline void Unfolding_Surface::Reset() +{ + myDataContainer->Reset(); + myErrorStatus = Unfolding_NotDone; + + if (!myGrid.IsNull()) + myGrid.Nullify(); +} diff --git a/src/UnfoldingTest/UnfoldingTest.cdl b/src/UnfoldingTest/UnfoldingTest.cdl new file mode 100644 index 0000000000..23d72fa827 --- /dev/null +++ b/src/UnfoldingTest/UnfoldingTest.cdl @@ -0,0 +1,24 @@ +-- File: UnfoldingTest.cdl +-- Created: Tue Jul 22 18:15:41 2008 +-- Author: Sergey KHROMOV +-- +---Copyright: Matra Datavision 2008 + + +package UnfoldingTest + ---Purpose: This package defines a set of Draw commands for testing of + -- functionality of the package Unfolding. + +uses + + Draw + +is + + Commands(theDI: in out Interpretor from Draw); + ---Purpose: Adds Draw commands to the draw interpretor. + + Factory(theDI: out Interpretor from Draw); + ---Purpose: Plugin entry point function. + +end UnfoldingTest; diff --git a/src/UnfoldingTest/UnfoldingTest.cxx b/src/UnfoldingTest/UnfoldingTest.cxx new file mode 100644 index 0000000000..ae08ecd029 --- /dev/null +++ b/src/UnfoldingTest/UnfoldingTest.cxx @@ -0,0 +1,272 @@ +// File: UnfoldingTest.cxx +// Created: Tue Jul 22 18:35:23 2008 +// Author: Sergey KHROMOV +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//======================================================================= +//function : dumpError +//purpose : +//======================================================================= + +static void dumpError (Draw_Interpretor &di, + const Standard_Integer theStatus) +{ + di << " Status: "; + + switch (theStatus) { + case Unfolding_Done: + di << "Done"; + break; + case Unfolding_NotDone: + di << "NotDone"; + break; + case Unfolding_Failure: + di << "Failure"; + break; + case Unfolding_InvalidSurface: + di << "InvalidSurface"; + break; + case Unfolding_InvalidInput: + di << "InvalidInput"; + break; + case Unfolding_InvalidShape: + di << "InvalidShape"; + break; + case Unfolding_ComplexShape: + di << "ComplexShape"; + break; + default: + di << "Unknown"; + break; + } + + di << " \n"; +} + +//======================================================================= +//function : unfolding +//purpose : +//======================================================================= +static Standard_Integer unfolding (Draw_Interpretor &di, + Standard_Integer n, const char** a) +{ + if (n < 4 || n > 7) { + di << "Usage: " << a[0] << " result face|shell plane [tol_contour] [tol_curvature] [deflection]" << "\n"; + return 1; + } + + // Get a shape from a[2]. + TopoDS_Shape aShape = DBRep::Get(a[2]); + + if (aShape.IsNull()) { + di << a[2] << " is not a shape!" << "\n"; + return 1; + } + + // Check if the shape is a face. + if (aShape.ShapeType() != TopAbs_FACE && + aShape.ShapeType() != TopAbs_SHELL) { + di << a[2] << " is not a face or shell!" << "\n"; + return 1; + } + TopoDS_Shell aShell; + TopoDS_Face aFace; + if (aShape.ShapeType() == TopAbs_FACE) { + aFace = TopoDS::Face( aShape ); + if (aFace.IsNull()) { + di << a[2] << " is not a face!" << "\n"; + return 1; + } + } + else { + aShell = TopoDS::Shell( aShape ); + } + + // Get a surface from a[3]. + Handle(Geom_Surface) aSurface = DrawTrSurf::GetSurface(a[3]); + + if (aSurface.IsNull()) { + di << a[3] << " is not a surface!" << "\n"; + return 1; + } + + // Cast the surface to a plane. + Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface); + + if (aPlane.IsNull()) { + di << a[3] << " is not a plane!" << "\n"; + return 1; + } + + // Get the tolerance value. + Standard_Real aTolContour = 0.001; + + if (n >= 5) { + aTolContour = Draw::Atof(a[4]); + } else { + di << "tolerance value is not provided. The default value " << aTolContour << " is used" << "\n"; + } + + // Get the curvature tolerance value. + Standard_Real aTolCurv = 0.001; + + if (n >= 6) { + aTolCurv = Draw::Atof(a[5]); + } else { + di << "curvature value is not provided. The default value " << aTolCurv << " is used" << "\n"; + } + + // Get the curvature tolerance value. + Standard_Real aDefl = 0.001; + + if (n == 7) { + aDefl = Draw::Atof(a[6]); + } else { + di << "deflection value is not provided. The default value " << aDefl << " is used" << "\n"; + } + + + // Initialization of the unfolding algorithm + Standard_Boolean isOK = Standard_False; + TopoDS_Shape aResult; + Standard_Integer aErrorStatus = 0; + + if ( !aFace.IsNull() ) { + TopTools_DataMapOfShapeInteger anEmptyMap; + Unfolding_Surface anUnfold(aFace, aPlane->Pln(), aTolContour, aTolCurv, aDefl); + isOK = anUnfold.Perform(anEmptyMap); + + Handle(Unfolding_FaceDataContainer) aData = anUnfold.GetDataContainer(); + + di << "Gauss curvature =" << aData->GetMaxGaussCurvature() << "\n"; + di << "Area of error =" << aData->GetDistortionArea() << "\n"; + if ( isOK ) + aResult = aData->GetUnfoldedFace(); + aErrorStatus = anUnfold.ErrorStatus(); + } + else if ( !aShell.IsNull() ) { + Unfolding_Shell anUnfold(aShell, aPlane->Pln(), aTolContour, aTolCurv, aDefl); + isOK = anUnfold.Perform(); + + di << "Gauss curvature =" << anUnfold.GetMaxGaussCurvature() << "\n"; + di << "Area of error =" << anUnfold.GetAreaError() << "\n"; + if ( isOK ) + aResult = anUnfold.GetResult(); + aErrorStatus = anUnfold.ErrorStatus(); + } + + if (isOK) { + DBRep::Set(a[1], aResult); + } else { + di << "Unfolding failure!" << "\n"; + dumpError(di, aErrorStatus); + + return 1; + } + + return 0; +} + +//======================================================================= +//function : toshell +//purpose : +//======================================================================= + +static Standard_Integer toshell (Draw_Interpretor &di, + Standard_Integer n, const char** a) +{ + if (n != 3 && n != 4) { + di << "Usage: " << a[0] << " result shape [tolerance]" << "\n";; + return 1; + } + + // Get a shape from a[2]. + TopoDS_Shape aShape = DBRep::Get(a[2]); + + if (aShape.IsNull()) { + di << a[2] << " is not a shape!" << "\n"; + return 1; + } + + // Get the tolerance value. + Standard_Real aTolerance = 1.e-6; + + if (n == 4) { + aTolerance = Draw::Atof(a[3]); + } else { + di << "tolerance value is not provided. The default value " << aTolerance << " is used" << "\n"; + } + + Unfolding_ErrorStatus aStatus; + TopoDS_Shell aResult = Unfolding::ToShell(aShape, aTolerance, aStatus); + + if (aResult.IsNull()) { + di << "toshell failure!" << "\n"; + dumpError(di, aStatus); + + return 1; + } + + DBRep::Set(a[1], aResult); + + return 0; +} + +//======================================================================= +//function : Commands +//purpose : +//======================================================================= + +void UnfoldingTest::Commands(Draw_Interpretor &theDI) +{ + static Standard_Boolean done = Standard_False; + + if (done) + return; + + done = Standard_True; + + // Chapter's name + const char* group = "Unfolding commands"; + + theDI.Add("unfolding","unfolding result face|shell plane [tol_contour] [tol_curvature] [deflection]", + __FILE__, unfolding, group); + + theDI.Add("toshell","toshell result shape [tolerance]", + __FILE__, toshell, group); +} + +//======================================================================= +//function : Factory +//purpose : +//======================================================================= + +void UnfoldingTest::Factory(Draw_Interpretor &theDI) +{ + UnfoldingTest::Commands(theDI); +#ifdef DEB + theDI << "Draw Plugin : Unfolding commands are loaded" << "\n"; +#endif +} + +// Declare entry point PLUGINFACTORY +DPLUGIN(UnfoldingTest) diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 0db16ce60b..96ace7dac1 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -13,7 +13,6 @@ // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. - #include #include #include @@ -2117,8 +2116,8 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd, } } break; - - case WM_MOUSEWHEEL: +#if _MSC_VER >= 1500 + case WM_MOUSEWHEEL: { int aDelta = GET_WHEEL_DELTA_WPARAM (wParam); if (wParam & MK_CONTROL) @@ -2134,12 +2133,13 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd, } } } - else + else { aView->Zoom (0, 0, aDelta / 40, aDelta / 40); } break; } +#endif case WM_MOUSEMOVE: {