From: nds Date: Wed, 16 Mar 2016 05:26:28 +0000 (+0300) Subject: Angle presentation from NewGEOM_2.0.0. It is moved here to prepare a patch for OCCT... X-Git-Tag: V_2.3.0~384 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=1cef78af4c4328ecf99a3ced86bda38e6e82e15c;p=modules%2Fshaper.git Angle presentation from NewGEOM_2.0.0. It is moved here to prepare a patch for OCCT with necessary functionality. --- diff --git a/src/SketcherPrs/AIS_AngleDimension.cxx b/src/SketcherPrs/AIS_AngleDimension.cxx new file mode 100755 index 000000000..2767e0310 --- /dev/null +++ b/src/SketcherPrs/AIS_AngleDimension.cxx @@ -0,0 +1,1400 @@ +// Created on: 1996-12-05 +// Created by: Arnaud BOUZY/Odile Olivier +// Copyright (c) 1996-1999 Matra Datavision +// Copyright (c) 1999-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#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 + +IMPLEMENT_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension) +IMPLEMENT_STANDARD_RTTIEXT (AIS_AngleDimension, AIS_Dimension) + +namespace +{ + 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 : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge, + const TopoDS_Edge& theSecondEdge) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theFirstEdge, theSecondEdge); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThirdPoint) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex, + const TopoDS_Vertex& theSecondVertex, + const TopoDS_Vertex& theThirdVertex) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theCone); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theFirstFace, theSecondFace); +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint) +: AIS_Dimension (AIS_KOD_PLANEANGLE) +{ + Init(); + SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint); +} + +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge, + const TopoDS_Edge& theSecondEdge) +{ + gp_Pln aComputedPlane; + + myFirstShape = theFirstEdge; + mySecondShape = theSecondEdge; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Edges; + myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThirdPoint) +{ + myFirstPoint = theFirstPoint; + myCenterPoint = theSecondPoint; + mySecondPoint = theThirdPoint; + myFirstShape = BRepLib_MakeVertex (myFirstPoint); + mySecondShape = BRepLib_MakeVertex (myCenterPoint); + myThirdShape = BRepLib_MakeVertex (mySecondPoint); + myGeometryType = GeometryType_Points; + myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//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; + myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone) +{ + myFirstShape = theCone; + mySecondShape = TopoDS_Shape(); + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Face; + myIsGeometryValid = InitConeAngle(); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace) +{ + myFirstShape = theFirstFace; + mySecondShape = theSecondFace; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Faces; + myIsGeometryValid = InitTwoFacesAngle(); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//function : SetMeasuredGeometry +//purpose : +//======================================================================= +void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint) +{ + myFirstShape = theFirstFace; + mySecondShape = theSecondFace; + myThirdShape = TopoDS_Shape(); + myGeometryType = GeometryType_Faces; + myIsGeometryValid = InitTwoFacesAngle (thePoint); + + if (myIsGeometryValid && !myIsPlaneCustom) + { + ComputePlane(); + } + + SetToUpdate(); +} + +//======================================================================= +//function : Init +//purpose : +//======================================================================= +void AIS_AngleDimension::Init() +{ + SetSpecialSymbol (THE_DEGREE_SYMBOL); + SetDisplaySpecialSymbol (AIS_DSS_After); + SetFlyout (15.0); +} + +//======================================================================= +//function: GetCenterOnArc +//purpose : +//======================================================================= +gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach, + const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter) const +{ + // construct plane where the circle and the arc are located + gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter); + if (!aConstructPlane.IsDone()) + { + return gp::Origin(); + } + + gp_Pln aPlane = aConstructPlane.Value(); + + Standard_Real aRadius = theFirstAttach.Distance (theCenter); + + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius); + if (!aConstructCircle.IsDone()) + { + return gp::Origin(); + } + + 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); +} + +//======================================================================= +//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()) + { + return; + } + + gp_Pln aPlane = aConstructPlane.Value(); + + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius); + if (!aConstructCircle.IsDone()) + { + return; + } + + gp_Circ aCircle = aConstructCircle.Value(); + + // construct the arc + GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True); + if (!aConstructArc.IsDone()) + { + return; + } + + // generate points with specified deflection + const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value(); + + GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter()); + + // 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)); + + GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints); + if (!aMakePnts.IsDone()) + { + return; + } + + // init data arrays for graphical and selection primitives + Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints); + + SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve(); + + // load data into arrays + for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt) + { + gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt)); + + aPrimSegments->AddVertex (aPnt); + + aSensitiveCurve.Append (aPnt); + } + + // 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 +//purpose : +//======================================================================= +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 Standard_Real theTextWidth, + const Standard_Integer theMode, + const Standard_Integer theLabelPosition) +{ + // 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(); + + Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint); + + // construct circle forming the arc + gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius); + if (!aConstructCircle.IsDone()) + { + return; + } + + 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); + + // middle point of arc parameter on circle + Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5; + + // 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); + } + + if (theMode != ComputeMode_All && theMode != ComputeMode_Line) + { + return; + } + + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + + Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center + && aDimensionAspect->IsText3d(); + + if (isLineBreak) + { + // 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 : CheckPlane +//purpose : +//======================================================================= +Standard_Boolean AIS_AngleDimension::CheckPlane (const gp_Pln& thePlane)const +{ + if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) && + !thePlane.Contains (mySecondPoint, Precision::Confusion()) && + !thePlane.Contains (myCenterPoint, Precision::Confusion())) + { + return Standard_False; + } + + return Standard_True; +} + +//======================================================================= +//function : ComputePlane +//purpose : +//======================================================================= +void AIS_AngleDimension::ComputePlane() +{ + if (!myIsGeometryValid) + { + return; + } + + 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()) + { + 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); +} + +//======================================================================= +//function : Compute +//purpose : Having three gp_Pnt points compute presentation +//======================================================================= +void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePM*/, + const Handle(Prs3d_Presentation)& thePresentation, + const Standard_Integer theMode) +{ + thePresentation->Clear(); + mySelectionGeom.Clear (theMode); + + if (!IsValid()) + { + return; + } + + // Parameters for presentation + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + + Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect()); + + 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; + } + + // Get parameters from aspect or adjust it according with custom text position + Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize(); + Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition(); + + if (IsTextPositionCustom()) + { + AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout); + } + + // Handle user-defined and automatic arrow placement + Standard_Boolean isArrowsExternal = Standard_False; + Standard_Integer aLabelPosition = LabelPosition_None; + + 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 (GetPlane().Axis().Direction()); + + 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; + + gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0); + gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0); + gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0); + gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0); + + if (isArrowsExternal) + { + aFirstArrowVec.Reverse(); + aSecondArrowVec.Reverse(); + } + + aFirstArrowBegin = aFirstAttach; + aSecondArrowBegin = aSecondAttach; + aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec); + aSecondArrowEnd = aSecondAttach.Translated (-aSecondArrowVec); + + // Group1: stenciling text and the angle dimension arc + Prs3d_Root::NewGroup (thePresentation); + + Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask; + + // draw text label + switch (aHPosition) + { + case LabelPosition_HCenter : + { + Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center + && aDimensionAspect->IsText3d(); + + if (isLineBreak) + { + DrawArcWithText (thePresentation, + aFirstAttach, + aSecondAttach, + myCenterPoint, + aLabelString, + aLabelWidth, + theMode, + aLabelPosition); + break; + } + + // compute text primitives + if (theMode == ComputeMode_All || theMode == ComputeMode_Text) + { + gp_Vec aDimensionDir (aFirstAttach, aSecondAttach); + gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition + : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint); + gp_Dir aTextDir = aDimensionDir; + + DrawText (thePresentation, + aTextPos, + aTextDir, + aLabelString, + aLabelPosition); + } + + 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, + anExtensionSize, + isArrowsExternal ? aFirstArrowEnd : aFirstAttach, + aFirstExtensionDir, + aLabelString, + aLabelWidth, + theMode, + aLabelPosition); + } + break; + + case LabelPosition_Right : + { + DrawExtension (thePresentation, + anExtensionSize, + isArrowsExternal ? aSecondArrowEnd : aSecondAttach, + aSecondExtensionDir, + aLabelString, + aLabelWidth, + theMode, + aLabelPosition); + } + break; + } + + // dimension arc without text + if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter) + { + Prs3d_Root::NewGroup (thePresentation); + + DrawArc (thePresentation, + isArrowsExternal ? aFirstAttach : aFirstArrowEnd, + isArrowsExternal ? aSecondAttach : aSecondArrowEnd, + myCenterPoint, + Abs(GetFlyout ()), + theMode); + } + + // arrows and arrow extensions + if (theMode == ComputeMode_All || theMode == ComputeMode_Line) + { + Prs3d_Root::NewGroup (thePresentation); + + DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec)); + DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec)); + } + + if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal) + { + Prs3d_Root::NewGroup (thePresentation); + + if (aHPosition != LabelPosition_Left) + { + DrawExtension (thePresentation, + aDimensionAspect->ArrowTailSize(), + aFirstArrowEnd, + aFirstExtensionDir, + THE_EMPTY_LABEL_STRING, + THE_EMPTY_LABEL_WIDTH, + theMode, + LabelPosition_None); + } + + if (aHPosition != LabelPosition_Right) + { + DrawExtension (thePresentation, + aDimensionAspect->ArrowTailSize(), + aSecondArrowEnd, + aSecondExtensionDir, + THE_EMPTY_LABEL_STRING, + THE_EMPTY_LABEL_WIDTH, + theMode, + LabelPosition_None); + } + } + + // flyouts + if (theMode == ComputeMode_All) + { + Prs3d_Root::NewGroup (thePresentation); + + Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4); + aPrimSegments->AddVertex (myCenterPoint); + aPrimSegments->AddVertex (aFirstAttach); + aPrimSegments->AddVertex (myCenterPoint); + aPrimSegments->AddVertex (aSecondAttach); + + Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect(); + Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aFlyoutStyle); + Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments); + } + + mySelectionGeom.IsComputed = Standard_True; +} + +//======================================================================= +//function : ComputeFlyoutSelection +//purpose : computes selection for flyouts +//======================================================================= +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 +{ + 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()); + + 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 : AdjustParameters +//purpose : +//======================================================================= +void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos, + Standard_Real& theExtensionSize, + Prs3d_DimensionTextHorizontalPosition& theAlignment, + Standard_Real& theFlyout) const +{ + Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect(); + Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length(); + + // 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) + { + theFlyout = aRadius; + return; + } + + aParamBeg += M_PI; + aParamEnd += M_PI; + ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd); + + if (aTextPar > aParamBeg && aTextPar < aParamEnd) + { + theFlyout = -aRadius; + 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); + + theFlyout = 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); + + theFlyout = 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; + } +} diff --git a/src/SketcherPrs/AIS_AngleDimension.hxx b/src/SketcherPrs/AIS_AngleDimension.hxx new file mode 100755 index 000000000..3a4495666 --- /dev/null +++ b/src/SketcherPrs/AIS_AngleDimension.hxx @@ -0,0 +1,347 @@ +// Copyright (c) 1995-1999 Matra Datavision +// Copyright (c) 1999-2013 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_AngleDimension_HeaderFile +#define _AIS_AngleDimension_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension) + +//! Angle dimension. Can be constructed: +//! - on two intersected edges. +//! - on three points or vertices. +//! - on conical face. +//! - between two intersected faces. +//! +//! In case of three points or two intersected edges the dimension plane +//! (on which dimension presentation is built) can be computed uniquely +//! as through three defined points can be built only one plane. +//! Therefore, if user-defined plane differs from this one, the dimension can't be built. +//! +//! In cases of two planes automatic plane by default is built on point of the +//! origin of parametric space of the first face (the basis surface) so, that +//! the working plane and two faces intersection forms minimal angle between the faces. +//! User can define the other point which the dimension plane should pass through +//! using the appropriate constructor. This point can lay on the one of the faces or not. +//! Also user can define his own plane but it should pass through the three points +//! computed on the geometry initialization step (when the constructor or SetMeasuredGeometry() method +//! is called). +//! +//! In case of the conical face the center point of the angle is the apex of the conical surface. +//! The attachment points are points of the first and the last parameter of the basis circle of the cone. +//! +class AIS_AngleDimension : public AIS_Dimension +{ +public: + + //! Constructs minimum angle dimension between two linear edges (where possible). + //! These two edges should be intersected by each other. Otherwise the geometry is not valid. + //! @param theFirstEdge [in] the first edge. + //! @param theSecondEdge [in] the second edge. + Standard_EXPORT AIS_AngleDimension (const TopoDS_Edge& theFirstEdge, + const TopoDS_Edge& theSecondEdge); + + //! Constructs the angle display object defined by three points. + //! @param theFirstPoint [in] the first point (point on first angle flyout). + //! @param theSecondPoint [in] the center point of angle dimension. + //! @param theThirdPoint [in] the second point (point on second angle flyout). + Standard_EXPORT AIS_AngleDimension (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThirdPoint); + + //! Constructs the angle display object defined by three vertices. + //! @param theFirstVertex [in] the first vertex (vertex for first angle flyout). + //! @param theSecondVertex [in] the center vertex of angle dimension. + //! @param theThirdPoint [in] the second vertex (vertex for second angle flyout). + Standard_EXPORT AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex, + const TopoDS_Vertex& theSecondVertex, + const TopoDS_Vertex& theThirdVertex); + + //! Constructs angle dimension for the cone face. + //! @param theCone [in] the conical face. + Standard_EXPORT AIS_AngleDimension (const TopoDS_Face& theCone); + + //! Constructs angle dimension between two planar faces. + //! @param theFirstFace [in] the first face. + //! @param theSecondFace [in] the second face. + Standard_EXPORT AIS_AngleDimension (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace); + + //! Constructs angle dimension between two planar faces. + //! @param theFirstFace [in] the first face. + //! @param theSecondFace [in] the second face. + //! @param thePoint [in] the point which the dimension plane should pass through. + //! This point can lay on the one of the faces or not. + Standard_EXPORT AIS_AngleDimension (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint); + +public: + + //! @return first point forming the angle. + const gp_Pnt& FirstPoint() const + { + return myFirstPoint; + } + + //! @return second point forming the angle. + const gp_Pnt& SecondPoint() const + { + return mySecondPoint; + } + + //! @return center point forming the angle. + const gp_Pnt& CenterPoint() const + { + return myCenterPoint; + } + + //! @return first argument shape. + const TopoDS_Shape& FirstShape() const + { + return myFirstShape; + } + + //! @return second argument shape. + const TopoDS_Shape& SecondShape() const + { + return mySecondShape; + } + + //! @return third argument shape. + const TopoDS_Shape& ThirdShape() const + { + return myThirdShape; + } + +public: + + //! Measures minimum angle dimension between two linear edges. + //! These two edges should be intersected by each other. Otherwise the geometry is not valid. + //! @param theFirstEdge [in] the first edge. + //! @param theSecondEdge [in] the second edge. + Standard_EXPORT void SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge, + const TopoDS_Edge& theSecondEdge); + + //! Measures angle defined by three points. + //! @param theFirstPoint [in] the first point (point on first angle flyout). + //! @param theSecondPoint [in] the center point of angle dimension. + //! @param theThirdPoint [in] the second point (point on second angle flyout). + Standard_EXPORT void SetMeasuredGeometry (const gp_Pnt& theFirstPoint, + const gp_Pnt& theSecondPoint, + const gp_Pnt& theThridPoint); + + //! Measures angle defined by three vertices. + //! @param theFirstVertex [in] the first vertex (vertex for first angle flyout). + //! @param theSecondVertex [in] the center vertex of angle dimension. + //! @param theThirdPoint [in] the second vertex (vertex for second angle flyout). + Standard_EXPORT void SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex, + const TopoDS_Vertex& theSecondVertex, + const TopoDS_Vertex& theThirdVertex); + + //! Measures angle of conical face. + //! @param theCone [in] the shape to measure. + Standard_EXPORT void SetMeasuredGeometry (const TopoDS_Face& theCone); + + //! Measures angle between two planar faces. + //! @param theFirstFace [in] the first face. + //! @param theSecondFace [in] the second face.. + Standard_EXPORT void SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace); + + //! Measures angle between two planar faces. + //! @param theFirstFace [in] the first face. + //! @param theSecondFace [in] the second face. + //! @param thePoint [in] the point which the dimension plane should pass through. + //! This point can lay on the one of the faces or not. + Standard_EXPORT void SetMeasuredGeometry (const TopoDS_Face& theFirstFace, + const TopoDS_Face& theSecondFace, + const gp_Pnt& thePoint); + + //! @return the display units string. + Standard_EXPORT virtual const TCollection_AsciiString& GetDisplayUnits() const; + + //! @return the model units string. + Standard_EXPORT virtual const TCollection_AsciiString& GetModelUnits() const; + + Standard_EXPORT virtual void SetDisplayUnits (const TCollection_AsciiString& theUnits); + + Standard_EXPORT virtual void SetModelUnits (const TCollection_AsciiString& theUnits); + + //! Principle of horizontal text alignment settings: + //! - divide circle into two halves according to attachment points + //! - if aTextPos is between attach points -> Center + positive flyout + //! - if aTextPos is not between attach points but in this half -> Left or Right + positive flyout + //! - if aTextPos is between reflections of attach points -> Center + negative flyout + //! - if aTextPos is not between reflections of attach points -> Left or Right + negative flyout + Standard_EXPORT virtual void SetTextPosition (const gp_Pnt& theTextPos); + + Standard_EXPORT virtual const gp_Pnt GetTextPosition () const; + +public: + + DEFINE_STANDARD_RTTI (AIS_AngleDimension) + +protected: + + //! Initialization of fields that is common to all constructors. + Standard_EXPORT void Init(); + + //! @param theFirstAttach [in] the first attachment point. + //! @param theSecondAttach [in] the second attachment point. + //! @param theCenter [in] the center point (center point of the angle). + //! @return the center of the dimension arc (the main dimension line in case of angle). + Standard_EXPORT gp_Pnt GetCenterOnArc (const gp_Pnt& theFirstAttach, + const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter) const; + + //! Draws main dimension line (arc). + //! @param thePresentation [in] the dimension presentation. + //! @param theFirstAttach [in] the first attachment point. + //! @param theSecondAttach [in] the second attachment point. + //! @param theCenter [in] the center point (center point of the angle). + //! @param theRadius [in] the radius of the dimension arc. + //! @param theMode [in] the display mode. + Standard_EXPORT void 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); + + //! Draws main dimension line (arc) with text. + //! @param thePresentation [in] the dimension presentation. + //! @param theFirstAttach [in] the first attachment point. + //! @param theSecondAttach [in] the second attachment point. + //! @param theCenter [in] the center point (center point of the angle). + //! @param theText [in] the text label string. + //! @param theTextWidth [in] the text label width. + //! @param theMode [in] the display mode. + //! @param theLabelPosition [in] the text label vertical and horizontal positioning option + //! respectively to the main dimension line. + Standard_EXPORT void DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation, + const gp_Pnt& theFirstAttach, + const gp_Pnt& theSecondAttach, + const gp_Pnt& theCenter, + const TCollection_ExtendedString& theText, + const Standard_Real theTextWidth, + const Standard_Integer theMode, + const Standard_Integer theLabelPosition); + + //! Fits text alignment relatively to the dimension line; + //! it computes the value of label position and arrow orientation + //! according set in the aspect and dimension properties. + //! @param theHorizontalTextPos [in] the horizontal alignment for text position. + //! @param theLabelPosition [out] the label position, contains bits that defines + //! vertical and horizontal alignment. (for internal usage in count text position). + //! @param theIsArrowExternal [out] is the arrows external, + //! if arrow orientation in the dimension aspect is Prs3d_DAO_Fit, it fits arrow + //! orientation automatically. + Standard_EXPORT void FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos, + Standard_Integer& theLabelPosition, + Standard_Boolean& theIsArrowsExternal) const; + + //! Adjusts aspect parameters according the text position: + //! extension size, vertical text alignment and flyout. + //! @param theTextPos [in] the user defined 3d point of text position. + //! @param theExtensionSize [out] the adjusted extension size. + //! @param theAlignment [out] the horizontal label alignment. + //! @param theFlyout [out] the adjusted value of flyout. + Standard_EXPORT void AdjustParameters (const gp_Pnt& theTextPos, + Standard_Real& theExtensionSize, + Prs3d_DimensionTextHorizontalPosition& theAlignment, + Standard_Real& theFlyout) const; + +protected: + + Standard_EXPORT virtual void ComputePlane(); + + //! Checks if the plane includes three angle points to build dimension. + Standard_EXPORT virtual Standard_Boolean CheckPlane (const gp_Pln& thePlane) const; + + Standard_EXPORT virtual Standard_Real ComputeValue() const; + + Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePM, + const Handle(Prs3d_Presentation)& thePresentation, + const Standard_Integer theMode = 0); + + Standard_EXPORT virtual void ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection, + const Handle(SelectMgr_EntityOwner)& theOwner); + +protected: + + //! Init angular dimension to measure angle between two linear edges. + //! @return TRUE if the angular dimension can be constructured + //! for the passed edges. + Standard_EXPORT Standard_Boolean InitTwoEdgesAngle (gp_Pln& theComputedPlane); + + //! Init angular dimension to measure angle between two planar faces. + //! there is no user-defined poisitoning. So attach points are set + //! according to faces geometry (in origin of the first face basis surface). + //! @return TRUE if the angular dimension can be constructed + //! for the passed faces. + Standard_EXPORT Standard_Boolean InitTwoFacesAngle(); + + //! Init angular dimension to measure angle between two planar faces. + //! @param thePointOnFirstFace [in] the point which the dimension plane should pass through. + //! This point can lay on the one of the faces or not. + //! It will be projected on the first face and this point will be set + //! as the first point attach point. + //! It defines some kind of dimension positioning over the faces. + //! @return TRUE if the angular dimension can be constructed + //! for the passed faces. + Standard_EXPORT Standard_Boolean InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace); + + //! Init angular dimension to measure cone face. + //! @return TRUE if the angular dimension can be constructed + //! for the passed cone. + Standard_EXPORT Standard_Boolean InitConeAngle(); + + //! Check that the points forming angle are valid. + //! @return TRUE if the points met the following requirements: + //! The (P1, Center), (P2, Center) can be built. + //! The angle between the vectors > Precision::Angular(). + Standard_EXPORT Standard_Boolean IsValidPoints (const gp_Pnt& theFirstPoint, + const gp_Pnt& theCenterPoint, + const gp_Pnt& theSecondPoint) const; + +private: + + gp_Pnt myFirstPoint; + gp_Pnt mySecondPoint; + gp_Pnt myCenterPoint; + TopoDS_Shape myFirstShape; + TopoDS_Shape mySecondShape; + TopoDS_Shape myThirdShape; +}; + +#endif // _AIS_AngleDimension_HeaderFile