// GEOM SKETCHER : basic sketcher // // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org // // // // File : GEOM_Sketcher.cxx // Author : Nicolas REJNERI // Module : GEOM // $Header$ using namespace std; #include "GEOM_Sketcher.h" #include "utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \class GEOM_Sketcher GEOM_Sketcher.h \brief ... */ Standard_Real resol = 1.0; /*! Constructor. */ Sketch::Sketch() { } /*! Destructor. */ Sketch::~Sketch() { } /*! Constructor. \param V3d_Viewer */ Sketch::Sketch(const Handle(V3d_Viewer)& aViewer) : myInteractiveContext(new AIS_InteractiveContext(aViewer)), myAxisColor(Quantity_Color(Quantity_NOC_YELLOW)), myCurrentColor(Quantity_Color(Quantity_NOC_GREEN)), myWireColor(Quantity_Color(Quantity_NOC_RED)) { Init(); } /*! Constructor. \param V3d_Viewer \param Quantity_Color \param Quantity_Color \param Quantity_Color */ Sketch::Sketch(const Handle(V3d_Viewer)& aViewer, const Quantity_Color& anAxisColor, const Quantity_Color& aCurrentColor, const Quantity_Color& aWireColor): myInteractiveContext(new AIS_InteractiveContext(aViewer)), myAxisColor(anAxisColor), myCurrentColor(aCurrentColor), myWireColor(aWireColor) { Init(); } /*! Build the current edge in a graphic mode. The first signature with view coordinates is used to connect to the move event from the user interface. The second signature is used when the current point is known by 2d real coordinates. \param Xp \param Yp \param V3d_View */ void Sketch::MakeCurrentEdge(const Standard_Integer Xp , const Standard_Integer Yp , const Handle(V3d_View)& aView ) { /* 3d coordinates of the picked point */ Standard_Real Xv,Yv,Zv; aView->Convert(Xp,Yp,Xv,Yv,Zv); /* computation of real 2d coordinates in plane of sketch */ Standard_Real Vx,Vy,Vz; aView->Proj(Vx,Vy,Vz); gp_Dir D(Vx,Vy,Vz); gp_Pnt P(Xv,Yv,Zv); gp_Lin L(P,D); Standard_Real X,Y; gp_Pnt Sol; IntAna_IntConicQuad Int(L,myPlane->Pln(),Precision::Angular()); if (Int.IsDone()) { if (!Int.IsParallel()) { if (Int.NbPoints() > 0 ) { Sol = Int.Point(1); ElSLib::Parameters(myPlane->Pln(),Sol,X,Y); } } } MakeCurrentEdge(X,Y); } /*! Build the current edge in a graphic mode. The first signature with view coordinates is used to connect to the move event from the user interface. The second signature is used when the current point is known by 2d real coordinates. \param X \param Y */ void Sketch::MakeCurrentEdge(const Standard_Real X, const Standard_Real Y) { /* Create the current edge depending on the active mode */ switch (myCurrentStatus) { case BEGIN_SKETCH: myCurrentEdge = BRepBuilderAPI_MakeVertex(ElCLib::To3d(myPlane->Pln().Position().Ax2(),gp_Pnt2d(X,Y))); break; case SEGMENT: MakeCurrentSegment(X,Y); break; case ARC_CHORD: MakeCurrentSegment(X,Y); break; case ARC_CHORD_END: MakeCurrentArc(X,Y); break; } DisplayCurrentEdge(); } /*! Build the current edge in a graphic mode. Function to connect to the input event from the user interface. */ void Sketch::ValidateEdge() { gp_Pnt pt; gp_Pnt2d pt2d; switch (myCurrentStatus) { case BEGIN_SKETCH: { myFirstPointSketch = TopoDS::Vertex(myCurrentEdge); myPresentableWire = new AIS_Shape(myFirstPointSketch); myPresentableWire->SetColor(myWireColor.Name()); myInteractiveContext->Display(myPresentableWire); pt = BRep_Tool::Pnt(myFirstPointSketch); pt2d = ProjLib::Project(myPlane->Pln(),pt); myLastX = pt2d.X(); myLastY = pt2d.Y(); myCurrentStatus = SEGMENT; break; } case SEGMENT: { Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,first,last); myCurrentEdge = BRepBuilderAPI_MakeEdge2d(Handle(Geom2d_Line)::DownCast(C)->Lin2d(),0.,myLengthDimension->Value()); if (myTransitionStatus == ANGLE || myTransitionStatus == LENGTH_FIXED || myTransitionStatus == X_FIXED || myTransitionStatus == Y_FIXED) myTransitionStatus = NOCONSTRAINT; AddEdgeToWire(); break; } case ARC_CHORD: { myInteractiveContext->CloseLocalContext(); myInteractiveContext->OpenLocalContext(); gp_Pnt2d p1 (myLastX,myLastY); pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myCurrentEdge))); gp_Pnt2d p2 = ProjLib::Project(myPlane->Pln(),pt); GccAna_Pnt2dBisec ComputeMediatrice(p1,p2); if (ComputeMediatrice.HasSolution()) { myMediatrice = new Geom2d_Line(ComputeMediatrice.ThisSolution()); Handle(Geom_Curve) aMediatrice3d = GeomAPI::To3d(myMediatrice,myPlane->Pln()); myPresentableMediatrice = new AIS_Axis(Handle(Geom_Line)::DownCast(aMediatrice3d)); myInteractiveContext->Display(myPresentableMediatrice); } TopoDS_Edge e = BRepBuilderAPI_MakeEdge2d(gce_MakeCirc2d(gp_Pnt2d(0.,0),1.)); BRepLib::BuildCurve3d(e); myLengthDimension->SetText(TCollection_ExtendedString()); myInteractiveContext->Redisplay(myLengthDimension,Standard_False); if (myEdgesNumber == 0) myPreviousEdge = TopoDS::Edge(myCurrentEdge); pt2d = ProjLib::Project(myPlane->Pln(),pt); myLastX = pt2d.X(); myLastY = pt2d.Y(); myTransitionStatus = NOCONSTRAINT; myCurrentStatus = ARC_CHORD_END; break; } case ARC_CHORD_END: myCurrentStatus = ARC_CHORD; AddEdgeToWire(); break; } } /*! Add edge to current wire on an edge validation . */ void Sketch::AddEdgeToWire() { myPreviousEdge = TopoDS::Edge(myCurrentEdge); BRepLib::BuildCurve3d(myPreviousEdge); myCurrentWire.Add(TopoDS::Edge(myPreviousEdge)); myEdgesNumber++; myPresentableWire->Set( myCurrentWire.Wire() ); myInteractiveContext->Redisplay(myPresentableWire); myConstructionMode.Append(myCurrentStatus); myConstraintMode.Append(myTransitionStatus); myInteractiveContext->CloseLocalContext(); gp_Pnt pt; if (myPreviousEdge.Orientation() == TopAbs_FORWARD ) pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myPreviousEdge))); else pt = BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(myPreviousEdge))); gp_Pnt2d pt2d= ProjLib::Project(myPlane->Pln(),pt); myLastX = pt2d.X(); myLastY = pt2d.Y(); } /*! Set the numeric dimension for the current edge and validate creation. \param aValue \return Standard_Boolean */ Standard_Boolean Sketch::SetDimension(Standard_Real& aValue) { fitInResol(aValue); if (myCurrentStatus == SEGMENT || myCurrentStatus == ARC_CHORD){ Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,first,last); myCurrentEdge = BRepBuilderAPI_MakeEdge2d(Handle(Geom2d_Line)::DownCast(C)->Lin2d(),0.,aValue); DisplayCurrentEdge(); if (myTransitionStatus == NOCONSTRAINT) { mySegmentLength = aValue; myTransitionStatus = LENGTH_FIXED; } else ValidateEdge(); return Standard_True; } else if( myCurrentStatus == ARC_CHORD_END){ if (myTransitionStatus == TANGENT) return Standard_False; gp_Pnt2d p; if (myEdgesNumber > 0) { if (myPreviousEdge.Orientation() == TopAbs_FORWARD) p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge))); else p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge))); } else p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(myFirstPointSketch)); GccAna_Circ2d2TanRad aSol(p, gp_Pnt2d(myLastX,myLastY),aValue,Precision::Confusion()); Standard_Real dist = RealLast(); if (aSol.NbSolutions() > 0) { gp_Circ2d CirSol; gp_Pnt2d pc = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopoDS::Vertex(myCenterCircle->Shape()))); for (Standard_Integer i =1; i<= aSol.NbSolutions(); i++) { if (pc.Distance(aSol.ThisSolution(i).Location()) < dist) CirSol = aSol.ThisSolution(i); } if (myCurrentEdge.Orientation() == TopAbs_FORWARD) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),p,gp_Pnt2d(myLastX,myLastY)); else { myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),gp_Pnt2d(myLastX,myLastY),p); myCurrentEdge.Reverse(); } DisplayCurrentEdge(); ValidateEdge(); return Standard_True; } } return Standard_False; } /*! Set the numeric dimension for the current edge and validate creation. \param deltaX \param deltaY */ void Sketch::SetDimension(Standard_Real& deltaX, Standard_Real& deltaY) { fitInResol(deltaX); fitInResol(deltaY); Standard_Real X = myLastX + deltaX; Standard_Real Y = myLastY + deltaY; MakeCurrentEdge(X,Y); ValidateEdge(); } /*! Set the numeric value of the X coordinate of current point giving a deltaX relative to previous point. \param deltaX */ void Sketch::SetXDimension(Standard_Real& deltaX) { fitInResol(deltaX); Standard_Real X = myLastX + deltaX; Standard_Real Y = myLastY; if ( deltaX == 0. ) Y = Y + 100.0 * Precision::Confusion(); if (myTransitionStatus == NOCONSTRAINT) { MakeCurrentEdge(X,Y); myTransitionStatus = X_FIXED; mySegmentX = X; } else if (myTransitionStatus == Y_FIXED) { myTransitionStatus = NOCONSTRAINT; MakeCurrentEdge(X,mySegmentY); ValidateEdge(); } else if (myTransitionStatus == ANGLE) { myTransitionStatus = NOCONSTRAINT; Standard_Real angle; if (0 <= mySegmentAngle && mySegmentAngle<= PI ) angle = PI - mySegmentAngle; else angle = mySegmentAngle - PI; Y = X*Tan(angle); MakeCurrentEdge(X,Y); ValidateEdge(); } else myTransitionStatus = NOCONSTRAINT; } /*! Set the numeric value of the Y coordinate of current point giving a deltaY relative to previous point. \param deltaY */ void Sketch::SetYDimension(Standard_Real& deltaY) { fitInResol(deltaY); Standard_Real X = myLastX; Standard_Real Y = myLastY + deltaY; if ( deltaY == 0. ) X = X + 100.0 * Precision::Confusion(); if (myTransitionStatus == NOCONSTRAINT) { MakeCurrentEdge(X,Y); myTransitionStatus = Y_FIXED; mySegmentY = Y; } else if (myTransitionStatus == X_FIXED) { myTransitionStatus = NOCONSTRAINT; MakeCurrentEdge(mySegmentX,Y); ValidateEdge(); } else if (myTransitionStatus == ANGLE) { myTransitionStatus = NOCONSTRAINT; Standard_Real angle; if (0 <= mySegmentAngle && mySegmentAngle<= PI ) angle = PI - mySegmentAngle; else angle = mySegmentAngle - PI; X = Y/Tan(angle); MakeCurrentEdge(X,Y); ValidateEdge(); } else myTransitionStatus = NOCONSTRAINT; } /*! Set the numeric value of angle between 2 segments. \param aValue */ void Sketch::SetSegmentAngle(Standard_Real& aValue) { if (myEdgesNumber > 0) { Standard_Real First,Last; TopLoc_Location L; Standard_Real angle; if (0 <= aValue && aValue<= PI ) angle = PI - aValue; else angle = aValue - PI; Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last); if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) { Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last); GccAna_Lin2dTanObl aSol(gp_Pnt2d(myLastX,myLastY),Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d(),angle); myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),0.,myLengthDimension->Value()); } if (myTransitionStatus == LENGTH_FIXED) { ValidateEdge(); } else if (myTransitionStatus == X_FIXED) { Standard_Real length = mySegmentX/Cos(angle); SetDimension(length); ValidateEdge(); } else if (myTransitionStatus == Y_FIXED) { Standard_Real length = mySegmentY/Sin(angle); SetDimension(length); ValidateEdge(); } else { mySegmentAngle = aValue; myTransitionStatus = ANGLE; } } } /*! Get the angle value between 2 segments. \return Standard_Real */ Standard_Real Sketch::GetSegmentAngle() { return mySegmentAngle; } /*! Close automatically an open sketch. \return TopoDS_Wire. Return null shape if not possible. */ TopoDS_Wire Sketch::Close() { myCurrentStatus = END_SKETCH; myInteractiveContext->CloseAllContexts(); myInteractiveContext->EraseAll(Standard_False); if (myEdgesNumber >= 2) { BRepTools_WireExplorer Ex(myCurrentWire.Wire()); TopoDS_Vertex V1; if (myPreviousEdge.Orientation() == TopAbs_FORWARD) V1 = TopExp::LastVertex(myPreviousEdge); else V1 = TopExp::FirstVertex(myPreviousEdge); myCurrentWire.Add(BRepBuilderAPI_MakeEdge(V1,myFirstPointSketch).Edge()); myEdgesNumber++; return myCurrentWire.Wire(); } else return TopoDS_Wire(); } /*! Clear sketch presentation. */ void Sketch::Clear() { myCurrentStatus = END_SKETCH; myInteractiveContext->CloseAllContexts(); myInteractiveContext->EraseAll(Standard_False); } /*! Terminate sketch without closing. \return TopoDS_Wire. Return null shape if not possible. */ TopoDS_Wire Sketch::End() { myCurrentStatus = END_SKETCH; myInteractiveContext->CloseAllContexts(); myInteractiveContext->EraseAll(Standard_False); if (myCurrentWire.IsDone()) { return myCurrentWire.Wire(); } else return TopoDS_Wire(); } /*! Delete current edge. */ Standard_Boolean Sketch::Delete() { myInteractiveContext->Erase(myAngleDimension,Standard_True,Standard_False); myInteractiveContext->Erase(myLengthDimension,Standard_True,Standard_False); myInteractiveContext->Erase(myRadiusDimension,Standard_True,Standard_False); myInteractiveContext->Erase(myCenterCircle,Standard_True,Standard_False); myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False); myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False); if (myCurrentStatus == BEGIN_SKETCH) { myCurrentStatus = END_SKETCH; myInteractiveContext->CloseAllContexts(); myInteractiveContext->EraseAll(Standard_False); return true; } else if(myCurrentStatus == SEGMENT || myCurrentStatus == ARC_CHORD ) { RemoveLastEdge(); } else if(myCurrentStatus == ARC_CHORD_END) { myCurrentStatus = ARC_CHORD; myInteractiveContext->CloseAllContexts(); } gp_Pnt pt; if (myEdgesNumber == 0) { //myInteractiveContext->EraseAll(Standard_False); ChangeMode(BEGIN_SKETCH); // DCQ pt = BRep_Tool::Pnt(myFirstPointSketch); } else { if (myPreviousEdge.Orientation() == TopAbs_FORWARD ) pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myPreviousEdge))); else pt = BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(myPreviousEdge))); } gp_Pnt2d pt2d= ProjLib::Project(myPlane->Pln(),pt); myLastX = pt2d.X(); myLastY = pt2d.Y(); return false; } /*! Set a specific plane for sketch. \param GeomyPlane */ void Sketch::SetPlane(const Handle(Geom_Plane)& aPlane) { myPlane = aPlane; } /*! Set display parameters. \param aColor */ void Sketch::SetWireColor(const Quantity_Color& aColor) { myWireColor = aColor; } /*! Set display parameters. \param aColor */ void Sketch::SetCurrentColor(const Quantity_Color& aColor) { myCurrentColor = aColor; } /*! Set display parameters. \param aColor */ void Sketch::SetAxisColor(const Quantity_Color& aColor) { myAxisColor = aColor; } /*! Change mode of construction line. \param aMode : SEGMENT, ARC_CHORD. */ void Sketch::ChangeMode(const SketchStatus aMode) { gp_Pnt2d p; if (myEdgesNumber > 0) { if (myPreviousEdge.Orientation() == TopAbs_FORWARD) p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge))); else p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge))); myLastX = p.X(); myLastY = p.Y(); myInteractiveContext->CloseLocalContext(myInteractiveContext->IndexOfCurrentLocal()); } if (!myCurrentStatus == BEGIN_SKETCH) myCurrentStatus = aMode; /* change the mode only when the sketch is not in state BEGIN_SKETCH, i.d. fist point has been fixed */ } /*! Set transition constraint between consecutive edges. \param aStatus : NOCONSTRAINT, TANGENT, PERPENDICULAR, ANGLE, LENGTH_FIXED, X_FIXED, Y_FIXED. */ void Sketch::SetTransitionStatus(const TransitionStatus aStatus) { myTransitionStatus = aStatus; } /*! Set or unset the display of dimensions. \param atype \param OnOff */ void Sketch::SetParameterVisibility(const TypeOfParameter atype, const Standard_Boolean OnOff) { switch (atype) { case ANGLE_PARAMETER: myIsAngleDimensionVisible = OnOff; if (!myIsAngleDimensionVisible && !myAngleDimension.IsNull()) myInteractiveContext->Erase(myAngleDimension,Standard_True,Standard_False); //else DCQ // DisplayCurrentEdge(); break; case LENGTH_PARAMETER: myIsLengthDimensionVisible = OnOff; if (!myIsLengthDimensionVisible&& !myLengthDimension.IsNull()) myInteractiveContext->Erase(myLengthDimension,Standard_True,Standard_False); //else DCQ // DisplayCurrentEdge(); break; case RADIUS_PARAMETER: myIsRadiusDimensionVisible = OnOff; if (!myIsRadiusDimensionVisible&& !myRadiusDimension.IsNull()){ myInteractiveContext->Erase(myRadiusDimension,Standard_True,Standard_False); myInteractiveContext->Erase(myCenterCircle,Standard_True,Standard_False); } //else DCQ // DisplayCurrentEdge(); break; case XVALUE_PARAMETER: myIsXDimensionVisible = OnOff; if (!myIsXDimensionVisible&& !myXDimension.IsNull()) myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False); break; case YVALUE_PARAMETER: myIsYDimensionVisible = OnOff; if (!myIsYDimensionVisible&& !myYDimension.IsNull()) myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False); break; } } /*! Hilight parameters. \param atype \param acolor */ void Sketch::HiligthWithColor(const TypeOfParameter atype, const Quantity_NameOfColor acolor) { switch (atype) { case ANGLE_PARAMETER: myInteractiveContext->HilightWithColor(myAngleDimension, acolor); break; case LENGTH_PARAMETER: myInteractiveContext->HilightWithColor(myLengthDimension, acolor); break; case RADIUS_PARAMETER: myInteractiveContext->HilightWithColor(myRadiusDimension, acolor); break; case XVALUE_PARAMETER: myInteractiveContext->HilightWithColor(myXDimension, acolor); break; case YVALUE_PARAMETER: myInteractiveContext->HilightWithColor(myYDimension, acolor); break; } } /*! Unhilight parameters. \param atype */ void Sketch::Unhiligth(const TypeOfParameter atype) { switch (atype) { case ANGLE_PARAMETER: myInteractiveContext->Unhilight(myAngleDimension); break; case LENGTH_PARAMETER: myInteractiveContext->Unhilight(myLengthDimension); break; case RADIUS_PARAMETER: myInteractiveContext->Unhilight(myRadiusDimension); break; case XVALUE_PARAMETER: myInteractiveContext->Unhilight(myXDimension); break; case YVALUE_PARAMETER: myInteractiveContext->Unhilight(myYDimension); break; } } /*! Check if the edition of a type of parameter is relevant depending on sketch current status. \param atype \return Standard_Boolean */ Standard_Boolean Sketch::IsValidCurrentParameter(const TypeOfParameter atype) { switch (atype) { case ANGLE_PARAMETER: if (myCurrentStatus != SEGMENT && myCurrentStatus != ARC_CHORD) return Standard_False; else if (myTransitionStatus == TANGENT || myTransitionStatus == PERPENDICULAR) return Standard_False; else if (myEdgesNumber < 1) return Standard_False; else { TopLoc_Location L; Standard_Real First,Last; Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last); if (!PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) return Standard_False; } break; case LENGTH_PARAMETER: if (myCurrentStatus != SEGMENT && myCurrentStatus != ARC_CHORD /*&& myCurrentStatus != CURVE_POINTS*/ ) return Standard_False; else if (myTransitionStatus == LENGTH_FIXED) return Standard_False; break; case RADIUS_PARAMETER: if (myCurrentStatus != ARC_CHORD_END) return Standard_False; break; case XVALUE_PARAMETER: if (myCurrentStatus != SEGMENT && myCurrentStatus != ARC_CHORD /*&& myCurrentStatus != CURVE_POINTS*/ ) return Standard_False; else if (myTransitionStatus == X_FIXED) return Standard_False; break; case YVALUE_PARAMETER: if (myCurrentStatus != SEGMENT && myCurrentStatus != ARC_CHORD /*&& myCurrentStatus != CURVE_POINTS*/ ) return Standard_False; else if (myTransitionStatus == Y_FIXED) return Standard_False; break; } return Standard_True; } /*! Set a parameter value. \param atype \param aValue */ void Sketch::SetParameterValue(const TypeOfParameter atype, Standard_Real aValue) { switch (atype) { case ANGLE_PARAMETER: SetSegmentAngle(aValue); break; case LENGTH_PARAMETER: SetDimension(aValue); break; case RADIUS_PARAMETER: SetDimension(aValue); break; case XVALUE_PARAMETER: SetXDimension(aValue); break; case YVALUE_PARAMETER: SetYDimension(aValue); break; } } /*! Initialisation of sketch parameters or options. */ void Sketch::Init() { myPlane = new Geom_Plane (0.,0.,1.,0.); CreateConstraints(); BRepLib::Plane(myPlane); myEdgesNumber = 0; myCurrentStatus = BEGIN_SKETCH; /* In order to update the visulisation of current objects by using Redisplay method from InteractiveContext */ myCurrentEdge = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.)); myPresentableEdge = new AIS_Shape(myCurrentEdge); myPresentableEdge->SetColor(myCurrentColor.Name()); myInteractiveContext->Display(myPresentableEdge); myTransitionStatus = NOCONSTRAINT; /* Init for display objects */ TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.)); TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(gp_Pnt(10.,0.,0.)); myLengthDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString()); myXDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString(),gp_Pnt(),DsgPrs_AS_NONE, AIS_TOD_Horizontal); myYDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString(),gp_Pnt(),DsgPrs_AS_NONE, AIS_TOD_Vertical); myRadiusDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString()); myCenterCircle = new AIS_Shape(V1); myIsLengthDimensionVisible = Standard_False; myIsXDimensionVisible = Standard_False; myIsYDimensionVisible = Standard_False; myIsRadiusDimensionVisible = Standard_False; } /*! Build the current segment. \param X \param Y */ void Sketch::MakeCurrentSegment(Standard_Real X, Standard_Real Y) { if (myTransitionStatus == NOCONSTRAINT) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y)); else if (myTransitionStatus == X_FIXED) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),gp_Pnt2d(mySegmentX,Y)); else if (myTransitionStatus == Y_FIXED) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),gp_Pnt2d(X,mySegmentY)); else if (myTransitionStatus == TANGENT && myEdgesNumber > 0) { Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last); gp_Pnt2d p1; gp_Vec2d Vt; if (myPreviousEdge.Orientation() == TopAbs_FORWARD) C->D1(last,p1,Vt); else C->D1(first,p1,Vt); gp_Lin2d aline(p1,Vt); Geom2dAPI_ProjectPointOnCurve proj(gp_Pnt2d(X,Y),new Geom2d_Line(aline)); if (proj.NbPoints() > 0) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(p1,proj.Point(1)); } else if (myTransitionStatus == PERPENDICULAR && myEdgesNumber > 0) { Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last); gp_Pnt2d p1; gp_Lin2d perpen; if (myPreviousEdge.Orientation() == TopAbs_FORWARD) C->D0(last,p1); else C->D0(first,p1); if (C->IsKind(STANDARD_TYPE(Geom2d_Line))) { GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Line)::DownCast(C)->Lin2d()); perpen = aSol.ThisSolution(1); } else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) { GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Circle)::DownCast(C)->Circ2d()); perpen = aSol.ThisSolution(1); } Geom2dAPI_ProjectPointOnCurve proj(gp_Pnt2d(X,Y),new Geom2d_Line(perpen)); if (proj.NbPoints() > 0) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(p1,proj.Point(1)); } else if (myTransitionStatus == ANGLE && myEdgesNumber > 0) { Standard_Real First,Last; TopLoc_Location L; Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last); if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) { Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last); Standard_Real angle; if (0 <= mySegmentAngle && mySegmentAngle<= PI ) angle = PI - mySegmentAngle; else angle = mySegmentAngle - PI; GccAna_Lin2dTanObl aSol(gp_Pnt2d(myLastX,myLastY),Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d(),angle); Standard_Real dist = RealLast(); gp_Pnt2d pt(X,Y),ptproj; for (Standard_Integer i =1; i<=aSol.NbSolutions(); i++) { Geom2dAPI_ProjectPointOnCurve proj(pt,new Geom2d_Line(aSol.ThisSolution(i))); if (pt.Distance(proj.Point(1)) < dist) { dist = pt.Distance(proj.Point(1)); ptproj = proj.Point(1); } } myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),ptproj); } } else if (myTransitionStatus == LENGTH_FIXED && myEdgesNumber > 0) { Standard_Real First,Last; TopLoc_Location L; Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last); if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) { Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last); gp_Lin2d aline = gce_MakeLin2d(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y)); myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aline,0.,mySegmentLength); } } } /*! Build the current arc. \param X \param Y */ void Sketch::MakeCurrentArc(Standard_Real X, Standard_Real Y) { gp_Circ2d CircSol; Standard_Boolean OK(Standard_False); if (myTransitionStatus == NOCONSTRAINT) { GccAna_Circ2d2TanOn aSol(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y),myMediatrice->Lin2d(),Precision::Confusion()); if (aSol.NbSolutions() > 0){ CircSol = aSol.ThisSolution(1); OK = Standard_True; } } /* Tangency with previous edge */ else if (myTransitionStatus == TANGENT && myEdgesNumber > 0) { Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last); if (C->IsKind(STANDARD_TYPE(Geom2d_Line))){ GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(Handle(Geom2d_Line)::DownCast(C)->Lin2d()), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion()); if (aSol.NbSolutions() > 0){ CircSol = aSol.ThisSolution(1); OK = Standard_True; } } else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) { GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(Handle(Geom2d_Circle)::DownCast(C)->Circ2d()), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion()); if (aSol.NbSolutions() > 0){ CircSol = aSol.ThisSolution(1); OK = Standard_True; } } else if(C->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) { gp_Pnt2d pc; gp_Vec2d Vt; C->D1(last,pc,Vt); gp_Lin2d alin2d(pc,gp_Dir2d(Vt)); GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(alin2d), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion()); if (aSol.NbSolutions() > 0){ CircSol = aSol.ThisSolution(1); OK = Standard_True; } } } /* Tangency with the perpendicular to the previous edge */ else if (myTransitionStatus == PERPENDICULAR && myEdgesNumber > 0) { Standard_Real first,last; TopLoc_Location L; Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last); gp_Pnt2d p1; gp_Lin2d perpen; if (myPreviousEdge.Orientation() == TopAbs_FORWARD) C->D0(last,p1); else C->D0(first,p1); if (C->IsKind(STANDARD_TYPE(Geom2d_Line))) { GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Line)::DownCast(C)->Lin2d()); perpen = aSol.ThisSolution(1); } else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) { GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Circle)::DownCast(C)->Circ2d()); perpen = aSol.ThisSolution(1); } GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(perpen), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion()); if (aSol.NbSolutions() > 0){ CircSol = aSol.ThisSolution(1); OK = Standard_True; } } gp_Pnt2d p; if (myEdgesNumber > 0) { if (myPreviousEdge.Orientation() == TopAbs_FORWARD) p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge))); else p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge))); } else p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(myFirstPointSketch)); if (OK){ gp_Vec2d V1(p,gp_Pnt2d(X,Y)); gp_Vec2d V2(p,gp_Pnt2d(myLastX,myLastY)); if (V1.Angle(V2) > 0 ) myCurrentEdge = BRepBuilderAPI_MakeEdge2d(CircSol,p,gp_Pnt2d(myLastX,myLastY)); else { myCurrentEdge = BRepBuilderAPI_MakeEdge2d(CircSol,gp_Pnt2d(myLastX,myLastY),p); myCurrentEdge.Reverse(); } } else { myCurrentStatus = ARC_CHORD; myLastX = p.X(); myLastY = p.Y(); myInteractiveContext->CloseLocalContext(); } } /*! Display the current edge under construction with it's dimension. */ void Sketch::DisplayCurrentEdge() { myPresentableEdge->Set(myCurrentEdge); myInteractiveContext->Redisplay(myPresentableEdge); if (myCurrentStatus == SEGMENT || myCurrentStatus == ARC_CHORD ) { /* Length dimension */ TopoDS_Vertex V1 = TopExp::FirstVertex(TopoDS::Edge(myCurrentEdge)); TopoDS_Vertex V2 = TopExp::LastVertex(TopoDS::Edge(myCurrentEdge)); DisplayLengthDimension(V1,V2); /* Angular dimension */ DisplayAngleDimension(); DisplayXDimension(V1,V2); DisplayYDimension(V1,V2); } else if (myCurrentStatus == ARC_CHORD_END ) DisplayRadiusDimension(); else { TopoDS_Vertex V1 = TopoDS::Vertex(myCurrentEdge); TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.)); DisplayXDimension(V1,V2); DisplayYDimension(V1,V2); } } /*! Display the current length dimension. \param V1 \param V2 */ void Sketch::DisplayLengthDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2) { gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1)); gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2)); Standard_Real length = p1.Distance(p2); if (length <= Precision::Confusion()) return; myLengthDimension->SetFirstShape(V1); myLengthDimension->SetSecondShape(V2); fitInResol(length); myLengthDimension->SetValue(length); QString S; S.sprintf("%.1f",length); myLengthDimension->SetText(TCollection_ExtendedString(strdup(S))); if (myIsLengthDimensionVisible) { if (myInteractiveContext->IsDisplayed(myLengthDimension)) myInteractiveContext->Redisplay(myLengthDimension); else myInteractiveContext->Display(myLengthDimension); } } /*! Display the current X dimension. \param V1 \param V2 */ void Sketch::DisplayXDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2) { if (myTransitionStatus != X_FIXED) { gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1)); gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2)); gp_Lin aline(p1,myPlane->Pln().XAxis().Direction()); GeomAPI_ProjectPointOnCurve proj(p2,new Geom_Line(aline)); gp_Pnt pb = p1; if (proj.NbPoints() > 0) { Standard_Real length = p1.Distance(proj.Point(1)); if (length <= Precision::Confusion()) return; myXDimension->SetFirstShape(V1); myXDimension->SetSecondShape(V2); fitInResol(length); myXDimension->SetValue(length); QString S; S.sprintf("%.1f",length); myXDimension->SetText(TCollection_ExtendedString(strdup(S))); // myXDimension->SetPosition(proj.Point(1)); pb.BaryCenter(5,proj.Point(1),5); myXDimension->SetPosition(pb); if (myIsXDimensionVisible) { if (myInteractiveContext->IsDisplayed(myXDimension)) myInteractiveContext->Redisplay(myXDimension); else myInteractiveContext->Display(myXDimension); } } } else myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False); } /*! Display the current Y dimension. \param V1 \param V2 */ void Sketch::DisplayYDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2) { if (myTransitionStatus != Y_FIXED) { gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1)); gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2)); gp_Lin aline(p2 /*p1*/, myPlane->Pln().YAxis().Direction()); gp_Pnt pb = p2 /*p1*/; GeomAPI_ProjectPointOnCurve proj(p1 /*p2*/,new Geom_Line(aline)); if (proj.NbPoints() > 0) { Standard_Real length = /*p1*/ p2.Distance(proj.Point(1)); if (length <= Precision::Confusion()) return; myYDimension->SetFirstShape(V1); myYDimension->SetSecondShape(V2); fitInResol(length); myYDimension->SetValue(length); QString S; S.sprintf("%.1f",length); myYDimension->SetText(TCollection_ExtendedString(strdup(S))); pb.BaryCenter(5,proj.Point(1),5); myYDimension->SetPosition(pb); // myYDimension->SetPosition(p2); if (myIsYDimensionVisible) { if (myInteractiveContext->IsDisplayed(myYDimension)) myInteractiveContext->Redisplay(myYDimension); else myInteractiveContext->Display(myYDimension); } } } else myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False); } /*! Display the current angle dimension. */ void Sketch::DisplayAngleDimension() { if (!myIsAngleDimensionVisible) return; if (myEdgesNumber > 0) { Standard_Real First,Last; TopLoc_Location L; Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last); Handle (Geom2d_Curve) CurrentCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,First,Last); if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line)) && CurrentCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) { Standard_Real angle = Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d().Angle(Handle(Geom2d_Line)::DownCast(CurrentCurve)->Lin2d()); gp_Pnt2d apos; if (0 <= angle && angle<= PI) angle = PI - angle; else angle = PI + angle; CurrentCurve->D0((First+Last)/5.,apos); gp_Pnt apos3d = ElCLib::To3d(myPlane->Pln().Position().Ax2(),apos); Standard_Real angtext = angle*180./PI; mySegmentAngle = angle; BRepLib::BuildCurve3d(TopoDS::Edge(myCurrentEdge)); fitInResol(angtext); QString S; S.sprintf("%.1f",angtext); if (myInteractiveContext->IndexOfCurrentLocal() == 0) { myInteractiveContext->OpenLocalContext(); myAngleDimension = new AIS_AngleDimension(myPreviousEdge,TopoDS::Edge(myCurrentEdge),myPlane,angle, TCollection_ExtendedString(strdup(S))); myInteractiveContext->Display(myAngleDimension); } else { myAngleDimension->SetSecondShape(myCurrentEdge); myAngleDimension->SetValue(angle); myAngleDimension->SetPosition(apos3d); myAngleDimension->SetText(TCollection_ExtendedString(strdup(S))); myInteractiveContext->Redisplay(myAngleDimension); } } } } /*! Display the current radius dimension. */ void Sketch::DisplayRadiusDimension() { if (! myIsRadiusDimensionVisible) return; BRepLib::BuildCurve3d(TopoDS::Edge(myCurrentEdge)); Standard_Real First,Last; Handle (Geom_Circle) C = Handle (Geom_Circle)::DownCast(BRep_Tool::Curve(TopoDS::Edge(myCurrentEdge),First,Last)); if (!C.IsNull()) { Standard_Real R = C->Radius(); TopoDS_Shape V1 = BRepBuilderAPI_MakeVertex(C->Location()); gp_Pnt MidlePoint ; C->D0((First+Last)/2.,MidlePoint); TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(MidlePoint); myRadiusDimension->SetFirstShape(V1); myRadiusDimension->SetSecondShape(V2); myRadiusDimension->SetValue(R); fitInResol(R); QString S; S.sprintf("%.1f",R); myRadiusDimension->SetText(TCollection_ExtendedString(strdup(S))); if (myInteractiveContext->IsDisplayed(myRadiusDimension)) myInteractiveContext->Redisplay(myRadiusDimension); else myInteractiveContext->Display(myRadiusDimension); myCenterCircle->Set(V1); if (myInteractiveContext->IsDisplayed(myCenterCircle)) myInteractiveContext->Redisplay(myCenterCircle); else myInteractiveContext->Display(myCenterCircle); } } /*! Remove last edge from the current wire. */ void Sketch::RemoveLastEdge() { if (myEdgesNumber == 0) { myCurrentStatus = END_SKETCH; myInteractiveContext->CloseAllContexts(); myInteractiveContext->EraseAll(Standard_False); return; } else { BRepTools_WireExplorer Ex; BRepBuilderAPI_MakeWire MW; Standard_Integer index = 1; myCurrentEdge = myPreviousEdge; for (Ex.Init(myCurrentWire.Wire());Ex.More();Ex.Next()){ if (index <= myEdgesNumber-1) { MW.Add(Ex.Current()); myPreviousEdge = Ex.Current(); index++; } } myCurrentWire = MW; myCurrentStatus = (SketchStatus)myConstructionMode(myEdgesNumber); myTransitionStatus = (TransitionStatus)myConstraintMode(myEdgesNumber); myEdgesNumber--; myConstructionMode.Remove(index); myConstraintMode.Remove(index); if (myEdgesNumber == 0) myPresentableWire->Set(myFirstPointSketch); else myPresentableWire->Set(myCurrentWire.Wire()); myInteractiveContext->Redisplay(myPresentableWire); myInteractiveContext->CloseLocalContext(); myPresentableEdge->Set(myCurrentEdge); myInteractiveContext->Redisplay(myPresentableEdge); } } /*! Create initial constraints. */ void Sketch::CreateConstraints() { Handle(Geom_Axis1Placement) xAxis = new Geom_Axis1Placement(myPlane->Pln().XAxis()); Handle(Geom_Axis1Placement) yAxis = new Geom_Axis1Placement(myPlane->Pln().YAxis()); myHAxis = new AIS_Axis(xAxis); myVAxis = new AIS_Axis(yAxis); myAngularAxis = myVAxis; myHAxis->SetColor(myAxisColor.Name()); myVAxis->SetColor(myAxisColor.Name()); myAngularAxis->SetColor(myAxisColor.Name()); } /*! fitInResol. \param toFit \param minIsResol */ void Sketch::fitInResol(Standard_Real &toFit, Standard_Boolean minIsResol) { Standard_Real sign = (toFit < 0) ? -1. : +1.; Standard_Real value = toFit + sign * resol/2.0; /* why "+ resol/2.0" ? because if resol = 0.5, 3.3 is rounded to 3.5 */ int nTimesResol = int(value/resol); if ((nTimesResol == 0) && (minIsResol)) nTimesResol = 1; toFit = nTimesResol*resol; } SketchStatus Sketch::GetCurrentStatus() { return myCurrentStatus; } Standard_Integer Sketch::GetmyEdgesNumber() { return myEdgesNumber; }