0024845: CLang warnings -Wunused-variable
[occt.git] / src / AIS / AIS_Dimension.cxx
old mode 100644 (file)
new mode 100755 (executable)
index e6f0e34..23b23ee
@@ -1,40 +1,37 @@
-// Copyright (c) 1999-2013 OPEN CASCADE SAS
+// Created on: 2013-11-11
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2013-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.hxx>
 #include <AIS_Dimension.hxx>
-#include <AIS_DimensionDisplayMode.hxx>
+
+#include <AIS.hxx>
 #include <AIS_DimensionOwner.hxx>
-#include <AIS_Drawer.hxx>
 #include <Adaptor3d_HCurve.hxx>
 #include <BRepAdaptor_Curve.hxx>
 #include <BRepAdaptor_Surface.hxx>
-#include <BRepBuilderAPI_MakeEdge.hxx>
-#include <BRepLib_MakeVertex.hxx>
 #include <BRepBndLib.hxx>
-#include <GeomAdaptor_Curve.hxx>
+#include <Bnd_Box.hxx>
 #include <ElCLib.hxx>
 #include <Font_BRepFont.hxx>
 #include <GC_MakeCircle.hxx>
+#include <Geom_Line.hxx>
+#include <GeomAdaptor_Curve.hxx>
 #include <Geom_Circle.hxx>
-#include <Geom_Plane.hxx>
 #include <Geom_TrimmedCurve.hxx>
 #include <gce_MakeDir.hxx>
 #include <gce_MakeLin.hxx>
+#include <gce_MakePln.hxx>
 #include <Graphic3d_ArrayOfSegments.hxx>
 #include <Graphic3d_ArrayOfTriangles.hxx>
 #include <Graphic3d_AspectLine3d.hxx>
 #include <SelectMgr_SequenceOfOwner.hxx>
 #include <Select3D_ListIteratorOfListOfSensitive.hxx>
 #include <Select3D_ListOfSensitive.hxx>
-#include <Select3D_SensitiveBox.hxx>
 #include <Select3D_SensitiveCircle.hxx>
 #include <Select3D_SensitiveGroup.hxx>
+#include <Select3D_SensitiveCurve.hxx>
 #include <Select3D_SensitiveSegment.hxx>
+#include <Select3D_SensitiveTriangle.hxx>
+#include <Select3D_SensitiveTriangulation.hxx>
+#include <Poly_Array1OfTriangle.hxx>
+#include <Poly_Triangulation.hxx>
 #include <Standard_CString.hxx>
+#include <Standard_ProgramError.hxx>
 #include <StdPrs_ShadedShape.hxx>
 #include <StdPrs_WFShape.hxx>
 #include <TCollection_AsciiString.hxx>
 IMPLEMENT_STANDARD_HANDLE(AIS_Dimension, AIS_InteractiveObject)
 IMPLEMENT_STANDARD_RTTIEXT(AIS_Dimension, AIS_InteractiveObject)
 
-//=======================================================================
-//function : Constructor
-//purpose  : 
-//=======================================================================
-
-AIS_Dimension::AIS_Dimension (const Standard_Real theExtensionSize /*= 1.0*/)
-: AIS_InteractiveObject(),
-  myDefaultPlane (gp_Pln (gp::XOY())),
-  myIsWorkingPlaneCustom (Standard_False),
-  myValue (0.0),
-  myIsValueCustom (Standard_False),
-  myUnitsQuantity (TCollection_AsciiString("LENGTH")),
-  myToDisplayUnits (Standard_False),
-  mySpecialSymbol (' '),
-  myDisplaySpecialSymbol (AIS_DSS_No),
-  myIsTextReversed (Standard_False),
-  myTextOffset (DimensionAspect()->ArrowAspect()->Length()),
-  myIsInitialized (Standard_False),
-  myFlyout (0.0),
-  myKindOfDimension (AIS_KOD_NONE),
-  myExtensionSize (theExtensionSize)
+namespace
 {
-  ResetWorkingPlane();
-  // Units default settings
-  UnitsAPI::SetLocalSystem (UnitsAPI_SI);
-  myModelUnits = Units::DictionaryOfUnits()->ActiveUnit (myUnitsQuantity.ToCString());
-  myDisplayUnits = Units::DictionaryOfUnits()->ActiveUnit (myUnitsQuantity.ToCString());
-}
+  // default text strings
+  static const Standard_Utf32Char THE_FILL_CHARACTER ('0');
+  static const TCollection_ExtendedString THE_EMPTY_LABEL;
+  static const TCollection_AsciiString    THE_UNDEFINED_UNITS;
+
+  // default text margin and resolution
+  static const Standard_Real THE_3D_TEXT_MARGIN    = 0.1;
+  static const unsigned int  THE_2D_TEXT_RESOLUTION = 72;
+
+  // default selection priorities
+  static const Standard_Integer THE_NEUTRAL_SEL_PRIORITY = 5;
+  static const Standard_Integer THE_LOCAL_SEL_PRIORITY   = 6;
+};
 
 //=======================================================================
 //function : Constructor
 //purpose  : 
 //=======================================================================
-
-AIS_Dimension::AIS_Dimension (const Handle(Prs3d_DimensionAspect)& theAspect,
-                              const Standard_Real theExtensionSize /*= 1.0*/)
+AIS_Dimension::AIS_Dimension (const AIS_KindOfDimension theType)
 : AIS_InteractiveObject(),
-  myDefaultPlane (gp_Pln (gp::XOY())),
-  myIsWorkingPlaneCustom (Standard_False),
-  myValue (0.0),
+  myCustomValue (0.0),
   myIsValueCustom (Standard_False),
-  myUnitsQuantity (TCollection_AsciiString("LENGTH")),
-  myToDisplayUnits (Standard_False),
   mySpecialSymbol (' '),
   myDisplaySpecialSymbol (AIS_DSS_No),
-  myIsTextReversed (Standard_False),
-  myTextOffset (DimensionAspect()->ArrowAspect()->Length()),
-  myIsInitialized (Standard_False),
+  myGeometryType (GeometryType_UndefShapes),
+  myIsPlaneCustom (Standard_False),
   myFlyout (0.0),
-  myKindOfDimension (AIS_KOD_NONE),
-  myExtensionSize (theExtensionSize)
+  myIsGeometryValid (Standard_False),
+  myKindOfDimension (theType)
 {
-  ResetWorkingPlane();
-  // Units default settings
-  UnitsAPI::SetLocalSystem (UnitsAPI_SI);
-  myModelUnits = Units::DictionaryOfUnits()->ActiveUnit (myUnitsQuantity.ToCString());
-  myDisplayUnits = Units::DictionaryOfUnits()->ActiveUnit (myUnitsQuantity.ToCString());
-  SetDimensionAspect (theAspect);
 }
 
 //=======================================================================
-//function : AcceptDisplayMode
-//purpose  : Checks if display mode <theMode> is allowed to display object.
+//function : SetCustomValue
+//purpose  : 
 //=======================================================================
-
-Standard_Boolean AIS_Dimension::AcceptDisplayMode (const Standard_Integer theMode) const
+void AIS_Dimension::SetCustomValue (const Standard_Real theValue)
 {
-  return theMode == 0 ? Standard_True : Standard_False;
-}
+  if (myIsValueCustom && myCustomValue == theValue)
+  {
+    return;
+  }
 
-//=======================================================================
-//function : computeValue
-//purpose  : Computes dimension value in display units.
-//=======================================================================
+  myIsValueCustom = Standard_True;
 
-void AIS_Dimension::computeValue()
-{
-  UnitsAPI::SetCurrentUnit (myUnitsQuantity.ToCString(), myModelUnits.ToCString());
-  myValue = UnitsAPI::CurrentFromLS (myValue, myUnitsQuantity.ToCString());
-  myValue = valueToDisplayUnits();
+  myCustomValue = theValue;
+
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : countDefaultPlane
+//function : GetPlane
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::countDefaultPlane()
+const gp_Pln& AIS_Dimension::GetPlane() const
 {
+  return myPlane;
 }
 
 //=======================================================================
-//function : GetWorkingPlane
+//function : GetGeometryType
 //purpose  : 
 //=======================================================================
-
-const gp_Pln& AIS_Dimension::GetWorkingPlane() const
+const Standard_Integer AIS_Dimension::GetGeometryType () const
 {
-  return myWorkingPlane;
+  return myGeometryType;
 }
 
 //=======================================================================
-//function : SetWorkingPlane
+//function : SetUserPlane
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::SetWorkingPlane (const gp_Pln& thePlane)
+void AIS_Dimension::SetCustomPlane (const gp_Pln& thePlane)
 {
-  myWorkingPlane = thePlane;
-  myIsWorkingPlaneCustom = Standard_True;
-}
+  myPlane = thePlane;
+  myIsPlaneCustom = Standard_True;
 
-//=======================================================================
-//function : ResetWorkingPlane
-//purpose  : Set default value of working plane
-//=======================================================================
+  // Disable fixed (custom) text position
+  UnsetFixedTextPosition();
 
-void AIS_Dimension::ResetWorkingPlane()
-{
-  myWorkingPlane = myDefaultPlane;
-  myIsWorkingPlaneCustom = Standard_False;
+  // Check validity if geometry has been set already.
+  if (IsValid())
+  {
+    SetToUpdate();
+  }
 }
 
 //=======================================================================
-//function : resetWorkingPlane
-//purpose  : Set default value of working plane
-//           Only for internal use.
+//function : SetDimensionAspect
+//purpose  :
 //=======================================================================
-
-void AIS_Dimension::resetWorkingPlane (const gp_Pln& theNewDefaultPlane)
+void AIS_Dimension::SetDimensionAspect (const Handle(Prs3d_DimensionAspect)& theDimensionAspect)
 {
-  myDefaultPlane = theNewDefaultPlane;
-  ResetWorkingPlane();
+  myDrawer->SetDimensionAspect (theDimensionAspect);
+
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : valueInDisplayUnits
+//function : SetDisplaySpecialSymbol
 //purpose  :
 //=======================================================================
-
-Standard_Real AIS_Dimension::valueToDisplayUnits()
+void AIS_Dimension::SetDisplaySpecialSymbol (const AIS_DisplaySpecialSymbol theDisplaySpecSymbol)
 {
-  return  UnitsAPI::AnyToAny (myValue,
-                              myModelUnits.ToCString(),
-                              myDisplayUnits.ToCString());
-}
+  if (myDisplaySpecialSymbol == theDisplaySpecSymbol)
+  {
+    return;
+  }
 
-//=======================================================================
-//function : KindOfDimension
-//purpose  : 
-//=======================================================================
+  myDisplaySpecialSymbol = theDisplaySpecSymbol;
 
-AIS_KindOfDimension AIS_Dimension::KindOfDimension() const 
-{
-  return myKindOfDimension;
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : SetKindOfDimension
-//purpose  : 
+//function : SetSpecialSymbol
+//purpose  :
 //=======================================================================
-
-void AIS_Dimension::SetKindOfDimension (const AIS_KindOfDimension theKindOfDimension)
+void AIS_Dimension::SetSpecialSymbol (const Standard_ExtCharacter theSpecialSymbol)
 {
-  myKindOfDimension = theKindOfDimension;
-}
+  if (mySpecialSymbol == theSpecialSymbol)
+  {
+    return;
+  }
 
-//=======================================================================
-//function : SetExtensionSize
-//purpose  : 
-//=======================================================================
+  mySpecialSymbol = theSpecialSymbol;
 
-void AIS_Dimension::SetExtensionSize (const Standard_Real theExtensionSize)
-{
-  myExtensionSize = theExtensionSize;
+  SetToUpdate();
 }
-   
+
 //=======================================================================
-//function : GetExtensionSize
-//purpose  : 
+//function : SetSelToleranceForText2d
+//purpose  :
 //=======================================================================
-
-Standard_Real AIS_Dimension::GetExtensionSize() const
+void AIS_Dimension::SetSelToleranceForText2d (const Standard_Real theTol)
 {
-  return myExtensionSize;
+  if (mySelToleranceForText2d == theTol)
+  {
+    return;
+  }
+
+  mySelToleranceForText2d = theTol;
+
+  SetToUpdate();
 }
 
 //=======================================================================
-//function : GetValue
-//purpose  : 
+//function : SetFlyout
+//purpose  :
 //=======================================================================
+void AIS_Dimension::SetFlyout (const Standard_Real theFlyout)
+{
+  if (myFlyout == theFlyout)
+  {
+    return;
+  }
 
-Standard_Real AIS_Dimension::GetValue() const
- {
-  return myValue;
- }
+  myFlyout = theFlyout;
+
+  // Disable fixed text position
+  UnsetFixedTextPosition();
+
+  SetToUpdate();
+}
 
 //=======================================================================
-//function : SetCustomValue
-//purpose  : 
+//function : GetDisplayUnits
+//purpose  :
 //=======================================================================
-
-void AIS_Dimension::SetCustomValue (const Standard_Real theValue)
+const TCollection_AsciiString& AIS_Dimension::GetDisplayUnits() const
 {
-  myValue = theValue;
-  myIsValueCustom = Standard_True;
+  return THE_UNDEFINED_UNITS;
 }
 
 //=======================================================================
-//function : SetFirstShape
-//purpose  : 
+//function : GetModelUnits
+//purpose  :
 //=======================================================================
-
-void AIS_Dimension::SetFirstShape (const TopoDS_Shape& theShape)
+const TCollection_AsciiString& AIS_Dimension::GetModelUnits() const
 {
-  myFirstShape = theShape;
-  myIsInitialized = Standard_False;
-  resetGeom();
+  return THE_UNDEFINED_UNITS;
 }
 
 //=======================================================================
-//function : SetSecondShape
-//purpose  : 
+//function : ValueToDisplayUnits
+//purpose  :
 //=======================================================================
-
-void AIS_Dimension::SetSecondShape (const TopoDS_Shape& theShape)
+Standard_Real AIS_Dimension::ValueToDisplayUnits() const
 {
-  mySecondShape = theShape;
-  myIsInitialized = Standard_False;
-  resetGeom();
+  return UnitsAPI::AnyToAny (GetValue(),
+                             GetModelUnits().ToCString(),
+                             GetDisplayUnits().ToCString());
 }
 
 //=======================================================================
-//function : getTextWidthAndString
+//function : GetValueString
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::getTextWidthAndString (Quantity_Length& theWidth,
-                                           TCollection_ExtendedString& theString) const
+TCollection_ExtendedString AIS_Dimension::GetValueString (Standard_Real& theWidth) const
 {
-  char aValueSimpleStr[25];
-  sprintf (aValueSimpleStr, "%g", GetValue());
-  theString = TCollection_ExtendedString (aValueSimpleStr);
+  // format value string using "sprintf"
+  TCollection_AsciiString aFormatStr = myDrawer->DimensionAspect()->ValueStringFormat();
 
-  if (IsUnitsDisplayed())
-  {
-    theString += " ";
-    theString += TCollection_ExtendedString (myDisplayUnits);
-  }
+  char aFmtBuffer[256];
+  sprintf (aFmtBuffer, aFormatStr.ToCString(), ValueToDisplayUnits());
+  TCollection_ExtendedString aValueStr = TCollection_ExtendedString (aFmtBuffer);
 
-  if (myDisplaySpecialSymbol == AIS_DSS_Before)
+  // add units to values string
+  if (myDrawer->DimensionAspect()->IsUnitsDisplayed())
   {
-    theString = TCollection_ExtendedString (mySpecialSymbol) + theString;
+    aValueStr += " ";
+    aValueStr += TCollection_ExtendedString (GetDisplayUnits());
   }
-  else if (myDisplaySpecialSymbol == AIS_DSS_After)
+
+  switch (myDisplaySpecialSymbol)
   {
-    theString += TCollection_ExtendedString (mySpecialSymbol);
+    case AIS_DSS_Before : aValueStr.Insert (1, mySpecialSymbol); break;
+    case AIS_DSS_After  : aValueStr.Insert (aValueStr.Length() + 1, mySpecialSymbol); break;
+    case AIS_DSS_No     : break;
   }
 
-  // Get font length
-  // Get expansion ratio for getting a width of symbols
+  // Get text style parameters
   Quantity_Color aColor; 
-  Standard_CString aFont;
+  Standard_CString aFontName;
   Standard_Real aFactor;
   Standard_Real aSpace;
-  myDrawer->DimensionAspect()->TextAspect()->Aspect()->Values (aColor, aFont, aFactor, aSpace);
-  theWidth = (myDrawer->DimensionAspect()->TextAspect()->Height() / aFactor) * theString.Length();
+  myDrawer->DimensionAspect()->TextAspect()->Aspect()->Values (aColor, aFontName, aFactor, aSpace);
+  Font_FontAspect aFontAspect = myDrawer->DimensionAspect()->TextAspect()->Aspect()->GetTextFontAspect();
+  Standard_Real   aFontHeight = myDrawer->DimensionAspect()->TextAspect()->Height();
+
+  NCollection_Utf8String anUTFString = (Standard_Utf16Char* )aValueStr.ToExtString();
+
+  theWidth = 0.0;
+
+  if (myDrawer->DimensionAspect()->IsText3d())
+  {
+    // text width produced by BRepFont
+    Font_BRepFont aFont (aFontName, aFontAspect, aFontHeight);
+
+    for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
+    {
+      Standard_Utf32Char aCurrChar = *anIter;
+      Standard_Utf32Char aNextChar = *(++anIter);
+      theWidth += aFont.AdvanceX (aCurrChar, aNextChar);
+    }
+  }
+  else
+  {
+    // Text width for 1:1 scale 2D case
+    Handle(Font_FTFont) aFont = new Font_FTFont();
+    aFont->Init (aFontName, aFontAspect, (const unsigned int)aFontHeight, THE_2D_TEXT_RESOLUTION);
+
+    for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
+    {
+      Standard_Utf32Char aCurrChar = *anIter;
+      Standard_Utf32Char aNextChar = *(++anIter);
+      theWidth += (Standard_Real) aFont->AdvanceX (aCurrChar, aNextChar);
+    }
+  }
+
+  return aValueStr;
 }
 
 //=======================================================================
-//function : drawArrow
+//function : DrawArrow
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::drawArrow (const Handle(Prs3d_Presentation)& thePresentation,
+void AIS_Dimension::DrawArrow (const Handle(Prs3d_Presentation)& thePresentation,
                                const gp_Pnt& theLocation,
                                const gp_Dir& theDirection)
 {
   Prs3d_Root::NewGroup (thePresentation);
-  Quantity_Length anArrowLength = myDrawer->DimensionAspect()->ArrowAspect()->Length();
+
+  Quantity_Length aLength = myDrawer->DimensionAspect()->ArrowAspect()->Length();
+  Standard_Real   anAngle = myDrawer->DimensionAspect()->ArrowAspect()->Angle();
 
   if (myDrawer->DimensionAspect()->IsArrows3d())
   {
     Prs3d_Arrow::Draw (thePresentation,
                        theLocation,
-                       theDirection.Reversed(),
-                       myDrawer->DimensionAspect()->ArrowAspect()->Angle(),
-                       anArrowLength);
+                       theDirection,
+                       anAngle,
+                       aLength);
   }
   else
   {
-    gp_Vec anArrowDir (theDirection);
-    Quantity_Length theCathetusLength = anArrowLength / Cos (M_PI / 9.0);
+    gp_Pnt aLeftPoint (gp::Origin());
+    gp_Pnt aRightPoint (gp::Origin());
+    const gp_Dir& aPlane = GetPlane().Axis().Direction();
+
+    PointsForArrow (theLocation, theDirection, aPlane, aLength, anAngle, aLeftPoint, aRightPoint);
+
     Handle(Graphic3d_ArrayOfTriangles) anArrow = new Graphic3d_ArrayOfTriangles(3);
-    gp_Pnt aLeftPoint (theLocation.Translated (anArrowDir.Rotated (myWorkingPlane.Axis(), M_PI / 9.0) * theCathetusLength));
-    gp_Pnt aRightPoint (theLocation.Translated (anArrowDir.Rotated (myWorkingPlane.Axis(), M_PI * 17.0 / 9.0) * theCathetusLength));
 
     anArrow->AddVertex (aLeftPoint);
     anArrow->AddVertex (theLocation);
@@ -385,92 +386,119 @@ void AIS_Dimension::drawArrow (const Handle(Prs3d_Presentation)& thePresentation
     aShadeMat.SetReflectionModeOff (Graphic3d_TOR_AMBIENT);
     aShadeMat.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE);
     aShadeMat.SetReflectionModeOff (Graphic3d_TOR_SPECULAR);
-    myDrawer->ShadingAspect()->Aspect()->SetInteriorColor (aColor);
-    myDrawer->ShadingAspect()->Aspect()->SetBackInteriorColor (aColor);
-    myDrawer->ShadingAspect()->SetMaterial (aShadeMat);
-    Prs3d_Root::CurrentGroup(thePresentation)->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
-    Prs3d_Root::CurrentGroup(thePresentation)->AddPrimitiveArray (anArrow);
+
+    Handle(Prs3d_ShadingAspect) aShadingStyle = new Prs3d_ShadingAspect();
+    aShadingStyle->SetColor (aColor);
+    aShadingStyle->SetMaterial (aShadeMat);
+
+    Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aShadingStyle->Aspect());
+    Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (anArrow);
   }
+
+  SelectionGeometry::Arrow& aSensitiveArrow = mySelectionGeom.NewArrow();
+  aSensitiveArrow.Position  = theLocation;
+  aSensitiveArrow.Direction = theDirection;
 }
 
 //=======================================================================
-//function : drawText
+//function : DrawText
 //purpose  : 
 //=======================================================================
-
-Standard_Real AIS_Dimension::drawText (const Handle(Prs3d_Presentation)& thePresentation,
-                                       const gp_Dir& theTextDir,
-                                       const TCollection_ExtendedString theText,
-                                       const AIS_DimensionDisplayMode theMode)
+void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
+                              const gp_Pnt& theTextPos,
+                              const gp_Dir& theTextDir,
+                              const TCollection_ExtendedString& theText,
+                              const Standard_Integer theLabelPosition)
 {
-  Standard_Real aTextWidth (0.0), aTextHeight (0.0);
-  if (theMode == AIS_DDM_Line)
-    return aTextWidth;
-  // Creating new group for text
-  Prs3d_Root::NewGroup (thePresentation);
-
   if (myDrawer->DimensionAspect()->IsText3d())
   {
-    // Getting font parameters
+    // getting font parameters
     Quantity_Color aColor;
     Standard_CString aFontName;
     Standard_Real anExpansionFactor;
     Standard_Real aSpace;
     myDrawer->DimensionAspect()->TextAspect()->Aspect()->Values (aColor, aFontName, anExpansionFactor, aSpace);
     Font_FontAspect aFontAspect = myDrawer->DimensionAspect()->TextAspect()->Aspect()->GetTextFontAspect();
-    Standard_Real aHeight = myDrawer->DimensionAspect()->TextAspect()->Height();
-
-    // Creating TopoDS_Shape for text
-    Font_BRepFont aFont (aFontName, aFontAspect, aHeight);
-    NCollection_String aText = (Standard_Utf16Char* )theText.ToExtString();
-    TopoDS_Shape aTextShape = aFont.RenderText (aText);
-
-    // Formating text position in XOY plane
-    Bnd_Box aTextBndBox;
-    BRepBndLib::AddClose (aTextShape, aTextBndBox);
-    Standard_Real aXMin, anYMin, aZMin, aXMax, anYMax, aZMax;
-    aTextBndBox.Get (aXMin, anYMin, aZMin, aXMax, anYMax, aZMax);
-    aTextWidth  = aXMax  - aXMin;
-    aTextHeight = anYMax - anYMin;
-    gp_Dir aTextDir (theTextDir);
-    Standard_Real aHorizontalOffset (0.0), aVerticalOffset (0.0);
-    switch (myDrawer->DimensionAspect()->HorizontalTextAlignment())
+    Standard_Real aFontHeight = myDrawer->DimensionAspect()->TextAspect()->Height();
+
+    // creating TopoDS_Shape for text
+    Font_BRepFont aFont (aFontName, aFontAspect, aFontHeight);
+    NCollection_Utf8String anUTFString = (Standard_Utf16Char* )theText.ToExtString();
+    TopoDS_Shape aTextShape = aFont.RenderText (anUTFString);
+
+    // compute text width with kerning
+    Standard_Real aTextWidth  = 0.0;
+    Standard_Real aTextHeight = aFont.Ascender() + aFont.Descender();
+
+    for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
+    {
+      Standard_Utf32Char aCurrChar = *anIter;
+      Standard_Utf32Char aNextChar = *(++anIter);
+      aTextWidth += aFont.AdvanceX (aCurrChar, aNextChar);
+    }
+
+    // formating text position in XOY plane
+    Standard_Integer aHLabelPos = theLabelPosition & LabelPosition_HMask;
+    Standard_Integer aVLabelPos = theLabelPosition & LabelPosition_VMask;
+
+    gp_Dir aTextDir (aHLabelPos == LabelPosition_Left ? -theTextDir : theTextDir);
+
+    // compute label offsets
+    Standard_Real aMarginSize    = aFontHeight * THE_3D_TEXT_MARGIN;
+    Standard_Real aCenterHOffset = 0.0;
+    Standard_Real aCenterVOffset = 0.0;
+    switch (aHLabelPos)
     {
-      case Prs3d_HTA_Left:
-        aTextDir.Reverse();
-        aHorizontalOffset = -aTextWidth;
-        break;
-      case Prs3d_HTA_Center:
-        aHorizontalOffset = -(aTextWidth / 2.0);
-        break;
-      case Prs3d_HTA_Right:
-        aHorizontalOffset = 0.0;
-        break;
+      case LabelPosition_HCenter : aCenterHOffset =  0.0; break;
+      case LabelPosition_Right   : aCenterHOffset =  aTextWidth / 2.0 + aMarginSize; break;
+      case LabelPosition_Left    : aCenterHOffset = -aTextWidth / 2.0 - aMarginSize; break;
     }
-    switch (myDrawer->DimensionAspect()->VerticalTextAlignment())
+    switch (aVLabelPos)
     {
-      case Prs3d_VTA_Top:
-        aVerticalOffset = 0.0;
-        break;
-      case Prs3d_VTA_Center:
-        aVerticalOffset = -(aTextHeight / 2.0);
-        break;
-      case Prs3d_VTA_Bottom:
-        aVerticalOffset = -aTextHeight;
-        break;
+      case LabelPosition_VCenter : aCenterVOffset =  0.0; break;
+      case LabelPosition_Above   : aCenterVOffset =  aTextHeight / 2.0 + aMarginSize; break;
+      case LabelPosition_Below   : aCenterVOffset = -aTextHeight / 2.0 - aMarginSize; break;
     }
-    gp_Trsf aTrsf;
-    aTrsf.SetTranslation (gp_Pnt (), gp_Pnt (aHorizontalOffset, aVerticalOffset, 0.0));
-    aTextShape.Move (aTrsf);
-
-    // Transform text to myWorkingPlane coordinate system
-    gp_Ax3 aPenAx3 (myGeom.myTextPosition, myWorkingPlane.Axis().Direction(), aTextDir);
-    aTrsf.SetTransformation (aPenAx3, gp_Ax3 (gp::XOY()));
-    aTextShape.Move (aTrsf);
-
-    // Set display parameters for advanced selection
-    BRepBndLib::AddClose (aTextShape, myGeom.myTextBndBox);
-    // Drawing text
+
+    // compute shape offset transformation
+    Standard_Real aShapeHOffset = aCenterHOffset - aTextWidth / 2.0;
+    Standard_Real aShapeVOffset = aCenterVOffset - aTextHeight / 2.0;
+
+    // center shape in its bounding box (suppress border spacing added by FT_Font)
+    Bnd_Box aShapeBnd;
+    BRepBndLib::AddClose (aTextShape, aShapeBnd);
+
+    Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
+    aShapeBnd.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+
+    Standard_Real aXalign = aTextWidth  * 0.5 - (aXmax + aXmin) * 0.5;
+    Standard_Real aYalign = aTextHeight * 0.5 - (aYmax + aYmin) * 0.5;
+    aShapeHOffset += aXalign;
+    aShapeVOffset += aYalign;
+
+    gp_Trsf anOffsetTrsf;
+    anOffsetTrsf.SetTranslation (gp::Origin(), gp_Pnt (aShapeHOffset, aShapeVOffset, 0.0));
+    aTextShape.Move (anOffsetTrsf);
+
+    // transform text to myWorkingPlane coordinate system
+    gp_Ax3 aTextCoordSystem (theTextPos, GetPlane().Axis().Direction(), aTextDir);
+    gp_Trsf aTextPlaneTrsf;
+    aTextPlaneTrsf.SetTransformation (aTextCoordSystem, gp_Ax3 (gp::XOY()));
+    aTextShape.Move (aTextPlaneTrsf);
+
+    // set text flipping anchors
+    gp_Trsf aCenterOffsetTrsf;
+    gp_Pnt aCenterOffset (aCenterHOffset, aCenterVOffset, 0.0);
+    aCenterOffsetTrsf.SetTranslation (gp::Origin(), aCenterOffset);
+
+    gp_Pnt aCenterOfLabel (gp::Origin());
+    aCenterOfLabel.Transform (aCenterOffsetTrsf);
+    aCenterOfLabel.Transform (aTextPlaneTrsf);
+
+    gp_Ax2 aFlippingAxes (aCenterOfLabel, GetPlane().Axis().Direction(), aTextDir);
+    Prs3d_Root::CurrentGroup (thePresentation)->SetFlippingOptions (Standard_True, aFlippingAxes);
+
+    // draw text
     if (myDrawer->DimensionAspect()->IsTextShaded())
     {
       // Setting text shading and color parameters
@@ -482,428 +510,500 @@ Standard_Real AIS_Dimension::drawText (const Handle(Prs3d_Presentation)& thePres
       myDrawer->ShadingAspect()->Aspect()->SetBackInteriorColor (aColor);
       myDrawer->ShadingAspect()->SetMaterial (aShadeMat);
 
-      // Drawing text
+      // drawing text
       StdPrs_ShadedShape::Add (thePresentation, aTextShape, myDrawer);
     }
     else
     {
-      // Setting color for text
+      // setting color for text
       myDrawer->FreeBoundaryAspect()->Aspect()->SetColor (aColor);
-      // Drawing text
+      // drawing text
       StdPrs_WFShape::Add (thePresentation, aTextShape, myDrawer);
     }
-    // Creating new group for lines
-    Prs3d_Root::NewGroup (thePresentation);
-  }
-  else
-  {
-    myDrawer->DimensionAspect()->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_DIMENSION);
-    Prs3d_Text::Draw (thePresentation,
-                      myDrawer->DimensionAspect()->TextAspect(),
-                      theText,
-                      myGeom.myTextPosition);
-
-    // For 2d text we don not create new group for lines and draw them in the same group with text
-    // for the proper handling of stencil test buffer.
-  }
+    Prs3d_Root::CurrentGroup (thePresentation)->SetFlippingOptions (Standard_False, gp_Ax2());
 
-  return aTextWidth;
-}
-
-  //=======================================================================
-//function : drawExtensionWithText
-//purpose  : 
-//=======================================================================
+    mySelectionGeom.TextPos    = aCenterOfLabel;
+    mySelectionGeom.TextDir    = aTextDir;
+    mySelectionGeom.TextWidth  = aTextWidth + aMarginSize * 2.0;
+    mySelectionGeom.TextHeight = aTextHeight;
 
-void AIS_Dimension::drawExtensionWithText (const Handle(Prs3d_Presentation)& thePresentation,
-                                           const gp_Pnt& theStartPoint,
-                                           const gp_Lin& theDimensionLine,
-                                           const TCollection_ExtendedString& theValueString,
-                                           const AIS_DimensionDisplayMode theMode)
-{
-  Handle(SelectMgr_EntityOwner) anEmptyOwner;
-  Standard_Boolean isGapInCenter = (myDrawer->DimensionAspect()->VerticalTextAlignment() == Prs3d_VTA_Center
-                                    && myDrawer->DimensionAspect()->IsText3d());
-
-  Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (isGapInCenter ? 4 : 2);
-
-  gp_Dir anAttachPointsVector = myWorkingPlane.Axis().Direction() ^ gce_MakeDir (myFirstPoint, mySecondPoint);
-  Standard_Real aGap = 1.;
-  Standard_Real aStartParam = ElCLib::Parameter (theDimensionLine, theStartPoint);
-
-  // Text
-  Standard_Real aTextParam = isGapInCenter ? aStartParam + myTextOffset + aGap : aStartParam + myTextOffset;
-  myGeom.myTextPosition = ElCLib::Value (aTextParam, theDimensionLine);
-  Standard_Real aTextWidth = drawText (thePresentation,
-                                       myIsTextReversed ? theDimensionLine.Direction().Reversed()
-                                                        : theDimensionLine.Direction(),
-                                       theValueString,
-                                       theMode);
-  gp_Pnt aFirstPoint, aLastPoint;
-  aFirstPoint = theStartPoint;
-  Standard_Real aParam = isGapInCenter ? aTextParam + aTextWidth + aGap : aTextParam + aTextWidth;
-
-  // If text separates dimension line into two parts (4 points)
-  if (isGapInCenter)
-  {
-    aLastPoint = ElCLib::Value (aStartParam + myTextOffset, theDimensionLine);
-    aPrimSegments->AddVertex (aFirstPoint);
-    aPrimSegments->AddVertex (aLastPoint);
-    myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
-    aFirstPoint = ElCLib::Value (aParam, theDimensionLine);
+    return;
   }
 
-  // Draw additional line segment only after 3D text
-  if (myDrawer->DimensionAspect()->IsText3d())
-  {
-    aParam += myTextOffset;
-  }
+  // generate primitives for 2D text
+  myDrawer->DimensionAspect()->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_DIMENSION);
 
-  aLastPoint = ElCLib::Value (aParam, theDimensionLine);
-  aPrimSegments->AddVertex (aFirstPoint);
-  aPrimSegments->AddVertex (aLastPoint);
-  myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
+  Prs3d_Text::Draw (thePresentation,
+                    myDrawer->DimensionAspect()->TextAspect(),
+                    theText,
+                    theTextPos);
 
-  // Extension line in the same group
-  if (theMode != AIS_DDM_Text)
-  {
-    if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
-    {
-      Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
-    }
-    Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (myDrawer->DimensionAspect()->LineAspect()->Aspect());
-    Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
-    if (!myDrawer->DimensionAspect()->IsText3d() && theMode == AIS_DDM_All)
-    {
-      Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
-    }
-  }
+  mySelectionGeom.TextPos    = theTextPos;
+  mySelectionGeom.TextDir    = theTextDir;
+  mySelectionGeom.TextWidth  = 0.0;
+  mySelectionGeom.TextHeight = 0.0;
 }
 
 //=======================================================================
-//function : SetDimensionAspect
+//function : DrawExtension
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::SetDimensionAspect (const Handle(Prs3d_DimensionAspect)& theDimensionAspect)
+void AIS_Dimension::DrawExtension (const Handle(Prs3d_Presentation)& thePresentation,
+                                   const Standard_Real theExtensionSize,
+                                   const gp_Pnt& theExtensionStart,
+                                   const gp_Dir& theExtensionDir,
+                                   const TCollection_ExtendedString& theLabelString,
+                                   const Standard_Real theLabelWidth,
+                                   const Standard_Integer theMode,
+                                   const Standard_Integer theLabelPosition)
 {
-  myDrawer->SetDimensionAspect (theDimensionAspect);
-}
+  // reference line for extension starting at its connection point
+  gp_Lin anExtensionLine (theExtensionStart, theExtensionDir);
 
-//=======================================================================
-//function : DimensionAspect
-//purpose  : 
-//=======================================================================
+  Standard_Boolean hasLabel = theLabelString.Length() > 0;
+  if (hasLabel && (theMode == ComputeMode_All || theMode == ComputeMode_Text))
+  {
+    // compute text primitives; get its model width
+    gp_Pnt aTextPos = ElCLib::Value (theExtensionSize, anExtensionLine);
+    gp_Dir aTextDir = theExtensionDir;
+
+    DrawText (thePresentation,
+              aTextPos,
+              aTextDir,
+              theLabelString,
+              theLabelPosition);
+  }
 
-Handle(Prs3d_DimensionAspect) AIS_Dimension::DimensionAspect() const
-{
-  return myDrawer->DimensionAspect();
-}
+  if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
+  {
+    return;
+  }
 
-//=======================================================================
-//function : SetTextOffset
-//purpose  : 
-//=======================================================================
+  Standard_Boolean isShortLine =  !myDrawer->DimensionAspect()->IsText3d()
+                               || theLabelPosition & LabelPosition_VCenter;
 
-void AIS_Dimension::SetTextOffset (const Standard_Real theOffset)
-{
-  myTextOffset = theOffset;
-}
+  // compute graphical primitives and sensitives for extension line
+  gp_Pnt anExtStart = theExtensionStart;
+  gp_Pnt anExtEnd   = !hasLabel || isShortLine
+    ? ElCLib::Value (theExtensionSize, anExtensionLine)
+    : ElCLib::Value (theExtensionSize + theLabelWidth, anExtensionLine);
 
-//=======================================================================
-//function : TextOffset
-//purpose  : 
-//=======================================================================
+  // add graphical primitives
+  Handle(Graphic3d_ArrayOfSegments) anExtPrimitive = new Graphic3d_ArrayOfSegments (2);
+  anExtPrimitive->AddVertex (anExtStart);
+  anExtPrimitive->AddVertex (anExtEnd);
 
-Standard_Real AIS_Dimension::TextOffset() const
-{
-  return myTextOffset;
+  // add selection primitives
+  SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
+  aSensitiveCurve.Append (anExtStart);
+  aSensitiveCurve.Append (anExtEnd);
+
+  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 (anExtPrimitive);
+  if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
+  {
+    Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
+  }
 }
 
 //=======================================================================
-//function : drawLinearDimension
+//function : DrawLinearDimension
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::drawLinearDimension (const Handle(Prs3d_Presentation)& thePresentation,
-                                         const gp_Pnt& theFirstAttach,
-                                         const gp_Pnt& theSecondAttach,
-                                         const AIS_DimensionDisplayMode theMode,
-                                         const Standard_Boolean isOneSideDimension/* = Standard_False*/)
+void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePresentation,
+                                         const Standard_Integer theMode,
+                                         const gp_Pnt& theFirstPoint,
+                                         const gp_Pnt& theSecondPoint,
+                                         const Standard_Boolean theIsOneSide)
 {
-  // Don't build any dimension for equal points
-  if (myFirstPoint.IsEqual (mySecondPoint, Precision::Confusion()))
+  // do not build any dimension for equal points
+  if (theFirstPoint.IsEqual (theSecondPoint, Precision::Confusion()))
   {
-    setComputed (Standard_False);
-    return;
+    Standard_ProgramError::Raise ("Can not build presentation for equal points.");
   }
-  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
-  Handle(SelectMgr_EntityOwner) anEmptyOwner;
-  myGeom.mySensitiveSegments.Clear();
 
-  gp_Dir aAttachPointsVector = GetWorkingPlane().Axis().Direction()^gce_MakeDir (myFirstPoint, mySecondPoint);
-  // Get line of the dimension
-  gp_Lin aDimensionLine = gce_MakeLin (theFirstAttach, theSecondAttach);
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
 
-  // Get parameters on dimension line of two layout points
-  Standard_Real aParam1 = ElCLib::Parameter (aDimensionLine, theFirstAttach);
-  Standard_Real aParam2 = ElCLib::Parameter (aDimensionLine, theSecondAttach);
+  // For extensions we need to know arrow size, text size and extension size: get it from aspect
+  Quantity_Length anArrowLength   = aDimensionAspect->ArrowAspect()->Length();
+  Standard_Real   anExtensionSize = aDimensionAspect->ExtensionSize();
+  // prepare label string and compute its geometrical width
+  Standard_Real aLabelWidth;
+  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
 
-  // For extensions we need to know arrow size and text size, get it from aspect
-  Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
-  // Set line parameters
-  Standard_Real aGap = 0.; // gap between line and text if AIS_VTA_Center
-  if (!myIsValueCustom)
+  // add margins to cut dimension lines for 3d text
+  if (aDimensionAspect->IsText3d())
   {
-   computeValue();
+    aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
   }
 
-  TCollection_ExtendedString aValueString;
-  Standard_Real aTextLength;
-  getTextWidthAndString (aTextLength, aValueString);
+  // handle user-defined and automatic arrow placement
+  Standard_Boolean isArrowsExternal = Standard_False;
+  Standard_Integer aLabelPosition = LabelPosition_None;
 
-  // Automatical text and arrow placement
-  Standard_Real aValue = myFirstPoint.Distance (mySecondPoint);
-  if (aDimensionAspect->HorizontalTextAlignment() == Prs3d_HTA_Center)
+  Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
+  if (IsTextPositionCustom())
   {
-    aDimensionAspect->SetArrowOrientation (Prs3d_DAO_Internal);
-    if (aValue < aTextLength + (isOneSideDimension ? anArrowLength : 2.0 * anArrowLength))
+    if (!AdjustParametersForLinear (myFixedTextPosition, theFirstPoint, theSecondPoint,
+                                    anExtensionSize, aHorisontalTextPos, myFlyout, myPlane, myIsPlaneCustom))
     {
-      aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
-      aDimensionAspect->SetHorizontalTextAlignment (Prs3d_HTA_Left);
+      Standard_ProgramError::Raise ("Can not adjust plane to the custom label position.");
     }
   }
-  else
-  {
-    aDimensionAspect->SetArrowOrientation (Prs3d_DAO_External);
-  }
 
-  // Arrows positions and directions
-  gp_Pnt aFirstArrowPosition = ElCLib::Value (aParam1, aDimensionLine);
-  gp_Pnt aSecondArrowPosition = ElCLib::Value (aParam2, aDimensionLine);
-  gp_Dir aFirstArrowDir = aDimensionLine.Direction();
-  gp_Dir aSecondArrowDir = aDimensionLine.Direction().Reversed();
-  Standard_Real aFirstArrowBegin, aFirstArrowEnd, aSecondArrowBegin, aSecondArrowEnd;
+  FitTextAlignmentForLinear (theFirstPoint, theSecondPoint, theIsOneSide, aHorisontalTextPos,
+                             aLabelPosition, isArrowsExternal);
 
-  if (aDimensionAspect->GetArrowOrientation() == Prs3d_DAO_External)
+    // compute dimension line points
+  gp_Ax1 aPlaneNormal = GetPlane().Axis();
+  gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
+
+  // compute flyout direction vector
+  gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
+
+  // create lines for layouts
+  gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
+  gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
+
+  // Get flyout end points
+  gp_Pnt aLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
+  gp_Pnt aLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
+
+  gp_Lin aDimensionLine = gce_MakeLin (aLineBegPoint, aLineEndPoint);
+
+  // compute arrows positions and directions
+  gp_Dir aFirstArrowDir       = aDimensionLine.Direction().Reversed();
+  gp_Dir aSecondArrowDir      = aDimensionLine.Direction();
+  gp_Dir aFirstExtensionDir   = aDimensionLine.Direction().Reversed();
+  gp_Dir aSecondExtensionDir  = aDimensionLine.Direction();
+
+  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)
   {
     aFirstArrowDir.Reverse();
     aSecondArrowDir.Reverse();
-
-    aFirstArrowBegin  = aParam1 - anArrowLength;
-    aFirstArrowEnd    = aParam1;
-    aSecondArrowBegin = aParam2;
-    aSecondArrowEnd   = aParam2 + anArrowLength;
-  }
-  else
-  {
-    aFirstArrowBegin  = aParam1;
-    aFirstArrowEnd    = aParam1 + anArrowLength;
-    aSecondArrowBegin = aParam2 - anArrowLength;
-    aSecondArrowEnd   = aParam2;
   }
 
-  Handle(Graphic3d_ArrayOfSegments) aPrimSegments;
-  gp_Pnt aFirstPoint, aLastPoint;
-  // Take into account vertical text alignment:
-  // only for 3D text! subtract the text length if it is in the center.
-  Standard_Boolean isGapInCenter = (aDimensionAspect->VerticalTextAlignment() == Prs3d_VTA_Center
-                                     && aDimensionAspect->IsText3d());
-  if (isGapInCenter)
-  {
-    aGap = 1.0;
-  }
+  aFirstArrowBegin  = aLineBegPoint;
+  aSecondArrowBegin = aLineEndPoint;
+  aFirstArrowEnd    = aLineBegPoint.Translated (-gp_Vec (aFirstArrowDir).Scaled (anArrowLength));
+  aSecondArrowEnd   = aLineEndPoint.Translated (-gp_Vec (aSecondArrowDir).Scaled (anArrowLength));
+
+  gp_Pnt aCenterLineBegin = isArrowsExternal 
+    ? aLineBegPoint : aFirstArrowEnd;
+
+  gp_Pnt aCenterLineEnd = isArrowsExternal || theIsOneSide
+    ? aLineEndPoint : aSecondArrowEnd;
 
-  switch (aDimensionAspect->HorizontalTextAlignment())
+
+  switch (aLabelPosition & LabelPosition_HMask)
   {
-    // Default case - text is to be in the center of length dimension line
-    case Prs3d_HTA_Center:
+    // ------------------------------------------------------------------------ //
+    //                                CENTER                                    //
+    // -------------------------------------------------------------------------//
+    case LabelPosition_HCenter:
     {
-      // Group1: arrows
-      if (theMode != AIS_DDM_Text)
-      {
-        drawArrow (thePresentation, aFirstArrowPosition, aFirstArrowDir);
-        if (!isOneSideDimension)
-        {
-          drawArrow (thePresentation, aSecondArrowPosition, aSecondArrowDir);
-        }
-      }
-
-      // Group 2: Text and dimension line
-      aPrimSegments = new Graphic3d_ArrayOfSegments (isGapInCenter ? 4 : 2);
-      myGeom.myTextPosition = ElCLib::Value ((aParam1 + aParam2) / 2.0, aDimensionLine);
+      // add label on dimension or extension line to presentation
+      Prs3d_Root::NewGroup (thePresentation);
 
-      gp_Vec aTextDir (myFirstPoint, mySecondPoint);
-      Standard_Real aTextWidth = drawText (thePresentation,
-                                           myIsTextReversed ? aTextDir.Reversed() : aTextDir,
-                                           aValueString,
-                                           theMode);
+      gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
+                                              : (aCenterLineBegin.XYZ() + aCenterLineEnd.XYZ()) * 0.5;
+      gp_Dir aTextDir = aDimensionLine.Direction();
 
-      aFirstPoint = ElCLib::Value (aFirstArrowEnd, aDimensionLine);
-      if (isGapInCenter)
-      {
-        aLastPoint = ElCLib::Value (ElCLib::Parameter (aDimensionLine,myGeom.myTextPosition) - aGap - (aTextWidth / 2.0), aDimensionLine);
-        aPrimSegments->AddVertex (aFirstPoint);
-        aPrimSegments->AddVertex (aLastPoint);
-        myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner,aFirstPoint,aLastPoint));
-        aFirstPoint = ElCLib::Value (ElCLib::Parameter(aDimensionLine,myGeom.myTextPosition) + (aTextWidth / 2.0) + aGap, aDimensionLine);
-      }
-      else if (aDimensionAspect->VerticalTextAlignment() == Prs3d_VTA_Top)
+      // add text primitives
+      if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
       {
-        aDimensionAspect->TextAspect()->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
+        DrawText (thePresentation,
+                  aTextPos,
+                  aTextDir,
+                  aLabelString,
+                  aLabelPosition);
       }
-      else if (aDimensionAspect->VerticalTextAlignment() == Prs3d_VTA_Bottom)
+
+      // add dimension line primitives
+      if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        aDimensionAspect->TextAspect()->SetVerticalJustification(Graphic3d_VTA_TOP);
-      }
+        Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
+                                    && aDimensionAspect->IsText3d();
 
-      aLastPoint = isOneSideDimension ? theSecondAttach : ElCLib::Value (aSecondArrowBegin, aDimensionLine);
+        Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (isLineBreak ? 4 : 2);
+
+        // compute continuous or sectioned main line segments
+        if (isLineBreak)
+        {
+          Standard_Real aPTextPosition = ElCLib::Parameter (aDimensionLine, aTextPos);
+          gp_Pnt aSection1Beg = aCenterLineBegin;
+          gp_Pnt aSection1End = ElCLib::Value (aPTextPosition - (aLabelWidth * 0.5), aDimensionLine);
+          gp_Pnt aSection2Beg = ElCLib::Value (aPTextPosition + (aLabelWidth * 0.5), aDimensionLine);
+          gp_Pnt aSection2End = aCenterLineEnd;
+
+          aPrimSegments->AddVertex (aSection1Beg);
+          aPrimSegments->AddVertex (aSection1End);
+          aPrimSegments->AddVertex (aSection2Beg);
+          aPrimSegments->AddVertex (aSection2End);
+
+          SelectionGeometry::Curve& aLeftSensitiveCurve  = mySelectionGeom.NewCurve();
+          SelectionGeometry::Curve& aRightSensitiveCurve = mySelectionGeom.NewCurve();
+          aLeftSensitiveCurve.Append (aSection1Beg);
+          aLeftSensitiveCurve.Append (aSection1End);
+          aRightSensitiveCurve.Append (aSection2Beg);
+          aRightSensitiveCurve.Append (aSection2End);
+        }
+        else
+        {
+          aPrimSegments->AddVertex (aCenterLineBegin);
+          aPrimSegments->AddVertex (aCenterLineEnd);
 
-      aPrimSegments->AddVertex (aFirstPoint);
-      aPrimSegments->AddVertex (aLastPoint);
-      myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
+          SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
+          aSensitiveCurve.Append (aCenterLineBegin);
+          aSensitiveCurve.Append (aCenterLineEnd);
+        }
 
-      // Main dimension line, short extension
-      if (theMode != AIS_DDM_Text)
-      {
-        if (!aDimensionAspect->IsText3d() && theMode == AIS_DDM_All)
+        // set text label justification
+        Graphic3d_VerticalTextAlignment aTextJustificaton = Graphic3d_VTA_BOTTOM;
+        switch (aLabelPosition & LabelPosition_VMask)
+        {
+          case LabelPosition_Above   :
+          case LabelPosition_VCenter : aTextJustificaton = Graphic3d_VTA_BOTTOM; break;
+          case LabelPosition_Below   : aTextJustificaton = Graphic3d_VTA_TOP;    break;
+        }
+        aDimensionAspect->TextAspect()->SetVerticalJustification (aTextJustificaton);
+
+        // main dimension line, short extension
+        if (!aDimensionAspect->IsText3d() && theMode == ComputeMode_All)
         {
           Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
         }
         Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
         Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
-        if (!aDimensionAspect->IsText3d() && theMode == AIS_DDM_All)
+        if (!aDimensionAspect->IsText3d() && theMode == ComputeMode_All)
         {
           Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
         }
-      }
-      break;
-    }
-    // Text is disposed from the left side of length dimension (after the left flyout line)
-    // Needs to create extensions: left for text and right for proper view of dimensions.
-    case Prs3d_HTA_Left:
-    {
-      aPrimSegments = new Graphic3d_ArrayOfSegments (4);
 
-      gp_Pnt aFirstArrowBeginPnt = ElCLib::Value (aFirstArrowBegin, aDimensionLine);
-      gp_Lin aLongExtLine (aDimensionLine.Location(), aDimensionLine.Direction().Reversed());
-      gp_Pnt aStartPoint = ElCLib::Value (aFirstArrowBegin, aDimensionLine);
-      // Left extension with the text
-      drawExtensionWithText (thePresentation, aStartPoint, aLongExtLine, aValueString, theMode);
+        // add arrows to presentation
+        Prs3d_Root::NewGroup (thePresentation);
 
-      // Central(main) dimension line
-      aFirstPoint = ElCLib::Value (aFirstArrowEnd, aDimensionLine);
-      aLastPoint = isOneSideDimension ? theSecondAttach : ElCLib::Value (aSecondArrowBegin, aDimensionLine);
-      aPrimSegments->AddVertex (aFirstPoint);
-      aPrimSegments->AddVertex (aLastPoint);
-      myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
+        DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
+        if (!theIsOneSide)
+        {
+          DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
+        }
 
-      // Right extension
-      if (!isOneSideDimension)
-      {
-        aFirstPoint = ElCLib::Value (aSecondArrowEnd, aDimensionLine);
-        aLastPoint = ElCLib::Value (aSecondArrowEnd + anArrowLength, aDimensionLine);
-        aPrimSegments->AddVertex (aFirstPoint);
-        aPrimSegments->AddVertex (aLastPoint);
-        myGeom.mySensitiveSegments.Append(new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
+        if (!isArrowsExternal)
+        {
+          break;
+        }
+
+        // add arrow extension lines to presentation
+        Prs3d_Root::NewGroup (thePresentation);
+
+        DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+                       aFirstArrowEnd, aFirstExtensionDir,
+                       THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        if (!theIsOneSide)
+        {
+          DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+                         aSecondArrowEnd, aSecondExtensionDir,
+                         THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        }
       }
-      if (theMode != AIS_DDM_Text)
+
+      break;
+    }
+    // ------------------------------------------------------------------------ //
+    //                                LEFT                                      //
+    // -------------------------------------------------------------------------//
+
+    case LabelPosition_Left:
+    {
+      // add label on dimension or extension line to presentation
+      Prs3d_Root::NewGroup (thePresentation);
+
+      // Left extension with the text
+      DrawExtension (thePresentation, anExtensionSize,
+                     isArrowsExternal
+                       ? aFirstArrowEnd
+                       : aFirstArrowBegin,
+                     aFirstExtensionDir,
+                     aLabelString,
+                     aLabelWidth,
+                     theMode,
+                     aLabelPosition);
+
+      // add dimension line primitives
+      if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        // Main dimension line, short extension
-        Prs3d_Root::NewGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
+        // add central dimension line
+        Prs3d_Root::NewGroup (thePresentation);
+
+        // add graphical primitives
+        Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (2);
+        aPrimSegments->AddVertex (aCenterLineBegin);
+        aPrimSegments->AddVertex (aCenterLineEnd);
+
+        Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
         Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
-        // Group1: Add arrows to a group
-        drawArrow (thePresentation, aFirstArrowPosition, aFirstArrowDir);
-        if (!isOneSideDimension)
+
+        // add selection primitives
+        SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
+        aSensitiveCurve.Append (aCenterLineBegin);
+        aSensitiveCurve.Append (aCenterLineEnd);
+
+        // add arrows to presentation
+        Prs3d_Root::NewGroup (thePresentation);
+
+        DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
+        if (!theIsOneSide)
         {
-          drawArrow (thePresentation, aSecondArrowPosition, aSecondArrowDir);
+          DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
         }
+
+        if (!isArrowsExternal || theIsOneSide)
+        {
+          break;
+        }
+
+        // add extension lines for external arrows
+        Prs3d_Root::NewGroup (thePresentation);
+
+        DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+                       aSecondArrowEnd, aSecondExtensionDir,
+                       THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
       }
+
       break;
     }
-    case Prs3d_HTA_Right:
+    // ------------------------------------------------------------------------ //
+    //                                RIGHT                                     //
+    // -------------------------------------------------------------------------//
+
+    case LabelPosition_Right:
     {
-      aPrimSegments = new Graphic3d_ArrayOfSegments (4);
-      // Left extension
-      if (!isOneSideDimension)
+      // add label on dimension or extension line to presentation
+      Prs3d_Root::NewGroup (thePresentation);
+
+      // Right extension with text
+      DrawExtension (thePresentation, anExtensionSize,
+                     isArrowsExternal
+                       ? aSecondArrowEnd
+                       : aSecondArrowBegin,
+                     aSecondExtensionDir,
+                     aLabelString, aLabelWidth,
+                     theMode,
+                     aLabelPosition);
+
+      if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        aFirstPoint = ElCLib::Value (aFirstArrowBegin - anArrowLength, aDimensionLine);
-        aLastPoint = ElCLib::Value (aFirstArrowEnd, aDimensionLine);
-        aPrimSegments->AddVertex (aFirstPoint);
-        aPrimSegments->AddVertex (aLastPoint);
-        myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
-      }
+        // add central dimension line
+        Prs3d_Root::NewGroup (thePresentation);
+
+        // add graphical primitives
+        Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (2);
+        aPrimSegments->AddVertex (aCenterLineBegin);
+        aPrimSegments->AddVertex (aCenterLineEnd);
+        Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
+        Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
 
-      // Central(main) dimension line
-      aFirstPoint = isOneSideDimension ? theFirstAttach :  ElCLib::Value (aFirstArrowEnd, aDimensionLine);
-      aLastPoint = ElCLib::Value (aSecondArrowBegin, aDimensionLine);
-      aPrimSegments->AddVertex (aFirstPoint);
-      aPrimSegments->AddVertex (aLastPoint);
-      myGeom.mySensitiveSegments.Append (new Select3D_SensitiveSegment (anEmptyOwner, aFirstPoint, aLastPoint));
+        // add selection primitives
+        SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
+        aSensitiveCurve.Append (aCenterLineBegin);
+        aSensitiveCurve.Append (aCenterLineEnd);
 
-      // Right extension with text
-      aFirstPoint = ElCLib::Value (aSecondArrowEnd, aDimensionLine);
-      drawExtensionWithText (thePresentation, aFirstPoint, aDimensionLine, aValueString, theMode);
+        // add arrows to presentation
+        Prs3d_Root::NewGroup (thePresentation);
 
-      if (theMode != AIS_DDM_Text)
-      {
-        // Main dimension line, short extension
-        Prs3d_Root::NewGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
-        Prs3d_Root::CurrentGroup(thePresentation)->AddPrimitiveArray (aPrimSegments);
-        // Group1, 2: Add arrows to a group
-        if (!isOneSideDimension)
+        DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
+        if (!theIsOneSide)
         {
-          drawArrow (thePresentation, aFirstArrowPosition, aFirstArrowDir);
+          DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
         }
 
-        drawArrow (thePresentation, aSecondArrowPosition, aSecondArrowDir);
+        if (!isArrowsExternal || theIsOneSide)
+        {
+          break;
+        }
+
+        // add extension lines for external arrows
+        Prs3d_Root::NewGroup (thePresentation);
+
+        DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+                       aFirstArrowEnd, aFirstExtensionDir,
+                       THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
       }
+
       break;
     }
   }
 
-  setComputed (Standard_True);
-}
+  // add flyout lines to presentation
+  if (theMode == ComputeMode_All)
+  {
+    Prs3d_Root::NewGroup (thePresentation);
 
-//=======================================================================
-//function : SetFirstPoint
-//purpose  : 
-//=======================================================================
+    Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments(4);
+    aPrimSegments->AddVertex (theFirstPoint);
+    aPrimSegments->AddVertex (aLineBegPoint);
 
-void AIS_Dimension::SetFirstPoint (const gp_Pnt& thePoint)
-{
-  myFirstPoint = thePoint;
-}
+    aPrimSegments->AddVertex (theSecondPoint);
+    aPrimSegments->AddVertex (aLineEndPoint);
 
-//=======================================================================
-//function : SetSecondPoint
-//purpose  : 
-//=======================================================================
+    Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
+    Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
+    Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
+  }
 
-void AIS_Dimension::SetSecondPoint (const gp_Pnt& thePoint)
-{
-  mySecondPoint = thePoint;
+  mySelectionGeom.IsComputed = Standard_True;
 }
 
 //=======================================================================
-//function : Type
+//function : ComputeLinearFlyouts
 //purpose  :
 //=======================================================================
-
-AIS_KindOfInteractive AIS_Dimension::Type() const
+void AIS_Dimension::ComputeLinearFlyouts (const Handle(SelectMgr_Selection)& theSelection,
+                                          const Handle(SelectMgr_EntityOwner)& theOwner,
+                                          const gp_Pnt& theFirstPoint,
+                                          const gp_Pnt& theSecondPoint)
 {
-  return AIS_KOI_Relation;
+  // count flyout direction
+  gp_Ax1 aPlaneNormal = GetPlane().Axis();
+  gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
+
+  // count a flyout direction vector.
+  gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
+
+  // create lines for layouts
+  gp_Lin aLine1 (theFirstPoint,  aFlyoutVector);
+  gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
+
+  // get flyout end points
+  gp_Pnt aFlyoutEnd1 = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint) + GetFlyout(), aLine1);
+  gp_Pnt aFlyoutEnd2 = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
+
+  // fill sensitive entity for flyouts
+  Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
+  aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, theFirstPoint, aFlyoutEnd1));
+  aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, theSecondPoint, aFlyoutEnd2));
+  theSelection->Add (aSensitiveEntity);
 }
 
 //=======================================================================
-//function : circleFromPlanarFace
+//function : CircleFromPlanarFace
 //purpose  : if possible computes circle from planar face
 //=======================================================================
-
-Standard_Boolean AIS_Dimension::circleFromPlanarFace (const TopoDS_Face& theFace,
+Standard_Boolean AIS_Dimension::CircleFromPlanarFace (const TopoDS_Face& theFace,
                                                       Handle(Geom_Curve)& theCurve,
-                                                      gp_Pnt & theFirstPoint,
-                                                      gp_Pnt & theLastPoint)
+                                                      gp_Pnt& theFirstPoint,
+                                                      gp_Pnt& theLastPoint)
 {
   TopExp_Explorer anIt (theFace, TopAbs_EDGE);
   for ( ; anIt.More(); anIt.Next())
@@ -921,14 +1021,13 @@ Standard_Boolean AIS_Dimension::circleFromPlanarFace (const TopoDS_Face& theFace
 }
 
 //=======================================================================
-//function : initCircularDimension
-//purpose  : if it's possible computes circle from planar face
+//function : InitCircularDimension
+//purpose  : 
 //=======================================================================
-
-Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theShape,
+Standard_Boolean AIS_Dimension::InitCircularDimension (const TopoDS_Shape& theShape,
                                                        gp_Circ& theCircle,
                                                        gp_Pnt& theMiddleArcPoint,
-                                                       gp_Pnt& theOppositeDiameterPoint)
+                                                       Standard_Boolean& theIsClosed)
 {
   gp_Pln aPln;
   Handle(Geom_Surface) aBasisSurf;
@@ -937,8 +1036,8 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
   Standard_Real anOffset    = 0.0;
   Standard_Real aFirstParam = 0.0;
   Standard_Real aLastParam  = 0.0;
-  Standard_Boolean isAnArc  = Standard_False;
 
+  // discover circular geometry
   if (theShape.ShapeType() == TopAbs_FACE)
   {
     AIS::GetPlaneFromFace (TopoDS::Face (theShape), aPln, aBasisSurf, aSurfType, anOffset);
@@ -946,14 +1045,12 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
     if (aSurfType == AIS_KOS_Plane)
     {
       Handle(Geom_Curve) aCurve;
-      if (!circleFromPlanarFace (TopoDS::Face (theShape), aCurve, aFirstPoint, aLastPoint))
+      if (!CircleFromPlanarFace (TopoDS::Face (theShape), aCurve, aFirstPoint, aLastPoint))
       {
-        Standard_ConstructionError::Raise ("AIS_Dimension:: Curve is not a circle or is Null") ;
         return Standard_False;
       }
 
       theCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
-      isAnArc = !(aFirstPoint.IsEqual (aLastPoint, Precision::Confusion()));
     }
     else
     {
@@ -965,7 +1062,7 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
       Standard_Real aLastV  = aSurf1.LastVParameter();
       Standard_Real aMidU   = (aFirstU + aLastU) * 0.5;
       Standard_Real aMidV   = (aFirstV + aLastV) * 0.5;
-      aSurf1.D0(aMidU, aMidV, aCurPos);
+      aSurf1.D0 (aMidU, aMidV, aCurPos);
       Handle (Adaptor3d_HCurve) aBasisCurve;
       Standard_Boolean isExpectedType = Standard_False;
       if (aSurfType == AIS_KOS_Cylinder)
@@ -994,9 +1091,9 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
 
       if (!isExpectedType)
       {
-        Standard_ConstructionError::Raise ("AIS_Dimension:: Unexpected type of surface") ;
         return Standard_False;
       }
+
       Handle(Geom_Curve) aCurve;
       aCurve = aBasisSurf->VIso(aMidV);
       if (aCurve->DynamicType() == STANDARD_TYPE (Geom_Circle))
@@ -1023,7 +1120,6 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
         theCircle = aMkCirc.Value()->Circ();
       }
 
-      gp_Vec aVec = gp_Vec (theCircle.Location(), aCurPos).Normalized();
       aFirstPoint = ElCLib::Value (aFirstU, theCircle);
       aLastPoint = ElCLib::Value (aLastU,  theCircle);
     }
@@ -1045,351 +1141,464 @@ Standard_Boolean AIS_Dimension::initCircularDimension (const TopoDS_Shape& theSh
     }
     else // Unexpected type of shape
     {
-      Standard_ConstructionError::Raise ("AIS_Dimension:: Unexpected type of shape");
       return Standard_False;
     }
+
     BRepAdaptor_Curve anAdaptedCurve (anEdge);
-    if (!anAdaptedCurve.GetType() == GeomAbs_Circle)
+    if (anAdaptedCurve.GetType() != GeomAbs_Circle)
     {
       return Standard_False;
     }
-    theCircle = anAdaptedCurve.Circle();
+
+    theCircle   = anAdaptedCurve.Circle();
     aFirstPoint = anAdaptedCurve.Value (anAdaptedCurve.FirstParameter());
-    aLastPoint = anAdaptedCurve.Value (anAdaptedCurve.LastParameter());
+    aLastPoint  = anAdaptedCurve.Value (anAdaptedCurve.LastParameter());
   }
-  // Get <theMiddleArcPoint> and <theOppositeDiameterPoint> values from <theCircle>
-  isAnArc = !(aFirstPoint.IsEqual (aLastPoint, Precision::Confusion()));
+
+  theIsClosed = aFirstPoint.IsEqual (aLastPoint, Precision::Confusion());
+
   gp_Pnt aCenter = theCircle.Location();
-  if (!isAnArc)
+
+  if (theIsClosed) // Circle
   {
-    // Circle
     gp_Dir anXDir = theCircle.XAxis().Direction();
     theMiddleArcPoint = aCenter.Translated (gp_Vec (anXDir) * theCircle.Radius());
-    theOppositeDiameterPoint = aCenter.Translated (-gp_Vec (anXDir) * theCircle.Radius());
   }
-  else
+  else // Arc
   {
-    // Arc
     aFirstParam = ElCLib::Parameter (theCircle, aFirstPoint);
     aLastParam  = ElCLib::Parameter (theCircle, aLastPoint);
     if (aFirstParam > aLastParam)
     {
       aFirstParam -= 2.0 * M_PI;
     }
+
     Standard_Real aParCurPos = (aFirstParam + aLastParam) * 0.5;
     gp_Vec aVec = gp_Vec (aCenter, ElCLib::Value (aParCurPos, theCircle)).Normalized () * theCircle.Radius ();
     theMiddleArcPoint = aCenter.Translated (aVec);
-    theOppositeDiameterPoint = aCenter.Translated (-aVec);
   }
 
   return Standard_True;
 }
 
 //=======================================================================
-//function : SetDisplaySpecialSymbol
-//purpose  : specifies dimension special symbol display options
+//function : ComputeSelection
+//purpose  : 
 //=======================================================================
-
-void AIS_Dimension::SetDisplaySpecialSymbol (const AIS_DisplaySpecialSymbol theDisplaySpecSymbol)
+void AIS_Dimension::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
+                                      const Standard_Integer theMode)
 {
-  myDisplaySpecialSymbol = theDisplaySpecSymbol;
-}
+  if (!mySelectionGeom.IsComputed)
+  {
+    return;
+  }
 
-//=======================================================================
-//function : DisplaySpecialSymbol
-//purpose  : shows dimension special symbol display options
-//=======================================================================
+  AIS_DimensionSelectionMode aSelectionMode = (AIS_DimensionSelectionMode)theMode;
 
-AIS_DisplaySpecialSymbol AIS_Dimension::DisplaySpecialSymbol() const
-{
-  return myDisplaySpecialSymbol;
-}
+  // init appropriate entity owner
+  Handle(SelectMgr_EntityOwner) aSensitiveOwner;
 
-//=======================================================================
-//function : SetSpecialSymbol
-//purpose  : specifies special symbol
-//=======================================================================
+  switch (aSelectionMode)
+  {
+    // neutral selection owner
+    case AIS_DSM_All :
+      aSensitiveOwner = new SelectMgr_EntityOwner (this, THE_NEUTRAL_SEL_PRIORITY);
+      break;
 
-void AIS_Dimension::SetSpecialSymbol (const Standard_ExtCharacter theSpecialSymbol)
-{
-  mySpecialSymbol = theSpecialSymbol;
-}
+    // local selection owners
+    case AIS_DSM_Line :
+    case AIS_DSM_Text :
+      aSensitiveOwner = new AIS_DimensionOwner (this, aSelectionMode, THE_LOCAL_SEL_PRIORITY);
+      break;
+  }
 
-//=======================================================================
-//function : SpecialSymbol
-//purpose  : returns special symbol
-//=======================================================================
+  if (aSelectionMode == AIS_DSM_All || aSelectionMode == AIS_DSM_Line)
+  {
+    // sensitives for dimension line segments
+    Handle(Select3D_SensitiveGroup) aGroupOfSensitives = new Select3D_SensitiveGroup (aSensitiveOwner);
 
-Standard_ExtCharacter AIS_Dimension::SpecialSymbol() const
-{
-  return mySpecialSymbol;
-}
+    SelectionGeometry::SeqOfCurves::Iterator aCurveIt (mySelectionGeom.DimensionLine);
+    for (; aCurveIt.More(); aCurveIt.Next())
+    {
+      const SelectionGeometry::HCurve& aCurveData = aCurveIt.Value();
 
-//=======================================================================
-//function : IsUnitsDisplayed
-//purpose  : shows if Units are to be displayed along with dimension value
-//=======================================================================
+      TColgp_Array1OfPnt aSensitivePnts (1, aCurveData->Length());
+      for (Standard_Integer aPntIt = 1; aPntIt <= aCurveData->Length(); ++aPntIt)
+      {
+        aSensitivePnts.ChangeValue (aPntIt) = aCurveData->Value (aPntIt);
+      }
 
-Standard_Boolean AIS_Dimension::IsUnitsDisplayed() const
-{
-  return myToDisplayUnits;
-}
+      aGroupOfSensitives->Add (new Select3D_SensitiveCurve (aSensitiveOwner, aSensitivePnts));
+    }
 
-//=======================================================================
-//function : MakeUnitsDisplayed
-//purpose  : sets to display units along with the dimension value or no
-//=======================================================================
+    Quantity_Length anArrowLength = myDrawer->DimensionAspect()->ArrowAspect()->Length();
+    Standard_Real   anArrowAngle  = myDrawer->DimensionAspect()->ArrowAspect()->Angle();
 
-void AIS_Dimension::MakeUnitsDisplayed (const Standard_Boolean toDisplayUnits)
-{
-  myToDisplayUnits = toDisplayUnits;
-}
+    // sensitives for arrows
+    SelectionGeometry::SeqOfArrows::Iterator anArrowIt (mySelectionGeom.Arrows);
+    for (; anArrowIt.More(); anArrowIt.Next())
+    {
+      const SelectionGeometry::HArrow& anArrow = anArrowIt.Value();
 
-//=======================================================================
-//function : MakeUnitsDisplayed
-//purpose  : returns the current type of units
-//=======================================================================
+      gp_Pnt aSidePnt1 (gp::Origin());
+      gp_Pnt aSidePnt2 (gp::Origin());
+      const gp_Dir& aPlane = GetPlane().Axis().Direction();
+      const gp_Pnt& aPeak  = anArrow->Position;
+      const gp_Dir& aDir   = anArrow->Direction;
 
-TCollection_AsciiString AIS_Dimension::UnitsQuantity() const
-{
-  return myUnitsQuantity;
-}
+      // compute points for arrow in plane
+      PointsForArrow (aPeak, aDir, aPlane, anArrowLength, anArrowAngle, aSidePnt1, aSidePnt2);
 
-//=======================================================================
-//function : SetUnitsQuantity
-//purpose  : sets the current type of units
-//=======================================================================
+      aGroupOfSensitives->Add (new Select3D_SensitiveTriangle (aSensitiveOwner, aPeak, aSidePnt1, aSidePnt2));
 
-void AIS_Dimension::SetUnitsQuantity (const TCollection_AsciiString& theUnitsQuantity)
-{
-  myUnitsQuantity = theUnitsQuantity;
-}
+      if (!myDrawer->DimensionAspect()->IsArrows3d())
+      {
+        continue;
+      }
 
-//=======================================================================
-//function : ModelUnits
-//purpose  : returns the current model units
-//=======================================================================
+      // compute points for orthogonal sensitive plane
+      gp_Dir anOrthoPlane = anArrow->Direction.Crossed (aPlane);
 
-TCollection_AsciiString AIS_Dimension::ModelUnits() const
-{
-  return myModelUnits;
-}
+      PointsForArrow (aPeak, aDir, anOrthoPlane, anArrowLength, anArrowAngle, aSidePnt1, aSidePnt2);
 
-//=======================================================================
-//function : SetModelUnits
-//purpose  : sets the current model units
-//=======================================================================
+      aGroupOfSensitives->Add (new Select3D_SensitiveTriangle (aSensitiveOwner, aPeak, aSidePnt1, aSidePnt2));
+    }
 
-void AIS_Dimension::SetModelUnits (const TCollection_AsciiString& theUnits)
-{
-  myModelUnits = theUnits;
-}
+    theSelection->Add (aGroupOfSensitives);
+  }
 
-//=======================================================================
-//function : DisplayUnits
-//purpose  : returns the current display units
-//=======================================================================
+  // sensitives for text element
+  if (aSelectionMode == AIS_DSM_All || aSelectionMode == AIS_DSM_Text)
+  {
+    Handle(Select3D_SensitiveEntity) aTextSensitive;
 
-TCollection_AsciiString AIS_Dimension::DisplayUnits() const
-{
-  return myDisplayUnits;
-}
+    gp_Ax2 aTextAxes (mySelectionGeom.TextPos,
+                      GetPlane().Axis().Direction(),
+                      mySelectionGeom.TextDir);
 
-//=======================================================================
-//function : SetDisplayUnits
-//purpose  : sets the current display units
-//=======================================================================
+    if (myDrawer->DimensionAspect()->IsText3d())
+    {
+      // sensitive planar rectangle for text
+      Standard_Real aDx = mySelectionGeom.TextWidth  * 0.5;
+      Standard_Real aDy = mySelectionGeom.TextHeight * 0.5;
 
-void AIS_Dimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
-{
-  myDisplayUnits = theUnits;
-}
+      gp_Trsf aLabelPlane;
+      aLabelPlane.SetTransformation (aTextAxes, gp::XOY());
 
-//=======================================================================
-//function : isComputed
-//purpose  :
-//=======================================================================
+      TColgp_Array1OfPnt aRectanglePoints(1, 4);
+      aRectanglePoints.ChangeValue(1) = gp_Pnt (-aDx, -aDy, 0.0).Transformed (aLabelPlane);
+      aRectanglePoints.ChangeValue(2) = gp_Pnt (-aDx,  aDy, 0.0).Transformed (aLabelPlane);
+      aRectanglePoints.ChangeValue(3) = gp_Pnt ( aDx,  aDy, 0.0).Transformed (aLabelPlane);
+      aRectanglePoints.ChangeValue(4) = gp_Pnt ( aDx, -aDy, 0.0).Transformed (aLabelPlane);
 
-Standard_Boolean AIS_Dimension::isComputed() const
-{
-  return myGeom.myIsComputed;
-}
+      Poly_Array1OfTriangle aTriangles(1, 2);
+      aTriangles.ChangeValue(1) = Poly_Triangle(1, 2, 3);
+      aTriangles.ChangeValue(2) = Poly_Triangle(1, 3, 4);
 
-//=======================================================================
-//function : setComputed
-//purpose  :
-//=======================================================================
+      Handle(Poly_Triangulation) aRectanglePoly = 
+        new Poly_Triangulation(aRectanglePoints, aTriangles);
 
-void AIS_Dimension::setComputed (Standard_Boolean isComputed)
-{
-  myGeom.myIsComputed = isComputed;
-}
+      aTextSensitive =
+        new Select3D_SensitiveTriangulation (aSensitiveOwner, aRectanglePoly, TopLoc_Location(), Standard_True);
+    }
+    else
+    {
+      gp_Circ aTextGeom (aTextAxes, mySelToleranceForText2d != 0.0 
+                                      ? mySelToleranceForText2d : 1.0);
 
-//=======================================================================
-//function : textPosition
-//purpose  :
-//=======================================================================
+      Handle(Geom_Circle) aSensGeom = new Geom_Circle (aTextGeom);
 
-gp_Pnt AIS_Dimension::textPosition() const
-{
-  return myGeom.myTextPosition;
-}
+      aTextSensitive = new Select3D_SensitiveCircle (aSensitiveOwner, aSensGeom, Standard_True);
+    }
 
-//=======================================================================
-//function : setTextPosition
-//purpose  :
-//=======================================================================
+    theSelection->Add (aTextSensitive);
+  }
 
-void AIS_Dimension::setTextPosition (const gp_Pnt thePosition)
-{
-  myGeom.myTextPosition = thePosition;
+  // callback for flyout sensitive calculation
+  if (aSelectionMode == AIS_DSM_All)
+  {
+    ComputeFlyoutSelection (theSelection, aSensitiveOwner);
+  }
 }
 
 //=======================================================================
-//function : resetGeom
-//purpose  :
+//function : PointsForArrow
+//purpose  : 
 //=======================================================================
-
-void AIS_Dimension::resetGeom()
+void AIS_Dimension::PointsForArrow (const gp_Pnt& thePeakPnt,
+                                    const gp_Dir& theDirection,
+                                    const gp_Dir& thePlane,
+                                    const Standard_Real theArrowLength,
+                                    const Standard_Real theArrowAngle,
+                                    gp_Pnt& theSidePnt1,
+                                    gp_Pnt& theSidePnt2)
 {
-  setComputed (Standard_False);
-}
+  gp_Lin anArrowLin (thePeakPnt, theDirection.Reversed());
+  gp_Pnt anArrowEnd = ElCLib::Value (theArrowLength, anArrowLin);
+  gp_Lin anEdgeLin (anArrowEnd, theDirection.Crossed (thePlane));
 
-//=======================================================================
-//function : IsTextReversed
-//purpose  :
-//=======================================================================
+  Standard_Real anEdgeLength = Tan (theArrowAngle) * theArrowLength;
 
-Standard_Boolean AIS_Dimension::IsTextReversed() const
-{
-  return myIsTextReversed;
+  theSidePnt1 = ElCLib::Value ( anEdgeLength, anEdgeLin);
+  theSidePnt2 = ElCLib::Value (-anEdgeLength, anEdgeLin);
 }
 
 //=======================================================================
-//function : MakeTextReversed
-//purpose  :
+//function : GetTextPositionForLinear
+//purpose  : 
 //=======================================================================
-
-void AIS_Dimension::MakeTextReversed (const Standard_Boolean isTextReversed)
+gp_Pnt AIS_Dimension::GetTextPositionForLinear (const gp_Pnt& theFirstPoint,
+                                                const gp_Pnt& theSecondPoint,
+                                                const Standard_Boolean theIsOneSide) const
 {
-  myIsTextReversed = isTextReversed;
-}
+  if (!IsValid())
+  {
+    return gp::Origin();
+  }
 
-//=======================================================================
-//function : SetSelToleranceForText2d
-//purpose  :
-//=======================================================================
+  gp_Pnt aTextPosition (gp::Origin());
 
-void AIS_Dimension::SetSelToleranceForText2d (const Standard_Real theTol)
-{
-  myGeom.mySelToleranceForText2d = theTol;
-}
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
 
-//=======================================================================
-//function : SelToleranceForText2d
-//purpose  :
-//=======================================================================
+  // Get label alignment and arrow orientation.
+  Standard_Integer aLabelPosition = 0;
+  Standard_Boolean isArrowsExternal = Standard_False;
+  FitTextAlignmentForLinear (theFirstPoint, theSecondPoint, theIsOneSide,
+                             aDimensionAspect->TextHorizontalPosition(),
+                             aLabelPosition, isArrowsExternal);
+
+  // Compute dimension line points.
+  gp_Dir aPlaneNormal = GetPlane().Axis().Direction();
+  gp_Vec aTargetPointsVec (theFirstPoint, theSecondPoint);
+
+  // Compute flyout direction vector
+  gp_Dir aFlyoutVector = aPlaneNormal ^ gp_Dir (aTargetPointsVec);
+
+  // create lines for layouts
+  gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
+  gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
+  // Get flyout end points
+  gp_Pnt aLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
+  gp_Pnt aLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
+
+  // Get text position.
+  switch (aLabelPosition & LabelPosition_HMask)
+  {
+  case LabelPosition_Left:
+    {
+      gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
+      Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
+
+      Standard_Real anOffset = isArrowsExternal
+                                 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
+                                 : anExtensionSize;
+      gp_Vec anExtensionVec = gp_Vec (aTargetPointsDir) * -anOffset;
+      aTextPosition = aLineEndPoint.Translated (anExtensionVec);
+    }
+    break;
+  case LabelPosition_Right:
+    {
+      gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
+      Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
+
+      Standard_Real anOffset = isArrowsExternal
+                                 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
+                                 : anExtensionSize;
+      gp_Vec anExtensionVec = gp_Vec (aTargetPointsDir) * anOffset;
+      aTextPosition = aLineBegPoint.Translated (anExtensionVec);
+    }
+    break;
+  case LabelPosition_HCenter:
+    {
+      aTextPosition = (aLineBegPoint.XYZ() + aLineEndPoint.XYZ()) * 0.5;
+    }
+    break;
+  }
 
-Standard_Real AIS_Dimension::SelToleranceForText2d() const
-{
-  return myGeom.mySelToleranceForText2d;
+  return aTextPosition;
 }
 
 //=======================================================================
-//function : SetFlyout
+//function : AdjustParametersForLinear
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::SetFlyout (const Standard_Real theFlyout)
+Standard_Boolean AIS_Dimension::AdjustParametersForLinear (const gp_Pnt& theTextPos,
+                                                           const gp_Pnt& theFirstPoint,
+                                                           const gp_Pnt& theSecondPoint,
+                                                           Standard_Real& theExtensionSize,
+                                                           Prs3d_DimensionTextHorizontalPosition& theAlignment,
+                                                           Standard_Real& theFlyout,
+                                                           gp_Pln& thePlane,
+                                                           Standard_Boolean& theIsPlaneOld) const
 {
myFlyout = theFlyout;
-}
 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
+  Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
 
-//=======================================================================
-//function : GetFlyout
-//purpose  : 
-//=======================================================================
+  gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
+  gp_Vec aTargetPointsVec (theFirstPoint, theSecondPoint);
 
-Standard_Real AIS_Dimension::GetFlyout () const
-{
- return myFlyout;
-}
+  // Don't set new plane if the text position lies on the attachment points line.
+  gp_Lin aTargetPointsLin (theFirstPoint, aTargetPointsDir);
+  if (!aTargetPointsLin.Contains (theTextPos, Precision::Confusion()))
+  {
+    //Set new automatic plane.
+    thePlane = gce_MakePln (theTextPos, theFirstPoint, theSecondPoint);
+    theIsPlaneOld = Standard_False;
+  }
 
-//=======================================================================
-//function : computeFlyoutSelection
-//purpose  : computes selection for flyouts
-//=======================================================================
+  // Compute flyout direction vector.
+  gp_Dir aPlaneNormal = GetPlane().Axis().Direction();
+  gp_Dir aPositiveFlyout = aPlaneNormal ^ aTargetPointsDir;
 
-void AIS_Dimension::computeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
-                                           const Handle(AIS_DimensionOwner)& theOwner)
-{
- //Count flyout direction
- gp_Ax1 aWorkingPlaneNormal = GetWorkingPlane().Axis();
- gp_Dir aTargetPointsVector = gce_MakeDir (myFirstPoint, mySecondPoint);
- // Count a flyout direction vector.
- gp_Dir aFlyoutVector = aWorkingPlaneNormal.Direction()^aTargetPointsVector;
- // Create lines for layouts
- gp_Lin aLine1 (myFirstPoint, aFlyoutVector);
- gp_Lin aLine2 (mySecondPoint, aFlyoutVector);
- // Get flyout end points
- gp_Pnt aFlyoutEnd1 = ElCLib::Value (ElCLib::Parameter (aLine1, myFirstPoint) + GetFlyout(), aLine1);
- gp_Pnt aFlyoutEnd2 = ElCLib::Value (ElCLib::Parameter (aLine2, mySecondPoint) + GetFlyout(), aLine2);
-
- // Fill sensitive entity for flyouts
- Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
- aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myFirstPoint, aFlyoutEnd1));
- aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, mySecondPoint, aFlyoutEnd2));
- theSelection->Add (aSensitiveEntity);
+  // Additional check of collinearity of the plane normal and attachment points vector.
+  if (aPlaneNormal.IsParallel (aTargetPointsDir, Precision::Angular()))
+  {
+    return Standard_False;
+  }
+
+  // Set flyout.
+  gp_Vec aFirstToTextVec (theFirstPoint, theTextPos);
+
+  Standard_Real aCos = aFirstToTextVec.Normalized() * gp_Vec (aTargetPointsDir);
+
+  gp_Pnt aTextPosProj = theFirstPoint.Translated
+    (gp_Vec (aTargetPointsDir) * aFirstToTextVec.Magnitude() * aCos);
+
+  // Compute flyout value and direction.
+  gp_Vec aFlyoutVector = gp_Vec (aTextPosProj, theTextPos);
+
+  theFlyout = 0.0;
+  if (aFlyoutVector.Magnitude() > Precision::Confusion())
+  {
+    theFlyout = gp_Dir (aFlyoutVector).IsOpposite (aPositiveFlyout, Precision::Angular())
+                ? -aFlyoutVector.Magnitude()
+                :  aFlyoutVector.Magnitude();
+  }
+  
+  // Compute attach points (through which main dimension line passes).
+  gp_Pnt aFirstAttach  = theFirstPoint.Translated (aFlyoutVector);
+  gp_Pnt aSecondAttach = theSecondPoint.Translated (aFlyoutVector);
+
+  // Set horizontal text alignment.
+  if (aCos < 0.0)
+  {
+    theAlignment = Prs3d_DTHP_Left;
+
+    Standard_Real aNewExtSize = theTextPos.Distance (aFirstAttach) - anArrowLength;
+    theExtensionSize = aNewExtSize < 0.0 ? 0.0 : aNewExtSize;
+  }
+  else if (aTextPosProj.Distance (theFirstPoint) > theFirstPoint.Distance (theSecondPoint))
+  {
+    theAlignment = Prs3d_DTHP_Right;
+
+    Standard_Real aNewExtSize = theTextPos.Distance (aSecondAttach) - anArrowLength;
+    theExtensionSize = aNewExtSize < 0.0 ? 0.0 : aNewExtSize;
+  }
+  else
+  {
+    theAlignment = Prs3d_DTHP_Center;
+  }
+  return Standard_True;
 }
 
 //=======================================================================
-//function : ComputeSelection
+//function : FitTextAlignmentForLinear
 //purpose  : 
 //=======================================================================
-
-void AIS_Dimension::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
-                                      const Standard_Integer theMode)
+void AIS_Dimension::FitTextAlignmentForLinear (const gp_Pnt& theFirstPoint,
+                                               const gp_Pnt& theSecondPoint,
+                                               const Standard_Boolean theIsOneSide,
+                                               const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
+                                               Standard_Integer& theLabelPosition,
+                                               Standard_Boolean& theIsArrowsExternal) const
 {
-  if (!isComputed())
-  {
-    return;
-  }
+  theLabelPosition = LabelPosition_None;
+  theIsArrowsExternal = Standard_False;
+
+  // Compute dimension line points
+  gp_Ax1 aPlaneNormal = GetPlane().Axis();
+  gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
+
+  // compute flyout direction vector
+  gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
 
-  Handle(Select3D_SensitiveGroup) aSensitiveForLine;
-  Handle(Select3D_SensitiveEntity) aSensitiveForText;
-  Select3D_ListOfSensitive aSensitiveList;
-  aSensitiveList.Assign (myGeom.mySensitiveSegments);
+  // create lines for layouts
+  gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
+  gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
 
-  // Full dimension selection
-  Handle(AIS_DimensionOwner) anOwner = new AIS_DimensionOwner (this, AIS_DDM_All, theMode == 0 ? 5 : 6);
-  for (Select3D_ListIteratorOfListOfSensitive anIt (aSensitiveList); anIt.More(); anIt.Next())
+  // Get flyout end points
+  gp_Pnt aLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
+  gp_Pnt aLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
+
+  Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
+
+  // For extensions we need to know arrow size, text size and extension size: get it from 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 cut dimension lines for 3d text
+  if (aDimensionAspect->IsText3d())
   {
-    anIt.Value()->Set (anOwner);
+    aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
   }
-  aSensitiveForLine = new Select3D_SensitiveGroup (anOwner, aSensitiveList);
 
-  // Text
-  if (myDrawer->DimensionAspect()->IsText3d())
+  // Handle user-defined and automatic arrow placement
+  switch (aDimensionAspect->ArrowOrientation())
   {
-    aSensitiveForText = new Select3D_SensitiveBox (anOwner,myGeom.myTextBndBox);
+    case Prs3d_DAO_External: theIsArrowsExternal = true; break;
+    case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
+    case Prs3d_DAO_Fit:
+    {
+      // 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 aDimensionWidth = aLineBegPoint.Distance (aLineEndPoint);
+      Standard_Real anArrowsWidth   = theIsOneSide 
+                                      ?  anArrowLength + anArrowMargin
+                                      : (anArrowLength + anArrowMargin) * 2.0;
+
+      theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
+      break;
+    }
   }
-  else
+
+  // Handle user-defined and automatic text placement
+  switch (theHorizontalTextPos)
   {
-    Handle(Geom_Circle) aSensitiveGeom = new Geom_Circle (gp_Circ (gp_Ax2 (myGeom.myTextPosition,
-                                                            myWorkingPlane.Position().XDirection()),
-                                                            myGeom.mySelToleranceForText2d != 0
-                                                          ? myGeom.mySelToleranceForText2d : 1.0));
-    aSensitiveForText = new Select3D_SensitiveCircle (anOwner, aSensitiveGeom, Standard_True);
+    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:
+    {
+      Standard_Real aDimensionWidth = aLineBegPoint.Distance (aLineEndPoint);
+      Standard_Real anArrowsWidth   = theIsOneSide ? anArrowLength : 2.0 * anArrowLength;
+      Standard_Real aContentWidth   = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
+
+      theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
+      break;
+    }
   }
-  if (theMode > 0)
+
+  // Handle vertical text placement options
+  switch (aDimensionAspect->TextVerticalPosition())
   {
-    anOwner->SetDisplayMode (AIS_DDM_Line);
-    Handle(AIS_DimensionOwner) aTextOwner = new AIS_DimensionOwner (this, AIS_DDM_Text, 7);
-    aSensitiveForText->Set (aTextOwner);
+    case Prs3d_DTVP_Above  : theLabelPosition |= LabelPosition_Above; break;
+    case Prs3d_DTVP_Below  : theLabelPosition |= LabelPosition_Below; break;
+    case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
   }
-  else
-    computeFlyoutSelection (theSelection, anOwner);
+}
 
-  theSelection->Add (aSensitiveForLine);
-  theSelection->Add (aSensitiveForText);
+//=======================================================================
+//function : UnsetFixedTextPosition
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::UnsetFixedTextPosition()
+{
+  myIsTextPositionFixed = Standard_False;
+  myFixedTextPosition = gp::Origin();
 }