]> OCCT Git - occt-copy.git/commitdiff
0026507: Visualization - Improved presentations of dimensions
authorsan <san@opencascade.com>
Thu, 24 Sep 2015 15:47:34 +0000 (18:47 +0300)
committersan <san@opencascade.com>
Thu, 24 Sep 2015 15:47:34 +0000 (18:47 +0300)
28 files changed:
src/AIS/AIS_AngleDimension.cxx
src/AIS/AIS_DiameterDimension.cxx
src/AIS/AIS_DiameterDimension.hxx
src/AIS/AIS_Dimension.cxx
src/AIS/AIS_Dimension.hxx
src/AIS/AIS_RadiusDimension.cxx
src/AIS/AIS_RadiusDimension.hxx
src/Font/FILES
src/Font/Font_BRepFont.cxx
src/Font/Font_BRepFont.hxx
src/Font/Font_FTFont.cxx
src/Font/Font_FTFont.hxx
src/Font/Font_TextFormatter.cxx [new file with mode: 0644]
src/Font/Font_TextFormatter.hxx [new file with mode: 0644]
src/OpenGl/FILES
src/OpenGl/OpenGl_Font.cxx
src/OpenGl/OpenGl_Font.hxx
src/OpenGl/OpenGl_Text.cxx
src/OpenGl/OpenGl_Text.hxx
src/OpenGl/OpenGl_TextBuilder.cxx [new file with mode: 0644]
src/OpenGl/OpenGl_TextBuilder.hxx [new file with mode: 0644]
src/Prs3d/Prs3d.cdl
src/ViewerTest/ViewerTest_RelationCommands.cxx
tests/bugs/vis/bug26507_1 [new file with mode: 0644]
tests/bugs/vis/bug26507_2 [new file with mode: 0644]
tests/bugs/vis/bug26507_3 [new file with mode: 0644]
tests/bugs/vis/bug26507_4 [new file with mode: 0644]
tests/bugs/vis/bug26507_5 [new file with mode: 0644]

index 2767e031070218d3bee6add0368be704f4a7c69f..6b81661445c58730810f6c8011cd073d496866a1 100644 (file)
@@ -597,9 +597,13 @@ void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*
 
   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
 
-  // prepare label string and compute its geometrical width
-  Standard_Real aLabelWidth;
-  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
+  TCollection_ExtendedString aLabelString = GetTextLabel();
+  // Text sizes
+  Standard_Real aLabelWidth = 0.0;
+  Standard_Real aLabelHeight = 0.0;
+  Standard_Real aSymbolWidth = 0.0;
+  Standard_Real aSymbolHeight = 0.0;
+  getLabelSizes (aLabelString, aLabelWidth, aLabelHeight, aSymbolWidth, aSymbolHeight);
 
   // add margins to label width
   if (aDimensionAspect->IsText3d())
@@ -1159,8 +1163,14 @@ const gp_Pnt AIS_AngleDimension::GetTextPosition() const
   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
 
   // Prepare label string and compute its geometrical width
-  Standard_Real aLabelWidth;
-  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
+  TCollection_ExtendedString aLabelString = GetTextLabel();
+  // Text sizes
+  Standard_Real aLabelWidth = 0.0;
+  Standard_Real aLabelHeight = 0.0;
+  Standard_Real aSymbolWidth = 0.0;
+  Standard_Real aSymbolHeight = 0.0;
+  getLabelSizes (aLabelString, aLabelWidth, aLabelHeight, aSymbolWidth, aSymbolHeight);
+
 
   gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
   gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
@@ -1339,8 +1349,14 @@ void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPo
   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
 
   // Prepare label string and compute its geometrical width
-  Standard_Real aLabelWidth;
-  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
+  TCollection_ExtendedString aLabelString = GetTextLabel();
+  // Text sizes
+  Standard_Real aLabelWidth = 0.0;
+  Standard_Real aLabelHeight = 0.0;
+  Standard_Real aSymbolWidth = 0.0;
+  Standard_Real aSymbolHeight = 0.0;
+  getLabelSizes (aLabelString, aLabelWidth, aLabelHeight, aSymbolWidth, aSymbolHeight);
+
 
   // add margins to label width
   if (aDimensionAspect->IsText3d())
index 244f46e62c25f86ace2a5a2d7877d22b671bdf17..66abc06ff48c2b878985b84b93872d00bfc1c4a8 100644 (file)
@@ -37,10 +37,11 @@ namespace
 //function : Constructor
 //purpose  : 
 //=======================================================================
-AIS_DiameterDimension::AIS_DiameterDimension (const gp_Circ& theCircle)
+AIS_DiameterDimension::AIS_DiameterDimension (const gp_Circ& theCircle,
+                                              const Standard_Real theParameter)
 : AIS_Dimension (AIS_KOD_DIAMETER)
 {
-  SetMeasuredGeometry (theCircle);
+  SetMeasuredGeometry (theCircle, theParameter);
   SetSpecialSymbol (THE_DIAMETER_SYMBOL);
   SetDisplaySpecialSymbol (AIS_DSS_Before);
   SetFlyout (0.0);
@@ -107,7 +108,8 @@ gp_Pnt AIS_DiameterDimension::AnchorPoint()
 //function : SetMeasuredGeometry
 //purpose  : 
 //=======================================================================
-void AIS_DiameterDimension::SetMeasuredGeometry (const gp_Circ& theCircle)
+void AIS_DiameterDimension::SetMeasuredGeometry (const gp_Circ& theCircle, 
+                                                 const Standard_Real theParameter)
 {
   myCircle          = theCircle;
   myGeometryType    = GeometryType_Edge;
@@ -122,7 +124,7 @@ void AIS_DiameterDimension::SetMeasuredGeometry (const gp_Circ& theCircle)
   else if (!myIsPlaneCustom)
   {
     ComputePlane();
-    myAnchorPoint = ElCLib::Value (0.0, myCircle);
+    myAnchorPoint = ElCLib::Value (theParameter, myCircle);
   }
 
   SetToUpdate();
@@ -294,7 +296,7 @@ void AIS_DiameterDimension::Compute (const Handle(PrsMgr_PresentationManager3d)&
   gp_Pnt aSecondPnt (gp::Origin());
   ComputeSidePoints (myCircle, aFirstPnt, aSecondPnt);
 
-  DrawLinearDimension (thePresentation, theMode, aFirstPnt, aSecondPnt);
+  DrawLinearDimension (thePresentation, theMode, aFirstPnt, aSecondPnt, Standard_False, myToDrawDimensionLine);
 }
 
 //=======================================================================
index de17879e616c0671b07b147f27cf873778a6d221..8b12a1dc1fe074a59e041f208cb68bf5fb9debd7 100644 (file)
@@ -58,7 +58,7 @@ public:
 
   //! Construct diameter dimension for the circle.
   //! @param theCircle [in] the circle to measure.
-  Standard_EXPORT AIS_DiameterDimension (const gp_Circ& theCircle);
+  Standard_EXPORT AIS_DiameterDimension (const gp_Circ& theCircle, const Standard_Real theParameter = 0);
 
   //! Construct diameter dimension for the circle and orient it correspondingly
   //! to the passed plane.
@@ -105,7 +105,7 @@ public:
   //! The dimension will become invalid if the diameter of the circle
   //! is less than Precision::Confusion().
   //! @param theCircle [in] the circle to measure.
-  Standard_EXPORT void SetMeasuredGeometry (const gp_Circ& theCircle);
+  Standard_EXPORT void SetMeasuredGeometry (const gp_Circ& theCircle, const Standard_Real theParameter = 0);
 
   //! Measure diameter on the passed shape, if applicable.
   //! The dimension will become invalid if the passed shape is not
index a09e1a1da27cf5cae4b1fd30c3bacfe2d4967ee6..de8af436835200f2d5c2e5bb5dabc49a1c207b3e 100755 (executable)
@@ -24,6 +24,7 @@
 #include <Bnd_Box.hxx>
 #include <ElCLib.hxx>
 #include <Font_BRepFont.hxx>
+#include <Font_FTFont.hxx>
 #include <GC_MakeCircle.hxx>
 #include <Geom_Line.hxx>
 #include <GeomAdaptor_Curve.hxx>
@@ -83,8 +84,8 @@ namespace
   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;
+  static const Standard_Real THE_3D_TEXT_MARGIN  = 0.1;
+  static const unsigned int  THE_FONT_RESOLUTION = 96;
 
   // default selection priorities
   static const Standard_Integer THE_NEUTRAL_SEL_PRIORITY = 5;
@@ -98,37 +99,102 @@ namespace
 AIS_Dimension::AIS_Dimension (const AIS_KindOfDimension theType)
 : AIS_InteractiveObject  (),
   mySelToleranceForText2d(0.0),
-  myCustomValue          (0.0),
-  myIsValueCustom        (Standard_False),
+  myTypeOfLabel          (TOL_Computed),
+  myLabel                (""),
   myIsTextPositionFixed  (Standard_False), 
   mySpecialSymbol        (' '),
   myDisplaySpecialSymbol (AIS_DSS_No),
+  myToDrawDimensionLine  (Standard_True),
   myGeometryType         (GeometryType_UndefShapes),
   myIsPlaneCustom        (Standard_False),
   myFlyout               (0.0),
+  myIsTextAligned        (Standard_False),
+  myTextDir              (1.0, 0.0, 0.0),
+  myLeaderSegmentLength  (0.0),
   myIsGeometryValid      (Standard_False),
   myKindOfDimension      (theType)
 {
 }
 
+//=======================================================================
+//function : GetValue
+//purpose  : 
+//=======================================================================
+Standard_Real AIS_Dimension::GetValue() const
+{
+  switch (myTypeOfLabel)
+  {
+    case TOL_Computed:
+      return ComputeValue();
+    case TOL_Value:
+      {
+        return myCustomValue;
+      }
+    case TOL_Text:
+    default:
+      return 0.0;
+  };
+}
+
 //=======================================================================
 //function : SetCustomValue
 //purpose  : 
 //=======================================================================
 void AIS_Dimension::SetCustomValue (const Standard_Real theValue)
 {
-  if (myIsValueCustom && myCustomValue == theValue)
+  if (myTypeOfLabel == TOL_Value && GetValue() == theValue)
   {
     return;
   }
 
-  myIsValueCustom = Standard_True;
+  myTypeOfLabel = TOL_Value;
 
   myCustomValue = theValue;
 
   SetToUpdate();
 }
 
+//=======================================================================
+//function : SetTextLabel
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::SetTextLabel (const TCollection_ExtendedString& theValue)
+{
+  myTypeOfLabel = TOL_Text;
+  myLabel = theValue;
+}
+
+//=======================================================================
+//function : GetTextLabel
+//purpose  : 
+//=======================================================================
+TCollection_ExtendedString AIS_Dimension::GetTextLabel() const
+{
+  if (myTypeOfLabel == TOL_Text)
+  {
+    return myLabel;
+  }
+  else
+  {
+    TCollection_ExtendedString aString;
+
+    // Format value string using "sprintf"
+    TCollection_AsciiString aFormatStr = myDrawer->DimensionAspect()->ValueStringFormat();
+
+    char aFmtBuffer[256];
+    sprintf (aFmtBuffer, aFormatStr.ToCString(), ValueToDisplayUnits());
+    aString = TCollection_ExtendedString (aFmtBuffer);
+
+    // Add units to values string
+    if (myDrawer->DimensionAspect()->IsUnitsDisplayed())
+    {
+      aString += " ";
+      aString += TCollection_ExtendedString (GetDisplayUnits());
+    }
+    return aString;
+  }
+}
+
 //=======================================================================
 //function : GetPlane
 //purpose  : 
@@ -142,7 +208,7 @@ const gp_Pln& AIS_Dimension::GetPlane() const
 //function : GetGeometryType
 //purpose  : 
 //=======================================================================
-const Standard_Integer AIS_Dimension::GetGeometryType () const
+const Standard_Integer AIS_Dimension::GetGeometryType() const
 {
   return myGeometryType;
 }
@@ -244,6 +310,75 @@ void AIS_Dimension::SetFlyout (const Standard_Real theFlyout)
   SetToUpdate();
 }
 
+//=======================================================================
+//function : ToDrawDimensionLine
+//purpose  : 
+//=======================================================================
+const Standard_Boolean AIS_Dimension::ToDrawDimensionLine() const
+{
+  return myToDrawDimensionLine;
+}
+
+//=======================================================================
+//function : SetToDrawDimensionLine
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::SetToDrawDimensionLine (const Standard_Boolean theToDraw)
+{
+  myToDrawDimensionLine = theToDraw;
+}
+
+//=======================================================================
+//function : SetToAlignText
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::SetToAlignText (const Standard_Boolean theToAlign,
+                                    const gp_Dir& theAlignmentDir)
+{
+  myIsTextAligned = theToAlign;
+  myTextDir = theAlignmentDir;
+  if (theToAlign && !myTextDir.IsNormal (myPlane.Axis().Direction(), Precision::Angular() ) )
+  {
+    myIsTextAligned = Standard_False;
+  }
+}
+
+//=======================================================================
+//function : IsTextAligned
+//purpose  : 
+//=======================================================================
+const Standard_Boolean AIS_Dimension::IsTextAligned() const
+{
+  return myIsTextAligned;
+}
+
+//=======================================================================
+//function : TextAlignmentDir
+//purpose  : 
+//=======================================================================
+const gp_Dir& AIS_Dimension::TextAlignmentDir() const
+{
+  return myTextDir;
+}
+
+//=======================================================================
+//function : SetLeaderSegment
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::SetLeaderSegment (const Standard_Real& theLength)
+{
+  myLeaderSegmentLength = theLength;
+}
+
+//=======================================================================
+//function : UnsetLeaderSegment
+//purpose  : 
+//=======================================================================
+void AIS_Dimension::UnsetLeaderSegment()
+{
+  myLeaderSegmentLength = 0.0;
+}
+
 //=======================================================================
 //function : GetDisplayUnits
 //purpose  :
@@ -273,73 +408,62 @@ Standard_Real AIS_Dimension::ValueToDisplayUnits() const
                              GetDisplayUnits().ToCString());
 }
 
-//=======================================================================
-//function : GetValueString
-//purpose  : 
-//=======================================================================
-TCollection_ExtendedString AIS_Dimension::GetValueString (Standard_Real& theWidth) const
+// =======================================================================
+// function : getLabelSizes
+// purpose  :
+// =======================================================================
+void  AIS_Dimension::getLabelSizes (const TCollection_ExtendedString& theLabel,
+                                    Standard_Real& theWidth,
+                                    Standard_Real& theHeight,
+                                    Standard_Real& theSymbolWidth,
+                                    Standard_Real& theSymbolHeight) const
 {
-  // format value string using "sprintf"
-  TCollection_AsciiString aFormatStr = myDrawer->DimensionAspect()->ValueStringFormat();
+  Handle(Prs3d_DimensionAspect) anAspect    = myDrawer->DimensionAspect();
+  Handle(Prs3d_TextAspect)      aTextAspect = myDrawer->DimensionAspect()->TextAspect();
+  Standard_Real                 aFontHeight = aTextAspect->Height();
 
-  char aFmtBuffer[256];
-  sprintf (aFmtBuffer, aFormatStr.ToCString(), ValueToDisplayUnits());
-  TCollection_ExtendedString aValueStr = TCollection_ExtendedString (aFmtBuffer);
+  Quantity_Color aColor;
+  Standard_CString aFontName;
+  Standard_Real anExpFactor, aSpace;
+  aTextAspect->Aspect()->Values (aColor, aFontName, anExpFactor, aSpace);
 
-  // add units to values string
-  if (myDrawer->DimensionAspect()->IsUnitsDisplayed())
+  NCollection_String aText   ((Standard_Utf16Char*) theLabel.ToExtString());
+  NCollection_String aSymbol;
+  if (DisplaySpecialSymbol() != AIS_DSS_No)
   {
-    aValueStr += " ";
-    aValueStr += TCollection_ExtendedString (GetDisplayUnits());
+    aSymbol.FromUnicode ((Standard_Utf16Char*) TCollection_ExtendedString (mySpecialSymbol).ToExtString());
   }
 
-  switch (myDisplaySpecialSymbol)
-  {
-    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;
-  }
+  Font_FTFont::Rect aTextBox;
+  Font_FTFont::Rect aSymbolBox;
 
-  // Get text style parameters
-  Quantity_Color aColor; 
-  Standard_CString aFontName;
-  Standard_Real aFactor;
-  Standard_Real aSpace;
-  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())
+  if (!anAspect->IsText3d())
   {
-    // text width produced by BRepFont
-    Font_BRepFont aFont (aFontName, aFontAspect, aFontHeight);
-
-    for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
+    Font_FTFont aFont;
+    aFont.Init (aFontName,
+                aTextAspect->Aspect()->GetTextFontAspect(),
+                static_cast<Standard_Integer> (aFontHeight),
+                THE_FONT_RESOLUTION);
+    aTextBox = aFont.BoundingBox (aText, Graphic3d_HTA_LEFT, Graphic3d_VTA_TOP);
+    if (!aSymbol.IsEmpty())
     {
-      Standard_Utf32Char aCurrChar = *anIter;
-      Standard_Utf32Char aNextChar = *(++anIter);
-      theWidth += aFont.AdvanceX (aCurrChar, aNextChar);
+      aSymbolBox = aFont.BoundingBox (aSymbol, Graphic3d_HTA_LEFT, Graphic3d_VTA_TOP);
     }
   }
   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; )
+    Font_BRepFont aFont (aFontName, aTextAspect->Aspect()->GetTextFontAspect(), aFontHeight);
+    aTextBox = aFont.BoundingBox (aText);
+    if (!aSymbol.IsEmpty())
     {
-      Standard_Utf32Char aCurrChar = *anIter;
-      Standard_Utf32Char aNextChar = *(++anIter);
-      theWidth += (Standard_Real) aFont->AdvanceX (aCurrChar, aNextChar);
+      aSymbolBox = aFont.BoundingBox (aSymbol);
     }
   }
 
-  return aValueStr;
+  theWidth        = aTextBox.Width();
+  theHeight       = aTextBox.Height();
+  theSymbolWidth  = aSymbolBox.Width();
+  theSymbolHeight = aSymbolBox.Height();
 }
 
 //=======================================================================
@@ -410,59 +534,104 @@ void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
                               const TCollection_ExtendedString& theText,
                               const Standard_Integer theLabelPosition)
 {
+  // Prepare font
+  const Handle(Prs3d_TextAspect)& aTextAspect = myDrawer->DimensionAspect()->TextAspect();
+  Handle(Graphic3d_AspectText3d) anAspectText3d = aTextAspect->Aspect();
+  Quantity_Color aColor;
+  Standard_CString aFontName;
+  Standard_Real anExpFactor, aSpace;
+  anAspectText3d->Values (aColor, aFontName, anExpFactor, aSpace);
+  Font_FontAspect aFontAspect = anAspectText3d->GetTextFontAspect();
+  const Standard_Real aFontHeight = aTextAspect->Height();
+
+  Standard_Real aWidth  = 0.0;
+  Standard_Real aHeight = 0.0;
+  Standard_Real aSymbolWidth = 0.0;
+  Standard_Real aSymbolHeight = 0.0;
+  getLabelSizes (theText, aWidth, aHeight, aSymbolWidth, aSymbolHeight);
+  aWidth += aSymbolWidth;
+
+  // Compute label offsets
+  Standard_Real aMarginSize    = aFontHeight * THE_3D_TEXT_MARGIN;
+  Standard_Real aCenterHOffset = 0.0;
+  Standard_Real aCenterVOffset = 0.0;
+  Standard_Real aSymbolVOffset = 0.0; //< Offset of symbol relative to the main text
+
+  Standard_Integer aVLabelPos = theLabelPosition & LabelPosition_VMask;
+
   if (myDrawer->DimensionAspect()->IsText3d())
   {
-    // 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 aFontHeight = myDrawer->DimensionAspect()->TextAspect()->Height();
-
-    // creating TopoDS_Shape for text
+    // 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; )
+    // Add special symbol
+    TopoDS_Shape aSymbolShape;
+    if (myDisplaySpecialSymbol != AIS_DSS_No)
     {
-      Standard_Utf32Char aCurrChar = *anIter;
-      Standard_Utf32Char aNextChar = *(++anIter);
-      aTextWidth += aFont.AdvanceX (aCurrChar, aNextChar);
+      NCollection_Utf8String anUTFSymbol = (Standard_Utf16Char* )TCollection_ExtendedString (mySpecialSymbol).ToExtString();
+      aSymbolShape = aFont.RenderText (anUTFSymbol);
     }
 
-    // formating text position in XOY plane
+    // 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 LabelPosition_HCenter : aCenterHOffset =  0.0; break;
-      case LabelPosition_Right   : aCenterHOffset =  aTextWidth / 2.0 + aMarginSize; break;
-      case LabelPosition_Left    : aCenterHOffset = -aTextWidth / 2.0 - aMarginSize; break;
+      case LabelPosition_Right   : aCenterHOffset =  aWidth / 2.0 + aMarginSize; break;
+      case LabelPosition_Left    : aCenterHOffset = -aWidth / 2.0 - aMarginSize; break;
     }
+
+    const Standard_Real aHeightOfLine = aFont.LineSpacing();
+
     switch (aVLabelPos)
     {
+      case LabelPosition_FirstLine:
+      {
+        if (myTypeOfLabel == TOL_Text && aHeight > aHeightOfLine)
+        {
+          aCenterVOffset = aHeight / 2.0 - aHeightOfLine;
+          aSymbolVOffset = aCenterVOffset - aHeightOfLine / 2.0 + aMarginSize;
+        }
+        break;
+      }
+      case LabelPosition_LastLine:
+      {
+        if (myTypeOfLabel == TOL_Text && aHeight > aHeightOfLine)
+        {
+          aCenterVOffset = aHeightOfLine - aHeight / 2.0 ;
+          aSymbolVOffset = aCenterVOffset - aHeight + aHeightOfLine / 2.0 - aMarginSize; 
+        }
+        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;
+      case LabelPosition_Above:
+      {
+        aCenterVOffset =  aHeight / 2.0 + aMarginSize;
+        if (myTypeOfLabel == TOL_Text)
+        {
+          aSymbolVOffset = aCenterVOffset / 2;
+        }
+        break;
+      }
+      case LabelPosition_Below:
+      {
+        aCenterVOffset = -aHeight / 2.0 - aMarginSize;
+        if (myTypeOfLabel == TOL_Text)
+        {
+          aSymbolVOffset = aCenterVOffset / 2;
+        }
+        break;
+      }
     }
 
-    // compute shape offset transformation
-    Standard_Real aShapeHOffset = aCenterHOffset - aTextWidth / 2.0;
-    Standard_Real aShapeVOffset = aCenterVOffset - aTextHeight / 2.0;
+    // Correct text direction
+    gp_Dir aTextDir  = (aHLabelPos == LabelPosition_Left ? -theTextDir : theTextDir);
+
+    // Compute shape offset transformation
+    Standard_Real aShapeHOffset = aCenterHOffset - aWidth / 2.0 + aSymbolWidth / 2.0;
+    Standard_Real aShapeVOffset = aCenterVOffset - aHeight / 2.0;
 
     // center shape in its bounding box (suppress border spacing added by FT_Font)
     Bnd_Box aShapeBnd;
@@ -471,8 +640,8 @@ void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
     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;
+    Standard_Real aXalign = aWidth  * 0.5 - (aXmax + aXmin) * 0.5;
+    Standard_Real aYalign = aHeight * 0.5 - (aYmax + aYmin) * 0.5;
     aShapeHOffset += aXalign;
     aShapeVOffset += aYalign;
 
@@ -486,11 +655,20 @@ void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
     aTextPlaneTrsf.SetTransformation (aTextCoordSystem, gp_Ax3 (gp::XOY()));
     aTextShape.Move (aTextPlaneTrsf);
 
-    // set text flipping anchors
+    if (!aSymbolShape.IsNull())
+    {
+      aSymbolVOffset += aYalign - aHeight / 2.0;
+
+      // Modify transformation for a special symbol relative! to the main text
+      anOffsetTrsf.SetTranslation (gp::Origin(), gp_Pnt (aShapeHOffset - aSymbolWidth, aSymbolVOffset, 0.0));
+      aSymbolShape.Move (anOffsetTrsf);
+      aSymbolShape.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);
@@ -498,7 +676,7 @@ void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
     gp_Ax2 aFlippingAxes (aCenterOfLabel, GetPlane().Axis().Direction(), aTextDir);
     Prs3d_Root::CurrentGroup (thePresentation)->SetFlippingOptions (Standard_True, aFlippingAxes);
 
-    // draw text
+    // Draw text
     if (myDrawer->DimensionAspect()->IsTextShaded())
     {
       // Setting text shading and color parameters
@@ -510,33 +688,85 @@ void AIS_Dimension::DrawText (const Handle(Prs3d_Presentation)& thePresentation,
       myDrawer->ShadingAspect()->Aspect()->SetBackInteriorColor (aColor);
       myDrawer->ShadingAspect()->SetMaterial (aShadeMat);
 
-      // drawing text
+      // Drawing text
       StdPrs_ShadedShape::Add (thePresentation, aTextShape, myDrawer);
+      StdPrs_ShadedShape::Add (thePresentation, aSymbolShape, 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);
+      StdPrs_WFShape::Add (thePresentation, aSymbolShape, myDrawer);
     }
     Prs3d_Root::CurrentGroup (thePresentation)->SetFlippingOptions (Standard_False, gp_Ax2());
 
     mySelectionGeom.TextPos    = aCenterOfLabel;
     mySelectionGeom.TextDir    = aTextDir;
-    mySelectionGeom.TextWidth  = aTextWidth + aMarginSize * 2.0;
-    mySelectionGeom.TextHeight = aTextHeight;
+    mySelectionGeom.TextWidth  = aWidth + aMarginSize * 2.0;
+    mySelectionGeom.TextHeight = aHeight + aSymbolHeight;
 
     return;
   }
 
-  // generate primitives for 2D text
+  // Generate primitives for 2D text
   myDrawer->DimensionAspect()->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_DIMENSION);
 
-  Prs3d_Text::Draw (thePresentation,
-                    myDrawer->DimensionAspect()->TextAspect(),
-                    theText,
-                    theTextPos);
+  gp_Pnt aTextPos = theTextPos;
+
+  Font_FTFont aFont;
+  aFont.Init (aFontName,
+              anAspectText3d->GetTextFontAspect(),
+              static_cast<Standard_Integer>(aFontHeight),
+              THE_FONT_RESOLUTION);
+  const Standard_Real aHeightOfLine = aFont.LineSpacing();
+
+  switch (aVLabelPos)
+  {
+    case LabelPosition_FirstLine: break;
+    case LabelPosition_LastLine : break;
+    case LabelPosition_VCenter  : break;
+    case LabelPosition_Above:
+    {
+      if (myTypeOfLabel == TOL_Text && aHeight > aHeightOfLine)
+      {
+        aSymbolVOffset = -aWidth / 2;
+      }
+      break;
+    }
+    case LabelPosition_Below:
+    {
+      if (myTypeOfLabel == TOL_Text && aHeight > aHeightOfLine)
+      {
+        aSymbolVOffset = aWidth / 2;
+      }
+      break;
+    }
+  }
+
+  Prs3d_Text::Draw (thePresentation, myDrawer->DimensionAspect()->TextAspect(),
+                    theText, aTextPos);
+
+  switch (myDisplaySpecialSymbol)
+  {
+    case AIS_DSS_Before:
+    {
+      gp_Pnt aSymbolPos (theTextPos.X(), theTextPos.Y() + aSymbolVOffset, theTextPos.Z());
+      Prs3d_Text::Draw (thePresentation, myDrawer->DimensionAspect()->TextAspect(),
+                        TCollection_ExtendedString (mySpecialSymbol), aSymbolPos);
+      break;
+    }
+    case AIS_DSS_After:
+    {
+       gp_Pnt aSymbolPos (theTextPos.X() + aWidth, theTextPos.Y() + aSymbolVOffset, theTextPos.Z());
+       Prs3d_Text::Draw (thePresentation, myDrawer->DimensionAspect()->TextAspect(),
+         TCollection_ExtendedString (mySpecialSymbol), aSymbolPos);
+       break;
+    }
+    case AIS_DSS_No: break;
+  }
 
   mySelectionGeom.TextPos    = theTextPos;
   mySelectionGeom.TextDir    = theTextDir;
@@ -561,11 +791,33 @@ void AIS_Dimension::DrawExtension (const Handle(Prs3d_Presentation)& thePresenta
   gp_Lin anExtensionLine (theExtensionStart, theExtensionDir);
 
   Standard_Boolean hasLabel = theLabelString.Length() > 0;
+
+  gp_Dir aTextDir = myIsTextAligned
+    ? (myTextDir*theExtensionDir < 0 ? -myTextDir : myTextDir)
+    : theExtensionDir;
+
+  // Compute graphical primitives and sensitives for extension line
+  gp_Pnt anExtStart = theExtensionStart;
+  gp_Pnt   anExtEnd = !hasLabel || !(theLabelPosition & LabelPosition_Above || theLabelPosition & LabelPosition_Below)
+    ? ElCLib::Value (theExtensionSize, anExtensionLine)
+    : ElCLib::Value (theExtensionSize + theLabelWidth, anExtensionLine);
+
+  gp_Pnt aSegmentPoint;
+
   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;
+
+    if (hasLabel && myLeaderSegmentLength > 0 && myIsTextAligned)
+    {
+      gp_Lin aSegmentLine (anExtEnd, aTextDir);
+      Standard_Real aSegmentLength = !(theLabelPosition & LabelPosition_Above || theLabelPosition & LabelPosition_Below)
+        ? myLeaderSegmentLength : theLabelWidth + myLeaderSegmentLength;
+      aSegmentPoint  = ElCLib::Value (aSegmentLength, aSegmentLine);
+      aTextPos = !(theLabelPosition & LabelPosition_Above || theLabelPosition & LabelPosition_Below)
+        ? aSegmentPoint : ElCLib::Value (myLeaderSegmentLength, aSegmentLine);
+    }
 
     DrawText (thePresentation,
               aTextPos,
@@ -579,21 +831,18 @@ void AIS_Dimension::DrawExtension (const Handle(Prs3d_Presentation)& thePresenta
     return;
   }
 
-  Standard_Boolean isShortLine =  !myDrawer->DimensionAspect()->IsText3d()
-                               || theLabelPosition & LabelPosition_VCenter;
-
-  // 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);
-
-  // add graphical primitives
-  Handle(Graphic3d_ArrayOfSegments) anExtPrimitive = new Graphic3d_ArrayOfSegments (2);
+  // Add graphical primitives
+  Handle(Graphic3d_ArrayOfSegments) anExtPrimitive = new Graphic3d_ArrayOfSegments ((hasLabel && myLeaderSegmentLength > 0 && myIsTextAligned) ? 4 : 2);
   anExtPrimitive->AddVertex (anExtStart);
   anExtPrimitive->AddVertex (anExtEnd);
+  // Draw segment
+  if (hasLabel && myLeaderSegmentLength > 0 && myIsTextAligned)
+  {
+    anExtPrimitive->AddVertex (anExtEnd);
+    anExtPrimitive->AddVertex (aSegmentPoint);
+  }
 
-  // add selection primitives
+  // Add selection primitives
   SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
   aSensitiveCurve.Append (anExtStart);
   aSensitiveCurve.Append (anExtEnd);
@@ -619,7 +868,8 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
                                          const Standard_Integer theMode,
                                          const gp_Pnt& theFirstPoint,
                                          const gp_Pnt& theSecondPoint,
-                                         const Standard_Boolean theIsOneSide)
+                                         const Standard_Boolean theIsOneSide,
+                                         const Standard_Boolean theToDrawDimensionLine)
 {
   // do not build any dimension for equal points
   if (theFirstPoint.IsEqual (theSecondPoint, Precision::Confusion()))
@@ -632,9 +882,14 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
   // 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);
+
+  // Prepare label string and compute its geometrical sizes
+  Standard_Real aLabelWidth, aLabelHeight;
+  Standard_Real aSymbolWidth, aSymbolHeight;
+  TCollection_ExtendedString aLabel = GetTextLabel();
+  getLabelSizes (aLabel, aLabelWidth, aLabelHeight, aSymbolWidth, aSymbolHeight);
+  aLabelHeight += aSymbolHeight;
+  aLabelWidth += aSymbolWidth;
 
   // add margins to cut dimension lines for 3d text
   if (aDimensionAspect->IsText3d())
@@ -659,7 +914,7 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
   FitTextAlignmentForLinear (theFirstPoint, theSecondPoint, theIsOneSide, aHorisontalTextPos,
                              aLabelPosition, isArrowsExternal);
 
-    // compute dimension line points
+  // compute dimension line points
   gp_Ax1 aPlaneNormal = GetPlane().Axis();
   gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
 
@@ -717,7 +972,11 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
 
       gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
                                               : (aCenterLineBegin.XYZ() + aCenterLineEnd.XYZ()) * 0.5;
-      gp_Dir aTextDir = aDimensionLine.Direction();
+
+      // Choose a text direction
+      gp_Dir aTextDir = myIsTextAligned
+        ? myTextDir
+        : aDimensionLine.Direction();
 
       // add text primitives
       if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
@@ -725,15 +984,18 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
         DrawText (thePresentation,
                   aTextPos,
                   aTextDir,
-                  aLabelString,
+                  aLabel,
                   aLabelPosition);
       }
 
       // add dimension line primitives
       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
-                                    && aDimensionAspect->IsText3d();
+        // Line break is made only for 3d text (for 2d text it is managed with stensil test)
+        // and for special alignment for multi-line text
+        Standard_Boolean isLineBreak = aDimensionAspect->IsText3d() &&
+         (aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center || (myTypeOfLabel == TOL_Text &&
+           (aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_FirstLine || aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_LastLine) ) );
 
         Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (isLineBreak ? 4 : 2);
 
@@ -770,11 +1032,15 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
 
         // set text label justification
         Graphic3d_VerticalTextAlignment aTextJustificaton = Graphic3d_VTA_BOTTOM;
+
+        // TODO check it!
         switch (aLabelPosition & LabelPosition_VMask)
         {
-          case LabelPosition_Above   :
-          case LabelPosition_VCenter : aTextJustificaton = Graphic3d_VTA_BOTTOM; break;
-          case LabelPosition_Below   : aTextJustificaton = Graphic3d_VTA_TOP;    break;
+          case LabelPosition_Above     :
+          case LabelPosition_LastLine  :
+          case LabelPosition_VCenter   : aTextJustificaton = Graphic3d_VTA_BOTTOM; break;
+          case LabelPosition_FirstLine :
+          case LabelPosition_Below     : aTextJustificaton = Graphic3d_VTA_TOP;    break;
         }
         aDimensionAspect->TextAspect()->SetVerticalJustification (aTextJustificaton);
 
@@ -835,7 +1101,7 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
                        ? aFirstArrowEnd
                        : aFirstArrowBegin,
                      aFirstExtensionDir,
-                     aLabelString,
+                     aLabel,
                      aLabelWidth,
                      theMode,
                      aLabelPosition);
@@ -843,27 +1109,30 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
       // add dimension line primitives
       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        // add central dimension line
-        Prs3d_Root::NewGroup (thePresentation);
+        if (theToDrawDimensionLine || !isArrowsExternal)
+        {
+          // 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);
+          // 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);
+          Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
+          Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
 
-        // add selection primitives
-        SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
-        aSensitiveCurve.Append (aCenterLineBegin);
-        aSensitiveCurve.Append (aCenterLineEnd);
+          // 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)
+        if (!theIsOneSide && (theToDrawDimensionLine || (!isArrowsExternal && !theToDrawDimensionLine) ))
         {
           DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
         }
@@ -876,9 +1145,12 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
         // add extension lines for external arrows
         Prs3d_Root::NewGroup (thePresentation);
 
-        DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
-                       aSecondArrowEnd, aSecondExtensionDir,
-                       THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        if (theToDrawDimensionLine)
+        {
+          DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+            aSecondArrowEnd, aSecondExtensionDir,
+            THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        }
       }
 
       break;
@@ -898,32 +1170,35 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
                        ? aSecondArrowEnd
                        : aSecondArrowBegin,
                      aSecondExtensionDir,
-                     aLabelString, aLabelWidth,
+                     aLabel, aLabelWidth,
                      theMode,
                      aLabelPosition);
 
       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
       {
-        // add central dimension line
-        Prs3d_Root::NewGroup (thePresentation);
+        if (theToDrawDimensionLine || !isArrowsExternal)
+        {
+          // 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);
+          // 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);
 
-        // add selection primitives
-        SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
-        aSensitiveCurve.Append (aCenterLineBegin);
-        aSensitiveCurve.Append (aCenterLineEnd);
+          // add selection primitives
+          SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
+          aSensitiveCurve.Append (aCenterLineBegin);
+          aSensitiveCurve.Append (aCenterLineEnd);
+        }
 
         // add arrows to presentation
         Prs3d_Root::NewGroup (thePresentation);
 
         DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
-        if (!theIsOneSide)
+        if (!theIsOneSide && (theToDrawDimensionLine || (!theToDrawDimensionLine && !isArrowsExternal) ))
         {
           DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
         }
@@ -936,9 +1211,12 @@ void AIS_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePr
         // add extension lines for external arrows
         Prs3d_Root::NewGroup (thePresentation);
 
-        DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
-                       aFirstArrowEnd, aFirstExtensionDir,
-                       THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        if (theToDrawDimensionLine)
+        {
+          DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
+                         aFirstArrowEnd, aFirstExtensionDir,
+                         THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
+        }
       }
 
       break;
@@ -1582,8 +1860,15 @@ void AIS_Dimension::FitTextAlignmentForLinear (const gp_Pnt& theFirstPoint,
   Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
 
   // prepare label string and compute its geometrical width
-  Standard_Real aLabelWidth;
-  TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
+  TCollection_ExtendedString aLabelString = GetTextLabel();
+
+  // Text sizes
+  Standard_Real aLabelWidth = 0.0;
+  Standard_Real aLabelHeight = 0.0;
+  Standard_Real aSymbolWidth = 0.0;
+  Standard_Real aSymbolHeight = 0.0;
+  getLabelSizes (aLabelString, aLabelWidth, aLabelHeight, aSymbolWidth, aSymbolHeight);
+
 
   // Add margins to cut dimension lines for 3d text
   if (aDimensionAspect->IsText3d())
@@ -1617,7 +1902,7 @@ void AIS_Dimension::FitTextAlignmentForLinear (const gp_Pnt& theFirstPoint,
   switch (theHorizontalTextPos)
   {
     case Prs3d_DTHP_Left  : theLabelPosition |= LabelPosition_Left; break;
-    case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
+    case Prs3d_DTHP_Right : theLabelPosition |= theIsOneSide ? LabelPosition_Left : LabelPosition_Right; break;
     case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
     case Prs3d_DTHP_Fit:
     {
@@ -1634,7 +1919,9 @@ void AIS_Dimension::FitTextAlignmentForLinear (const gp_Pnt& theFirstPoint,
   switch (aDimensionAspect->TextVerticalPosition())
   {
     case Prs3d_DTVP_Above  : theLabelPosition |= LabelPosition_Above; break;
+    case Prs3d_DTVP_FirstLine : theLabelPosition |= LabelPosition_FirstLine; break;
     case Prs3d_DTVP_Below  : theLabelPosition |= LabelPosition_Below; break;
+    case Prs3d_DTVP_LastLine : theLabelPosition |= LabelPosition_LastLine; break;
     case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
   }
 }
index 6992339ff9a56765f4e209d271ee71144740c96c..3b8c32e1e1d9d7078d08111bf5fcc4107d2ea0ff 100755 (executable)
@@ -195,10 +195,12 @@ protected:
     LabelPosition_HCenter = 0x04,
     LabelPosition_HMask   = LabelPosition_Left | LabelPosition_Right | LabelPosition_HCenter,
 
-    LabelPosition_Above   = 0x10,
-    LabelPosition_Below   = 0x20,
-    LabelPosition_VCenter = 0x40,
-    LabelPosition_VMask   = LabelPosition_Above | LabelPosition_Below | LabelPosition_VCenter
+    LabelPosition_Above     = 0x0010,
+    LabelPosition_FirstLine = 0x0020,
+    LabelPosition_Below     = 0x0040,
+    LabelPosition_LastLine  = 0x0080,
+    LabelPosition_VCenter   = 0x0100,
+    LabelPosition_VMask     = LabelPosition_Above | LabelPosition_Below | LabelPosition_VCenter | LabelPosition_FirstLine | LabelPosition_LastLine
   };
 
 public:
@@ -224,10 +226,7 @@ public:
   //! compute it on its own in model space coordinates.
   //! @return the dimension value (in model units) which is used
   //! during display of the presentation.
-  Standard_Real GetValue() const
-  {
-    return myIsValueCustom ? myCustomValue : ComputeValue();
-  }
+  Standard_EXPORT Standard_Real GetValue() const;
 
   //! Sets user-defined dimension value.
   //! The user-defined dimension value is specified in model space,
@@ -235,6 +234,14 @@ public:
   //! @param theValue [in] the user-defined value to display.
   Standard_EXPORT void SetCustomValue (const Standard_Real theValue);
 
+  //! Sets nultiline text for dimension label.
+  //! @param theValue [in] multiline string of Unicode symbols.
+  //! Can be used along with spectial symbol (like radius and diameter symbol)
+  Standard_EXPORT void SetTextLabel (const TCollection_ExtendedString& theValue);
+
+  //! @return the text for text label.
+  Standard_EXPORT TCollection_ExtendedString GetTextLabel() const;
+
   //! Get the dimension plane in which the 2D dimension presentation is computed.
   //! By default, if plane is not defined by user, it is computed automatically
   //! after dimension geometry is computed.
@@ -375,6 +382,26 @@ public:
     return myIsGeometryValid && CheckPlane (GetPlane());
   }
 
+  //! @return state that shows if the radius inner segment
+  //! is to be displayed.
+  Standard_EXPORT const Standard_Boolean ToDrawDimensionLine() const;
+
+  //! Sets the flag that defines whether the dimenion line segment is displayed
+  //! @warning Dimension line won't be displayed only if arrows and label are moved
+  //! outside on dimension line extensions
+  Standard_EXPORT void SetToDrawDimensionLine (const Standard_Boolean theToDrawInnerSegment);
+
+  Standard_EXPORT void SetToAlignText (const Standard_Boolean theToAlign,
+                                       const gp_Dir& theAlignmentDir = gp_Dir (1.0, 0.0, 0.0));
+
+  Standard_EXPORT const Standard_Boolean IsTextAligned() const;
+
+  Standard_EXPORT const gp_Dir& TextAlignmentDir() const;
+
+  Standard_EXPORT void SetLeaderSegment (const Standard_Real& theLength);
+
+  Standard_EXPORT void UnsetLeaderSegment();
+
 public:
 
   DEFINE_STANDARD_RTTI(AIS_Dimension)
@@ -383,10 +410,9 @@ protected:
 
   Standard_EXPORT Standard_Real ValueToDisplayUnits() const;
 
-  //! Get formatted value string and its model space width.
-  //! @param theWidth [out] the model space with of the string.
-  //! @return formatted dimension value string.
-  Standard_EXPORT TCollection_ExtendedString GetValueString (Standard_Real& theWidth) const;
+  Standard_EXPORT void getLabelSizes (const TCollection_ExtendedString& theLabel,
+                                      Standard_Real& theWidth, Standard_Real& theHeight,
+                                      Standard_Real& theSymbolWidth, Standard_Real& theSymbolHeight) const;
 
   //! Performs drawing of 2d or 3d arrows on the working plane
   //! @param theLocation [in] the location of the arrow tip.
@@ -434,11 +460,15 @@ protected:
   //! @param theFirstPoint [in] the first attach point of linear dimension.
   //! @param theSecondPoint [in] the second attach point of linear dimension.
   //! @param theIsOneSide [in] specifies whether the dimension has only one flyout line.
+  //! @param theToDrawDimensionLine [in] specifies whether the dimension line is to be displayed.
+  //! @warning Dimension line won't be displayed only if arrows and label are moved
+  //! outside on dimension line extensions
   Standard_EXPORT void DrawLinearDimension (const Handle(Prs3d_Presentation)& thePresentation,
                                             const Standard_Integer theMode,
                                             const gp_Pnt& theFirstPoint,
                                             const gp_Pnt& theSecondPoint,
-                                            const Standard_Boolean theIsOneSide = Standard_False);
+                                            const Standard_Boolean theIsOneSide = Standard_False,
+                                            const Standard_Boolean theToDrawDimensionLine = Standard_True);
 
   //! Compute selection sensitives for linear dimension flyout lines (length, diameter, radius).
   //! Please note that this method uses base dimension properties: working plane and flyout length.
@@ -650,29 +680,57 @@ protected: //! @name Selection geometry
 
   Standard_Real mySelToleranceForText2d; //!< Sensitive point tolerance for 2d text selection.
 
-protected: //! @name Value properties
+protected:
+
+  enum TypeOfLabel
+  {
+    TOL_Computed = 0, //< is default
+    TOL_Value    = 1,
+    TOL_Text 
+  };
+
+protected: //! @name Label properties
+
+  TypeOfLabel myTypeOfLabel;
 
-  Standard_Real    myCustomValue;   //!< Value of the dimension (computed or user-defined).
-  Standard_Boolean myIsValueCustom; //!< Is user-defined value.
+  Standard_Real              myCustomValue; //!< Value of the dimension (computed or user-defined).
+  TCollection_ExtendedString myLabel;        //!< Label text. Sets the user defined multiline text
 
 protected: //! @name Fixed text position properties
 
-  gp_Pnt                  myFixedTextPosition;   //!< Stores text position fixed by user.
-  Standard_Boolean        myIsTextPositionFixed; //!< Is the text label position fixed by user.
+  gp_Pnt                   myFixedTextPosition;   //!< Stores text position fixed by user.
+  Standard_Boolean         myIsTextPositionFixed; //!< Is the text label position fixed by user.
 
 protected: //! @name Units properties
 
   Standard_ExtCharacter    mySpecialSymbol;        //!< Special symbol.
   AIS_DisplaySpecialSymbol myDisplaySpecialSymbol; //!< Special symbol display options.
 
+protected:
+
+  //! Shows if the dimension line is to be drawn
+  //! It is used only if the text is placed on the one of the dimension line extensions.
+  //! By default it is TRUE
+  //! @warning Dimension line won't be displayed only if arrows and label are moved
+  //! outside on dimension line extensions
+  Standard_Boolean myToDrawDimensionLine;
+
 protected: //! @name Geometrical properties
 
   GeometryType myGeometryType;  //!< defines type of shapes on which the dimension is to be built. 
 
-  gp_Pln           myPlane;           //!< Plane where dimension will be built (computed or user defined).
-  Standard_Boolean myIsPlaneCustom;   //!< Is plane defined by user (otherwise it will be computed automatically).
-  Standard_Real    myFlyout;          //!< Flyout distance.
-  Standard_Boolean myIsGeometryValid; //!< Is dimension geometry properly defined.
+  gp_Pln           myPlane;               //!< Plane where dimension will be built (computed or user defined).
+  Standard_Boolean myIsPlaneCustom;       //!< Is plane defined by user (otherwise it will be computed automatically).
+  Standard_Real    myFlyout;              //!< Flyout distance.
+  
+  //! Shows if the text label is aligned to user-defined direction myTextDir
+  //! Otherwise it is alligned to the dimension line extension direction
+  //! @warning Only for text placed outside of the dimension line
+  Standard_Boolean myIsTextAligned;       
+  gp_Dir           myTextDir;             //!< Alignment direction for the text
+  Standard_Real    myLeaderSegmentLength; //!< Length of leader line segment aligned with text to myTextDir direction
+  
+  Standard_Boolean myIsGeometryValid;     //!< Is dimension geometry properly defined.
 
 private:
 
index 265201117fc3353d731c087b8d79aa8e74bd3abd..0319b5696171ff4565489e78692d52ea63c6810e 100644 (file)
@@ -33,15 +33,25 @@ namespace
 //function : Constructor
 //purpose  : 
 //=======================================================================
-AIS_RadiusDimension::AIS_RadiusDimension (const gp_Circ& theCircle)
-: AIS_Dimension (AIS_KOD_RADIUS)
+void AIS_RadiusDimension::init()
 {
-  SetMeasuredGeometry (theCircle);
   SetSpecialSymbol (THE_RADIUS_SYMBOL);
   SetDisplaySpecialSymbol (AIS_DSS_Before);
   SetFlyout (0.0);
 }
 
+//=======================================================================
+//function : Constructor
+//purpose  : 
+//=======================================================================
+AIS_RadiusDimension::AIS_RadiusDimension (const gp_Circ& theCircle,
+                                          const Standard_Real theParameter)
+: AIS_Dimension (AIS_KOD_RADIUS)
+{
+  init();
+  SetMeasuredGeometry (theCircle, theParameter);
+}
+
 //=======================================================================
 //function : Constructor
 //purpose  : 
@@ -50,10 +60,8 @@ AIS_RadiusDimension::AIS_RadiusDimension (const gp_Circ& theCircle,
                                           const gp_Pnt& theAttachPoint)
 : AIS_Dimension (AIS_KOD_RADIUS)
 {
+  init();
   SetMeasuredGeometry (theCircle, theAttachPoint);
-  SetSpecialSymbol (THE_RADIUS_SYMBOL);
-  SetDisplaySpecialSymbol (AIS_DSS_Before);
-  SetFlyout (0.0);
 }
 
 //=======================================================================
@@ -63,22 +71,21 @@ AIS_RadiusDimension::AIS_RadiusDimension (const gp_Circ& theCircle,
 AIS_RadiusDimension::AIS_RadiusDimension (const TopoDS_Shape& theShape)
 : AIS_Dimension (AIS_KOD_RADIUS)
 {
+  init();
   SetMeasuredGeometry (theShape);
-  SetSpecialSymbol (THE_RADIUS_SYMBOL);
-  SetDisplaySpecialSymbol (AIS_DSS_Before);
-  SetFlyout (0.0);
 }
 
 //=======================================================================
 //function : SetMeasuredGeometry
 //purpose  : 
 //=======================================================================
-void AIS_RadiusDimension::SetMeasuredGeometry (const gp_Circ& theCircle)
+void AIS_RadiusDimension::SetMeasuredGeometry (const gp_Circ& theCircle,
+                                               const Standard_Real theParameter)
 {
   myCircle          = theCircle;
   myGeometryType    = GeometryType_Edge;
   myShape           = BRepLib_MakeEdge (theCircle);
-  myAnchorPoint     = ElCLib::Value (0, myCircle);
+  myAnchorPoint     = ElCLib::Value (theParameter, myCircle);
   myIsGeometryValid = IsValidCircle (myCircle);
 
   if (myIsGeometryValid)
@@ -130,6 +137,33 @@ void AIS_RadiusDimension::SetMeasuredGeometry (const TopoDS_Shape& theShape)
   SetToUpdate();
 }
 
+//=======================================================================
+//function : Circle
+//purpose  : 
+//=======================================================================
+const gp_Circ& AIS_RadiusDimension::Circle() const
+{
+  return myCircle;
+}
+
+//=======================================================================
+//function : AnchorPoint
+//purpose  : 
+//=======================================================================
+const gp_Pnt& AIS_RadiusDimension::AnchorPoint() const
+{
+  return myAnchorPoint;
+}
+
+//=======================================================================
+//function : Shape
+//purpose  : 
+//=======================================================================
+const TopoDS_Shape& AIS_RadiusDimension::Shape() const
+{
+  return myShape;
+}
+
 //=======================================================================
 //function : CheckPlane
 //purpose  : 
@@ -230,7 +264,7 @@ void AIS_RadiusDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /
     return;
   }
 
-  DrawLinearDimension (thePresentation, theMode, myAnchorPoint, myCircle.Location(), Standard_True);
+  DrawLinearDimension (thePresentation, theMode, myAnchorPoint, myCircle.Location(), Standard_True, myToDrawDimensionLine);
 }
 
 //=======================================================================
index 991c4a28aa15912acc70ab6e73d744a12c5527f6..e9b896193d9e0e69cc7c5e30e33dcc9ac6263a28 100644 (file)
@@ -38,13 +38,19 @@ DEFINE_STANDARD_HANDLE (AIS_RadiusDimension,AIS_Dimension)
 //! In case if the dimension is built on the arbitrary shape,
 //! it can be considered as invalid if the shape does not contain
 //! circle geometry.
+//! Use IsValid() method to check that created dimension is valid.
 class AIS_RadiusDimension : public AIS_Dimension
 {
+protected:
+  
+  //! Setting of default construction paramters
+  void init();
+
 public:
 
   //! Create radius dimension for the circle geometry.
   //! @param theCircle [in] the circle to measure.
-  Standard_EXPORT AIS_RadiusDimension (const gp_Circ& theCircle);
+  Standard_EXPORT AIS_RadiusDimension (const gp_Circ& theCircle, const Standard_Real theParameter = 0);
 
   //! Create radius dimension for the circle geometry and define its
   //! orientation by location of the first point on that circle.
@@ -61,22 +67,13 @@ public:
 public:
 
   //! @return measured geometry circle.
-  const gp_Circ& Circle() const
-  {
-    return myCircle;
-  }
+  Standard_EXPORT const gp_Circ& Circle() const;
 
   //! @return anchor point on circle for radius dimension.
-  const gp_Pnt& AnchorPoint() const
-  {
-    return myAnchorPoint;
-  }
+  Standard_EXPORT const gp_Pnt& AnchorPoint() const;
 
   //! @return the measured shape.
-  const TopoDS_Shape& Shape() const
-  {
-    return myShape;
-  }
+  Standard_EXPORT const TopoDS_Shape& Shape() const;
 
 public:
 
@@ -84,7 +81,7 @@ public:
   //! The dimension will become invalid if the radius of the circle
   //! is less than Precision::Confusion().
   //! @param theCircle [in] the circle to measure.
-  Standard_EXPORT void SetMeasuredGeometry (const gp_Circ& theCircle);
+  Standard_EXPORT void SetMeasuredGeometry (const gp_Circ& theCircle, const Standard_Real theParameter = 0);
 
   //! Measure radius of the circle and orient the dimension so
   //! the dimension lines attaches to anchor point on the circle.
@@ -121,16 +118,16 @@ public:
 
 protected:
 
-  Standard_EXPORT virtual void ComputePlane();
+  Standard_EXPORT virtual void ComputePlane() Standard_OVERRIDE;
 
   //! Checks if anchor point and the center of the circle are on the plane.
-  Standard_EXPORT virtual Standard_Boolean CheckPlane (const gp_Pln& thePlane) const;
+  Standard_EXPORT virtual Standard_Boolean CheckPlane (const gp_Pln& thePlane) const Standard_OVERRIDE;
 
-  Standard_EXPORT virtual Standard_Real ComputeValue() const;
+  Standard_EXPORT virtual Standard_Real ComputeValue() const Standard_OVERRIDE;
 
   Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
                                         const Handle(Prs3d_Presentation)& thePresentation,
-                                        const Standard_Integer theMode = 0);
+                                        const Standard_Integer theMode = 0) Standard_OVERRIDE;
 
 protected:
 
index ad2c3280a2ef505ae341e25152cdbbab813fd487..2aa2c0b149435a4b4918e4df6d05b9d39618c780 100644 (file)
@@ -7,3 +7,5 @@ Font_FTLibrary.hxx
 Font_FTLibrary.cxx
 Font_NListOfSystemFont.hxx
 Font_NameOfFont.hxx
+Font_TextFormatter.hxx
+Font_TextFormatter.cxx
\ No newline at end of file
index 4d20aaa2dd06b8357f7ecd5ed3a612e9f1287ea5..636bd2954075b7a4221c032ab5743cf5205081d6 100755 (executable)
@@ -516,3 +516,53 @@ TopoDS_Shape Font_BRepFont::RenderText (const NCollection_String& theString)
   }
   return aResult;
 }
+
+// =======================================================================
+// function : BoundingBox
+// purpose  :
+// =======================================================================
+Font_FTFont::Rect Font_BRepFont::BoundingBox (const NCollection_String& theString,
+                                              const Graphic3d_HorizontalTextAlignment theHAlign,
+                                              const Graphic3d_VerticalTextAlignment   theVAlign)
+{
+  Rect aBox;
+  aBox.Left   = 0.f;
+  aBox.Right  = 0.f;
+  aBox.Bottom = 0.f;
+  aBox.Top    = static_cast<float> (Ascender());
+
+  Standard_Integer aLine = 0;
+  Standard_Real aCurrWidth = 0.;
+  for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
+  {
+    const Standard_Utf32Char aCharCurr =   *anIter;
+    const Standard_Utf32Char aCharNext = *++anIter;
+    if (aCharCurr == '\x0D' // CR  (carriage return)
+     || aCharCurr == '\a'   // BEL (alarm)
+     || aCharCurr == '\f'   // FF  (form feed) NP (new page)
+     || aCharCurr == '\b'   // BS  (backspace)
+     || aCharCurr == '\v')  // VT  (vertical tab)
+    {
+      continue; // skip unsupported carriage control codes
+    }
+    else if (aCharCurr == ' ' || aCharCurr == '\t')
+    {
+      aCurrWidth += AdvanceX (aCharCurr, aCharNext);
+      continue;
+    }
+    else if (aCharCurr == '\n')
+    {
+      aBox.Right = Max (aBox.Right, static_cast<float> (aCurrWidth));
+      aCurrWidth = 0;
+      ++aLine;
+      continue;
+    }
+
+    aCurrWidth += AdvanceX (aCharCurr, aCharNext);
+  }
+
+  aBox.Right  = Max (aBox.Right, static_cast<float> (aCurrWidth));
+  aBox.Bottom = aBox.Top - static_cast<float> (LineSpacing() * Standard_Real (aLine + 1));
+
+  return aBox;
+}
index 71bd0a2af0041f6be7f500ed3e0196ad522ff5ba..df13223c8ce3b3bd07cf5758b657c9e4e548aaac 100755 (executable)
@@ -95,6 +95,12 @@ public:
   //! Notice that altering this flag clears currently accumulated cache!
   Standard_EXPORT void SetCompositeCurveMode (const Standard_Boolean theToConcatenate);
 
+  //! Compute bounding rectangle of resultant BRep text shape from input string
+  //! @return bounding rectangle
+  Standard_EXPORT Font_FTFont::Rect BoundingBox (const NCollection_String& theString,
+                                                 const Graphic3d_HorizontalTextAlignment theHAlign = Graphic3d_HTA_LEFT,
+                                                 const Graphic3d_VerticalTextAlignment   theVAlign = Graphic3d_VTA_BOTTOM);
+
 public:
 
   //! Render text as BRep shape.
index 684a831185b96c81ef52512f09cf6f32818257a6..b0f422ccbe38bde167f074944aa7e37dafdf819f 100755 (executable)
@@ -15,6 +15,8 @@
 
 #include <Font_FTFont.hxx>
 #include <Font_FontMgr.hxx>
+#include <Font_TextFormatter.hxx>
+
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_HAsciiString.hxx>
 
@@ -257,3 +259,25 @@ float Font_FTFont::AdvanceY (const Standard_Utf32Char theUCharNext)
   }
   return fromFTPoints<float> (myKernAdvance.y + myFTFace->glyph->advance.y);
 }
+
+// =======================================================================
+// function : BoundingBox
+// purpose  :
+// =======================================================================
+Font_FTFont::Rect Font_FTFont::BoundingBox (const NCollection_String&               theString,
+                                            const Graphic3d_HorizontalTextAlignment theAlignX,
+                                            const Graphic3d_VerticalTextAlignment   theAlignY)
+{
+  Font_TextFormatter aFormatter;
+  aFormatter.SetupAlignment (theAlignX, theAlignY);
+  aFormatter.Reset();
+
+  aFormatter.Append (theString, *this);
+  aFormatter.Format();
+
+  Rect aBndBox;
+
+  aFormatter.BndBox (aBndBox);
+
+  return aBndBox;
+}
index f4ba85ca8afddb5a6a790aaddd947a64f564a3ee..5c425494c6472c50797610247a62f62880996224 100755 (executable)
 #ifndef _Font_FTFont_H__
 #define _Font_FTFont_H__
 
-#include <NCollection_Vec2.hxx>
-#include <NCollection_String.hxx>
+#include <Font_FontAspect.hxx>
 #include <Font_FTLibrary.hxx>
+#include <Graphic3d_HorizontalTextAlignment.hxx>
+#include <Graphic3d_VerticalTextAlignment.hxx>
 #include <Image_PixMap.hxx>
-#include <Font_FontAspect.hxx>
+#include <NCollection_String.hxx>
+#include <NCollection_Vec2.hxx>
 
 //! Wrapper over FreeType font.
 //! Notice that this class uses internal buffers for loaded glyphs
@@ -38,6 +40,11 @@ public:
     float Top;
     float Bottom;
 
+    NCollection_Vec2<float> TopLeft() const
+    {
+      return NCollection_Vec2<float> (Left, Top);
+    }
+
     NCollection_Vec2<float>& TopLeft (NCollection_Vec2<float>& theVec) const
     {
       theVec.x() = Left;
@@ -66,6 +73,16 @@ public:
       return theVec;
     }
 
+    float Width () const
+    {
+      return Right - Left;
+    }
+
+    float Height () const
+    {
+      return Top - Bottom;
+    }
+
   };
 
 public:
@@ -178,6 +195,13 @@ public:
     theRect.Bottom = float(myFTFace->glyph->bitmap_top  - (int )aBitmap.rows);
   }
 
+  //! Computes bounding box of the given text using plain-text formatter (Font_TextFormatter).
+  //! Note that bounding box takes into account the text alignment options.
+  //! Its corners are relative to the text alignment anchor point, their coordinates can be negative.
+  Standard_EXPORT Rect BoundingBox (const NCollection_String&               theString,
+                                    const Graphic3d_HorizontalTextAlignment theAlignX,
+                                    const Graphic3d_VerticalTextAlignment   theAlignY);
+
 protected:
 
   //! Convert value to 26.6 fixed-point format for FT library API.
diff --git a/src/Font/Font_TextFormatter.cxx b/src/Font/Font_TextFormatter.cxx
new file mode 100644 (file)
index 0000000..61b1544
--- /dev/null
@@ -0,0 +1,312 @@
+// Created on: 2013-01-29
+// Created by: Kirill GAVRILOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Font_TextFormatter.hxx>
+
+namespace
+{
+  typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
+
+  //! Auxiliary function to translate corners by the vector.
+  inline void move (NCollection_Vector< Vec2f >& theCorners,
+                    const Vec2f&                 theMoveVec,
+                    Standard_Integer             theCharLower,
+                    const Standard_Integer       theCharUpper)
+  {
+    for(; theCharLower <= theCharUpper; ++theCharLower)
+    {
+      theCorners.ChangeValue (theCharLower) += theMoveVec;
+    }
+  }
+
+  //! Auxiliary function to translate corners in vertical direction.
+  inline void moveY (NCollection_Vector<Vec2f>& theCorners,
+                     const Standard_ShortReal   theMoveVec,
+                     Standard_Integer           theCharLower,
+                     const Standard_Integer     theCharUpper)
+  {
+    for(; theCharLower <= theCharUpper; ++theCharLower)
+    {
+      theCorners.ChangeValue (theCharLower).y() += theMoveVec;
+    }
+  }
+
+  //! Apply floor to vector components.
+  //! @param  theVec - vector to change (by reference!)
+  //! @return modified vector
+  inline Vec2f& floor (Vec2f& theVec)
+  {
+    theVec.x() = std::floor (theVec.x());
+    theVec.y() = std::floor (theVec.y());
+    return theVec;
+  }
+
+}
+
+
+IMPLEMENT_STANDARD_HANDLE (Font_TextFormatter, Standard_Transient)
+IMPLEMENT_STANDARD_RTTIEXT(Font_TextFormatter, Standard_Transient)
+
+// =======================================================================
+// function : Font_TextFormatter
+// purpose  :
+// =======================================================================
+Font_TextFormatter::Font_TextFormatter()
+: myAlignX (Graphic3d_HTA_LEFT),
+  myAlignY (Graphic3d_VTA_TOP),
+  myTabSize (8),
+  //
+  myPen (0.0f, 0.0f),
+  myRectsNb (0),
+  myLineSpacing (0.0f),
+  myAscender (0.0f),
+  myIsFormatted (false),
+  //
+  myLinesNb (0),
+  myRectLineStart (0),
+  myRectWordStart (0),
+  myNewLineNb(0),
+  myPenCurrLine (0.0f),
+  myBndTop   (0.0f),
+  myBndWidth (0.0f),
+  myMoveVec (0.0f, 0.0f)
+{
+  //
+}
+
+// =======================================================================
+// function : SetupAlignment
+// purpose  :
+// =======================================================================
+void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
+                                         const Graphic3d_VerticalTextAlignment   theAlignY)
+{
+  myAlignX = theAlignX;
+  myAlignY = theAlignY;
+}
+
+// =======================================================================
+// function : Reset
+// purpose  :
+// =======================================================================
+void Font_TextFormatter::Reset()
+{
+  myIsFormatted = false;
+  myString.Clear();
+  myPen.x() = myPen.y() = 0.0f;
+  myRectsNb = 0;
+  myLineSpacing = myAscender = 0.0f;
+  myCorners.Clear();
+  myNewLines.Clear();
+}
+
+// =======================================================================
+// function : Append
+// purpose  :
+// =======================================================================
+void Font_TextFormatter::Append (const NCollection_String& theString,
+                                 Font_FTFont&              theFont)
+{
+  if (theString.IsEmpty())
+  {
+    return;
+  }
+
+  myAscender    = Max (myAscender,    theFont.Ascender());
+  myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
+  myString     += theString;
+
+  int aSymbolsCounter = 0; // special counter to process tabulation symbols
+
+  // first pass - render all symbols using associated font on single ZERO baseline
+  for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
+  {
+    const Standard_Utf32Char aCharThis =   *anIter;
+    const Standard_Utf32Char aCharNext = *++anIter;
+
+    if (aCharThis == '\x0D' // CR  (carriage return)
+     || aCharThis == '\a'   // BEL (alarm)
+     || aCharThis == '\f'   // FF  (form feed) NP (new page)
+     || aCharThis == '\b'   // BS  (backspace)
+     || aCharThis == '\v')  // VT  (vertical tab)
+    {
+      continue; // skip unsupported carriage control codes
+    }
+    else if (aCharThis == '\x0A') // LF (line feed, new line)
+    {
+      aSymbolsCounter = 0;
+      myNewLines.Append (myPen.x());
+      continue; // will be processed on second pass
+    }
+    else if (aCharThis == ' ')
+    {
+      ++aSymbolsCounter;
+      myPen.x() += theFont.AdvanceX (' ', aCharNext);
+      continue;
+    }
+    else if (aCharThis == '\t')
+    {
+      const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
+      myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
+      aSymbolsCounter += aSpacesNum;
+      continue;
+    }
+
+    ++aSymbolsCounter;
+
+    myCorners.Append (myPen);
+
+    myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
+
+    ++myRectsNb;
+  }
+}
+
+// =======================================================================
+// function : newLine
+// purpose  :
+// =======================================================================
+void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
+{
+  if (myRectLineStart >= myRectsNb)
+  {
+    ++myLinesNb;
+    myPenCurrLine -= myLineSpacing;
+    return;
+  }
+
+  myMoveVec.y() = myPenCurrLine;
+  switch (myAlignX)
+  {
+    default:
+    case Graphic3d_HTA_LEFT:
+    {
+      myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
+      break;
+    }
+    case Graphic3d_HTA_RIGHT:
+    {
+      myMoveVec.x() = (myNewLineNb < myNewLines.Length())
+                    ? -myNewLines.Value (myNewLineNb)
+                    : -myPen.x();
+      break;
+    }
+    case Graphic3d_HTA_CENTER:
+    {
+      const Standard_ShortReal aFrom = (myNewLineNb > 0)
+                                     ? myNewLines.Value (myNewLineNb - 1)
+                                     : 0.0f;
+      const Standard_ShortReal aTo   = (myNewLineNb < myNewLines.Length())
+                                     ? myNewLines.Value (myNewLineNb)
+                                     : myPen.x();
+      myMoveVec.x() = -0.5f * (aFrom + aTo);
+      break;
+    }
+  }
+
+  move (myCorners, myMoveVec, myRectLineStart, theLastRect);
+
+  ++myLinesNb;
+  myPenCurrLine -= myLineSpacing;
+  myRectLineStart = myRectWordStart = theLastRect + 1;
+}
+
+// =======================================================================
+// function : Format
+// purpose  :
+// =======================================================================
+void Font_TextFormatter::Format()
+{
+  if (myRectsNb == 0 || myIsFormatted)
+  {
+    return;
+  }
+
+  myIsFormatted = true;
+  myLinesNb = myRectLineStart = myRectWordStart = 0;
+  myBndTop     = 0.0f;
+  myBndWidth   = 0.0f;
+  myMoveVec.x() = myMoveVec.y() = 0.0f;
+
+  // split text into lines and apply horizontal alignment
+  myPenCurrLine = -myAscender;
+  Standard_Integer aRectIter = 0;
+  myNewLineNb = 0;
+  Standard_ShortReal aMaxLineWidth = -1.0f;
+  for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
+  {
+    const Standard_Utf32Char aCharThis = *anIter;
+    if (aCharThis == '\x0D' // CR  (carriage return)
+     || aCharThis == '\a'   // BEL (alarm)
+     || aCharThis == '\f'   // FF  (form feed) NP (new page)
+     || aCharThis == '\b'   // BS  (backspace)
+     || aCharThis == '\v')  // VT  (vertical tab)
+    {
+      continue; // skip unsupported carriage control codes
+    }
+    else if (aCharThis == '\x0A') // LF (line feed, new line)
+    {
+      // calculate max line width
+      if (myNewLineNb == 0)
+      {
+        aMaxLineWidth = myNewLines.Value(0);
+      }
+      else
+      {
+        aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
+      }
+
+      const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
+      newLine (aLastRect);
+      ++myNewLineNb;
+      continue;
+    }
+    else if (aCharThis == ' '
+          || aCharThis == '\t')
+    {
+      myRectWordStart = aRectIter;
+      continue;
+    }
+
+    ++aRectIter;
+  }
+
+  // If only one line
+  if (aMaxLineWidth < 0.0f)
+  {
+    aMaxLineWidth = myPen.x();
+  }
+  else // Consider last line
+  {
+    aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1));
+  }
+
+  myBndWidth = aMaxLineWidth;
+
+  // move last line
+  newLine (myRectsNb - 1);
+
+  // apply vertical alignment style
+  if (myAlignY == Graphic3d_VTA_BOTTOM)
+  {
+    myBndTop = -myLineSpacing - myPenCurrLine;
+    moveY (myCorners, myBndTop, 0, myRectsNb - 1);
+  }
+  else if (myAlignY == Graphic3d_VTA_CENTER)
+  {
+    myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
+    moveY (myCorners, myBndTop, 0, myRectsNb - 1);
+  }
+}
diff --git a/src/Font/Font_TextFormatter.hxx b/src/Font/Font_TextFormatter.hxx
new file mode 100644 (file)
index 0000000..2ce2b23
--- /dev/null
@@ -0,0 +1,142 @@
+// Created on: 2013-01-29
+// Created by: Kirill GAVRILOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef Font_TextFormatter_Header
+#define Font_TextFormatter_Header
+
+#include <Font_FTFont.hxx>
+#include <NCollection_DataMap.hxx>
+#include <NCollection_Vector.hxx>
+
+//! This class intended to prepare formatted text.
+class Font_TextFormatter : public Standard_Transient
+{
+public:
+
+  //! Default constructor.
+  Standard_EXPORT Font_TextFormatter();
+
+  //! Setup alignment style.
+  Standard_EXPORT void SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
+                                       const Graphic3d_VerticalTextAlignment   theAlignY);
+
+  //! Reset current progress.
+  Standard_EXPORT void Reset();
+
+  //! Render specified text to inner buffer.
+  Standard_EXPORT void Append (const NCollection_String& theString,
+                               Font_FTFont&              theFont);
+
+  //! Perform formatting on the buffered text.
+  //! Should not be called more than once after initialization!
+  Standard_EXPORT void Format();
+
+  //! Returns specific glyph rectangle.
+  inline const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
+  {
+    return myCorners.Value (theIndex);
+  }
+
+  //! Returns current rendering string.
+  inline const NCollection_String& String() const
+  {
+    return myString;
+  }
+
+  //! Returns tab size.
+  inline Standard_Integer TabSize() const
+  {
+    return myTabSize;
+  }
+
+  //! @return width of formatted text.
+  inline Standard_ShortReal ResultWidth() const
+  {
+    return myBndWidth;
+  }
+
+  //! @return height of formatted text.
+  inline Standard_ShortReal ResultHeight() const
+  {
+    return myLineSpacing * Standard_ShortReal(myLinesNb);
+  }
+
+  //! @param bounding box.
+  inline void BndBox (Font_FTFont::Rect& theBndBox) const
+  {
+    theBndBox.Left = 0.0f;
+    switch (myAlignX)
+    {
+      default:
+      case Graphic3d_HTA_LEFT:  theBndBox.Right  =  myBndWidth; break;
+      case Graphic3d_HTA_RIGHT: theBndBox.Right  = -myBndWidth; break;
+      case Graphic3d_HTA_CENTER:
+      {
+        theBndBox.Left  = -0.5f * myBndWidth;
+        theBndBox.Right =  0.5f * myBndWidth;
+        break;
+      }
+    }
+    theBndBox.Top    = myBndTop;
+    theBndBox.Bottom = theBndBox.Top - myLineSpacing * Standard_ShortReal(myLinesNb);
+  }
+
+protected: //! @name class auxiliary methods
+
+  //! Move glyphs on the current line to correct position.
+  Standard_EXPORT void newLine (const Standard_Integer theLastRect);
+
+protected: //! @name configuration
+
+  Graphic3d_HorizontalTextAlignment myAlignX;  //!< horizontal alignment style
+  Graphic3d_VerticalTextAlignment   myAlignY;  //!< vertical   alignment style
+  Standard_Integer                  myTabSize; //!< horizontal tabulation width (number of space symbols)
+
+protected: //! @name input data
+
+  NCollection_String myString;        //!< currently rendered text
+  NCollection_Vec2<Standard_ShortReal>
+                     myPen;           //!< current pen position
+  NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >
+                     myCorners;       //!< The top left corners of a formatted rectangles.
+  Standard_Integer   myRectsNb;       //!< rectangles number
+  NCollection_Vector<Standard_ShortReal>
+                     myNewLines;      //!< position at LF
+  Standard_ShortReal myLineSpacing;   //!< line spacing (computed as maximum of all fonts involved in text formatting)
+  Standard_ShortReal myAscender;      //!<
+  bool               myIsFormatted;   //!< formatting state
+
+protected: //! @name temporary variables for formatting routines
+
+  Standard_Integer   myLinesNb;       //!< overall (new)lines number (including splitting by width limit)
+  Standard_Integer   myRectLineStart; //!< id of first rectangle on the current line
+  Standard_Integer   myRectWordStart; //!< id of first rectangle in the current word
+  Standard_Integer   myNewLineNb;
+
+  Standard_ShortReal myPenCurrLine;   //!< current baseline position
+  Standard_ShortReal myBndTop;
+  Standard_ShortReal myBndWidth;
+  NCollection_Vec2<Standard_ShortReal>
+                     myMoveVec;       //!< local variable
+
+public:
+
+  DEFINE_STANDARD_RTTI(Font_TextFormatter) // Type definition
+
+};
+
+DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
+
+#endif // Font_TextFormatter_Header
index 37d3e63a1fd2aaaec51f6bd4477b84a861925e59..de9014dd12631371ce40272209a052e38ac455ba 100755 (executable)
@@ -26,8 +26,6 @@ OpenGl_Element.hxx
 OpenGl_Element.cxx
 OpenGl_Text.hxx
 OpenGl_Text.cxx
-OpenGl_TextFormatter.hxx
-OpenGl_TextFormatter.cxx
 OpenGl_PointSprite.hxx
 OpenGl_PointSprite.cxx
 Handle_OpenGl_PointSprite.hxx
@@ -169,3 +167,5 @@ OpenGl_Sphere.hxx
 OpenGl_Sphere.cxx
 OpenGl_BackgroundArray.hxx
 OpenGl_BackgroundArray.cxx
+OpenGl_TextBuilder.hxx
+OpenGl_TextBuilder.cxx
index 1a17c604ab2d6ff483ec7fff71fb6a252ff6dc2c..114bb0d156c92bdd0bf4f182c51b66cb0e7219af 100755 (executable)
@@ -203,14 +203,12 @@ bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
 // function : RenderGlyph
 // purpose  :
 // =======================================================================
-void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
+bool OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
                                const Standard_Utf32Char      theUChar,
-                               const Standard_Utf32Char      theUCharNext,
-                               OpenGl_Font::Tile&            theGlyph,
-                               OpenGl_Vec2&                  thePen)
+                               Tile&                         theGlyph)
 {
   Standard_Integer aTileId = 0;
-  if (!myGlyphMap.Find (theUChar, aTileId))
+  if (!myGlyphMap.Find (theUChar,aTileId))
   {
     if (renderGlyph (theCtx, theUChar))
     {
@@ -218,19 +216,16 @@ void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
     }
     else
     {
-      thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
-      return;
+      return false;
     }
+
     myGlyphMap.Bind (theUChar, aTileId);
   }
 
   const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId);
-  theGlyph.px.Top    = thePen.y() + aTile.px.Top;
-  theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom;
-  theGlyph.px.Left   = thePen.x() + aTile.px.Left;
-  theGlyph.px.Right  = thePen.x() + aTile.px.Right;
-  theGlyph.uv        = aTile.uv;
-  theGlyph.texture   = aTile.texture;
-
-  thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
+  theGlyph.px      = aTile.px;
+  theGlyph.uv      = aTile.uv;
+  theGlyph.texture = aTile.texture;
+
+  return true;
 }
index fd95912d1dd9392c4b36970ac8e7ee9edd40ae40..7e8f7149bdf77d999ec2822f072d5365362d8144 100755 (executable)
@@ -115,18 +115,13 @@ public:
     return myLineSpacing;
   }
 
-  //! Compute glyph rectangle at specified pen position (on baseline)
-  //! and render it to texture if not already.
+  //! Render glyph to texture if not already.
   //! @param theCtx       active context
   //! @param theUChar     unicode symbol to render
-  //! @param theUCharNext next symbol to compute advance with kerning when available
   //! @param theGlyph     computed glyph position rectangle, texture ID and UV coordinates
-  //! @param thePen       pen position on baseline to place new glyph
-  Standard_EXPORT void RenderGlyph (const Handle(OpenGl_Context)& theCtx,
+  Standard_EXPORT bool RenderGlyph (const Handle(OpenGl_Context)& theCtx,
                                     const Standard_Utf32Char      theUChar,
-                                    const Standard_Utf32Char      theUCharNext,
-                                    Tile&                         theGlyph,
-                                    OpenGl_Vec2&                  thePen);
+                                    Tile&                         theGlyph);
 
 protected:
 
index a67ea82ed6999a73b51b6be7cfb248dedfd14786..6acc096456568edf42300ef7a8f2fecae1af47b8 100644 (file)
@@ -464,8 +464,7 @@ void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
                                             anObjZ);
 
     OpenGl_Utils::Translate<GLdouble> (aModViewMat, anObjX, anObjY, anObjZ);
-    OpenGl_Utils::Rotate<GLdouble> (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0);
-
+    OpenGl_Utils::Rotate<GLdouble>    (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0);
     if (!theTextAspect.IsZoomable())
     {
     #ifdef _WIN32
@@ -580,6 +579,7 @@ Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
     if (!aRequestedFont.IsNull())
     {
       aFontFt = new Font_FTFont (NULL);
+
       if (aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight))
       {
         aFont = new OpenGl_Font (aFontFt, theKey);
@@ -655,13 +655,21 @@ void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
 
   if (myTextures.IsEmpty())
   {
-    OpenGl_TextFormatter aFormatter;
+    Font_TextFormatter aFormatter;
     aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
     aFormatter.Reset();
-    aFormatter.Append (theCtx, myString, *myFont.operator->());
+
+    aFormatter.Append (myString, *myFont->FTFont());
     aFormatter.Format();
 
-    aFormatter.Result (theCtx, myTextures, myVertsVbo, myTCrdsVbo);
+    OpenGl_TextBuilder aBuilder;
+    aBuilder.Perform (aFormatter,
+                      theCtx,
+                      *myFont.operator->(),
+                      myTextures,
+                      myVertsVbo,
+                      myTCrdsVbo);
+
     aFormatter.BndBox (myBndBox);
   }
 
index 68d8514a5100450da4bd59abafc5ce2a5ffe417e..71200ee30ac00700c41245ce12eddcced9439bc6 100755 (executable)
@@ -20,7 +20,7 @@
 
 #include <OpenGl_AspectText.hxx>
 #include <OpenGl_TextParam.hxx>
-#include <OpenGl_TextFormatter.hxx>
+#include <OpenGl_TextBuilder.hxx>
 
 #include <TCollection_ExtendedString.hxx>
 #include <Graphic3d_Vertex.hxx>
diff --git a/src/OpenGl/OpenGl_TextBuilder.cxx b/src/OpenGl/OpenGl_TextBuilder.cxx
new file mode 100644 (file)
index 0000000..c814e24
--- /dev/null
@@ -0,0 +1,221 @@
+// Created on: 2015-06-18
+// Created by: Ilya SEVRIKOV
+// Copyright (c) 2015 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <OpenGl_TextBuilder.hxx>
+#include <OpenGl_VertexBufferCompat.hxx>
+
+namespace
+{
+  //! Apply floor to vector components.
+  //! @param  theVec - vector to change (by reference!)
+  //! @return modified vector
+  inline OpenGl_Vec2& floor (OpenGl_Vec2& theVec)
+  {
+    theVec.x() = std::floor (theVec.x());
+    theVec.y() = std::floor (theVec.y());
+    return theVec;
+  }
+}
+
+// =======================================================================
+// function : OpenGl_TextBuilder
+// purpose  :
+// =======================================================================
+OpenGl_TextBuilder::OpenGl_TextBuilder()
+{
+  //
+}
+
+// =======================================================================
+// function : createGlyphs
+// purpose  :
+// =======================================================================
+void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&                                                  theFormatter,
+                                       const Handle(OpenGl_Context)&                                              theCtx,
+                                       OpenGl_Font&                                                               theFont,
+                                       NCollection_Vector<GLuint>&                                                theTextures,
+                                       NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theVertsPerTexture,
+                                       NCollection_Vector<NCollection_Handle<NCollection_Vector<OpenGl_Vec2> > >& theTCrdsPerTexture)
+{
+  OpenGl_Vec2 aVec (0.0f, 0.0f);
+
+  theTextures.Clear();
+  theVertsPerTexture.Clear();
+  theTCrdsPerTexture.Clear();
+
+  OpenGl_Font::Tile aTile = {};
+  OpenGl_Vec2       aPen (0.0f, 0.0f);
+  Standard_Integer  aRectsNb = 0;
+  Standard_Integer  aSymbolsCounter = 0;
+
+  for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0;)
+  {
+    const Standard_Utf32Char aCharThis =   *anIter;
+    const Standard_Utf32Char aCharNext = *++anIter;
+
+    if (aCharThis == '\x0D' // CR  (carriage return)
+     || aCharThis == '\a'   // BEL (alarm)
+     || aCharThis == '\f'   // FF  (form feed) NP (new page)
+     || aCharThis == '\b'   // BS  (backspace)
+     || aCharThis == '\v')  // VT  (vertical tab)
+    {
+      continue; // skip unsupported carriage control codes
+    }
+    else if (aCharThis == '\x0A') // LF (line feed, new line)
+    {
+      aSymbolsCounter = 0;
+      continue; // will be processed on second pass
+    }
+    else if (aCharThis == ' ')
+    {
+      ++aSymbolsCounter;
+      aPen.x() += theFont.AdvanceX (' ', aCharNext);
+      continue;
+    }
+    else if (aCharThis == '\t')
+    {
+      const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize());
+      aPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
+      aSymbolsCounter += aSpacesNum;
+      continue;
+    }
+
+    ++aSymbolsCounter;
+
+    theFont.RenderGlyph (theCtx, aCharThis, aTile);
+
+    const OpenGl_Vec2& aTopLeft = theFormatter.TopLeft (aRectsNb);
+    aTile.px.Right  += aTopLeft.x();
+    aTile.px.Left   += aTopLeft.x();
+    aTile.px.Bottom += aTopLeft.y();
+    aTile.px.Top    += aTopLeft.y();
+    const Font_FTFont::Rect& aRectUV  = aTile.uv;
+    const GLuint             aTexture = aTile.texture;
+
+    Standard_Integer aListId = 0;
+    for (aListId = 0; aListId < theTextures.Length(); ++aListId)
+    {
+      if (theTextures.Value (aListId) == aTexture)
+      {
+        break;
+      }
+    }
+    if (aListId >= theTextures.Length())
+    {
+      theTextures.Append (aTexture);
+      theVertsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
+      theTCrdsPerTexture.Append (new NCollection_Vector<OpenGl_Vec2>());
+    }
+
+    NCollection_Vector<OpenGl_Vec2>& aVerts = *theVertsPerTexture.ChangeValue (aListId);
+    NCollection_Vector<OpenGl_Vec2>& aTCrds = *theTCrdsPerTexture.ChangeValue (aListId);
+
+    // apply floor on position to avoid blurring issues
+    // due to cross-pixel coordinates
+    aVerts.Append (floor(aTile.px.TopRight   (aVec)));
+    aVerts.Append (floor(aTile.px.TopLeft    (aVec)));
+    aVerts.Append (floor(aTile.px.BottomLeft (aVec)));
+    aTCrds.Append (aRectUV.TopRight   (aVec));
+    aTCrds.Append (aRectUV.TopLeft    (aVec));
+    aTCrds.Append (aRectUV.BottomLeft (aVec));
+
+    aVerts.Append (floor(aTile.px.BottomRight (aVec)));
+    aVerts.Append (floor(aTile.px.TopRight    (aVec)));
+    aVerts.Append (floor(aTile.px.BottomLeft  (aVec)));
+    aTCrds.Append (aRectUV.BottomRight (aVec));
+    aTCrds.Append (aRectUV.TopRight    (aVec));
+    aTCrds.Append (aRectUV.BottomLeft  (aVec));
+
+    ++aRectsNb;
+  }
+}
+
+// =======================================================================
+// function : CreateTextures
+// purpose  :
+// =======================================================================
+void OpenGl_TextBuilder::Perform (const Font_TextFormatter&                        theFormatter,
+                                  const Handle(OpenGl_Context)&                    theCtx,
+                                  OpenGl_Font&                                     theFont,
+                                  NCollection_Vector<GLuint>&                      theTextures,
+                                  NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
+                                  NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture)
+{
+  NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aVertsPerTexture;
+  NCollection_Vector< NCollection_Handle <NCollection_Vector <OpenGl_Vec2> > > aTCrdsPerTexture;
+
+  createGlyphs (theFormatter, theCtx, theFont, theTextures, aVertsPerTexture, aTCrdsPerTexture);
+
+  if (theVertsPerTexture.Length() != theTextures.Length())
+  {
+    for (Standard_Integer aTextureIter = 0; aTextureIter < theVertsPerTexture.Length(); ++aTextureIter)
+    {
+      theVertsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
+      theTCrdsPerTexture.Value (aTextureIter)->Release (theCtx.operator->());
+    }
+    theVertsPerTexture.Clear();
+    theTCrdsPerTexture.Clear();
+
+    const bool isNormalMode = theCtx->ToUseVbo();
+    Handle(OpenGl_VertexBuffer) aVertsVbo, aTcrdsVbo;
+    while (theVertsPerTexture.Length() < theTextures.Length())
+    {
+      if (isNormalMode)
+      {
+        aVertsVbo = new OpenGl_VertexBuffer();
+        aTcrdsVbo = new OpenGl_VertexBuffer();
+      }
+      else
+      {
+        aVertsVbo = new OpenGl_VertexBufferCompat();
+        aTcrdsVbo = new OpenGl_VertexBufferCompat();
+      }
+      theVertsPerTexture.Append (aVertsVbo);
+      theTCrdsPerTexture.Append (aTcrdsVbo);
+      aVertsVbo->Create (theCtx);
+      aTcrdsVbo->Create (theCtx);
+    }
+  }
+
+  for (Standard_Integer aTextureIter = 0; aTextureIter < theTextures.Length(); ++aTextureIter)
+  {
+    const NCollection_Vector<OpenGl_Vec2>& aVerts = *aVertsPerTexture.Value (aTextureIter);
+    Handle(OpenGl_VertexBuffer)& aVertsVbo = theVertsPerTexture.ChangeValue (aTextureIter);
+    if (!aVertsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
+     || !myVboEditor.Init (theCtx, aVertsVbo))
+    {
+      continue;
+    }
+    for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
+    {
+      myVboEditor.Value() = aVerts.Value (aVertIter);
+    }
+    myVboEditor.Flush();
+
+    const NCollection_Vector<OpenGl_Vec2>& aTCrds = *aTCrdsPerTexture.Value (aTextureIter);
+    Handle(OpenGl_VertexBuffer)& aTCrdsVbo = theTCrdsPerTexture.ChangeValue (aTextureIter);
+    if (!aTCrdsVbo->Init (theCtx, 2, aVerts.Length(), (GLfloat* )NULL)
+     || !myVboEditor.Init (theCtx, aTCrdsVbo))
+    {
+      continue;
+    }
+    for (Standard_Integer aVertIter = 0; aVertIter < aVerts.Length(); ++aVertIter, myVboEditor.Next())
+    {
+      myVboEditor.Value() = aTCrds.Value (aVertIter);
+    }
+    myVboEditor.Flush();
+  }
+  myVboEditor.Init (NULL, NULL);
+}
diff --git a/src/OpenGl/OpenGl_TextBuilder.hxx b/src/OpenGl/OpenGl_TextBuilder.hxx
new file mode 100644 (file)
index 0000000..016e518
--- /dev/null
@@ -0,0 +1,62 @@
+// Created on: 2015-06-18
+// Created by: Ilya SEVRIKOV
+// Copyright (c) 2015 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef OpenGl_TextBuilder_Header
+#define OpenGl_TextBuilder_Header
+
+#include <Font_TextFormatter.hxx>
+
+#include <OpenGl_Context.hxx>
+#include <OpenGl_Font.hxx>
+#include <OpenGl_VertexBuffer.hxx>
+#include <OpenGl_VertexBufferEditor.hxx>
+#include <OpenGl_Vec.hxx>
+
+#include <NCollection_Vector.hxx>
+#include <NCollection_Handle.hxx>
+
+
+//! This class generates primitive array required for rendering textured text using OpenGl_Font instance.
+class OpenGl_TextBuilder
+{
+public:
+
+  //! Creates empty object.
+  OpenGl_TextBuilder();
+
+  //! Creates texture quads for the given text.
+  Standard_EXPORT void Perform (const Font_TextFormatter&                        theFormatter,
+                                const Handle(OpenGl_Context)&                    theContext,
+                                OpenGl_Font&                                     theFont,
+                                NCollection_Vector<GLuint>&                      theTextures,
+                                NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theVertsPerTexture,
+                                NCollection_Vector<Handle(OpenGl_VertexBuffer)>& theTCrdsPerTexture);
+
+protected: //! @name class auxillary methods
+
+  Standard_EXPORT void createGlyphs (const Font_TextFormatter&                                                      theFormatter,
+                                     const Handle(OpenGl_Context)&                                                  theCtx,
+                                     OpenGl_Font&                                                                   theFont,
+                                     NCollection_Vector<GLuint>&                                                    theTextures,
+                                     NCollection_Vector< NCollection_Handle < NCollection_Vector <OpenGl_Vec2> > >& theVertsPerTexture,
+                                     NCollection_Vector< NCollection_Handle < NCollection_Vector <OpenGl_Vec2> > >& theTCrdsPerTexture);
+
+protected: //! @name class auxillary fields
+
+  NCollection_Vector<OpenGl_Font::Tile>  myTileRects;
+  OpenGl_VertexBufferEditor<OpenGl_Vec2> myVboEditor;
+};
+
+#endif // OpenGl_TextBuilder_Header
index da879ef8e32f8cc03740284a5dba510f95b0a6a5..2ebe681816742c13dba56d2565863daaa33142e8 100644 (file)
@@ -78,11 +78,13 @@ is
   -- DTHP_Fit    - value label located automatically at left side if does not fits
   --               the dimension space, otherwise the value label is placed at center.
 
-  enumeration DimensionTextVerticalPosition is DTVP_Above, DTVP_Below, DTVP_Center;
+  enumeration DimensionTextVerticalPosition is DTVP_Above, DTVP_FirstLine, DTVP_Below, DTVP_LastLine, DTVP_Center;
   ---Purpose: Specifies options for positioning dimension value label in vertical direction
   -- with respect to dimension (extension) line.
   -- DTVP_Above - text label is located above the dimension or extension line.
+  -- DTVP_FirstLine - for multi-line text: first line alignment (is by default for multi-line label)
   -- DTVP_Below - text label is located below the dimension or extension line.
+  -- DTVP_LastLine - for multi-line text: last line alignment (is by default for multi-line label)
   -- DTVP_Center - the text label middle-point is in line with dimension or extension line.
 
   enumeration DimensionArrowOrientation is DAO_Internal, DAO_External, DAO_Fit;
index d15dafe84fc50bc2e7bc1cff42cab44212107e24..7a8bdff5f3f478ddff2cdbbb04264e562e0bcfa0 100644 (file)
@@ -38,6 +38,7 @@
 #include <Draw_Appli.hxx>
 #include <Draw_Window.hxx>
 #include <DBRep.hxx>
+#include <ElCLib.hxx>
 #include <ElSLib.hxx>
 #include <GC_MakePlane.hxx>
 #include <Geom_CartesianPoint.hxx>
@@ -168,16 +169,21 @@ static Standard_Boolean Get3DPointAtMousePosition (const gp_Pnt& theFirstPoint,
 //           length, angle, radius and diameter dimension.
 //
 //draw args: -text [3d|2d] [wf|sh|wireframe|shading] [Size]
-//           -label [left|right|hcenter|hfit] [top|bottom|vcenter|vfit]
+//           -label [left|right|hcenter|hfit] [top|bottom|vcenter|firstline|lastline|vfit]
 //           -arrow [external|internal|fit] [Length(int)]
 //           -arrowangle ArrowAngle(degrees)
 //           -plane xoy|yoz|zox
 //           -flyout FloatValue -extension FloatValue
 //           -value CustomNumberValue
+//           -valuetext CustomText
 //           -dispunits DisplayUnitsString
 //           -modelunits ModelUnitsString
-//           -showunits
+//           -showunits (DEFAULT)
 //           -hideunits
+//           -drawdimline (DEFAULT)
+//           -hidedimline
+//           -aligntext DirX DirY DirZ
+//           -segment Length
 //
 // Warning! flyout is not an aspect value, it is for dimension parameter
 // likewise text position, but text position override other paramaters.
@@ -190,6 +196,8 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
                                  Standard_Boolean& theIsCustomPlane, gp_Pln& thePlane,
                                  NCollection_DataMap<TCollection_AsciiString, Standard_Real>& theRealParams,
                                  NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams,
+                                 NCollection_DataMap<TCollection_AsciiString, Standard_Boolean>& theBooleanParams,
+                                 Standard_Boolean& theIsTextAligned, gp_Dir& theTextDir,
                                  NCollection_List<Handle(AIS_InteractiveObject)>* theShapeList = NULL)
 {
   theRealParams.Clear();
@@ -208,7 +216,7 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
       continue;
     }
 
-    // Boolean flags
+    // BOOLEAN flags
     if (aParam.IsEqual ("-showunits"))
     {
       theAspect->MakeUnitsDisplayed (Standard_True);
@@ -220,14 +228,25 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
       continue;
     }
 
-    // Before all non-boolean flags parsing check if a flag have at least one value.
+    if (aParam.IsEqual ("-drawdimline"))
+    {
+      theBooleanParams.Bind ("drawdimline", Standard_True);
+      continue;
+    }
+    else if (aParam.IsEqual ("-hidedimline"))
+    {
+      theBooleanParams.Bind ("drawdimline", Standard_False);
+      continue;
+    }
+
+    // Before all NON-BOOLEAN flags parsing check if a flag have at least one value.
     if (anIt + 1 >= theArgNum)
     {
       std::cerr << "Error: "<< aParam <<" flag should have value.\n";
       return 1;
     }
 
-    // Non-boolean flags
+    // NON-BOOLEAN flags
     if (aParam.IsEqual ("-shape")
      || aParam.IsEqual ("-shapes"))
     {
@@ -305,13 +324,15 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
         TCollection_AsciiString aParamValue (theArgVec[anIt]);
         aParamValue.LowerCase();
 
-        if (aParamValue == "left")         { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Left);  }
-        else if (aParamValue == "right")   { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Right); }
-        else if (aParamValue == "hcenter") { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Center);}
-        else if (aParamValue == "hfit")    { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Fit);   }
-        else if (aParamValue == "above")   { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Above); }
-        else if (aParamValue == "below")   { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Below); }
-        else if (aParamValue == "vcenter") { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Center);}
+        if      (aParamValue == "left")      { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Left);      }
+        else if (aParamValue == "right")     { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Right);     }
+        else if (aParamValue == "hcenter")   { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Center);    }
+        else if (aParamValue == "hfit")      { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Fit);       }
+        else if (aParamValue == "above")     { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Above);     }
+        else if (aParamValue == "below")     { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Below);     }
+        else if (aParamValue == "vcenter")   { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Center);    }
+        else if (aParamValue == "firstline") { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_FirstLine); }
+        else if (aParamValue == "lastline")  { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_LastLine);  }
         else
         {
           std::cerr << "Error: invalid label position: '" << aParamValue << "'.\n";
@@ -334,7 +355,7 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
       TCollection_AsciiString aValue (theArgVec[++anIt]);
       if (!aValue.IsRealValue())
       {
-        std::cerr << "Error: arrow lenght should be float degree value.\n";
+        std::cerr << "Error: arrow length should be float degree value.\n";
         return 1;
       }
       theAspect->ArrowAspect()->SetLength (Draw::Atof (aValue.ToCString()));
@@ -388,6 +409,20 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
         return 1;
       }
     }
+    else if (aParam.IsEqual ("-aligntext"))
+    {
+      theIsTextAligned = Standard_True;
+      TCollection_AsciiString aParam1 (theArgVec[++anIt]);
+      TCollection_AsciiString aParam2 (theArgVec[++anIt]);
+      TCollection_AsciiString aParam3 (theArgVec[++anIt]);
+      if (!aParam1.IsRealValue() || !aParam2.IsRealValue() || !aParam3.IsRealValue())
+      {
+        std::cerr << "Error: direction coordinate should be real value.\n";
+        return 1;
+      }
+      theTextDir.SetCoord (aParam1.RealValue(), aParam2.RealValue(), aParam3.RealValue());
+    }
+    // REAL parameters
     else if (aParam.IsEqual ("-flyout"))
     {
       TCollection_AsciiString aParam (theArgVec[++anIt]);
@@ -402,13 +437,43 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
     else if (aParam.IsEqual ("-value"))
     {
       TCollection_AsciiString aParam (theArgVec[++anIt]);
+
+      // Custom real value
       if (!aParam.IsRealValue())
       {
-        std::cerr << "Error: dimension value for dimension should be real value.\n";
+        std::cerr << "Error: custom value should be real value.\n";
         return 1;
       }
-
       theRealParams.Bind ("value", Draw::Atof (aParam.ToCString()));
+
+    }
+    else if (aParam.IsEqual ("-circleparam"))
+    {
+      TCollection_AsciiString aParam (theArgVec[++anIt]);
+      if (!aParam.IsRealValue())
+      {
+        std::cerr << "Error: circle parameter should be real value.\n";
+        return 1;
+      }
+
+      theRealParams.Bind ("circleparam", aParam.RealValue());
+    }
+    else if (aParam.IsEqual ("-segment"))
+    {
+       TCollection_AsciiString aParam (theArgVec[++anIt]);
+      if (!aParam.IsRealValue() || aParam.RealValue() < 0.0)
+      {
+        std::cerr << "Error: segment length should be positive real value.\n";
+        return 1;
+      }
+
+      theRealParams.Bind ("segment", aParam.RealValue());
+    }
+    // STRING parameters
+    else if (aParam.IsEqual ("-valuetext"))
+    {
+      TCollection_AsciiString aParam (theArgVec[++anIt]);
+      theStringParams.Bind ("valuetext", aParam);
     }
     else if (aParam.IsEqual ("-modelunits"))
     {
@@ -438,7 +503,8 @@ static int ParseDimensionParams (Standard_Integer  theArgNum,
 //=======================================================================
 static void SetDimensionParams (const Handle(AIS_Dimension)& theDim,
                                 const NCollection_DataMap<TCollection_AsciiString, Standard_Real>& theRealParams,
-                                const NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams)
+                                const NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams,
+                                const NCollection_DataMap<TCollection_AsciiString, Standard_Boolean>& theBooleanParams)
 {
   if (theRealParams.IsBound ("flyout"))
   {
@@ -449,6 +515,10 @@ static void SetDimensionParams (const Handle(AIS_Dimension)& theDim,
   {
     theDim->SetCustomValue (theRealParams.Find ("value"));
   }
+  else if (theStringParams.IsBound ("valuetext"))
+  {
+    theDim->SetTextLabel (theStringParams.Find ("valuetext"));
+  }
 
   if (theStringParams.IsBound ("modelunits"))
   {
@@ -459,6 +529,16 @@ static void SetDimensionParams (const Handle(AIS_Dimension)& theDim,
   {
     theDim->SetDisplayUnits (theStringParams.Find ("dispunits"));
   }
+
+  if (theBooleanParams.IsBound ("drawdimline"))
+  {
+    theDim->SetToDrawDimensionLine (theBooleanParams.Find ("drawdimline"));
+  }
+
+  if (theRealParams.IsBound ("segment"))
+  {
+    theDim->SetLeaderSegment (theRealParams.Find ("segment"));
+  }
 }
 
 //=======================================================================
@@ -483,9 +563,12 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
   Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect;
   Standard_Boolean isPlaneCustom = Standard_False;
   gp_Pln aWorkingPlane;
+  Standard_Boolean isTextAligned = Standard_False;
+  gp_Dir aTextDir (1.0, 0.0, 0.0);
 
   NCollection_DataMap<TCollection_AsciiString, Standard_Real> aRealParams;
   NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> aStringParams;
+  NCollection_DataMap<TCollection_AsciiString, Standard_Boolean> aBoolParams;
 
   TCollection_AsciiString aDimType(theArgs[2]);
   aDimType.LowerCase();
@@ -515,7 +598,7 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
 
   if (ParseDimensionParams (theArgsNb, theArgs, 3,
                             anAspect,isPlaneCustom,aWorkingPlane,
-                            aRealParams, aStringParams, &aShapes))
+                            aRealParams, aStringParams, aBoolParams, isTextAligned, aTextDir, &aShapes))
   {
     return 1;
   }
@@ -656,7 +739,15 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
         {
           Handle(AIS_Circle) aShape = Handle(AIS_Circle)::DownCast (aShapes.First());
           gp_Circ aCircle = aShape->Circle()->Circ();
-          aDim = new AIS_RadiusDimension (aCircle);
+          Standard_Real aParam = 0;
+
+          // Check if circle parameter is set
+          if (aRealParams.IsBound ("circleparam"))
+          {
+            aParam = aRealParams.Find ("circleparam");
+          }
+
+          aDim = new AIS_RadiusDimension (aCircle, aParam);
         }
         else
         {
@@ -685,7 +776,16 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
         {
           Handle(AIS_Circle) aShape = Handle(AIS_Circle)::DownCast (aShapes.First());
           gp_Circ aCircle = aShape->Circle()->Circ();
-          aDim = new AIS_DiameterDimension (aCircle);
+
+          Standard_Real aParam = 0;
+
+          // Check if circle parameter is set
+          if (aRealParams.IsBound ("circleparam"))
+          {
+            aParam = aRealParams.Find ("circleparam");
+          }
+
+          aDim = new AIS_DiameterDimension (aCircle, aParam);
         }
         else
         {
@@ -713,6 +813,11 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
     }
   }
 
+  if (isTextAligned)
+  {
+    aDim->SetToAlignText (isTextAligned, aTextDir);
+  }
+
   // Check dimension geometry
   if (!aDim->IsValid())
   {
@@ -723,7 +828,7 @@ static int VDimBuilder (Draw_Interpretor& /*theDi*/,
 
   aDim->SetDimensionAspect (anAspect);
 
-  SetDimensionParams (aDim, aRealParams, aStringParams);
+  SetDimensionParams (aDim, aRealParams, aStringParams, aBoolParams);
 
   VDisplayAISObject (aName,aDim);
 
@@ -2544,10 +2649,13 @@ static int VDimParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const
   TCollection_AsciiString aName (theArgVec[1]);
   gp_Pln aWorkingPlane;
   Standard_Boolean isCustomPlane = Standard_False;
+  Standard_Boolean isTextAligned = Standard_False;
+  gp_Dir aTextDir (1.0, 0.0, 0.0);
   Standard_Boolean toUpdate = Standard_True;
 
   NCollection_DataMap<TCollection_AsciiString, Standard_Real> aRealParams;
   NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> aStringParams;
+  NCollection_DataMap<TCollection_AsciiString, Standard_Boolean> aBoolParams;
 
   if (!GetMapOfAIS().IsBound2 (aName))
   {
@@ -2558,7 +2666,7 @@ static int VDimParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const
   Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast(GetMapOfAIS().Find2 (aName));
   if (anObject->Type() != AIS_KOI_Dimension)
   {
-    theDi << theArgVec[0] << "error: no dimension with this name.\n";
+    theDi << theArgVec[0] << "error: no dimension with the name: " << aName.ToCString() << ".\n";
     return 1;
   }
 
@@ -2567,7 +2675,7 @@ static int VDimParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const
 
   if (ParseDimensionParams (theArgNum, theArgVec, 2, anAspect,
                             isCustomPlane, aWorkingPlane,
-                            aRealParams, aStringParams))
+                            aRealParams, aStringParams, aBoolParams, isTextAligned, aTextDir))
   {
     return 1;
   }
@@ -2577,7 +2685,12 @@ static int VDimParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const
     aDim->SetCustomPlane (aWorkingPlane);
   }
 
-  SetDimensionParams (aDim, aRealParams, aStringParams);
+  if (isTextAligned)
+  {
+    aDim->SetToAlignText (isTextAligned, aTextDir);
+  }
+
+  SetDimensionParams (aDim, aRealParams, aStringParams, aBoolParams);
 
   if (!aDim->IsValid())
   {
@@ -2773,16 +2886,20 @@ void ViewerTest::RelationCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vdimension",
       "vdimension name {-angle|-length|-radius|-diameter} -shapes shape1 [shape2 [shape3]]\n"
       "[-text 3d|2d wf|sh|wireframe|shading IntegerSize]\n"
-      "[-label left|right|hcenter|hfit top|bottom|vcenter|vfit]\n"
+      "[-label left|right|hcenter|hfit above|below|vcenter|vfit]\n"
       "[-arrow external|internal|fit]\n"
       "[{-arrowlength|-arlen} RealArrowLength]\n"
       "[{-arrowangle|-arangle} ArrowAngle(degrees)]\n"
       "[-plane xoy|yoz|zox]\n"
       "[-flyout FloatValue -extension FloatValue]\n"
-      "[-value CustomNumberValue]\n"
+      "[-value CustomNumberValue] OR [-valuetext CustomMultilineLabel]\n"
       "[-dispunits DisplayUnitsString]\n"
       "[-modelunits ModelUnitsString]\n"
       "[-showunits | -hideunits]\n"
+      "[-drawdimline] <- dimension line is displayed by default\n"
+      "[-hidedimline]/n"
+      "[-aligntext DirX DirY DirZ]\n"
+      "[-segment Length\n"
       " -Builds angle, length, radius and diameter dimensions.\n"
       " -See also: vdimparam, vmovedim.\n",
       __FILE__,VDimBuilder,group);
@@ -2800,6 +2917,11 @@ void ViewerTest::RelationCommands(Draw_Interpretor& theCommands)
     "[-dispunits DisplayUnitsString]\n"
     "[-modelunits ModelUnitsString]\n"
     "[-showunits | -hideunits]\n"
+    "[-drawdimline] <- dimension line is displayed by default\n"
+    "[-hidedimline]/n"
+    "[-aligntext DirX DirY DirZ]\n"
+    "[-segment Length\n"
+    " -Builds angle, length, radius and diameter dimensions.\n"
     " -Sets parameters for angle, length, radius and diameter dimensions.\n"
     " -See also: vmovedim, vdimension.\n",
     __FILE__,VDimParam,group);
diff --git a/tests/bugs/vis/bug26507_1 b/tests/bugs/vis/bug26507_1
new file mode 100644 (file)
index 0000000..8162e91
--- /dev/null
@@ -0,0 +1,26 @@
+puts "================================================================"
+puts "CR26507"
+puts "Visualization - Improved presentations of dimensions"
+puts "================================================================"
+puts ""
+puts "Radius dimension line not continued to the center of a circle"
+
+#set anImage1 $imagedir/${casename}_1.png
+
+vinit Viewer1/View
+vright
+
+vpoint aCircleP1 0 0 60
+vpoint aCircleP2 60 0 0
+vpoint aCircleP3 120 0 60
+vcircle aCircle aCircleP1 aCircleP2 aCircleP3 0
+
+#Check all text and arrow positions
+vdimension aDim1 -radius -shapes aCircle -text 3d -plane zox -label hfit -arrow external -hidedimline
+vdimension aDim2 -radius -shapes aCircle -circleparam 20 -text 3d -plane zox -label right -arrow external -hidedimline
+vdimension aDim3 -radius -shapes aCircle -circleparam 40 -text 3d -plane zox -label vcenter -arrow internal -hidedimline
+vdimension aDim3 -radius -shapes aCircle -circleparam 40 -text 3d -plane zox -label hfit -arrow internal -hidedimline
+vfit
+
+#finalize and dump
+set only_screen 1
diff --git a/tests/bugs/vis/bug26507_2 b/tests/bugs/vis/bug26507_2
new file mode 100644 (file)
index 0000000..d3e464b
--- /dev/null
@@ -0,0 +1,34 @@
+puts "================================================================"
+puts "CR26507"
+puts "Visualization - Improved presentations of dimensions"
+puts "================================================================"
+puts ""
+puts "User-defined orientation of text label"
+puts "Line segment aligned with text"
+
+#set anImage1 $imagedir/${casename}_1.png
+
+vinit Viewer1/View
+vbottom
+
+vpoint lengthP1 0 0 0
+vpoint lengthP2 50 100 0
+vpoint lengthP3 -50 100 0
+vpoint lengthP4 0 200 0
+# Text in center - custom aligment does not taken into account
+vdimension dim1 -length -plane xoy -shapes lengthP1 lengthP2 -text 3d -aligntext 1.0 0.0 0.0 -flyout -10
+
+# Text on the right side - it is aligned
+vdimension dim2 -length -plane xoy -shapes lengthP1 lengthP3 -text 3d -aligntext 1.0 0.0 0.0 -segment 0 -label right
+
+# Text on the left side - it is aligned
+vdimension dim3 -length -plane xoy -shapes lengthP2 lengthP3 -text 3d -flyout -10 -aligntext 1.0 0.0 0.0 -segment 5 -label left
+
+# Text on the left side - it is aligned
+vdimension dim4 -length -plane xoy -shapes lengthP2 lengthP4 -text 3d -flyout -10 -aligntext 1.0 0.0 0.0 -segment 25 -label right
+
+# Text on the left side - it is aligned
+vdimension dim5 -length -plane xoy -shapes lengthP4 lengthP3 -text 3d -flyout -10 -aligntext 1.0 0.0 0.0 -label left above -segment 10 
+vfit
+#finalize and dump
+set only_screen 1
\ No newline at end of file
diff --git a/tests/bugs/vis/bug26507_3 b/tests/bugs/vis/bug26507_3
new file mode 100644 (file)
index 0000000..82cde88
--- /dev/null
@@ -0,0 +1,28 @@
+puts "================================================================"
+puts "CR26507"
+puts "Visualization - Improved presentations of dimensions"
+puts "================================================================"
+puts ""
+puts "Multi-line custom text label"
+
+#set anImage1 $imagedir/${casename}_1.png
+
+vinit Viewer1/View
+vbottom
+
+vpoint lengthP1 0 0 0
+vpoint lengthP2 50 100 0
+vpoint lengthP3 -50 100 0
+# Text in center - custom aligment does not taken into account
+vdimension dim1 -length -plane xoy -shapes lengthP1 lengthP2 -valuetext "+2.0\n-3.0\nThickness" -text 2d -aligntext 1.0 0.0 0.0 -segment 15 -flyout -10 -label left firstline
+
+# Text on the right side - it is aligned
+vdimension dim2 -length -plane xoy -shapes lengthP1 lengthP3 -valuetext "+3.0\n-15.0\nThickness" -text 2d -aligntext 1.0 0.0 0.0 -segment 15 -label right
+
+# Text on the left side - it is aligned
+vdimension dim3 -length -plane xoy -shapes lengthP2 lengthP3 -text 2d -valuetext "+3.0\n-15.0" -flyout -10 -aligntext 1.0 0.0 0.0 -segment 10
+
+
+vfit
+#finalize and dump
+set only_screen 1
\ No newline at end of file
diff --git a/tests/bugs/vis/bug26507_4 b/tests/bugs/vis/bug26507_4
new file mode 100644 (file)
index 0000000..1a82836
--- /dev/null
@@ -0,0 +1,28 @@
+puts "================================================================"
+puts "CR26507"
+puts "Visualization - Improved presentations of dimensions"
+puts "================================================================"
+puts ""
+puts "Radius dimension with multiline custom text"
+
+#set anImage1 $imagedir/${casename}_1.png
+
+vinit Viewer1/View
+vright
+
+vpoint aCircleP1 0 0 60
+vpoint aCircleP2 60 0 0
+vpoint aCircleP3 120 0 60
+vcircle aCircle aCircleP1 aCircleP2 aCircleP3 0
+
+#Check all text and arrow positions
+vdimension aDim1 -radius -shapes aCircle -circleparam 10 -text 3d -label right -arrow external -hidedimline -valuetext "+2.0\n-3.0\nThickness" -aligntext 1.0 0.0 0.0 -segment 15 -label left firstline
+vdimension aDim2 -diameter -shapes aCircle -circleparam 5 -text 3d -label left -arrow external -hidedimline -valuetext "+4.0\n -6.0" -aligntext 1.0 0.0 0.0 -segment 15 -label left firstline
+vdimension aDim3 -radius -shapes aCircle -circleparam 20 -text 3d -plane zox -label right -arrow external -hidedimline
+vdimension aDim4 -radius -shapes aCircle -circleparam 40 -text 3d -plane zox -label vcenter -arrow internal -hidedimline
+vdimparam aDim1 -text 6
+vdimparam aDim3 -text 6
+vfit
+
+#finalize and dump
+set only_screen 1
diff --git a/tests/bugs/vis/bug26507_5 b/tests/bugs/vis/bug26507_5
new file mode 100644 (file)
index 0000000..ab823f3
--- /dev/null
@@ -0,0 +1,34 @@
+puts "================================================================"
+puts "CR26507"
+puts "Visualization - Improved presentations of dimensions"
+puts "================================================================"
+puts ""
+puts "User-defined orientation of text label"
+puts "Line segment aligned with text"
+
+#set anImage1 $imagedir/${casename}_1.png
+
+vinit Viewer1/View
+vbottom
+
+vpoint lengthP1 0 0 0
+vpoint lengthP2 100 0 0
+vpoint lengthP3 100 100 0
+vpoint lengthP4 0 100 0
+# Text in center - custom aligment does not taken into account
+#vdimension dim1 -length -plane xoy -shapes lengthP1 lengthP2 -text 3d -aligntext 1.0 0.0 0.0 -flyout -10
+
+# Text on the right side - it is aligned
+vdimension dim2 -length -plane xoy -shapes lengthP1 lengthP3 -text 3d -aligntext 1.0 0.0 0.0 -segment 0 -label right
+
+# Text on the left side - it is aligned
+vdimension dim3 -length -plane xoy -shapes lengthP2 lengthP3 -text 3d -flyout -10 -aligntext 1.0 0.0 0.0 -segment 5 -label left
+
+# Text on the left side - it is aligned
+vdimension dim4 -length -plane xoy -shapes lengthP4 lengthP1 -text 3d -valuetext "0.6\n1.58\nTHICKNESS" -flyout -10 -aligntext 1.0 0.0 0.0 -segment 10 -label right vcenter
+
+# Text on the left side - it is aligned
+vdimension dim5 -length -plane xoy -shapes lengthP4 lengthP3 -text 3d -flyout -10 -aligntext 1.0 0.0 0.0 -label left above -segment 10 
+vfit
+#finalize and dump
+set only_screen 1
\ No newline at end of file