0022048: Visualization, AIS_InteractiveContext - single object selection should alway...
[occt.git] / src / AIS / AIS_AngleDimension.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 9327a58..f55900b
 // 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 <AIS_AngleDimension.hxx>
 
 #include <AIS.hxx>
-#include <AIS_Dimension.hxx>
-#include <AIS_DimensionOwner.hxx>
-#include <AIS_Drawer.hxx>
-#include <BRep_Tool.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
 #include <BRepAdaptor_Curve.hxx>
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepLib_MakeVertex.hxx>
-
-#include <DsgPrs.hxx>
-#include <DsgPrs_AnglePresentation.hxx>
-
+#include <BRep_Tool.hxx>
 #include <ElCLib.hxx>
-#include <ElSLib.hxx>
-
-#include <GC_MakeCircle.hxx>
-#include <GC_MakeConicalSurface.hxx>
-#include <gce_MakeLin.hxx>
+#include <GCPnts_UniformAbscissa.hxx>
+#include <GC_MakeArcOfCircle.hxx>
 #include <gce_MakeLin2d.hxx>
-#include <gce_MakePln.hxx>
+#include <gce_MakeLin.hxx>
 #include <gce_MakeCirc.hxx>
 #include <gce_MakeCone.hxx>
-#include <Geom2d_Circle.hxx>
-#include <Geom2d_Curve.hxx>
-#include <Geom2d_Line.hxx>
-#include <Geom2dAPI_ExtremaCurveCurve.hxx>
-#include <GeomAPI.hxx>
+#include <gce_MakePln.hxx>
+#include <gce_MakeDir.hxx>
 #include <Geom_Circle.hxx>
-#include <Geom_Line.hxx>
-#include <Geom_Plane.hxx>
 #include <Geom_TrimmedCurve.hxx>
-#include <Geom_Surface.hxx>
-#include <Geom_CylindricalSurface.hxx>
 #include <Geom_ConicalSurface.hxx>
 #include <Geom_SurfaceOfRevolution.hxx>
-#include <Geom_SurfaceOfLinearExtrusion.hxx>
 #include <Geom_OffsetSurface.hxx>
-#include <GeomAPI_ExtremaCurveCurve.hxx>
 #include <Graphic3d_ArrayOfSegments.hxx>
-#include <Graphic3d_AspectLine3d.hxx>
-#include <gp.hxx>
-#include <gp_Ax1.hxx>
-#include <gp_Lin.hxx>
-#include <gp_Cone.hxx>
-#include <gp_Pln.hxx>
-#include <gp_Pnt.hxx>
-#include <gp_Pnt2d.hxx>
-#include <gp_Vec.hxx> 
-#include <gp_XYZ.hxx>
 #include <Graphic3d_Group.hxx>
-#include <Graphic3d_ArrayOfPrimitives.hxx>
 #include <Graphic3d_ArrayOfPolylines.hxx>
-
 #include <IntAna2d_AnaIntersection.hxx>
-#include <IntAna2d_IntPoint.hxx>
-#include <IntAna_QuadQuadGeo.hxx>
-#include <IntAna_ResultType.hxx>
-#include <Poly_Polygon3D.hxx>
-#include <Precision.hxx>
 #include <ProjLib.hxx>
-#include <Prs3d_ArrowAspect.hxx>
-#include <Prs3d_DimensionAspect.hxx>
-#include <Prs3d_Drawer.hxx>
 #include <Prs3d_Root.hxx>
+#include <Prs3d_ShadingAspect.hxx>
 #include <PrsMgr_PresentationManager3d.hxx>
-#include <Select3D_SensitiveCurve.hxx>
+#include <Select3D_SensitiveGroup.hxx>
 #include <Select3D_SensitiveSegment.hxx>
-#include <Select3D_SensitiveBox.hxx>
-#include <SelectMgr_EntityOwner.hxx>
 #include <SelectMgr_Selection.hxx>
-#include <Standard_NotImplemented.hxx>
-#include <Standard_Type.hxx>
-#include <Standard_Macro.hxx>
-#include <Standard_DefineHandle.hxx>
-
-#include <TColStd_Array1OfReal.hxx>
-#include <TopExp.hxx>
-#include <TopExp_Explorer.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Shape.hxx>
-#include <TopoDS_Vertex.hxx>
+#include <Standard_ProgramError.hxx>
 #include <UnitsAPI.hxx>
+#include <Geom_Line.hxx>
+#include <Geom_Plane.hxx>
 
-IMPLEMENT_STANDARD_HANDLE (AIS_AngleDimension, AIS_Dimension)
-IMPLEMENT_STANDARD_RTTIEXT (AIS_AngleDimension, AIS_Dimension)
 
-//=======================================================================
-//function : init
-//purpose  : Private constructor for default initialization
-//=======================================================================
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AngleDimension,AIS_Dimension)
 
-void AIS_AngleDimension::init()
+namespace
 {
-  // Default values of units
-  UnitsAPI::SetLocalSystem (UnitsAPI_SI);
-  SetUnitsQuantity ("PLANE ANGLE");
-  SetModelUnits ("rad");
-  SetDisplayUnits ("deg");
-  SetSpecialSymbol (0x00B0);
-  SetDisplaySpecialSymbol (AIS_DSS_After);
-  MakeUnitsDisplayed (Standard_False);
+  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;
+
+  //! Returns true if the given points lie on a same line.
+  static Standard_Boolean isSameLine (const gp_Pnt& theFirstPoint,
+                                      const gp_Pnt& theCenterPoint,
+                                      const gp_Pnt& theSecondPoint)
+  {
+    gp_Vec aVec1 (theFirstPoint, theCenterPoint);
+    gp_Vec aVec2 (theCenterPoint, theSecondPoint);
+
+    return aVec1.IsParallel (aVec2, Precision::Angular());
+  }
 }
 
 //=======================================================================
 //function : Constructor
-//purpose  : Two edges dimension
+//purpose  : 
 //=======================================================================
-
 AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
                                         const TopoDS_Edge& theSecondEdge)
-: AIS_Dimension(),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+: AIS_Dimension (AIS_KOD_PLANEANGLE)
 {
-  init();
-  myShapesNumber = 2;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstShape  = theFirstEdge;
-  mySecondShape = theSecondEdge;
+  Init();
+  SetMeasuredGeometry (theFirstEdge, theSecondEdge);
 }
 
 //=======================================================================
 //function : Constructor
-//purpose  : Two edges dimension
-//           <thePlane> is used in case of Angle=PI
+//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);
+}
 
-AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
-                                        const TopoDS_Edge& theSecondEdge,
-                                        const gp_Pln& thePlane)
-: AIS_Dimension(),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+//=======================================================================
+//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();
-  myShapesNumber = 2;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstShape  = theFirstEdge;
-  mySecondShape = theSecondEdge;
-  SetWorkingPlane (thePlane);
+  Init();
+  SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
 }
 
 //=======================================================================
 //function : Constructor
-//purpose  : Two edges dimension with aspect
-//           <thePlane> is used in case of Angle=PI
+//purpose  : 
 //=======================================================================
+AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
+: AIS_Dimension (AIS_KOD_PLANEANGLE)
+{
+  Init();
+  SetMeasuredGeometry (theCone);
+}
 
-AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
-                                        const TopoDS_Edge& theSecondEdge,
-                                        const gp_Pln& thePlane,
-                                        const Handle(Prs3d_DimensionAspect)& theDimensionAspect,
-                                        const Standard_Real theExtensionSize)
-: AIS_Dimension (theDimensionAspect,theExtensionSize),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+//=======================================================================
+//function : Constructor
+//purpose  : 
+//=======================================================================
+AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
+                                        const TopoDS_Face& theSecondFace)
+: AIS_Dimension (AIS_KOD_PLANEANGLE)
 {
-  myShapesNumber = 2;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstShape  = theFirstEdge;
-  mySecondShape = theSecondEdge;
-  SetWorkingPlane (thePlane);
+  Init();
+  SetMeasuredGeometry (theFirstFace, theSecondFace);
 }
 
 //=======================================================================
 //function : Constructor
-//purpose  : Three points dimension
+//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);
+}
 
-AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
-                                        const gp_Pnt& theSecondPoint,
-                                        const gp_Pnt& theThirdPoint)
-: AIS_Dimension(),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+//=======================================================================
+//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)
+  {
+    myPlane = aComputedPlane;
+  }
+
+  SetToUpdate();
+}
+
+//=======================================================================
+//function : SetMeasuredGeometry
+//purpose  : 
+//=======================================================================
+void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
+                                              const gp_Pnt& theSecondPoint,
+                                              const gp_Pnt& theThirdPoint)
 {
-  init();
-  myIsInitialized = Standard_True;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstPoint   = theFirstPoint;
-  myCenter       = theSecondPoint;
-  mySecondPoint  = theThirdPoint;
-  myShapesNumber = 3;
+  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);
+
+  Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
+  if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
+  {
+    ComputePlane();
+  }
+
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : Constructor
-//purpose  : Three points dimension
+//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);
+
+  Standard_Boolean anIsSameLine = isSameLine (myFirstPoint, myCenterPoint, mySecondPoint);
+  if (myIsGeometryValid && !myIsPlaneCustom && !anIsSameLine)
+  {
+    ComputePlane();
+  }
 
-AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
-                                        const gp_Pnt& theSecondPoint,
-                                        const gp_Pnt& theThirdPoint,
-                                        const Handle(Prs3d_DimensionAspect)& theDimensionAspect,
-                                        const Standard_Real theExtensionSize)
-: AIS_Dimension (theDimensionAspect,theExtensionSize),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+  SetToUpdate();
+}
+
+//=======================================================================
+//function : SetMeasuredGeometry
+//purpose  : 
+//=======================================================================
+void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
 {
-  myIsInitialized = Standard_True;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstPoint   = theFirstPoint;
-  myCenter       = theSecondPoint;
-  mySecondPoint  = theThirdPoint;
-  myShapesNumber =3;
+  myFirstShape      = theCone;
+  mySecondShape     = TopoDS_Shape();
+  myThirdShape      = TopoDS_Shape();
+  myGeometryType    = GeometryType_Face;
+  myIsGeometryValid = InitConeAngle();
+
+  if (myIsGeometryValid && !myIsPlaneCustom)
+  {
+    ComputePlane();
+  }
+
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : Constructor
-//purpose  : Cone dimension
+//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()
+{
+  SetType (AIS_TOA_Interior);
+  SetArrowsVisibility (AIS_TOAV_Both);
+  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();
+  // to have an exterior angle presentation, a plane for further constructed circle should be reversed
+  if (myType == AIS_TOA_Exterior)
+  {
+    gp_Ax1 anAxis = aPlane.Axis();
+    gp_Dir aDir = anAxis.Direction();
+    aDir.Reverse();
+    aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
+  }
+
+  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 : GetNormalForMinAngle
+//purpose  :
+//=======================================================================
+gp_Dir AIS_AngleDimension::GetNormalForMinAngle() const
+{
+  const gp_Dir& aNormal = myPlane.Axis().Direction();
+  gp_Dir aFirst (gp_Vec (myCenterPoint, myFirstPoint) );
+  gp_Dir aSecond (gp_Vec (myCenterPoint, mySecondPoint) );
+
+  return aFirst.AngleWithRef (aSecond, aNormal) < 0.0
+    ? aNormal.Reversed()
+    : aNormal;
+}
+
+//=======================================================================
+//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)
+{
+  gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
+
+  // to have an exterior angle presentation, a plane for further constructed circle should be reversed
+  if (myType == AIS_TOA_Exterior)
+  {
+    gp_Ax1 anAxis = aPlane.Axis();
+    gp_Dir aDir = anAxis.Direction();
+    aDir.Reverse();
+    aPlane.SetAxis(gp_Ax1(anAxis.Location(), aDir));
+  }
+
+  // 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);
+  Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec);
+  if (myType == AIS_TOA_Exterior)
+    anAngle = 2.0 * M_PI - anAngle;
+  // it sets 50 points on PI, and a part of points if angle is less
+  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)
+{
+  gp_Pln aPlane (myCenterPoint, GetNormalForMinAngle());
+  
+  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 aSectorOfText = theTextWidth / aRadius;
+    Standard_Real aTextBegin = aParamMid - aSectorOfText * 0.5;
+    Standard_Real aTextEnd = aParamMid + aSectorOfText * 0.5;
+    gp_Pnt aTextPntBeg = ElCLib::Value (aTextBegin, aCircle);
+    gp_Pnt aTextPntEnd = ElCLib::Value (aTextEnd, aCircle);
+
+    // Drawing arcs
+    if (aTextBegin > aParamBeg)
+    {
+      DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
+    }
+    if (aTextEnd < aParamEnd)
+    {
+      DrawArc (thePresentation, aTextPntEnd, theSecondAttach, 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;
+  }
+
+  // Compute working plane so that Y axis is codirectional
+  // with Y axis of text coordinate system (necessary for text alignment)
+  gp_Vec aFirstVec   = gp_Vec (myCenterPoint, myFirstPoint);
+  gp_Vec aSecondVec  = gp_Vec (myCenterPoint, mySecondPoint);
+  gp_Vec aDirectionN = aSecondVec ^ aFirstVec;
+  gp_Vec aDirectionY = aFirstVec + aSecondVec;
+  gp_Vec aDirectionX = aDirectionY ^ aDirectionN;
+
+  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 = aVec1.AngleWithRef (aVec2, GetNormalForMinAngle());
+
+  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)
+{
+  mySelectionGeom.Clear (theMode);
+
+  if (!IsValid())
+  {
+    return;
+  }
+
+  // Parameters for presentation
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
+
+  Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
+
+  Standard_Real 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 aWorkingPlaneDir (GetNormalForMinAngle());
+
+  gp_Dir aFirstExtensionDir  = aWorkingPlaneDir.Reversed() ^ gp_Vec (myCenterPoint, aFirstAttach);
+  gp_Dir aSecondExtensionDir = aWorkingPlaneDir            ^ gp_Vec (myCenterPoint, aSecondAttach);
+
+  gp_Vec aFirstArrowVec  = gp_Vec (aFirstExtensionDir)  * anArrowLength;
+  gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
+
+  if (isArrowsExternal)
+  {
+    aFirstArrowVec.Reverse();
+    aSecondArrowVec.Reverse();
+  }
+
+  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);
+
+  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 || !isArrowVisible(AIS_TOAV_First)) ? aFirstAttach : aFirstArrowEnd,
+                 (isArrowsExternal || !isArrowVisible(AIS_TOAV_Second)) ? aSecondAttach : aSecondArrowEnd,
+                 myCenterPoint,
+                 Abs (GetFlyout()),
+                 theMode);
+      }
+    }
+    break;
+
+    case LabelPosition_Left :
+    {
+      DrawExtension (thePresentation,
+                     anExtensionSize,
+                     (isArrowsExternal && isArrowVisible(AIS_TOAV_First)) ? aFirstArrowEnd : aFirstAttach,
+                     aFirstExtensionDir,
+                     aLabelString,
+                     aLabelWidth,
+                     theMode,
+                     aLabelPosition);
+    }
+    break;
+
+    case LabelPosition_Right :
+    {
+      DrawExtension (thePresentation,
+                     anExtensionSize,
+                     (isArrowsExternal && isArrowVisible(AIS_TOAV_Second)) ? 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 || !isArrowVisible(AIS_TOAV_First)) ? aFirstAttach  : aFirstArrowEnd,
+             (isArrowsExternal || !isArrowVisible(AIS_TOAV_Second)) ? aSecondAttach : aSecondArrowEnd,
+             myCenterPoint,
+             Abs(GetFlyout ()),
+             theMode);
+  }
+
+  // arrows and arrow extensions
+  if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
+  {
+    Prs3d_Root::NewGroup (thePresentation);
+
+    if (isArrowVisible(AIS_TOAV_First))
+      DrawArrow (thePresentation, aFirstArrowBegin,  gp_Dir (aFirstArrowVec));
+    if (isArrowVisible(AIS_TOAV_Second))
+      DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
+  }
+
+  if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
+  {
+    Prs3d_Root::NewGroup (thePresentation);
+
+    if (aHPosition != LabelPosition_Left && isArrowVisible(AIS_TOAV_First))
+    {
+      DrawExtension (thePresentation,
+                     aDimensionAspect->ArrowTailSize(),
+                     aFirstArrowEnd,
+                     aFirstExtensionDir,
+                     THE_EMPTY_LABEL_STRING,
+                     THE_EMPTY_LABEL_WIDTH,
+                     theMode,
+                     LabelPosition_None);
+    }
+
+    if (aHPosition != LabelPosition_Right && isArrowVisible(AIS_TOAV_Second))
+    {
+      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 = aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular());
+
+  theComputedPlane = isParallelLines ? gp_Pln(gp::XOY())
+                                     : gp_Pln (aSecondLin.Location(), gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction()));
+
+  // Compute geometry for this plane and edges
+  Standard_Boolean isInfinite1,isInfinite2;
+  gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
+  Handle(Geom_Curve) aFirstCurve = aFirstLine, aSecondCurve = aSecondLine;
+  if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge,
+                             aFirstCurve, aSecondCurve,
+                             aFirstPoint1, aLastPoint1,
+                             aFirstPoint2, aLastPoint2,
+                             isInfinite1, isInfinite2))
+  {
+    return Standard_False;
+  }
+
+  Standard_Boolean isSameLines = aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
+                              && aFirstLin.Location().IsEqual (aSecondLin.Location(),Precision::Confusion());
+
+  // It can be the same gp_Lin geometry but the different begin and end parameters
+  Standard_Boolean isSameEdges =
+    (aFirstPoint1.IsEqual (aFirstPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aLastPoint2, Precision::Confusion()))
+    || (aFirstPoint1.IsEqual (aLastPoint2, Precision::Confusion()) && aLastPoint1.IsEqual (aFirstPoint2, Precision::Confusion()));
+
+  if (isParallelLines)
+  {
+    // Zero angle, it could not handle this geometry
+    if (isSameLines && isSameEdges)
+    {
+      return Standard_False;
+    }
+
+    // Handle the case of Pi angle
+    const Standard_Real aParam11 = ElCLib::Parameter (aFirstLin, aFirstPoint1);
+    const Standard_Real aParam12 = ElCLib::Parameter (aFirstLin, aLastPoint1);
+    const Standard_Real aParam21 = ElCLib::Parameter (aFirstLin, aFirstPoint2);
+    const Standard_Real aParam22 = ElCLib::Parameter (aFirstLin, aLastPoint2);
+    myCenterPoint = ElCLib::Value ( (Min (aParam11, aParam12) + Max (aParam21, aParam22)) * 0.5, aFirstLin);
+    myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
+    mySecondPoint = myCenterPoint.XYZ() + (aFirstLin.Direction().IsEqual (aSecondLin.Direction(), Precision::Angular())
+      ? aFirstLin.Direction().Reversed().XYZ() * Abs (GetFlyout())
+      : aSecondLin.Direction().XYZ() * Abs (GetFlyout()));
+  }
+  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 aFirstPln, aSecondPln;
+  Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
+  AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
+  Standard_Real aFirstOffset, aSecondOffset;
+
+  AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
+                         aFirstBasisSurf,aFirstSurfType,aFirstOffset);
 
-AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
-: AIS_Dimension(),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
-{
-  init();
-  myIsInitialized = Standard_False;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstShape   = theCone;
-  myShapesNumber = 1;
+  AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
+                         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 : Constructor
-//purpose  : Two faces dimension
+//function : InitTwoFacesAngle
+//purpose  : initialization of angle dimension between two faces
 //=======================================================================
-
-AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
-                                        const TopoDS_Face& theSecondFace,
-                                        const gp_Ax1& theAxis)
-: AIS_Dimension(),
-  myIsFlyoutLines (Standard_True),
-  myFlyout (15.0)
+Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace)
 {
-  init();
-  myIsInitialized = Standard_False;
-  SetKindOfDimension (AIS_KOD_PLANEANGLE);
-  myFirstShape   = theFirstFace;
-  mySecondShape  = theSecondFace;
-  myShapesNumber = 2;
-  gp_Pln aPlane;
-  aPlane.SetAxis (theAxis);
-  SetWorkingPlane (aPlane);
-}
+  TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
+  TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
 
-//=======================================================================
-//function : SetFirstShape
-//purpose  : 
-//=======================================================================
+  gp_Dir aFirstDir, aSecondDir;
+  gp_Pln aFirstPln, aSecondPln;
+  Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
+  AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
+  Standard_Real aFirstOffset, aSecondOffset;
 
-void AIS_AngleDimension::SetFirstShape (const TopoDS_Shape& theShape,
-                                        const Standard_Boolean isSingleShape /*= Standard_False*/)
-{
-  AIS_Dimension::SetFirstShape (theShape);
-  if (isSingleShape)
-    myShapesNumber = 1;
-}
+  AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
+                         aFirstBasisSurf,aFirstSurfType,aFirstOffset);
 
-//=======================================================================
-//function : aboveInBelowCone
-//purpose  : Returns 1 if <theC> center is above of <theCMin> center;
-//                   0 if <theC> center is between <theCMin> and
-//                        <theCMax> centers;
-//                  -1 if <theC> center is below <theCMax> center.
-//=======================================================================
+  AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
+                         aSecondBasisSurf, aSecondSurfType, aSecondOffset);
 
-Standard_Integer AIS_AngleDimension::aboveInBelowCone (const gp_Circ &theCMax,
-                                                       const gp_Circ &theCMin,
-                                                       const gp_Circ &theC)
-{
-  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());
-
-  if (aD >= aD1 && aD >= aD2) return  0;
-  if (aD  < aD2 && aD1 < aD2) return -1;
-  if (aD  < aD1 && aD2 < aD1) return  1;
-  return 0;
+  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
+//function : InitConeAngle
 //purpose  : initialization of the cone angle
 //=======================================================================
-
-Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
+Standard_Boolean AIS_AngleDimension::InitConeAngle()
 {
-  if (theCone.IsNull ())
+  if (myFirstShape.IsNull())
+  {
     return Standard_False;
+  }
 
+  TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
   gp_Pln aPln;
   gp_Cone aCone;
   gp_Circ aCircle;
@@ -322,7 +1098,7 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
   Handle(Geom_ConicalSurface) aConicalSurf;
   Handle(Geom_SurfaceOfRevolution) aRevSurf;
   Handle(Geom_Line) aLine;
-  BRepAdaptor_Surface aConeAdaptor (theCone);
+  BRepAdaptor_Surface aConeAdaptor (aConeShape);
   TopoDS_Face aFace;
   AIS_KindOfSurface aSurfType;
   Standard_Real anOffset = 0.;
@@ -331,7 +1107,7 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
   Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
   Standard_Real aMinV = aConeAdaptor.LastVParameter();
 
-  AIS::GetPlaneFromFace(theCone, aPln, aSurf, aSurfType, anOffset);
+  AIS::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
 
   if (aSurfType == AIS_KOS_Revolution)
   {
@@ -361,7 +1137,7 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
 
     gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
     aCone =  aMkCone.Value();
-    myCenter = aCone.Apex();
+    myCenterPoint = aCone.Apex();
   }
   else
   {
@@ -379,7 +1155,7 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
     }
     aCone = aConeAdaptor.Cone();
     aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
-    myCenter =  aConicalSurf->Apex();
+    myCenterPoint =  aConicalSurf->Apex();
   }
 
   // A circle where the angle is drawn
@@ -393,7 +1169,6 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
   aCurve = aSurf->VIso(aMinV);
   gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
 
-
   if (aCircVmax.Radius() < aCircVmin.Radius())
   {
    gp_Circ aTmpCirc = aCircVmax;
@@ -407,623 +1182,297 @@ Standard_Boolean AIS_AngleDimension::initConeAngle (const TopoDS_Face& theCone)
 }
 
 //=======================================================================
-//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)
-  {
-    //Planar faces angle
-    AIS::ComputeAngleBetweenPlanarFaces (aFirstFace,
-                                        aSecondFace,
-                                        aSecondBasisSurf,
-                                        GetWorkingPlane().Axis(),
-                                        myValue,
-                                        Standard_True,
-                                        myGeom.myTextPosition,
-                                        myCenter,
-                                        myFirstPoint,
-                                        mySecondPoint,
-                                        aFirstDir,
-                                        aSecondDir);
-  }
-  else
-  {
-        // 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());
-  }
-  return Standard_True;
-}
-
-//=======================================================================
-//function : SetFlyout
-//purpose  : 
-//=======================================================================
-
-void AIS_AngleDimension::SetFlyout (const Standard_Real theFlyout)
-{
-  myFlyout = theFlyout;
-}
-
-//=======================================================================
-//function : GetFlyout
+//function : IsValidPoints
 //purpose  : 
 //=======================================================================
-
-Standard_Real AIS_AngleDimension::GetFlyout () const
+Standard_Boolean AIS_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
+                                                    const gp_Pnt& theCenterPoint,
+                                                    const gp_Pnt& theSecondPoint) const
 {
-  return myFlyout;
+  return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
+      && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
+      && gp_Vec (theCenterPoint, theFirstPoint).Angle (
+           gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
 }
 
 //=======================================================================
-//function : countDefaultPlane
-//purpose  : 
+//function : isArrowVisible
+//purpose  : compares given and internal arrows types, returns true if the the type should be shown
 //=======================================================================
-
-void AIS_AngleDimension::countDefaultPlane ()
+Standard_Boolean AIS_AngleDimension::isArrowVisible(const AIS_TypeOfAngleArrowVisibility& theArrowType) const
 {
-  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 <myWorkingPlane>
-  ResetWorkingPlane ();
+  switch (theArrowType)
+  {
+    case AIS_TOAV_Both:
+      return myArrowsVisibility == AIS_TOAV_Both;
+    case AIS_TOAV_First:
+      return myArrowsVisibility == AIS_TOAV_Both || myArrowsVisibility == AIS_TOAV_First;
+    case AIS_TOAV_Second:
+      return myArrowsVisibility == AIS_TOAV_Both || myArrowsVisibility == AIS_TOAV_Second;
+    case AIS_TOAV_None:
+      return false;
+  }
+  return false;
 }
 
 //=======================================================================
-//function : computeValue
+//function : GetTextPosition
 //purpose  : 
 //=======================================================================
-
-void AIS_AngleDimension::computeValue ()
-{
-  gp_Vec aVec1 (myCenter, myFirstPoint),
-         aVec2 (myCenter, mySecondPoint);
-  myValue = aVec1.Angle (aVec2);
-  // To model units
-  AIS_Dimension::computeValue();
-}
-
-//=======================================================================
-//function : initTwoEdgesAngle
-//purpose  : Fill gp_Pnt fields for further presentation computation
-//           If intersection between two edges doesn't exist
-//           <myIsInitialized> is set to false
-//=======================================================================
-
-Standard_Boolean AIS_AngleDimension::initTwoEdgesAngle ()
+const gp_Pnt AIS_AngleDimension::GetTextPosition() 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)
-  {
-    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 ();
-  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)
-  {
-    return Standard_False;
-  }
-
-  gp_Pln aPlane;
-
-  /// PART 1 is for automatic plane computation from two edges if it is possible
-  // Build plane
-  if (!myIsWorkingPlaneCustom)
+  if (!IsValid())
   {
-    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);
-  }
-  else
-  {
-    aPlane = GetWorkingPlane();
+    return gp::Origin();
   }
 
-  // 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))
+  if (IsTextPositionCustom())
   {
-    return Standard_False;
+    return myFixedTextPosition;
   }
 
-  // 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()));
-      }
+  // Counts text position according to the dimension parameters
+  gp_Pnt aTextPosition (gp::Origin());
 
-      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()));
-      }
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
 
-      aSecondLine = new Geom_Line (aSecondLin);
-    }
-  }
+  // Prepare label string and compute its geometrical width
+  Standard_Real aLabelWidth;
+  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
 
-  /// PART 2 is for dimension computation using the working plane
+  gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
+  gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
 
-  if (aFirstLin.Direction ().IsParallel (aSecondLin.Direction (), Precision::Angular ()))
-  {
-    // Parallel lines
-    isSameLines = aFirstLin.Distance(aSecondLin.Location()) <= Precision::Confusion();
-    if (!isSameLines)
-      return Standard_False;
+  // Handle user-defined and automatic arrow placement
+  Standard_Boolean isArrowsExternal = Standard_False;
+  Standard_Integer aLabelPosition = LabelPosition_None;
+  FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
+                    aLabelPosition, isArrowsExternal);
 
-     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
+  // Get text position
+  switch (aLabelPosition & LabelPosition_HMask)
   {
-    // 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())
+  case LabelPosition_HCenter:
     {
-      return Standard_False;
+      aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
     }
-
-    anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
-    myCenter = ElCLib::To3d(aPlane.Position().Ax2(), anIntersectPoint);
-
-    if (isInfinite1 || isInfinite2)
+    break;
+  case LabelPosition_Left:
     {
-      myFirstPoint  = myCenter.Translated (gp_Vec (aFirstLin.Direction())*Abs (GetFlyout()));
-      mySecondPoint = myCenter.Translated (gp_Vec (aSecondLin.Direction())*Abs (GetFlyout()));
-      return Standard_True;
+      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);
     }
-
-    // |
-    // | <- dimension should be here
-    // *----
-    myFirstPoint  = myCenter.Distance (aFirstPoint1) > myCenter.Distance (aLastPoint1) ? aFirstPoint1 : aLastPoint1;
-    mySecondPoint = myCenter.Distance (aFirstPoint2) > myCenter.Distance (aLastPoint2) ? aFirstPoint2 : aLastPoint2;
+    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 Standard_True;
-}
-
-//=======================================================================
-//function : canTextBeInCenter
-//purpose  : Auxiliary method to arrange text and arrows
-//=======================================================================
 
-Standard_Boolean AIS_AngleDimension::canTextBeInCenter (const gp_Pnt& theFirstAttach,
-                                                        const gp_Pnt& theSecondAttach,
-                                                        const Quantity_Length& theTextLength,
-                                                        const Quantity_Length& theArrowLength)
-{
-  gp_Vec anAttachVector (theFirstAttach, theSecondAttach);
-  Standard_Real aValue = anAttachVector.Magnitude();
-  return (aValue < theTextLength + 2.*theArrowLength) ? Standard_False : Standard_True;
+  return aTextPosition;
 }
 
 //=======================================================================
-//function: getCenterOnArc
-//purpose :
+//function : SetTextPosition
+//purpose  : 
 //=======================================================================
-gp_Pnt AIS_AngleDimension::getCenterOnArc (const gp_Pnt& theFirstAttach,
-                                           const gp_Pnt& theSecondAttach)
+void AIS_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
 {
-  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;
-}
-
-//=======================================================================
-//function: drawArcWithText
-//purpose :
-//=======================================================================
+  if (!IsValid())
+  {
+    return;
+  }
 
-void AIS_AngleDimension::drawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
-                                          const gp_Pnt& theFirstAttach,
-                                          const gp_Pnt& theSecondAttach,
-                                          const TCollection_ExtendedString& theText,
-                                          const AIS_DimensionDisplayMode theMode)
-{
-  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());
-  myGeom.myTextPosition = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextCenterOnArc2d);
-
-  // Drawing text
-  gp_Vec aVec (theFirstAttach, theSecondAttach);
-  Standard_Real aTextWidth = drawText (thePresentation,
-                                       myIsTextReversed ? aVec.Reversed() : aVec,
-                                       theText,theMode);
-
-  // 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);
-
-
-  gp_Lin2d aCenterToTextBeginLin = gce_MakeLin2d (aCenter2d, aTextBeginPnt),
-           aCenterToTextEndLin   = gce_MakeLin2d (aCenter2d, aTextEndPnt);
-
-  // 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());
-
-  anInt2d.Perform (aCenterToTextEndLin, aCircle);
-  if (anInt2d.IsDone())
-    if (!anInt2d.IsEmpty())
-      aTextEndOnArc2d = gp_Pnt2d (anInt2d.Point (1).Value());
-
-  gp_Pnt aTextBeginOnArc = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextBeginOnArc2d);
-  gp_Pnt aTextEndOnArc   = ElCLib::To3d (GetWorkingPlane().Position().Ax2(), aTextEndOnArc2d);
-
-  // Drawing arcs
-  if (theMode != AIS_DDM_Text)
+  // The text position point for angle dimension should belong to the working plane.
+  if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
   {
-    drawArc (thePresentation, theFirstAttach, aTextBeginOnArc, myCenter, aRadius, theMode);
-    drawArc (thePresentation, aTextEndOnArc, theSecondAttach, myCenter, aRadius, theMode);
+    throw Standard_ProgramError("The text position point for angle dimension doesn't belong to the working plane.");
   }
 
+  myIsTextPositionFixed = Standard_True;
+  myFixedTextPosition = theTextPos;
 }
 
 //=======================================================================
-//function : drawArc
-//purpose  : draws the arc between two attach points
+//function : AdjustParameters
+//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)
+void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
+                                           Standard_Real& theExtensionSize,
+                                           Prs3d_DimensionTextHorizontalPosition& theAlignment,
+                                           Standard_Real& theFlyout) const
 {
-  Handle(SelectMgr_EntityOwner) anEmptyOwner;
-  Prs3d_Root::CurrentGroup (thePresentation)->
-    SetPrimitivesAspect(myDrawer->DimensionAspect()->LineAspect()->Aspect());
-
-  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)
+  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())
   {
-    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;
   }
-  aPrimSegments->AddVertex (theSecondAttach);
-  aPointArray.SetValue (aPointsOnArc - 1,theSecondAttach);
+  gp_Circ aCircle = aConstructCircle.Value();
 
-  // Fill sensitive list
-  myGeom.mySensitiveSegments.Append(new Select3D_SensitiveCurve(anEmptyOwner,aPointArray));
+  // Default values
+  theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
+  theAlignment = Prs3d_DTHP_Center;
 
-  // Fill display presentation
-  if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
+  Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
+  Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
+  if (aParamEnd < aParamBeg)
   {
-    Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
+    Standard_Real aParam = aParamEnd;
+    aParamEnd = aParamBeg;
+    aParamBeg = aParam;
   }
-  Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
-  if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
+
+  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)
   {
-    Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
+    theFlyout = aRadius;
+    return;
   }
-}
-
-//=======================================================================
-//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();
-  myGeom.mySensitiveSegments.Clear();
-  Handle(SelectMgr_EntityOwner) anEmptyOwner;
+  aParamBeg += M_PI;
+  aParamEnd += M_PI;
+  ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
 
-  if (!myIsInitialized)
+  if (aTextPar > aParamBeg  && aTextPar < aParamEnd)
   {
-    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;
+    theFlyout = -aRadius;
+    return;
   }
 
-  // If initialization failed
-  if (!myIsInitialized)
-    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);
 
-  // Parameters for presentation
-  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
-  Prs3d_Root::CurrentGroup(thePresentation)->
-    SetPrimitivesAspect(aDimensionAspect->LineAspect()->Aspect());
-  Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
-  if (!myIsValueCustom)
-    computeValue ();
-  TCollection_ExtendedString aValueString;
-  Standard_Real aTextLength;
-  getTextWidthAndString (aTextLength, aValueString);
-  if (!myIsWorkingPlaneCustom)
-    countDefaultPlane();
-  gp_Pnt aFirstAttach = myCenter.Translated (gp_Vec(myCenter, myFirstPoint).Normalized() * GetFlyout());
-  gp_Pnt aSecondAttach = myCenter.Translated (gp_Vec(myCenter, mySecondPoint).Normalized() * GetFlyout());
-  // Attach points and radius
-  if (aDimensionAspect->HorizontalTextAlignment () == Prs3d_HTA_Center)
+  if (aFirstDist <= aSecondDist)
   {
-    aDimensionAspect->SetArrowOrientation (Prs3d_DAO_Internal);
+    aRadius = myCenterPoint.Distance (aFirstTextProj);
+    Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
+    theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
 
-    if (!canTextBeInCenter (aFirstAttach, aSecondAttach, aTextLength, anArrowLength))
-    {
-      aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
-      aDimensionAspect->SetHorizontalTextAlignment (Prs3d_HTA_Left);
-    }
+    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
-    aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
+  {
+    aRadius = myCenterPoint.Distance (aSecondTextProj);
 
-  //Arrows positions and directions
-  gp_Vec aFirstArrowVec = (gp_Vec(myCenter, aFirstAttach)^gp_Vec(GetWorkingPlane().Axis().Direction())).Normalized().Reversed()*anArrowLength;
-  gp_Vec aSecondArrowVec = (gp_Vec(myCenter, aSecondAttach)^gp_Vec(GetWorkingPlane().Axis().Direction())).Normalized()*anArrowLength;
+    Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
 
-  gp_Pnt aFirstArrowBegin,
-         aFirstArrowEnd,
-         aSecondArrowBegin,
-         aSecondArrowEnd;
+    theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
 
-  if (aDimensionAspect->GetArrowOrientation() == Prs3d_DAO_External)
-  {
-    aFirstArrowVec.Reverse();
-    aSecondArrowVec.Reverse();
+    theAlignment = Prs3d_DTHP_Right;
 
-    aFirstArrowBegin = aFirstAttach.Translated (aFirstArrowVec);
-    aFirstArrowEnd = aFirstAttach;
-    aSecondArrowBegin = aSecondAttach;
-    aSecondArrowEnd = aSecondAttach.Translated (aSecondArrowVec);
+    gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
+
+    theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
+                ? -aRadius : aRadius;
   }
-  else
+}
+
+//=======================================================================
+//function : FitTextAlignment
+//purpose  : 
+//=======================================================================
+void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
+                                           Standard_Integer& theLabelPosition,
+                                           Standard_Boolean& theIsArrowsExternal) const
+{
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
+
+  Standard_Real 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())
   {
-    aFirstArrowBegin = aFirstAttach;
-    aFirstArrowEnd = aFirstAttach.Translated (aFirstArrowVec);
-    aSecondArrowBegin = aSecondAttach.Translated (aSecondArrowVec);
-    aSecondArrowEnd = aSecondAttach;
+    aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
   }
 
-  // Fill presentation
-  Handle(Graphic3d_ArrayOfSegments) aPrimSegments;
-  Standard_Boolean isTextInCenter = aDimensionAspect->VerticalTextAlignment() == Prs3d_VTA_Center;
-  if (aDimensionAspect->HorizontalTextAlignment() == Prs3d_HTA_Center)
+  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())
   {
-    // Important! Current implementation doesn't draw the extensions here
-    aPrimSegments = new Graphic3d_ArrayOfSegments (4);
-    // Get text begin and end positions (text is positioned in the center between two attach points)
-    gp_Pnt aTextBeginOnArc, aTextEndOnArc, anArcCenter;
-    if (isTextInCenter && aDimensionAspect->IsText3d())
-    {
-      drawArcWithText (thePresentation, aFirstAttach, aSecondAttach, aValueString, (AIS_DimensionDisplayMode)theMode);
-    }
-    else
+    case Prs3d_DAO_External: theIsArrowsExternal = true; break;
+    case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
+    case Prs3d_DAO_Fit:
     {
-      gp_Vec aTextDir (aFirstArrowEnd, aSecondArrowBegin);
-      myGeom.myTextPosition = getCenterOnArc (aFirstArrowEnd, aSecondArrowBegin);
-      drawText (thePresentation,
-                myIsTextReversed ? aTextDir.Reversed() : aTextDir,
-                aValueString, (AIS_DimensionDisplayMode)theMode);
-      if (theMode != AIS_DDM_Text)
-        drawArc (thePresentation, aFirstArrowEnd, aSecondArrowBegin, myCenter, Abs (GetFlyout()), (AIS_DimensionDisplayMode)theMode);
+      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;
     }
   }
-  else
+
+  // Handle user-defined and automatic text placement
+  switch (theHorizontalTextPos)
   {
-    // Lines for extensions
-    gp_Lin aLeftExtension (aFirstAttach,gp_Dir(aFirstArrowVec));
-    gp_Lin aRightExtension (aSecondAttach, gp_Dir(aSecondArrowVec));
-    aPrimSegments = new Graphic3d_ArrayOfSegments (6);
-    gp_Pnt aStartPoint;
-    if (aDimensionAspect->HorizontalTextAlignment() == Prs3d_HTA_Left)
-    {
-       aStartPoint = aFirstArrowBegin;
-       // Short extension
-       aPrimSegments->AddVertex (aSecondArrowEnd);
-       aPrimSegments->AddVertex (aSecondArrowEnd.Translated(gp_Vec(aRightExtension.Direction())*anArrowLength));
-       myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment(anEmptyOwner,
-                                          aSecondArrowEnd,
-                                          aSecondArrowEnd.Translated(gp_Vec(aRightExtension.Direction())*anArrowLength)));
-
-       // Long extension
-       drawExtensionWithText (thePresentation, aStartPoint, aLeftExtension, aValueString, (AIS_DimensionDisplayMode)theMode);
-    }
-    else // Prs3d_HTA_Right
+    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:
     {
-       aStartPoint = aSecondArrowEnd;
-       // Short extension
-       aPrimSegments->AddVertex (aFirstArrowBegin);
-       aPrimSegments->AddVertex (aFirstArrowBegin.Translated (gp_Vec (aLeftExtension.Direction()) * anArrowLength));
-       myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment(anEmptyOwner,
-                                          aFirstArrowBegin,
-                                          aFirstArrowBegin.Translated (gp_Vec (aLeftExtension.Direction()) * anArrowLength)));
-
-       // Long extension
-       drawExtensionWithText (thePresentation, aStartPoint, aRightExtension, aValueString, (AIS_DimensionDisplayMode)theMode);
-    }
+      gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
+      Standard_Real aDimensionWidth = anAttachVector.Magnitude();
+      Standard_Real anArrowsWidth   = anArrowLength * 2.0;
+      Standard_Real aContentWidth   = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
 
-    if (theMode != AIS_DDM_Text)
-    {
-      // Draw main arc
-      drawArc (thePresentation, aFirstArrowEnd, aSecondArrowBegin, myCenter, Abs(GetFlyout ()), (AIS_DimensionDisplayMode)theMode);
+      theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
+      break;
     }
   }
 
-  // Draw flyout lines and arrows in new group.
-  Prs3d_Root::NewGroup (thePresentation)
-    ->SetPrimitivesAspect (myDrawer->DimensionAspect()->LineAspect()->Aspect());
-  if (theMode == AIS_DDM_All && myIsFlyoutLines)
-  {
-    aPrimSegments->AddVertex (myCenter);
-    aPrimSegments->AddVertex (aFirstAttach);
-    aPrimSegments->AddVertex (myCenter);
-    aPrimSegments->AddVertex (aSecondAttach);
-  }
-  if (theMode != AIS_DDM_Text)
+  switch (aDimensionAspect->TextVerticalPosition())
   {
-    Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
-    drawArrow (thePresentation, aFirstAttach, gp_Dir (aFirstArrowVec));
-    drawArrow (thePresentation, aSecondAttach, gp_Dir (aSecondArrowVec));
+    case Prs3d_DTVP_Above  : theLabelPosition |= LabelPosition_Above; break;
+    case Prs3d_DTVP_Below  : theLabelPosition |= LabelPosition_Below; break;
+    case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
   }
-
-  setComputed (Standard_True);
 }