X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=blobdiff_plain;f=src%2FAIS%2FAIS_AngleDimension.cxx;h=48b182a3194d4371717d895e86cb19e07a7c1e35;hp=e9432be35fc827a12324774900162c44b8a393eb;hb=d5f74e42d6160fc451ef4e464a93a0de9b384adc;hpb=d7bffd44eacc919e14267de0e5db68deab50365d diff --git a/src/AIS/AIS_AngleDimension.cxx b/src/AIS/AIS_AngleDimension.cxx old mode 100755 new mode 100644 index e9432be35f..48b182a319 --- a/src/AIS/AIS_AngleDimension.cxx +++ b/src/AIS/AIS_AngleDimension.cxx @@ -1,22 +1,18 @@ // Created on: 1996-12-05 // Created by: Arnaud BOUZY/Odile Olivier // Copyright (c) 1996-1999 Matra Datavision -// Copyright (c) 1999-2012 OPEN CASCADE SAS +// Copyright (c) 1999-2014 OPEN CASCADE SAS // -// The content of this file is subject to the Open CASCADE Technology Public -// License Version 6.5 (the "License"). You may not use the content of this file -// except in compliance with the License. Please obtain a copy of the License -// at http://www.opencascade.org and read it completely before using this file. +// This file is part of Open CASCADE Technology software library. // -// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its -// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. // -// The Original Code and all software distributed under the License is -// distributed on an "AS IS" basis, without warranty of any kind, and the -// Initial Developer hereby disclaims all such warranties, including without -// limitation, any warranties of merchantability, fitness for a particular -// purpose or non-infringement. Please see the License for the specific terms -// and conditions governing the rights and limitations under the License. +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. #include @@ -25,10 +21,19 @@ #include #include #include +#include +#include #include +#include +#include #include +#include +#include #include +#include +#include #include +#include #include #include #include @@ -36,16 +41,14 @@ #include #include #include -#include -#include #include #include #include #include -#include #include #include #include +#include #include IMPLEMENT_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension) @@ -53,643 +56,535 @@ IMPLEMENT_STANDARD_RTTIEXT (AIS_AngleDimension, AIS_Dimension) namespace { - static const TCollection_ExtendedString THE_EMPTY_LABEL; - static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0); + static const TCollection_ExtendedString THE_EMPTY_LABEL_STRING; + static const Standard_Real THE_EMPTY_LABEL_WIDTH = 0.0; + static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0); + static const Standard_Real THE_3D_TEXT_MARGIN = 0.1; }; -//======================================================================= -//function : init -//purpose : Private constructor for default initialization -//======================================================================= -void AIS_AngleDimension::init() -{ - // Default values of units - UnitsAPI::SetLocalSystem (UnitsAPI_SI); - SetUnitsQuantity ("PLANE ANGLE"); - SetModelUnits ("rad"); - SetDisplayUnits ("deg"); - SetSpecialSymbol (THE_DEGREE_SYMBOL); - SetDisplaySpecialSymbol (AIS_DSS_After); - SetFlyout (15.0); - SetKindOfDimension (AIS_KOD_PLANEANGLE); - MakeUnitsDisplayed (Standard_False); -} - //======================================================================= //function : Constructor -//purpose : Two edges dimension +//purpose : //======================================================================= AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge, const TopoDS_Edge& theSecondEdge) -: AIS_Dimension(), - myIsFlyoutLines (Standard_True) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - init(); - myShapesNumber = 2; - myFirstShape = theFirstEdge; - mySecondShape = theSecondEdge; + Init(); + SetMeasuredGeometry (theFirstEdge, theSecondEdge); } //======================================================================= //function : Constructor -//purpose : Two edges dimension -// is used in case of Angle=PI +//purpose : //======================================================================= -AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge, - const TopoDS_Edge& theSecondEdge, - const gp_Pln& thePlane) -: AIS_Dimension(), - myIsFlyoutLines (Standard_True) +AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThirdPoint) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - init(); - myShapesNumber = 2; - myFirstShape = theFirstEdge; - mySecondShape = theSecondEdge; - SetWorkingPlane (thePlane); + Init(); + SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint); } //======================================================================= //function : Constructor -//purpose : Three points dimension +//purpose : //======================================================================= -AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint, - const gp_Pnt& theSecondPoint, - const gp_Pnt& theThirdPoint) -: AIS_Dimension(), - myIsFlyoutLines (Standard_True) +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex, + const TopoDS_Vertex& theSecondVertex, + const TopoDS_Vertex& theThirdVertex) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - init(); - myIsInitialized = Standard_True; - myFirstPoint = theFirstPoint; - myCenter = theSecondPoint; - mySecondPoint = theThirdPoint; - myShapesNumber = 3; + Init(); + SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex); } //======================================================================= //function : Constructor -//purpose : Cone dimension +//purpose : //======================================================================= AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone) -: AIS_Dimension(), - myIsFlyoutLines (Standard_True) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - init(); - myIsInitialized = Standard_False; - myFirstShape = theCone; - myShapesNumber = 1; + Init(); + SetMeasuredGeometry (theCone); } //======================================================================= //function : Constructor -//purpose : Two faces dimension +//purpose : //======================================================================= AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace, - const TopoDS_Face& theSecondFace, - const gp_Ax1& theAxis) -: AIS_Dimension(), - myIsFlyoutLines (Standard_True) + const TopoDS_Face& theSecondFace) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - init(); - myIsInitialized = Standard_False; - myFirstShape = theFirstFace; - mySecondShape = theSecondFace; - myShapesNumber = 2; - gp_Pln aPlane; - aPlane.SetAxis (theAxis); - SetWorkingPlane (aPlane); + Init(); + SetMeasuredGeometry (theFirstFace, theSecondFace); } //======================================================================= -//function : SetFirstShape +//function : Constructor //purpose : //======================================================================= -void AIS_AngleDimension::SetFirstShape (const TopoDS_Shape& theShape, - const Standard_Boolean isSingleShape /*= Standard_False*/) +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint) +: AIS_Dimension (AIS_KOD_PLANEANGLE) { - AIS_Dimension::SetFirstShape (theShape); - if (isSingleShape) - myShapesNumber = 1; + Init(); + SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint); } //======================================================================= -//function : aboveInBelowCone -//purpose : Returns 1 if center is above of center; -// 0 if center is between and -// centers; -// -1 if center is below center. +//function : SetMeasuredGeometry +//purpose : //======================================================================= -Standard_Integer AIS_AngleDimension::aboveInBelowCone (const gp_Circ &theCMax, - const gp_Circ &theCMin, - const gp_Circ &theC) +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge, + const TopoDS_Edge& theSecondEdge) { - const Standard_Real aD = theCMax.Location().Distance (theCMin.Location()); - const Standard_Real aD1 = theCMax.Location().Distance (theC.Location()); - const Standard_Real aD2 = theCMin.Location().Distance (theC.Location()); + gp_Pln aComputedPlane; + + myFirstShape = theFirstEdge; + mySecondShape = theSecondEdge; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Edges; + myIsValid = InitTwoEdgesAngle (aComputedPlane); + + if (myIsValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + myIsValid &= CheckPlane (myPlane); - if (aD >= aD1 && aD >= aD2) return 0; - if (aD < aD2 && aD1 < aD2) return -1; - if (aD < aD1 && aD2 < aD1) return 1; - return 0; + SetToUpdate(); } //======================================================================= -//function : initConeAngle -//purpose : initialization of the cone angle +//function : SetMeasuredGeometry +//purpose : //======================================================================= -Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone) +void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThirdPoint) { - if (theCone.IsNull ()) - return Standard_False; - - gp_Pln aPln; - gp_Cone aCone; - gp_Circ aCircle; - // A surface from the Face - Handle(Geom_Surface) aSurf; - Handle(Geom_OffsetSurface) aOffsetSurf; - Handle(Geom_ConicalSurface) aConicalSurf; - Handle(Geom_SurfaceOfRevolution) aRevSurf; - Handle(Geom_Line) aLine; - BRepAdaptor_Surface aConeAdaptor (theCone); - TopoDS_Face aFace; - AIS_KindOfSurface aSurfType; - Standard_Real anOffset = 0.; - Handle(Standard_Type) aType; - - Standard_Real aMaxV = aConeAdaptor.FirstVParameter(); - Standard_Real aMinV = aConeAdaptor.LastVParameter(); - - AIS::GetPlaneFromFace(theCone, aPln, aSurf, aSurfType, anOffset); + myFirstPoint = theFirstPoint; + myCenterPoint = theSecondPoint; + mySecondPoint = theThirdPoint; + myFirstShape = BRepLib_MakeVertex (myFirstPoint); + mySecondShape = BRepLib_MakeVertex (myCenterPoint); + myThirdShape = BRepLib_MakeVertex (mySecondPoint); + myGeometryType = GeometryType_Points; + myIsValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); - if (aSurfType == AIS_KOS_Revolution) + if (myIsValid && !myIsPlaneCustom) { - // Surface of revolution - aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf); - gp_Lin aLin (aRevSurf->Axis()); - Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve(); - //Must be a part of line (basis curve should be linear) - if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line)) - return Standard_False; - - gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV); - gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV); - gp_Vec aVec1 (aFirst1, aLast1); - - //Projection on - gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin); - // Projection on - gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin); + ComputePlane(); + } - gp_Vec aVec2 (aFirst2, aLast2); + myIsValid &= CheckPlane (myPlane); - // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle). - if (aVec1.IsParallel (aVec2, Precision::Angular()) - || aVec1.IsNormal (aVec2,Precision::Angular())) - return Standard_False; + SetToUpdate(); +} - gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1); - aCone = aMkCone.Value(); - myCenter = aCone.Apex(); - } - else +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex, + const TopoDS_Vertex& theSecondVertex, + const TopoDS_Vertex& theThirdVertex) +{ + myFirstShape = theFirstVertex; + mySecondShape = theSecondVertex; + myThirdShape = theThirdVertex; + myFirstPoint = BRep_Tool::Pnt (theFirstVertex); + myCenterPoint = BRep_Tool::Pnt (theSecondVertex); + mySecondPoint = BRep_Tool::Pnt (theThirdVertex); + myGeometryType = GeometryType_Points; + myIsValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); + + if (myIsValid && !myIsPlaneCustom) { - aType = aSurf->DynamicType(); - if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01) - { - // Offset surface - aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset); - aSurf = aOffsetSurf->Surface(); - BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion()); - aMkFace.Build(); - if (!aMkFace.IsDone()) - return Standard_False; - aConeAdaptor.Initialize (aMkFace.Face()); - } - aCone = aConeAdaptor.Cone(); - aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf); - myCenter = aConicalSurf->Apex(); + ComputePlane(); } - // A circle where the angle is drawn - Handle(Geom_Curve) aCurve; - Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5; - aCurve = aSurf->VIso (aMidV); - aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ(); + myIsValid &= CheckPlane (myPlane); - aCurve = aSurf->VIso(aMaxV); - gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ(); - aCurve = aSurf->VIso(aMinV); - gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ(); + SetToUpdate(); +} +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone) +{ + myFirstShape = theCone; + mySecondShape = TopoDS_Shape(); + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Face; + myIsValid = InitConeAngle(); - if (aCircVmax.Radius() < aCircVmin.Radius()) + if (myIsValid && !myIsPlaneCustom) { - gp_Circ aTmpCirc = aCircVmax; - aCircVmax = aCircVmin; - aCircVmin = aTmpCirc; + ComputePlane(); } - myFirstPoint = ElCLib::Value (0, aCircle); - mySecondPoint = ElCLib::Value (M_PI, aCircle); - return Standard_True; + myIsValid &= CheckPlane (myPlane); + + SetToUpdate(); } //======================================================================= -//function : initTwoFacesAngle -//purpose : initialization of angle dimension between two faces +//function : SetMeasuredGeometry +//purpose : //======================================================================= -Standard_Boolean AIS_AngleDimension::initTwoFacesAngle () +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace) { - TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape); - TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape); - gp_Dir aFirstDir, aSecondDir; - gp_Pln aFirstPlane, aSecondPlane; - Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf; - AIS_KindOfSurface aFirstSurfType, aSecondSurfType; - Standard_Real aFirstOffset, aSecondOffset; - - AIS::GetPlaneFromFace (aFirstFace, aFirstPlane, - aFirstBasisSurf,aFirstSurfType,aFirstOffset); - AIS::GetPlaneFromFace (aSecondFace, aSecondPlane, - aSecondBasisSurf, aSecondSurfType, aSecondOffset); + myFirstShape = theFirstFace; + mySecondShape = theSecondFace; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Faces; + myIsValid = InitTwoFacesAngle(); - if (aFirstSurfType == AIS_KOS_Plane) - { - //Planar faces angle - AIS::ComputeAngleBetweenPlanarFaces (aFirstFace, - aSecondFace, - aSecondBasisSurf, - GetWorkingPlane().Axis(), - myValue, - Standard_True, - myGeom.myTextPosition, - myCenter, - myFirstPoint, - mySecondPoint, - aFirstDir, - aSecondDir); - } - else + if (myIsValid && !myIsPlaneCustom) { - // Curvilinear faces angle - Handle(Geom_Plane) aPlane = new Geom_Plane (GetWorkingPlane()); - AIS::ComputeAngleBetweenCurvilinearFaces (aFirstFace, - aSecondFace, - aFirstBasisSurf, - aSecondBasisSurf, - aFirstSurfType, - aSecondSurfType, - GetWorkingPlane().Axis(), - myValue, - Standard_True, - myGeom.myTextPosition, - myCenter, - myFirstPoint, - mySecondPoint, - aFirstDir, - aSecondDir, - aPlane); - SetWorkingPlane (aPlane->Pln()); + ComputePlane(); } - return Standard_True; + + myIsValid &= CheckPlane (myPlane); + + SetToUpdate(); } //======================================================================= -//function : countDefaultPlane +//function : SetMeasuredGeometry //purpose : //======================================================================= -void AIS_AngleDimension::countDefaultPlane () +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint) { - if (!myIsInitialized) - return; - // Compute normal of the default plane. - gp_Vec aVec1(myCenter, myFirstPoint), - aVec2(myCenter, mySecondPoint); - myDefaultPlane = gp_Pln(myCenter, aVec1^aVec2); - // Set computed value to - ResetWorkingPlane (); + myFirstShape = theFirstFace; + mySecondShape = theSecondFace; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Faces; + myIsValid = InitTwoFacesAngle (thePoint); + + if (myIsValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + myIsValid &= CheckPlane (myPlane); + + SetToUpdate(); } //======================================================================= -//function : computeValue +//function : Init //purpose : //======================================================================= -void AIS_AngleDimension::computeValue () +void AIS_AngleDimension::Init() { - gp_Vec aVec1 (myCenter, myFirstPoint), - aVec2 (myCenter, mySecondPoint); - myValue = aVec1.Angle (aVec2); - // To model units - AIS_Dimension::computeValue(); + SetSpecialSymbol (THE_DEGREE_SYMBOL); + SetDisplaySpecialSymbol (AIS_DSS_After); + SetFlyout (15.0); } //======================================================================= -//function : initTwoEdgesAngle -//purpose : Fill gp_Pnt fields for further presentation computation -// If intersection between two edges doesn't exist -// is set to false +//function: GetCenterOnArc +//purpose : //======================================================================= -Standard_Boolean AIS_AngleDimension::initTwoEdgesAngle () +gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach, + const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter) const { - // Data initialization - TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape); - TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape); - BRepAdaptor_Curve aMakeFirstLine (aFirstEdge); - BRepAdaptor_Curve aMakeSecondLine (aSecondEdge); - - if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line) + // construct plane where the circle and the arc are located + gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); + if (!aConstructPlane.IsDone()) { - return Standard_False; + return gp::Origin(); } + + gp_Pln aPlane = aConstructPlane.Value(); - Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line()); - Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line()); + Standard_Real aRadius = theFirstAttach.Distance (theCenter); - gp_Lin aFirstLin = aFirstLine->Lin (); - gp_Lin aSecondLin = aSecondLine->Lin (); - gp_Lin2d aFirstLin2d, aSecondLin2d; - Standard_Boolean isParallelLines = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular()); - Standard_Boolean isSameLines = isParallelLines && aFirstLin.Distance (aSecondLin.Location()) <= Precision::Confusion(); - // In case where we can't compute plane automatically - if ((isParallelLines || isSameLines) && !myIsWorkingPlaneCustom) + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius); + if (!aConstructCircle.IsDone()) { - return Standard_False; + return gp::Origin(); } - gp_Pln aPlane; + gp_Circ aCircle = aConstructCircle.Value(); + + // compute angle parameters of arc end-points on circle + Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach); + Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach); + ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd); + + return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle); +} - /// PART 1 is for automatic plane computation from two edges if it is possible - // Build plane - if (!myIsWorkingPlaneCustom) +//======================================================================= +//function : DrawArc +//purpose : draws the arc between two attach points +//======================================================================= +void AIS_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation, + const gp_Pnt& theFirstAttach, + const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter, + const Standard_Real theRadius, + const Standard_Integer theMode) +{ + // construct plane where the circle and the arc are located + gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); + if (!aConstructPlane.IsDone()) { - gp_Pnt aPoint = aFirstLine->Value (0.); - gp_Dir aNormal = isParallelLines - ? gp_Vec(aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction()) - : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()); - aPlane = gp_Pln (aPoint, aNormal); - resetWorkingPlane (aPlane); + return; } - else + + gp_Pln aPlane = aConstructPlane.Value(); + + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius); + if (!aConstructCircle.IsDone()) { - aPlane = GetWorkingPlane(); + return; } - // Compute geometry for this plane and edges - Standard_Boolean isInfinite1,isInfinite2; - gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2; - Standard_Integer anExtIndex = -1; - Handle(Geom_Curve) anExtCurve; - Handle(Geom_Plane) aGeomPlane = new Geom_Plane (aPlane); - if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge, - anExtIndex, - aFirstLine, aSecondLine, - aFirstPoint1, aLastPoint1, - aFirstPoint2, aLastPoint2, - anExtCurve, - isInfinite1, isInfinite2, - aGeomPlane)) + gp_Circ aCircle = aConstructCircle.Value(); + + // construct the arc + GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True); + if (!aConstructArc.IsDone()) { - return Standard_False; + return; } - // Check if both edges are on this plane - if (!anExtCurve.IsNull()) - { - if (anExtIndex == 1) // First curve is out of the plane - { - // Project curve on the plane - if (myIsWorkingPlaneCustom) - { - aFirstLin2d = ProjLib::Project (aPlane, aFirstLin); - aFirstLin = ElCLib::To3d (aPlane.Position().Ax2(), aFirstLin2d); - } - else - { - aFirstLin.Translate (gp_Vec (aFirstLin.Location(), aSecondLin.Location())); - } + // generate points with specified deflection + const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value(); + + GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter()); - aFirstLine = new Geom_Line (aFirstLin); - } - else if (anExtIndex == 2) // Second curve is out of the plane - { - if (myIsWorkingPlaneCustom) - { - aSecondLin2d = ProjLib::Project (aPlane, aSecondLin); - aSecondLin = ElCLib::To3d (aPlane.Position().Ax2(), aSecondLin2d); - } - else - { - aSecondLin.Translate (gp_Vec (aSecondLin.Location(), aFirstLin.Location())); - } + // compute number of discretization elements in old-fanshioned way + gp_Vec aCenterToFirstVec (theCenter, theFirstAttach); + gp_Vec aCenterToSecondVec (theCenter, theSecondAttach); + const Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec); + const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI)); - aSecondLine = new Geom_Line (aSecondLin); - } + GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints); + if (!aMakePnts.IsDone()) + { + return; } - /// PART 2 is for dimension computation using the working plane + // init data arrays for graphical and selection primitives + Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints); - if (aFirstLin.Direction ().IsParallel (aSecondLin.Direction (), Precision::Angular ())) - { - // Parallel lines - isSameLines = aFirstLin.Distance(aSecondLin.Location()) <= Precision::Confusion(); - if (!isSameLines) - return Standard_False; + SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve(); - myFirstPoint = aFirstLin.Location(); - mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin); - if (mySecondPoint.Distance (mySecondPoint) <= Precision::Confusion ()) - mySecondPoint.Translate (gp_Vec (aSecondLin.Direction ())*Abs(GetFlyout())); - myCenter.SetXYZ( (myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2. ); - } - else + // load data into arrays + for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt) { - // Find intersection - aFirstLin2d = ProjLib::Project (aPlane, aFirstLin); - aSecondLin2d = ProjLib::Project (aPlane, aSecondLin); - - IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d); - gp_Pnt2d anIntersectPoint; - if (!anInt2d.IsDone() || anInt2d.IsEmpty()) - { - return Standard_False; - } + gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt)); - anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value()); - myCenter = ElCLib::To3d(aPlane.Position().Ax2(), anIntersectPoint); - - if (isInfinite1 || isInfinite2) - { - myFirstPoint = myCenter.Translated (gp_Vec (aFirstLin.Direction())*Abs (GetFlyout())); - mySecondPoint = myCenter.Translated (gp_Vec (aSecondLin.Direction())*Abs (GetFlyout())); - return Standard_True; - } + aPrimSegments->AddVertex (aPnt); - // | - // | <- dimension should be here - // *---- - myFirstPoint = myCenter.Distance (aFirstPoint1) > myCenter.Distance (aLastPoint1) ? aFirstPoint1 : aLastPoint1; - mySecondPoint = myCenter.Distance (aFirstPoint2) > myCenter.Distance (aLastPoint2) ? aFirstPoint2 : aLastPoint2; + aSensitiveCurve.Append (aPnt); } - return Standard_True; -} - -//======================================================================= -//function: getCenterOnArc -//purpose : -//======================================================================= -gp_Pnt AIS_AngleDimension::getCenterOnArc (const gp_Pnt& theFirstAttach, - const gp_Pnt& theSecondAttach) -{ - gp_Pnt2d aCenter2d = ProjLib::Project (GetWorkingPlane(), myCenter), - aFirstAttach2d = ProjLib::Project (GetWorkingPlane(), theFirstAttach), - aSecondAttach2d = ProjLib::Project (GetWorkingPlane(), theSecondAttach); - gp_Lin2d anAttachLine2d = gce_MakeLin2d (aFirstAttach2d, aSecondAttach2d); - - // Getting text center - gp_Pnt2d aTextCenterPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) + ElCLib::Parameter (anAttachLine2d, aSecondAttach2d)) / 2., anAttachLine2d); - gp_Lin2d aCenterToTextCenterLin = gce_MakeLin2d (aCenter2d, aTextCenterPnt); - // Drawing circle - Standard_Real aRadius = theFirstAttach.Distance (myCenter); - gp_Circ2d aCircle (gp_Ax22d (aCenter2d, gp_Dir2d (1, 0)), aRadius); - - // Getting text position in the center of arc - IntAna2d_AnaIntersection anInt2d (aCenterToTextCenterLin, aCircle); - gp_Pnt2d aTextCenterOnArc2d; - if (anInt2d.IsDone()) - if (!anInt2d.IsEmpty()) - aTextCenterOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value()); - gp_Pnt aCenterOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextCenterOnArc2d); - return aCenterOnArc; + // add display presentation + if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All) + { + Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True); + } + Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect(); + Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionLineStyle); + Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments); + if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All) + { + Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False); + } } //======================================================================= -//function: drawArcWithText +//function: DrawArcWithText //purpose : //======================================================================= -void AIS_AngleDimension::drawArcWithText (const Handle(Prs3d_Presentation)& thePresentation, +void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation, const gp_Pnt& theFirstAttach, const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter, const TCollection_ExtendedString& theText, - const AIS_DimensionDisplayMode theMode, + const Standard_Real theTextWidth, + const Standard_Integer theMode, const Standard_Integer theLabelPosition) { - gp_Pnt2d aCenter2d = ProjLib::Project (GetWorkingPlane(), myCenter), - aFirstAttach2d = ProjLib::Project (GetWorkingPlane(), theFirstAttach), - aSecondAttach2d = ProjLib::Project (GetWorkingPlane(), theSecondAttach); - gp_Lin2d anAttachLine2d = gce_MakeLin2d (aFirstAttach2d, aSecondAttach2d); - - // Getting text center - gp_Pnt2d aTextCenterPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) + ElCLib::Parameter (anAttachLine2d, aSecondAttach2d)) / 2., anAttachLine2d); - gp_Lin2d aCenterToTextCenterLin = gce_MakeLin2d (aCenter2d, aTextCenterPnt); - - // Drawing circle - Standard_Real aRadius = theFirstAttach.Distance (myCenter); - gp_Circ2d aCircle (gp_Ax22d (aCenter2d, gp_Dir2d (1, 0)), aRadius); + // construct plane where the circle and the arc are located + gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); + if (!aConstructPlane.IsDone()) + { + return; + } + + gp_Pln aPlane = aConstructPlane.Value(); - // Getting text position in the center of arc - IntAna2d_AnaIntersection anInt2d (aCenterToTextCenterLin, aCircle); - gp_Pnt2d aTextCenterOnArc2d; - if (anInt2d.IsDone()) - if (!anInt2d.IsEmpty()) - aTextCenterOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value()); - myGeom.myTextPosition = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextCenterOnArc2d); + Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint); + + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius); + if (!aConstructCircle.IsDone()) + { + return; + } - // Drawing text - gp_Vec aVec (theFirstAttach, theSecondAttach); - Standard_Real aTextWidth = drawText (thePresentation, - myIsTextReversed ? aVec.Reversed() : aVec, - theText, theMode, - theLabelPosition); + gp_Circ aCircle = aConstructCircle.Value(); - // Getting text begin and end points - gp_Pnt2d aTextBeginPnt = ElCLib::Value ((ElCLib::Parameter (anAttachLine2d, aFirstAttach2d) + - ElCLib::Parameter (anAttachLine2d, aSecondAttach2d) - - aTextWidth) / 2., anAttachLine2d), - aTextEndPnt = ElCLib::Value (ElCLib::Parameter (anAttachLine2d,aTextBeginPnt) + aTextWidth, anAttachLine2d); + // compute angle parameters of arc end-points on circle + Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach); + Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach); + ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd); + // middle point of arc parameter on circle + Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5; - gp_Lin2d aCenterToTextBeginLin = gce_MakeLin2d (aCenter2d, aTextBeginPnt), - aCenterToTextEndLin = gce_MakeLin2d (aCenter2d, aTextEndPnt); + // add text graphical primitives + if (theMode == ComputeMode_All || theMode == ComputeMode_Text) + { + gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle); + gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach); + + // Drawing text + DrawText (thePresentation, + aTextPos, + aTextDir, + theText, + theLabelPosition); + } - // Text begin and end on the dimension arc - gp_Pnt2d aTextBeginOnArc2d, aTextEndOnArc2d; - anInt2d.Perform (aCenterToTextBeginLin, aCircle); - if (anInt2d.IsDone()) - if (!anInt2d.IsEmpty()) - aTextBeginOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value()); + if (theMode != ComputeMode_All && theMode != ComputeMode_Line) + { + return; + } - anInt2d.Perform (aCenterToTextEndLin, aCircle); - if (anInt2d.IsDone()) - if (!anInt2d.IsEmpty()) - aTextEndOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value()); + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); - gp_Pnt aTextBeginOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextBeginOnArc2d); - gp_Pnt aTextEndOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextEndOnArc2d); + Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center + && aDimensionAspect->IsText3d(); - // Drawing arcs - if (theMode != AIS_DDM_Text) + if (isLineBreak) { - drawArc (thePresentation, theFirstAttach, aTextBeginOnArc, myCenter, aRadius, theMode); - drawArc (thePresentation, aTextEndOnArc, theSecondAttach, myCenter, aRadius, theMode); + // compute gap for label as parameteric size of sector on circle segment + Standard_Real aSectorOnCircle = theTextWidth / aRadius; + + gp_Pnt aTextPntBeg = ElCLib::Value (aParamMid - aSectorOnCircle * 0.5, aCircle); + gp_Pnt aTextPntEnd = ElCLib::Value (aParamMid + aSectorOnCircle * 0.5, aCircle); + + // Drawing arcs + DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode); + DrawArc (thePresentation, theSecondAttach, aTextPntEnd, theCenter, aRadius, theMode); + } + else + { + DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode); } } //======================================================================= -//function : drawArc -//purpose : draws the arc between two attach points +//function : CheckPlane +//purpose : //======================================================================= -void AIS_AngleDimension::drawArc (const Handle(Prs3d_Presentation)& thePresentation, - const gp_Pnt& theFirstAttach, - const gp_Pnt& theSecondAttach, - const gp_Pnt& theCenter, - const Standard_Real theRadius, - const AIS_DimensionDisplayMode theMode) +Standard_Boolean AIS_AngleDimension::CheckPlane (const gp_Pln& thePlane)const { - Handle(SelectMgr_EntityOwner) anEmptyOwner; - - gp_Vec aCenterToFirstVec (theCenter,theFirstAttach); - gp_Vec aCenterToSecondVec (theCenter,theSecondAttach); - gp_Dir aCenterToFirstDir (aCenterToFirstVec); - gp_Dir aPlaneNormal = GetWorkingPlane().Axis().Direction(); - gp_Dir aCenterToSecondDir = aPlaneNormal.Crossed (aCenterToFirstDir); - - const Standard_Real anAngle = aCenterToFirstVec.Angle(aCenterToSecondVec); - const Standard_Integer aPointsOnArc = Max (4 , Standard_Integer (50. * anAngle / M_PI)); - const Standard_Real anAngleStep = anAngle / (aPointsOnArc - 1); - TColgp_Array1OfPnt aPointArray (0,aPointsOnArc-1); - Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aPointsOnArc,2); - aPrimSegments->AddVertex (theFirstAttach); - aPointArray.SetValue(0, theFirstAttach); - gp_Pnt aPoint = theFirstAttach; - gp_Vec aVector; - - for (Standard_Integer anI = 1; anI < aPointsOnArc - 1; ++anI) + if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) && + !thePlane.Contains (mySecondPoint, Precision::Confusion()) && + !thePlane.Contains (myCenterPoint, Precision::Confusion())) { - aVector = (gp_Vec(aCenterToFirstDir) * Cos ( (anI - 1) * anAngleStep) + gp_Vec(aCenterToSecondDir) * Sin ( (anI - 1) * anAngleStep)) * theRadius; - aPoint = theCenter.Translated(aVector); - aPrimSegments->AddVertex(aPoint); - aPointArray.SetValue (anI,aPoint); + return Standard_False; } - aPrimSegments->AddVertex (theSecondAttach); - aPointArray.SetValue (aPointsOnArc - 1,theSecondAttach); - // Fill sensitive list - myGeom.mySensitiveSegments.Append(new Select3D_SensitiveCurve(anEmptyOwner,aPointArray)); + return Standard_True; +} - // Fill display presentation - if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All) +//======================================================================= +//function : ComputePlane +//purpose : +//======================================================================= +void AIS_AngleDimension::ComputePlane() +{ + if (!IsValid()) { - Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True); + return; } - Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect(); - Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionLineStyle); - Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments); - if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All) + + gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint).Normalized(); + gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint).Normalized(); + gp_Vec aDirectionN = aSecondVec.Crossed (aFirstVec).Normalized(); + gp_Vec aDirectionY = (aFirstVec + aSecondVec).Normalized(); + gp_Vec aDirectionX = aDirectionY.Crossed (aDirectionN).Normalized(); + + myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX))); +} + +//======================================================================= +//function : GetModelUnits +//purpose : +//======================================================================= +const TCollection_AsciiString& AIS_AngleDimension::GetModelUnits() const +{ + return myDrawer->DimAngleModelUnits(); +} + +//======================================================================= +//function : GetDisplayUnits +//purpose : +//======================================================================= +const TCollection_AsciiString& AIS_AngleDimension::GetDisplayUnits() const +{ + return myDrawer->DimAngleDisplayUnits(); +} + +//======================================================================= +//function : SetModelUnits +//purpose : +//======================================================================= +void AIS_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits) +{ + myDrawer->SetDimAngleModelUnits (theUnits); +} + +//======================================================================= +//function : SetDisplayUnits +//purpose : +//======================================================================= +void AIS_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits) +{ + myDrawer->SetDimAngleDisplayUnits (theUnits); +} + +//======================================================================= +//function : ComputeValue +//purpose : +//======================================================================= +Standard_Real AIS_AngleDimension::ComputeValue() const +{ + if (!IsValid()) { - Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False); + return 0.0; } + + gp_Vec aVec1 (myCenterPoint, myFirstPoint); + gp_Vec aVec2 (myCenterPoint, mySecondPoint); + + Standard_Real anAngle = aVec2.AngleWithRef (aVec1, GetPlane().Axis().Direction()); + + return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle); } //======================================================================= @@ -701,87 +596,53 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /* const Standard_Integer theMode) { thePresentation->Clear(); - myGeom.mySensitiveSegments.Clear(); - Handle(SelectMgr_EntityOwner) anEmptyOwner; + mySelectionGeom.Clear (theMode); - if (!myIsInitialized) + if (!IsValid()) { - if (myShapesNumber == 1) - { - myIsInitialized = initConeAngle (TopoDS::Face (myFirstShape)); - } - else if (myShapesNumber == 2) - { - switch (myFirstShape.ShapeType()) - { - case TopAbs_FACE: - { - myIsInitialized = initTwoFacesAngle (); - } - break; - case TopAbs_EDGE: - { - myIsInitialized = initTwoEdgesAngle (); - } - break; - default: - return; - } - } - else - return; - } - - // If initialization failed - if (!myIsInitialized) return; + } // Parameters for presentation Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); - Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect(aDimensionAspect->LineAspect()->Aspect()); + Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect()); Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length(); - if (!myIsValueCustom) + // prepare label string and compute its geometrical width + Standard_Real aLabelWidth; + TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth); + + // add margins to label width + if (aDimensionAspect->IsText3d()) { - computeValue(); + aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0; } - TCollection_ExtendedString aValueString; - Standard_Real aTextLength; - getTextWidthAndString (aTextLength, aValueString); + // Get parameters from aspect or adjust it according with custom text position + Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize(); + Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition(); - if (!myIsWorkingPlaneCustom) + if (IsTextPositionCustom()) { - countDefaultPlane(); + AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos); } - gp_Pnt aFirstAttach = myCenter.Translated (gp_Vec(myCenter, myFirstPoint).Normalized() * GetFlyout()); - gp_Pnt aSecondAttach = myCenter.Translated (gp_Vec(myCenter, mySecondPoint).Normalized() * GetFlyout()); - // Handle user-defined and automatic arrow placement - bool isArrowsExternal = false; - switch (aDimensionAspect->ArrowOrientation()) - { - case Prs3d_DAO_External: isArrowsExternal = true; break; - case Prs3d_DAO_Internal: isArrowsExternal = false; break; - case Prs3d_DAO_Fit: - { - gp_Vec anAttachVector (aFirstAttach, aSecondAttach); - Standard_Real aDimensionWidth = anAttachVector.Magnitude(); - Standard_Real anArrowsWidth = anArrowLength * 2.0; + Standard_Boolean isArrowsExternal = Standard_False; + Standard_Integer aLabelPosition = LabelPosition_None; - isArrowsExternal = aDimensionWidth < aTextLength + anArrowsWidth; - break; - } - } + FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal); + + gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout()); + gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout()); //Arrows positions and directions - gp_Vec aWPDir = gp_Vec (GetWorkingPlane().Axis().Direction()); + gp_Vec aWPDir = gp_Vec (GetPlane().Axis().Direction()); - gp_Dir aFirstExtensionDir = gp_Vec (myCenter, aFirstAttach) ^ aWPDir; - gp_Dir aSecondExtensionDir = gp_Vec (myCenter, aSecondAttach)^ aWPDir.Reversed(); + gp_Dir aFirstExtensionDir = aWPDir ^ gp_Vec (myCenterPoint, aFirstAttach); + gp_Dir aSecondExtensionDir = aWPDir.Reversed() ^ gp_Vec (myCenterPoint, aSecondAttach); gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength; gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength; @@ -802,38 +663,9 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /* aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec); aSecondArrowEnd = aSecondAttach.Translated (-aSecondArrowVec); - Standard_Integer aLabelPosition = LabelPosition_None; - - // Handle user-defined and automatic text placement - switch (aDimensionAspect->TextHorizontalPosition()) - { - case Prs3d_DTHP_Left : aLabelPosition |= LabelPosition_Left; break; - case Prs3d_DTHP_Right : aLabelPosition |= LabelPosition_Right; break; - case Prs3d_DTHP_Center: aLabelPosition |= LabelPosition_HCenter; break; - case Prs3d_DTHP_Fit: - { - gp_Vec anAttachVector (aFirstAttach, aSecondAttach); - Standard_Real aDimensionWidth = anAttachVector.Magnitude(); - Standard_Real anArrowsWidth = anArrowLength * 2.0; - Standard_Real aContentWidth = isArrowsExternal ? aTextLength : aTextLength + anArrowsWidth; - - aLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter; - break; - } - } - - switch (aDimensionAspect->TextVerticalPosition()) - { - case Prs3d_DTVP_Above : aLabelPosition |= LabelPosition_Above; break; - case Prs3d_DTVP_Below : aLabelPosition |= LabelPosition_Below; break; - case Prs3d_DTVP_Center : aLabelPosition |= LabelPosition_VCenter; break; - } - // Group1: stenciling text and the angle dimension arc Prs3d_Root::NewGroup (thePresentation); - Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize(); - Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask; // draw text label @@ -846,121 +678,131 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /* if (isLineBreak) { - drawArcWithText (thePresentation, + DrawArcWithText (thePresentation, aFirstAttach, aSecondAttach, - aValueString, - (AIS_DimensionDisplayMode)theMode, + myCenterPoint, + aLabelString, + aLabelWidth, + theMode, aLabelPosition); break; } - gp_Vec aTextDir (aFirstArrowEnd, aSecondArrowBegin); - myGeom.myTextPosition = getCenterOnArc (aFirstArrowEnd, aSecondArrowBegin); - - drawText (thePresentation, - myIsTextReversed ? aTextDir.Reversed() : aTextDir, - aValueString, - (AIS_DimensionDisplayMode)theMode, - aLabelPosition); - - if (theMode == AIS_DDM_Text) + // compute text primitives + if (theMode == ComputeMode_All || theMode == ComputeMode_Text) { - break; + gp_Vec aDimensionDir (aFirstAttach, aSecondAttach); + gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition + : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint); + gp_Dir aTextDir = aDimensionDir; + + DrawText (thePresentation, + aTextPos, + aTextDir, + aLabelString, + aLabelPosition); } - drawArc (thePresentation, - isArrowsExternal ? aFirstAttach : aFirstArrowEnd, - isArrowsExternal ? aSecondAttach : aSecondArrowEnd, - myCenter, - Abs (GetFlyout()), - (AIS_DimensionDisplayMode)theMode); + if (theMode == ComputeMode_All || theMode == ComputeMode_Line) + { + DrawArc (thePresentation, + isArrowsExternal ? aFirstAttach : aFirstArrowEnd, + isArrowsExternal ? aSecondAttach : aSecondArrowEnd, + myCenterPoint, + Abs (GetFlyout()), + theMode); + } } break; case LabelPosition_Left : { - drawExtension (thePresentation, + DrawExtension (thePresentation, anExtensionSize, isArrowsExternal ? aFirstArrowEnd : aFirstAttach, aFirstExtensionDir, - aValueString, - (AIS_DimensionDisplayMode)theMode, + aLabelString, + aLabelWidth, + theMode, aLabelPosition); } break; case LabelPosition_Right : { - drawExtension (thePresentation, + DrawExtension (thePresentation, anExtensionSize, isArrowsExternal ? aSecondArrowEnd : aSecondAttach, aSecondExtensionDir, - aValueString, - (AIS_DimensionDisplayMode)theMode, + aLabelString, + aLabelWidth, + theMode, aLabelPosition); } break; } // dimension arc without text - if (theMode != AIS_DDM_Text && aHPosition != LabelPosition_HCenter) + if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter) { Prs3d_Root::NewGroup (thePresentation); - drawArc (thePresentation, + DrawArc (thePresentation, isArrowsExternal ? aFirstAttach : aFirstArrowEnd, isArrowsExternal ? aSecondAttach : aSecondArrowEnd, - myCenter, + myCenterPoint, Abs(GetFlyout ()), - (AIS_DimensionDisplayMode)theMode); + theMode); } // arrows and arrow extensions - if (theMode != AIS_DDM_Text) + if (theMode == ComputeMode_All || theMode == ComputeMode_Line) { Prs3d_Root::NewGroup (thePresentation); - drawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec)); - drawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec)); + DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec)); + DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec)); } - if (theMode != AIS_DDM_Text && isArrowsExternal) + if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal) { Prs3d_Root::NewGroup (thePresentation); if (aHPosition != LabelPosition_Left) { - drawExtension (thePresentation, - anExtensionSize, + DrawExtension (thePresentation, + aDimensionAspect->ArrowTailSize(), aFirstArrowEnd, aFirstExtensionDir, - THE_EMPTY_LABEL, - (AIS_DimensionDisplayMode)theMode, + THE_EMPTY_LABEL_STRING, + THE_EMPTY_LABEL_WIDTH, + theMode, LabelPosition_None); } if (aHPosition != LabelPosition_Right) { - drawExtension (thePresentation, - anExtensionSize, + DrawExtension (thePresentation, + aDimensionAspect->ArrowTailSize(), aSecondArrowEnd, aSecondExtensionDir, - THE_EMPTY_LABEL, - (AIS_DimensionDisplayMode)theMode, + THE_EMPTY_LABEL_STRING, + THE_EMPTY_LABEL_WIDTH, + theMode, LabelPosition_None); } } // flyouts - if (theMode == AIS_DDM_All && myIsFlyoutLines) + if (theMode == ComputeMode_All) { Prs3d_Root::NewGroup (thePresentation); Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4); - aPrimSegments->AddVertex (myCenter); + aPrimSegments->AddVertex (myCenterPoint); aPrimSegments->AddVertex (aFirstAttach); - aPrimSegments->AddVertex (myCenter); + aPrimSegments->AddVertex (myCenterPoint); aPrimSegments->AddVertex (aSecondAttach); Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect(); @@ -968,25 +810,611 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /* Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments); } - setComputed (Standard_True); + myIsComputed = Standard_True; } //======================================================================= -//function : computeFlyoutSelection +//function : ComputeFlyoutSelection //purpose : computes selection for flyouts //======================================================================= -void AIS_AngleDimension::computeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection, - const Handle(AIS_DimensionOwner)& theOwner) +void AIS_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection, + const Handle(SelectMgr_EntityOwner)& theOwner) +{ + gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout()); + gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout()); + + Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner); + aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach)); + aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach)); + + theSelection->Add (aSensitiveEntity); +} + +//======================================================================= +//function : InitTwoEdgesAngle +//purpose : +//======================================================================= +Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane) +{ + TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape); + TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape); + + BRepAdaptor_Curve aMakeFirstLine (aFirstEdge); + BRepAdaptor_Curve aMakeSecondLine (aSecondEdge); + + if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line) + { + return Standard_False; + } + + Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line()); + Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line()); + + gp_Lin aFirstLin = aFirstLine->Lin(); + gp_Lin aSecondLin = aSecondLine->Lin(); + + Standard_Boolean isParallelLines = Abs (aFirstLin.Angle (aSecondLin) - M_PI) <= Precision::Angular(); + + gp_Pnt aPoint = aFirstLine->Value (0.0); + gp_Dir aNormal = isParallelLines + ? gp_Vec (aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction()) + : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()); + + theComputedPlane = gp_Pln (aPoint, aNormal); + + // Compute geometry for this plane and edges + Standard_Boolean isInfinite1,isInfinite2; + gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2; + gp_Lin2d aFirstLin2d, aSecondLin2d; + + if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge, + aFirstLine, aSecondLine, + aFirstPoint1, aLastPoint1, + aFirstPoint2, aLastPoint2, + isInfinite1, isInfinite2)) + { + return Standard_False; + } + + if (aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular())) + { + myFirstPoint = aFirstLin.Location(); + mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin); + + if (mySecondPoint.Distance (myFirstPoint) <= Precision::Confusion()) + { + mySecondPoint.Translate (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout())); + } + + myCenterPoint.SetXYZ ((myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2.0); + } + else + { + // Find intersection + gp_Lin2d aFirstLin2d = ProjLib::Project (theComputedPlane, aFirstLin); + gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin); + + IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d); + gp_Pnt2d anIntersectPoint; + if (!anInt2d.IsDone() || anInt2d.IsEmpty()) + { + return Standard_False; + } + + anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value()); + myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint); + + if (isInfinite1 || isInfinite2) + { + myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout())); + mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout())); + + return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); + } + + // | + // | <- dimension should be here + // *---- + myFirstPoint = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1) + ? aFirstPoint1 + : aLastPoint1; + + mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2) + ? aFirstPoint2 + : aLastPoint2; + } + + return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); +} + +//======================================================================= +//function : InitTwoFacesAngle +//purpose : initialization of angle dimension between two faces +//======================================================================= +Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle() +{ + TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape); + TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape); + + gp_Dir aFirstDir, aSecondDir; + gp_Pln aFirstPlane, aSecondPlane; + Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf; + AIS_KindOfSurface aFirstSurfType, aSecondSurfType; + Standard_Real aFirstOffset, aSecondOffset; + + AIS::GetPlaneFromFace (aFirstFace, aFirstPlane, + aFirstBasisSurf,aFirstSurfType,aFirstOffset); + + AIS::GetPlaneFromFace (aSecondFace, aSecondPlane, + aSecondBasisSurf, aSecondSurfType, aSecondOffset); + + if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane) + { + //Planar faces angle + Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf); + Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf); + return AIS::InitAngleBetweenPlanarFaces (aFirstFace, + aSecondFace, + myCenterPoint, + myFirstPoint, + mySecondPoint) + && IsValidPoints (myFirstPoint, + myCenterPoint, + mySecondPoint); + } + else + { + // Curvilinear faces angle + return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace, + aSecondFace, + aFirstSurfType, + aSecondSurfType, + myCenterPoint, + myFirstPoint, + mySecondPoint) + && IsValidPoints (myFirstPoint, + myCenterPoint, + mySecondPoint); + } +} + +//======================================================================= +//function : InitTwoFacesAngle +//purpose : initialization of angle dimension between two faces +//======================================================================= +Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace) +{ + TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape); + TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape); + + gp_Dir aFirstDir, aSecondDir; + gp_Pln aFirstPlane, aSecondPlane; + Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf; + AIS_KindOfSurface aFirstSurfType, aSecondSurfType; + Standard_Real aFirstOffset, aSecondOffset; + + AIS::GetPlaneFromFace (aFirstFace, aFirstPlane, + aFirstBasisSurf,aFirstSurfType,aFirstOffset); + + AIS::GetPlaneFromFace (aSecondFace, aSecondPlane, + aSecondBasisSurf, aSecondSurfType, aSecondOffset); + + myFirstPoint = thePointOnFirstFace; + if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane) + { + //Planar faces angle + Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf); + Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf); + return AIS::InitAngleBetweenPlanarFaces (aFirstFace, + aSecondFace, + myCenterPoint, + myFirstPoint, + mySecondPoint, + Standard_True) + && IsValidPoints (myFirstPoint, + myCenterPoint, + mySecondPoint); + } + else + { + // Curvilinear faces angle + return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace, + aSecondFace, + aFirstSurfType, + aSecondSurfType, + myCenterPoint, + myFirstPoint, + mySecondPoint, + Standard_True) + && IsValidPoints (myFirstPoint, + myCenterPoint, + mySecondPoint); + } +} + +//======================================================================= +//function : InitConeAngle +//purpose : initialization of the cone angle +//======================================================================= +Standard_Boolean AIS_AngleDimension::InitConeAngle() +{ + if (myFirstShape.IsNull()) + { + return Standard_False; + } + + TopoDS_Face aConeShape = TopoDS::Face (myFirstShape); + gp_Pln aPln; + gp_Cone aCone; + gp_Circ aCircle; + // A surface from the Face + Handle(Geom_Surface) aSurf; + Handle(Geom_OffsetSurface) aOffsetSurf; + Handle(Geom_ConicalSurface) aConicalSurf; + Handle(Geom_SurfaceOfRevolution) aRevSurf; + Handle(Geom_Line) aLine; + BRepAdaptor_Surface aConeAdaptor (aConeShape); + TopoDS_Face aFace; + AIS_KindOfSurface aSurfType; + Standard_Real anOffset = 0.; + Handle(Standard_Type) aType; + + Standard_Real aMaxV = aConeAdaptor.FirstVParameter(); + Standard_Real aMinV = aConeAdaptor.LastVParameter(); + + AIS::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset); + + if (aSurfType == AIS_KOS_Revolution) + { + // Surface of revolution + aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf); + gp_Lin aLin (aRevSurf->Axis()); + Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve(); + //Must be a part of line (basis curve should be linear) + if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line)) + return Standard_False; + + gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV); + gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV); + gp_Vec aVec1 (aFirst1, aLast1); + + //Projection on + gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin); + // Projection on + gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin); + + gp_Vec aVec2 (aFirst2, aLast2); + + // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle). + if (aVec1.IsParallel (aVec2, Precision::Angular()) + || aVec1.IsNormal (aVec2,Precision::Angular())) + return Standard_False; + + gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1); + aCone = aMkCone.Value(); + myCenterPoint = aCone.Apex(); + } + else + { + aType = aSurf->DynamicType(); + if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01) + { + // Offset surface + aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset); + aSurf = aOffsetSurf->Surface(); + BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion()); + aMkFace.Build(); + if (!aMkFace.IsDone()) + return Standard_False; + aConeAdaptor.Initialize (aMkFace.Face()); + } + aCone = aConeAdaptor.Cone(); + aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf); + myCenterPoint = aConicalSurf->Apex(); + } + + // A circle where the angle is drawn + Handle(Geom_Curve) aCurve; + Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5; + aCurve = aSurf->VIso (aMidV); + aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ(); + + aCurve = aSurf->VIso(aMaxV); + gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ(); + aCurve = aSurf->VIso(aMinV); + gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ(); + + if (aCircVmax.Radius() < aCircVmin.Radius()) + { + gp_Circ aTmpCirc = aCircVmax; + aCircVmax = aCircVmin; + aCircVmin = aTmpCirc; + } + + myFirstPoint = ElCLib::Value (0, aCircle); + mySecondPoint = ElCLib::Value (M_PI, aCircle); + return Standard_True; +} + +//======================================================================= +//function : IsValidPoints +//purpose : +//======================================================================= +Standard_Boolean AIS_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint, + const gp_Pnt& theCenterPoint, + const gp_Pnt& theSecondPoint) const { - if (!myIsFlyoutLines) - { - return; - } + return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion() + && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion() + && gp_Vec (theCenterPoint, theFirstPoint).Angle ( + gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular(); +} + +//======================================================================= +//function : GetTextPosition +//purpose : +//======================================================================= +const gp_Pnt AIS_AngleDimension::GetTextPosition() const +{ + if (!IsValid()) + { + return gp::Origin(); + } + + if (IsTextPositionCustom()) + { + return myFixedTextPosition; + } + + // Counts text position according to the dimension parameters + gp_Pnt aTextPosition (gp::Origin()); - gp_Pnt aFirstAttach = myCenter.Translated (gp_Vec (myCenter, myFirstPoint).Normalized() * GetFlyout()); - gp_Pnt aSecondAttach = myCenter.Translated (gp_Vec (myCenter, mySecondPoint).Normalized() * GetFlyout()); - Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner); - aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenter, aFirstAttach)); - aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenter, aSecondAttach)); - theSelection->Add (aSensitiveEntity); + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + + // Prepare label string and compute its geometrical width + Standard_Real aLabelWidth; + TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth); + + gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout()); + gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout()); + + // Handle user-defined and automatic arrow placement + Standard_Boolean isArrowsExternal = Standard_False; + Standard_Integer aLabelPosition = LabelPosition_None; + FitTextAlignment (aDimensionAspect->TextHorizontalPosition(), + aLabelPosition, isArrowsExternal); + + // Get text position + switch (aLabelPosition & LabelPosition_HMask) + { + case LabelPosition_HCenter: + { + aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint); + } + break; + case LabelPosition_Left: + { + gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach); + gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach); + Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize(); + Standard_Real anOffset = isArrowsExternal + ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length() + : anExtensionSize; + gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * -anOffset; + aTextPosition = aFirstAttach.Translated (anExtensionVec); + } + break; + case LabelPosition_Right: + { + gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach); + gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach); + Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize(); + Standard_Real anOffset = isArrowsExternal + ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length() + : anExtensionSize; + gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * anOffset; + aTextPosition = aSecondAttach.Translated (anExtensionVec); + } + break; + } + + return aTextPosition; +} + +//======================================================================= +//function : SetTextPosition +//purpose : +//======================================================================= +void AIS_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos) +{ + if (!IsValid()) + { + return; + } + + // The text position point for angle dimension should belong to the working plane. + if (!GetPlane().Contains (theTextPos, Precision::Confusion())) + { + Standard_ProgramError::Raise ("The text position point for angle dimension doesn't belong to the working plane."); + } + + myIsTextPositionFixed = Standard_True; + myFixedTextPosition = theTextPos; +} + +//======================================================================= +//function : AdjustAspectParameters +//purpose : +//======================================================================= +void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos, + Standard_Real& theExtensionSize, + Prs3d_DimensionTextHorizontalPosition& theAlignment) +{ + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length(); + + // Compute flyout direction vector. + gp_Dir aPlaneNormal = GetPlane().Axis().Direction(); + gp_Dir aTargetPointsDir = gce_MakeDir (myFirstPoint, mySecondPoint); + + // Build circle with radius that is equal to distance from text position to the center point. + Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude(); + + // Set attach points in positive direction of the flyout. + gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius); + gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius); + + gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius); + if (!aConstructCircle.IsDone()) + { + return; + } + gp_Circ aCircle = aConstructCircle.Value(); + + // Default values + theExtensionSize = aDimensionAspect->ArrowAspect()->Length(); + theAlignment = Prs3d_DTHP_Center; + + Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach); + Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach); + if (aParamEnd < aParamBeg) + { + Standard_Real aParam = aParamEnd; + aParamEnd = aParamBeg; + aParamBeg = aParam; + } + + ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd); + Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos); + + // Horizontal center + if (aTextPar > aParamBeg && aTextPar < aParamEnd) + { + myFlyout = aRadius; + + SetToUpdate(); + return; + } + + aParamBeg += M_PI; + aParamEnd += M_PI; + ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd); + + if (aTextPar > aParamBeg && aTextPar < aParamEnd) + { + myFlyout = -aRadius; + + SetToUpdate(); + return; + } + + // Text on the extensions + gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint); + gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint); + gp_Pnt aFirstTextProj = AIS::Nearest (aFirstLine, theTextPos); + gp_Pnt aSecondTextProj = AIS::Nearest (aSecondLine, theTextPos); + Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos); + Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos); + + if (aFirstDist <= aSecondDist) + { + aRadius = myCenterPoint.Distance (aFirstTextProj); + Standard_Real aNewExtensionSize = aFirstDist - anArrowLength; + theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize; + + theAlignment = Prs3d_DTHP_Left; + + gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius); + + myFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion() + ? -aRadius : aRadius; + } + else + { + aRadius = myCenterPoint.Distance (aSecondTextProj); + + Standard_Real aNewExtensionSize = aSecondDist - anArrowLength; + + theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize; + + theAlignment = Prs3d_DTHP_Right; + + gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius); + + myFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion() + ? -aRadius : aRadius; + } +} + +//======================================================================= +//function : FitTextAlignment +//purpose : +//======================================================================= +void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos, + Standard_Integer& theLabelPosition, + Standard_Boolean& theIsArrowsExternal) const +{ + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + + Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length(); + + // Prepare label string and compute its geometrical width + Standard_Real aLabelWidth; + TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth); + + // add margins to label width + if (aDimensionAspect->IsText3d()) + { + aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0; + } + + gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout()); + gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout()); + + // Handle user-defined and automatic arrow placement + switch (aDimensionAspect->ArrowOrientation()) + { + case Prs3d_DAO_External: theIsArrowsExternal = true; break; + case Prs3d_DAO_Internal: theIsArrowsExternal = false; break; + case Prs3d_DAO_Fit: + { + gp_Vec anAttachVector (aFirstAttach, aSecondAttach); + Standard_Real aDimensionWidth = anAttachVector.Magnitude(); + + // Add margin to ensure a small tail between text and arrow + Standard_Real anArrowMargin = aDimensionAspect->IsText3d() + ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN + : 0.0; + + Standard_Real anArrowsWidth = (anArrowLength + anArrowMargin) * 2.0; + + theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth; + break; + } + } + + // Handle user-defined and automatic text placement + switch (theHorizontalTextPos) + { + case Prs3d_DTHP_Left : theLabelPosition |= LabelPosition_Left; break; + case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break; + case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break; + case Prs3d_DTHP_Fit: + { + gp_Vec anAttachVector (aFirstAttach, aSecondAttach); + Standard_Real aDimensionWidth = anAttachVector.Magnitude(); + Standard_Real anArrowsWidth = anArrowLength * 2.0; + Standard_Real aContentWidth = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth; + + theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter; + break; + } + } + + switch (aDimensionAspect->TextVerticalPosition()) + { + case Prs3d_DTVP_Above : theLabelPosition |= LabelPosition_Above; break; + case Prs3d_DTVP_Below : theLabelPosition |= LabelPosition_Below; break; + case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break; + } }