0030537: Visualization - wrapping text in font text formatter
authornds <nds@opencascade.com>
Mon, 7 Sep 2020 08:10:32 +0000 (11:10 +0300)
committernds <nds@opencascade.com>
Mon, 7 Sep 2020 08:10:32 +0000 (11:10 +0300)
Font_TextFormatter inherits Standard_Transient, now it is given as a handle in functions.
Graphic3d_Text - extended with Font_TextFormatter to be able to have it filled out of text render. If it is not defined here, the default text formatter of context is used.
OpenGl_Context - has default Font_TextFormatter for rendering OpenGl_Text.
AIS_TextLabel extending with Font_TextFormatter to prepare test case for text wrapping.
Prs3d_Text returns created graphic text to be able to manage it outside.

14 files changed:
src/AIS/AIS_TextLabel.cxx
src/AIS/AIS_TextLabel.hxx
src/Font/Font_TextFormatter.cxx
src/Font/Font_TextFormatter.hxx
src/Graphic3d/Graphic3d_Text.hxx
src/OpenGl/OpenGl_Text.cxx
src/OpenGl/OpenGl_TextBuilder.cxx
src/OpenGl/OpenGl_TextBuilder.hxx
src/Prs3d/Prs3d_Text.cxx
src/Prs3d/Prs3d_Text.hxx
src/StdPrs/StdPrs_BRepTextBuilder.cxx
src/StdPrs/StdPrs_BRepTextBuilder.hxx
src/ViewerTest/ViewerTest_ObjectCommands.cxx
tests/3rdparty/text3d/text_wrapped [new file with mode: 0644]

index f387faf..8344e85 100644 (file)
@@ -20,6 +20,7 @@
 #include <Font_Rect.hxx>
 #include <Graphic3d_AspectText3d.hxx>
 #include <Graphic3d_RenderingParams.hxx>
+#include <Graphic3d_Text.hxx>
 
 #include <Prs3d_Text.hxx>
 #include <Prs3d_TextAspect.hxx>
@@ -308,7 +309,9 @@ void AIS_TextLabel::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePr
         {
           aHasOwnAnchor = Standard_False; // always not using own anchor if flipping
         }
-        Prs3d_Text::Draw (thePrs->CurrentGroup(), anAsp, myText, anOrientation, aHasOwnAnchor);
+        Handle(Graphic3d_Text) aText = 
+          Prs3d_Text::Draw (thePrs->CurrentGroup(), anAsp, myText, anOrientation, aHasOwnAnchor);
+        aText->SetTextFormatter (myFormatter);
         if (myHasFlipping && isInit)
         {
           thePrs->CurrentGroup()->SetFlippingOptions (Standard_False, gp_Ax2());
@@ -316,7 +319,9 @@ void AIS_TextLabel::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePr
       }
       else
       {
-        Prs3d_Text::Draw (thePrs->CurrentGroup(), anAsp, myText, aPosition);
+        Handle(Graphic3d_Text) aText =
+          Prs3d_Text::Draw (thePrs->CurrentGroup(), anAsp, myText, aPosition);
+        aText->SetTextFormatter (myFormatter);
       }
 
       if (isInit)
index b3ae257..90b1c5c 100644 (file)
@@ -24,6 +24,8 @@
 #include <Font_FontAspect.hxx>
 #include <TCollection_ExtendedString.hxx>
 
+class Font_TextFormatter;
+
 //! Presentation of the text.
 class AIS_TextLabel : public AIS_InteractiveObject
 {
@@ -121,6 +123,12 @@ public:
   //! and the colour of backgroubd for the TODT_DEKALE TextDisplayType.
   Standard_EXPORT void SetColorSubTitle (const Quantity_Color& theColor);
 
+  //! Returns text presentation formatter; NULL by default, which means standard text formatter will be used.
+  const Handle(Font_TextFormatter)& TextFormatter() const { return myFormatter; }
+
+  //! Setup text formatter for presentation. It's empty by default.
+  void SetTextFormatter (const Handle(Font_TextFormatter)& theFormatter) { myFormatter = theFormatter; }
+
 protected:
 
   //! Compute
@@ -144,6 +152,8 @@ protected:
 
 protected:
 
+  Handle(Font_TextFormatter) myFormatter;
+
   TCollection_ExtendedString myText;
   gp_Ax2                     myOrientation3D;
   Standard_Boolean           myHasOrientation3D;
index 520b3c9..c32f253 100644 (file)
 
 #include <Font_FTFont.hxx>
 
+#include <Precision.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
+
 namespace
 {
   typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
@@ -55,16 +59,17 @@ Font_TextFormatter::Font_TextFormatter()
 : myAlignX (Graphic3d_HTA_LEFT),
   myAlignY (Graphic3d_VTA_TOP),
   myTabSize (8),
+  myWrappingWidth (0.0f),
+  myLastSymbolWidth (0.0f),
+  myMaxSymbolWidth (0.0f),
   //
   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),
@@ -94,10 +99,12 @@ void Font_TextFormatter::Reset()
   myIsFormatted = false;
   myString.Clear();
   myPen.x() = myPen.y() = 0.0f;
-  myRectsNb = 0;
   myLineSpacing = myAscender = 0.0f;
   myCorners.Clear();
   myNewLines.Clear();
+
+  myLastSymbolWidth = 0.0f;
+  myMaxSymbolWidth = 0.0f;
 }
 
 // =======================================================================
@@ -119,16 +126,13 @@ void Font_TextFormatter::Append (const NCollection_String& 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;)
+  for (Font_TextFormatter::Iterator aFormatterIt (*this); aFormatterIt.More(); aFormatterIt.Next())
   {
-    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)
+    const Standard_Utf32Char aCharThis = aFormatterIt.Symbol();
+    const Standard_Utf32Char aCharNext = aFormatterIt.SymbolNext();
+
+    Standard_ShortReal anAdvanceX = 0;
+    if (IsCommandSymbol (aCharThis))
     {
       continue; // skip unsupported carriage control codes
     }
@@ -136,79 +140,69 @@ void Font_TextFormatter::Append (const NCollection_String& theString,
     {
       aSymbolsCounter = 0;
       myNewLines.Append (myPen.x());
-      continue; // will be processed on second pass
+      anAdvanceX = 0; // the symbol has null width
     }
     else if (aCharThis == ' ')
     {
-      ++aSymbolsCounter;
-      myPen.x() += theFont.AdvanceX (' ', aCharNext);
-      continue;
+      anAdvanceX = theFont.AdvanceX (' ', aCharNext);
     }
     else if (aCharThis == '\t')
     {
       const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
-      myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
+      anAdvanceX = theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
       aSymbolsCounter += aSpacesNum;
-      continue;
     }
-
+    else
+    {
+      anAdvanceX = theFont.AdvanceX (aCharThis, aCharNext);
+    }
     ++aSymbolsCounter;
-
     myCorners.Append (myPen);
-
-    myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
-
-    ++myRectsNb;
+    myPen.x() += anAdvanceX;
+    myMaxSymbolWidth = Max (myMaxSymbolWidth, anAdvanceX);
   }
+  myLastSymbolWidth = myPen.x() - myCorners.Last().x();
 }
 
 // =======================================================================
 // function : newLine
 // purpose  :
 // =======================================================================
-void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
+void Font_TextFormatter::newLine (const Standard_Integer theLastRect,
+                                  const Standard_ShortReal theMaxLineWidth)
 {
-  if (myRectLineStart >= myRectsNb)
+  Standard_Integer aFirstCornerId = myRectLineStart;
+  Standard_Integer aLastCornerId = theLastRect;
+
+  if (aFirstCornerId >= myCorners.Length())
   {
     ++myLinesNb;
     myPenCurrLine -= myLineSpacing;
     return;
   }
 
+  Standard_ShortReal aXMin = BottomLeft (aFirstCornerId).x();
+  Font_Rect aBndBox;
+  GlyphBoundingBox (aLastCornerId, aBndBox);
+  Standard_ShortReal aXMax = aBndBox.Right;
+
   myMoveVec.y() = myPenCurrLine;
   switch (myAlignX)
   {
     default:
-    case Graphic3d_HTA_LEFT:
-    {
-      myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
+    case Graphic3d_HTA_LEFT:   myMoveVec.x() = -aXMin;
       break;
-    }
-    case Graphic3d_HTA_RIGHT:
-    {
-      myMoveVec.x() = (myNewLineNb < myNewLines.Length())
-                    ? -myNewLines.Value (myNewLineNb)
-                    : -myPen.x();
+    case Graphic3d_HTA_RIGHT:  myMoveVec.x() = -aXMin +        (theMaxLineWidth - (aXMax - aXMin)) -        theMaxLineWidth;
       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);
+    case Graphic3d_HTA_CENTER: myMoveVec.x() = -aXMin + 0.5f * (theMaxLineWidth - (aXMax - aXMin)) - 0.5f * theMaxLineWidth;
       break;
-    }
   }
 
   move (myCorners, myMoveVec, myRectLineStart, theLastRect);
 
   ++myLinesNb;
   myPenCurrLine -= myLineSpacing;
-  myRectLineStart = myRectWordStart = theLastRect + 1;
+  myRectLineStart = theLastRect + 1;
 }
 
 // =======================================================================
@@ -217,13 +211,13 @@ void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
 // =======================================================================
 void Font_TextFormatter::Format()
 {
-  if (myRectsNb == 0 || myIsFormatted)
+  if (myCorners.Length() == 0 || myIsFormatted)
   {
     return;
   }
 
   myIsFormatted = true;
-  myLinesNb = myRectLineStart = myRectWordStart = 0;
+  myLinesNb = myRectLineStart = 0;
   myBndTop     = 0.0f;
   myBndWidth   = 0.0f;
   myMoveVec.x() = myMoveVec.y() = 0.0f;
@@ -232,59 +226,61 @@ void Font_TextFormatter::Format()
   myPenCurrLine = -myAscender;
   Standard_Integer aRectIter = 0;
   myNewLineNb = 0;
-  Standard_ShortReal aMaxLineWidth = -1.0f;
-  for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
+
+  Standard_ShortReal aMaxLineWidth = Wrapping();
+  if (HasWrapping())
   {
-    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)
+    // it is not possible to wrap less than symbol width
+    aMaxLineWidth = Max (aMaxLineWidth, MaximumSymbolWidth());
+  }
+  else
+  {
+    if (myNewLines.IsEmpty()) // If only one line
     {
-      continue; // skip unsupported carriage control codes
+      aMaxLineWidth = myPen.x();
     }
-    else if (aCharThis == '\x0A') // LF (line feed, new line)
+    else
     {
-      // calculate max line width
-      if (myNewLineNb == 0)
-      {
-        aMaxLineWidth = myNewLines.Value(0);
-      }
-      else
+      for (int aLineIt = 0; aLineIt < myNewLines.Size(); aLineIt++)
       {
-        aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
+        aMaxLineWidth = Max (aMaxLineWidth, LineWidth (aLineIt));
       }
+      aMaxLineWidth = Max (aMaxLineWidth, LineWidth (myNewLines.Size())); // processing the last line also
+    }
+  }
+
+  for (Font_TextFormatter::Iterator aFormatterIt(*this);
+       aFormatterIt.More(); aFormatterIt.Next())
+  {
+    const Standard_Utf32Char aCharThis = aFormatterIt.Symbol();
+    aRectIter = aFormatterIt.SymbolPosition();
 
-      const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
-      newLine (aLastRect);
+    if (aCharThis == '\x0A') // LF (line feed, new line)
+    {
+      const Standard_Integer aLastRect = aRectIter; // last rect on current line
+      newLine (aLastRect, aMaxLineWidth);
       ++myNewLineNb;
       continue;
     }
-    else if (aCharThis == ' '
-          || aCharThis == '\t')
+    else if (HasWrapping()) // wrap lines longer than maximum width
     {
-      myRectWordStart = aRectIter;
-      continue;
-    }
+      Standard_Integer aFirstCornerId = myRectLineStart;
 
-    ++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));
+      Font_Rect aBndBox;
+      GlyphBoundingBox (aRectIter, aBndBox);
+      const Standard_ShortReal aNextXPos = aBndBox.Right - BottomLeft (aFirstCornerId).x();
+      if (aNextXPos > aMaxLineWidth) // wrap the line and do processing of the symbol
+      {
+        const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
+        newLine (aLastRect, aMaxLineWidth);
+      }
+    }
   }
 
   myBndWidth = aMaxLineWidth;
 
   // move last line
-  newLine (myRectsNb - 1);
+  newLine (myCorners.Length() - 1, aMaxLineWidth);
 
   // apply vertical alignment style
   if (myAlignY == Graphic3d_VTA_BOTTOM)
@@ -302,6 +298,129 @@ void Font_TextFormatter::Format()
 
   if (myAlignY != Graphic3d_VTA_TOP)
   {
-    moveY (myCorners, myBndTop, 0, myRectsNb - 1);
+    moveY (myCorners, myBndTop, 0, myCorners.Length() - 1);
   }
 }
+
+// =======================================================================
+// function : GlyphBoundingBox
+// purpose  :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::GlyphBoundingBox (const Standard_Integer theIndex,
+                                                       Font_Rect& theBndBox) const
+{
+  if (theIndex < 0 || theIndex >= Corners().Size())
+    return Standard_False;
+
+  const NCollection_Vec2<Standard_ShortReal>& aLeftCorner = BottomLeft (theIndex);
+  if (theIndex + 1 < myCorners.Length()) // not the last symbol
+  {
+    const NCollection_Vec2<Standard_ShortReal>& aNextLeftCorner = BottomLeft (theIndex + 1);
+    theBndBox.Left = aLeftCorner.x();
+    theBndBox.Bottom = aLeftCorner.y();
+    theBndBox.Top = theBndBox.Bottom + myLineSpacing;
+    if (Abs (aLeftCorner.y() - aNextLeftCorner.y()) < Precision::Confusion()) // in the same row
+    {
+      theBndBox.Right = aNextLeftCorner.x();
+    }
+    else
+    {
+      // the next symbol is on the next row either by '\n' or by wrapping
+      Standard_ShortReal aLineWidth = LineWidth (LineIndex (theIndex));
+      theBndBox.Left = aLeftCorner.x();
+      switch (myAlignX)
+      {
+        case Graphic3d_HTA_LEFT:   theBndBox.Right = aLineWidth; break;
+        case Graphic3d_HTA_RIGHT:  theBndBox.Right = myBndWidth; break;
+        case Graphic3d_HTA_CENTER: theBndBox.Right = 0.5f * (myBndWidth + aLineWidth); break;
+      }
+    }
+  }
+  else // the last symbol
+  {
+    theBndBox.Left = aLeftCorner.x();
+    theBndBox.Right = aLeftCorner.x() + myLastSymbolWidth;
+    theBndBox.Bottom = aLeftCorner.y();
+    theBndBox.Top = theBndBox.Bottom + myLineSpacing;
+  }
+  return Standard_True;
+}
+
+
+// =======================================================================
+// function : IsLFSymbol
+// purpose  :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::IsLFSymbol (const Standard_Integer theIndex) const
+{
+  Font_Rect aBndBox;
+  if (!GlyphBoundingBox (theIndex, aBndBox))
+    return Standard_False;
+
+  return Abs (aBndBox.Right - aBndBox.Left) < Precision::Confusion();
+}
+
+// =======================================================================
+// function : FirstPosition
+// purpose  :
+// =======================================================================
+Standard_ShortReal Font_TextFormatter::FirstPosition() const
+{
+  switch (myAlignX)
+  {
+    default:
+    case Graphic3d_HTA_LEFT:   return 0;
+    case Graphic3d_HTA_RIGHT:  return myBndWidth;
+    case Graphic3d_HTA_CENTER: return 0.5f * myBndWidth;
+  }
+}
+
+// =======================================================================
+// function : LinePositionIndex
+// purpose  :
+// =======================================================================
+Standard_Integer Font_TextFormatter::LinePositionIndex (const Standard_Integer theIndex) const
+{
+  Standard_Integer anIndex = 0;
+
+  Standard_ShortReal anIndexHeight = BottomLeft (theIndex).y();
+  for (Standard_Integer aPrevIndex = theIndex-1; aPrevIndex >= 0; aPrevIndex--)
+  {
+    if (BottomLeft (aPrevIndex).y() > anIndexHeight)
+    {
+      break;
+    }
+    anIndex++;
+  }
+  return anIndex;
+}
+
+// =======================================================================
+// function : LineIndex
+// purpose  :
+// =======================================================================
+Standard_Integer Font_TextFormatter::LineIndex (const Standard_Integer theIndex) const
+{
+  if (myLineSpacing < 0.0f)
+    return 0;
+
+  return (Standard_Integer)Abs((BottomLeft (theIndex).y() + myAscender) / myLineSpacing);
+}
+
+// =======================================================================
+// function : LineWidth
+// purpose  :
+// =======================================================================
+Standard_ShortReal Font_TextFormatter::LineWidth (const Standard_Integer theIndex) const
+{
+  if (theIndex < 0)
+    return 0;
+
+  if (theIndex < myNewLines.Length())
+    return theIndex == 0 ? myNewLines[0] : myNewLines[theIndex] - myNewLines[theIndex -1];
+
+  if (theIndex == myNewLines.Length()) // the last line
+    return theIndex == 0 ? myPen.x() : myPen.x() - myNewLines[theIndex -1];
+
+  return 0;
+}
index 19d68e7..1d917f2 100755 (executable)
 
 class Font_FTFont;
 
-//! This class intended to prepare formatted text.
-class Font_TextFormatter
+DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
+
+//! This class is intended to prepare formatted text by using:<br>
+//! - font to string combination,<br>
+//! - alignment,<br>
+//! - wrapping.<br>
+//!
+//! After text formatting, each symbol of formatted text is placed in some position.
+//! Further work with the formatter is using an iterator.
+//! The iterator gives an access to each symbol inside the initial row.
+//! Also it's possible to get only significant/writable symbols of the text.<br>
+//! Formatter gives an access to geometrical position of a symbol by the symbol index in the text.<br>
+//! Example of correspondence of some text symbol to an index in "row_1\n\nrow_2\n":<br>
+//! "row_1\n"  - 0-5 indices;<br>
+//! "\n"       - 6 index;<br>
+//! "\n"       - 7 index;<br>
+//! "row_2\n"  - 8-13 indices.<br>
+//! Pay attention that fonts should have the same LineSpacing value for correct formatting.<br>
+//! Example of the formatter using:
+//! @code
+//!   Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
+//!   aFormatter->Append(text_1, aFont1);
+//!   aFormatter->Append(text_2, aFont2);
+//!   // setting of additional properties such as wrapping or alignment
+//!   aFormatter->Format();
+//! @endcode
+class Font_TextFormatter : public Standard_Transient
 {
 public:
+  //! Iteration filter flags. Command symbols are skipped with any filter.
+  enum IterationFilter
+  {
+    IterationFilter_None             = 0x0000, //!< no filter
+    IterationFilter_ExcludeInvisible = 0x0002, //!< exclude ' ', '\t', '\n'
+  };
+
+  //! Iterator through formatted symbols.
+  //! It's possible to filter returned symbols to have only significant ones.
+  class Iterator
+  {
+  public:
+    //! Constructor with initialization.
+    Iterator (const Font_TextFormatter& theFormatter,
+              IterationFilter theFilter = IterationFilter_None)
+    : myFilter (theFilter), myIter (theFormatter.myString.Iterator()), mySymbolChar (0), mySymbolCharNext (0)
+    {
+      mySymbolPosition = readNextSymbol (-1, mySymbolChar);
+      mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
+    }
+
+    //! Returns TRUE if iterator points to a valid item.
+    Standard_Boolean More() const { return mySymbolPosition >= 0; }
+
+    //! Returns TRUE if next item exists
+    Standard_Boolean HasNext() const { return mySymbolNext >= 0; }
+
+    //! Returns current symbol.
+    Standard_Utf32Char Symbol() const { return mySymbolChar; }
+
+    //! Returns the next symbol if exists.
+    Standard_Utf32Char SymbolNext() const { return mySymbolCharNext; }
+
+    //! Returns current symbol position.
+    Standard_Integer SymbolPosition() const { return mySymbolPosition; }
+
+    //! Returns the next symbol position.
+    Standard_Integer SymbolPositionNext() const { return mySymbolNext; }
+
+    //! Moves to the next item.
+    void Next()
+    {
+      mySymbolPosition = mySymbolNext;
+      mySymbolChar = mySymbolCharNext;
+      mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
+    }
+
+  protected:
+    //! Finds index of the next symbol
+    Standard_Integer readNextSymbol (const Standard_Integer theSymbolStartingFrom,
+                                     Standard_Utf32Char& theSymbolChar)
+    {
+      Standard_Integer aNextSymbol = theSymbolStartingFrom;
+      for (; *myIter != 0; ++myIter)
+      {
+        const Standard_Utf32Char aCharCurr = *myIter;
+        if (Font_TextFormatter::IsCommandSymbol (aCharCurr))
+        {
+          continue; // skip unsupported carriage control codes
+        }
+        aNextSymbol++;
+        if ((myFilter & IterationFilter_ExcludeInvisible) != 0)
+        {
+          if (aCharCurr == '\x0A'|| // LF (line feed, new line)
+              aCharCurr == ' ' ||
+              aCharCurr == '\t')
+          {
+            continue;
+          }
+        }
+        ++myIter;
+        theSymbolChar = aCharCurr;
+        return aNextSymbol; // found the first next, not command and not filtered symbol
+      }
+      return -1; // the next symbol is not found
+    }
+
+  protected:
+    IterationFilter      myFilter; //!< possibility to filter not-necessary symbols
+    NCollection_Utf8Iter myIter; //!< the next symbol iterator value over the text formatter string
+    Standard_Integer     mySymbolPosition; //!< the current position
+    Standard_Utf32Char   mySymbolChar; //!< the current symbol
+    Standard_Integer     mySymbolNext; //!< position of the next symbol in iterator, if zero, the iterator is finished
+    Standard_Utf32Char   mySymbolCharNext; //!< the current symbol
+  };
 
   //! Default constructor.
   Standard_EXPORT Font_TextFormatter();
@@ -48,24 +158,68 @@ public:
   //! 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
+  Standard_DEPRECATED("BottomLeft should be used instead")
+  const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
   {
-    return myCorners.Value (theIndex);
+    return BottomLeft (theIndex);
   }
 
+  //! Returns specific glyph rectangle.
+  const NCollection_Vec2<Standard_ShortReal>& BottomLeft (const Standard_Integer theIndex) const
+  { return myCorners.Value (theIndex); }
+
   //! Returns current rendering string.
   inline const NCollection_String& String() const
   {
     return myString;
   }
 
+  //! Returns symbol bounding box
+  //! @param bounding box.
+  Standard_EXPORT Standard_Boolean GlyphBoundingBox (const Standard_Integer theIndex,
+                                                     Font_Rect& theBndBox) const;
+
+  //! Returns the line height
+  //! @param theIndex a line index, obtained by LineIndex()
+  Standard_ShortReal LineHeight (const Standard_Integer theIndex) const
+  { return theIndex == 0 ? myAscender : myLineSpacing; }
+
+  //! Returns width of a line
+  Standard_EXPORT Standard_ShortReal LineWidth (const Standard_Integer theIndex) const;
+
+  //! Returns true if the symbol by the index is '\n'. The width of the symbol is zero.
+  Standard_EXPORT Standard_Boolean IsLFSymbol (const Standard_Integer theIndex) const;
+
+  //! Returns position of the first symbol in a line using alignment
+  Standard_EXPORT Standard_ShortReal FirstPosition() const;
+
+  //! Returns column index of the corner index in the current line
+  Standard_EXPORT Standard_Integer LinePositionIndex (const Standard_Integer theIndex) const;
+
+  //! Returns row index of the corner index among text lines
+  Standard_EXPORT Standard_Integer LineIndex (const Standard_Integer theIndex) const;
+
   //! Returns tab size.
   inline Standard_Integer TabSize() const
   {
     return myTabSize;
   }
 
+  //! Returns horizontal alignment style
+  Graphic3d_HorizontalTextAlignment HorizontalTextAlignment() const { return myAlignX; }
+
+  //! Returns vertical   alignment style
+  Graphic3d_VerticalTextAlignment VerticalTextAlignment() const { return myAlignY; }
+
+  //! Sets text wrapping width, zero means that the text is not bounded by width
+  void SetWrapping (const Standard_ShortReal theWidth) { myWrappingWidth = theWidth; }
+
+  //! Returns text maximum width, zero means that the text is not bounded by width
+  Standard_Boolean HasWrapping() const { return myWrappingWidth > 0; }
+
+  //! Returns text maximum width, zero means that the text is not bounded by width
+  Standard_ShortReal Wrapping() const { return myWrappingWidth; }
+
   //! @return width of formatted text.
   inline Standard_ShortReal ResultWidth() const
   {
@@ -78,6 +232,9 @@ public:
     return myLineSpacing * Standard_ShortReal(myLinesNb);
   }
 
+  //! @return maximum width of the text symbol
+  Standard_ShortReal MaximumSymbolWidth() const { return myMaxSymbolWidth; }
+
   //! @param bounding box.
   inline void BndBox (Font_Rect& theBndBox) const
   {
@@ -98,16 +255,41 @@ public:
     theBndBox.Bottom = theBndBox.Top - myLineSpacing * Standard_ShortReal(myLinesNb);
   }
 
+  //! Returns internal container of the top left corners of a formatted rectangles.
+  const NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >& Corners() const { return myCorners; }
+
+  //! Returns container of each line position at LF in formatted text
+  const NCollection_Vector<Standard_ShortReal>& NewLines() const { return myNewLines; }
+
+  //! Returns true if the symbol is CR, BEL, FF, NP, BS or VT
+  static inline Standard_Boolean IsCommandSymbol (const Standard_Utf32Char& theSymbol)
+  {
+    if (theSymbol == '\x0D' // CR  (carriage return)
+     || theSymbol == '\a'   // BEL (alarm)
+     || theSymbol == '\f'   // FF  (form feed) NP (new page)
+     || theSymbol == '\b'   // BS  (backspace)
+     || theSymbol == '\v')  // VT  (vertical tab)
+      return Standard_True;
+
+    return Standard_False;
+  }
+
+  DEFINE_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
+
 protected: //! @name class auxiliary methods
 
   //! Move glyphs on the current line to correct position.
-  Standard_EXPORT void newLine (const Standard_Integer theLastRect);
+  Standard_EXPORT void newLine (const Standard_Integer theLastRect,
+                                const Standard_ShortReal theMaxLineWidth);
 
 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)
+  Standard_ShortReal                myWrappingWidth; //!< text is wrapped by the width if defined (more 0)
+  Standard_ShortReal                myLastSymbolWidth; //!< width of the last symbol
+  Standard_ShortReal                myMaxSymbolWidth; //!< maximum symbol width of the formatter string
 
 protected: //! @name input data
 
@@ -115,19 +297,17 @@ protected: //! @name input data
   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
+                     myCorners;       //!< The bottom left corners of a formatted rectangles.
   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;      //!<
+  Standard_ShortReal myAscender;      //!< line spacing for the first line
   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
index c1fd70b..76e2dd4 100644 (file)
@@ -17,6 +17,7 @@
 #include <gp_Ax2.hxx>
 
 #include <Graphic3d_Vertex.hxx>
+#include <Font_TextFormatter.hxx>
 #include <Graphic3d_HorizontalTextAlignment.hxx>
 #include <Graphic3d_VerticalTextAlignment.hxx>
 #include <NCollection_String.hxx>
@@ -31,6 +32,7 @@
 //! - text formatter. Formatter contains text, height and alignment parameter.
 //!
 //! This class also has parameters of the text height and H/V alignments.
+//! Custom formatting is available using Font_TextFormatter.
 class Graphic3d_Text : public Standard_Transient
 {
   DEFINE_STANDARD_RTTIEXT(Graphic3d_Text, Standard_Transient)
@@ -55,6 +57,12 @@ public:
   //! Sets text value.
   void SetText (Standard_CString theText) { myText = theText; }
 
+  //! @return text formatter; NULL by default, which means standard text formatter will be used.
+  const Handle(Font_TextFormatter)& TextFormatter() const { return myFormatter; }
+
+  //! Setup text default formatter for text within this context.
+  void SetTextFormatter (const Handle(Font_TextFormatter)& theFormatter) { myFormatter = theFormatter; }
+
   //! The 3D point of attachment is projected.
   //! If the orientation is defined, the text is written in the plane of projection.
   const gp_Pnt& Position() const { return myOrientation.Location(); }
@@ -99,6 +107,8 @@ public:
   void SetVerticalAlignment (const Graphic3d_VerticalTextAlignment theJustification) { myVAlign = theJustification; }
 
 protected:
+  Handle(Font_TextFormatter) myFormatter; //!< text formatter
+
   NCollection_String myText; //!< text value
   gp_Ax2 myOrientation; //!< Text orientation in 3D space.
 
index 6a9b844..09c6397 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <Font_FontMgr.hxx>
 #include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
 #include <Graphic3d_TransformUtils.hxx>
 #include <TCollection_HAsciiString.hxx>
 
@@ -659,7 +660,7 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
                           const OpenGl_Vec4& theColorSubs,
                           unsigned int theResolution) const
 {
-  if (myText->Text().IsEmpty())
+  if (myText->Text().IsEmpty() && myText->TextFormatter().IsNull())
   {
     return;
   }
@@ -685,13 +686,16 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
 
   if (myTextures.IsEmpty())
   {
-    Font_TextFormatter aFormatter;
-
-    aFormatter.SetupAlignment (myText->HorizontalAlignment(), myText->VerticalAlignment());
-    aFormatter.Reset();
+    Handle(Font_TextFormatter) aFormatter = myText->TextFormatter();
+    if (aFormatter.IsNull())
+    {
+      aFormatter = new Font_TextFormatter();
+    }
+    aFormatter->SetupAlignment (myText->HorizontalAlignment(), myText->VerticalAlignment());
+    aFormatter->Reset();
 
-    aFormatter.Append (myText->Text(), *myFont->FTFont());
-    aFormatter.Format();
+    aFormatter->Append (myText->Text(), *myFont->FTFont());
+    aFormatter->Format();
 
     OpenGl_TextBuilder aBuilder;
     aBuilder.Perform (aFormatter,
@@ -701,7 +705,7 @@ void OpenGl_Text::render (const Handle(OpenGl_Context)& theCtx,
                       myVertsVbo,
                       myTCrdsVbo);
 
-    aFormatter.BndBox (myBndBox);
+    aFormatter->BndBox (myBndBox);
     if (!myBndVertsVbo.IsNull())
     {
       myBndVertsVbo->Release (theCtx.get());
index 9505f74..f22c094 100644 (file)
@@ -17,6 +17,7 @@
 #include <OpenGl_VertexBufferCompat.hxx>
 
 #include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
 
 namespace
 {
@@ -44,7 +45,7 @@ OpenGl_TextBuilder::OpenGl_TextBuilder()
 // function : createGlyphs
 // purpose  :
 // =======================================================================
-void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&                                                  theFormatter,
+void OpenGl_TextBuilder::createGlyphs (const Handle(Font_TextFormatter)&                                          theFormatter,
                                        const Handle(OpenGl_Context)&                                              theCtx,
                                        OpenGl_Font&                                                               theFont,
                                        NCollection_Vector<GLuint>&                                                theTextures,
@@ -58,51 +59,16 @@ void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&
   theTCrdsPerTexture.Clear();
 
   OpenGl_Font::Tile aTile = {Font_Rect(), Font_Rect(), 0u};
-  OpenGl_Vec2       aPen (0.0f, 0.0f);
-  Standard_Integer  aRectsNb = 0;
-  Standard_Integer  aSymbolsCounter = 0;
-
-  for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0;)
+  for (Font_TextFormatter::Iterator aFormatterIt (*theFormatter, Font_TextFormatter::IterationFilter_ExcludeInvisible);
+       aFormatterIt.More(); aFormatterIt.Next())
   {
-    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.FTFont()->AdvanceX (' ', aCharNext);
-      continue;
-    }
-    else if (aCharThis == '\t')
-    {
-      const Standard_Integer aSpacesNum = (theFormatter.TabSize() - (aSymbolsCounter - 1) % theFormatter.TabSize());
-      aPen.x() += theFont.FTFont()->AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
-      aSymbolsCounter += aSpacesNum;
-      continue;
-    }
+    theFont.RenderGlyph (theCtx, aFormatterIt.Symbol(), aTile);
 
-    ++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 OpenGl_Vec2& aBottomLeft = theFormatter->BottomLeft (aFormatterIt.SymbolPosition());
+    aTile.px.Right  += aBottomLeft.x();
+    aTile.px.Left   += aBottomLeft.x();
+    aTile.px.Bottom += aBottomLeft.y();
+    aTile.px.Top    += aBottomLeft.y();
     const Font_Rect& aRectUV  = aTile.uv;
     const GLuint     aTexture = aTile.texture;
 
@@ -139,8 +105,6 @@ void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&
     aTCrds.Append (aRectUV.BottomRight (aVec));
     aTCrds.Append (aRectUV.TopRight    (aVec));
     aTCrds.Append (aRectUV.BottomLeft  (aVec));
-
-    ++aRectsNb;
   }
 }
 
@@ -148,7 +112,7 @@ void OpenGl_TextBuilder::createGlyphs (const Font_TextFormatter&
 // function : CreateTextures
 // purpose  :
 // =======================================================================
-void OpenGl_TextBuilder::Perform (const Font_TextFormatter&                        theFormatter,
+void OpenGl_TextBuilder::Perform (const Handle(Font_TextFormatter)&                theFormatter,
                                   const Handle(OpenGl_Context)&                    theCtx,
                                   OpenGl_Font&                                     theFont,
                                   NCollection_Vector<GLuint>&                      theTextures,
index 6ed37b8..2fcd775 100644 (file)
@@ -16,8 +16,6 @@
 #ifndef OpenGl_TextBuilder_Header
 #define OpenGl_TextBuilder_Header
 
-#include <Font_TextFormatter.hxx>
-
 #include <OpenGl_Context.hxx>
 #include <OpenGl_Font.hxx>
 #include <OpenGl_VertexBuffer.hxx>
@@ -27,6 +25,7 @@
 #include <NCollection_Vector.hxx>
 #include <NCollection_Handle.hxx>
 
+class Font_TextFormatter;
 
 //! This class generates primitive array required for rendering textured text using OpenGl_Font instance.
 class OpenGl_TextBuilder
@@ -37,7 +36,7 @@ public:
   Standard_EXPORT OpenGl_TextBuilder();
 
   //! Creates texture quads for the given text.
-  Standard_EXPORT void Perform (const Font_TextFormatter&                        theFormatter,
+  Standard_EXPORT void Perform (const Handle(Font_TextFormatter)&                theFormatter,
                                 const Handle(OpenGl_Context)&                    theContext,
                                 OpenGl_Font&                                     theFont,
                                 NCollection_Vector<GLuint>&                      theTextures,
@@ -46,7 +45,7 @@ public:
 
 protected: //! @name class auxillary methods
 
-  Standard_EXPORT void createGlyphs (const Font_TextFormatter&                                                      theFormatter,
+  Standard_EXPORT void createGlyphs (const Handle(Font_TextFormatter)&                                              theFormatter,
                                      const Handle(OpenGl_Context)&                                                  theCtx,
                                      OpenGl_Font&                                                                   theFont,
                                      NCollection_Vector<GLuint>&                                                    theTextures,
index 78dfb32..35b9d35 100644 (file)
 // function : Draw
 // purpose  :
 // =======================================================================
-void Prs3d_Text::Draw (const Handle(Graphic3d_Group)& theGroup,
-                       const Handle(Prs3d_TextAspect)& theAspect,
-                       const TCollection_ExtendedString& theText,
-                       const gp_Pnt& theAttachmentPoint)
+Handle(Graphic3d_Text) Prs3d_Text::Draw (const Handle(Graphic3d_Group)& theGroup,
+                                         const Handle(Prs3d_TextAspect)& theAspect,
+                                         const TCollection_ExtendedString& theText,
+                                         const gp_Pnt& theAttachmentPoint)
 {
   theGroup->SetPrimitivesAspect (theAspect->Aspect());
 
@@ -42,17 +42,18 @@ void Prs3d_Text::Draw (const Handle(Graphic3d_Group)& theGroup,
   aText->SetHorizontalAlignment (theAspect->HorizontalJustification());
   aText->SetVerticalAlignment (theAspect->VerticalJustification());
   theGroup->AddText (aText);
+  return aText;
 }
 
 // =======================================================================
 // function : Draw
 // purpose  :
 // =======================================================================
-void Prs3d_Text::Draw (const Handle(Graphic3d_Group)&    theGroup,
-                       const Handle(Prs3d_TextAspect)&   theAspect,
-                       const TCollection_ExtendedString& theText,
-                       const gp_Ax2&                     theOrientation,
-                       const Standard_Boolean            theHasOwnAnchor)
+Handle(Graphic3d_Text) Prs3d_Text::Draw (const Handle(Graphic3d_Group)&    theGroup,
+                                         const Handle(Prs3d_TextAspect)&   theAspect,
+                                         const TCollection_ExtendedString& theText,
+                                         const gp_Ax2&                     theOrientation,
+                                         const Standard_Boolean            theHasOwnAnchor)
 {
   theGroup->SetPrimitivesAspect (theAspect->Aspect());
 
@@ -63,4 +64,5 @@ void Prs3d_Text::Draw (const Handle(Graphic3d_Group)&    theGroup,
   aText->SetHorizontalAlignment (theAspect->HorizontalJustification());
   aText->SetVerticalAlignment (theAspect->VerticalJustification());
   theGroup->AddText (aText);
+  return aText;
 }
index 6a26365..c924fec 100644 (file)
@@ -37,10 +37,11 @@ public:
   //! @param theAspect presentation attributes
   //! @param theText   text to draw
   //! @param theAttachmentPoint attachment point
-  Standard_EXPORT static void Draw (const Handle(Graphic3d_Group)& theGroup,
-                                    const Handle(Prs3d_TextAspect)& theAspect,
-                                    const TCollection_ExtendedString& theText,
-                                    const gp_Pnt& theAttachmentPoint);
+  //! @return text to draw
+  Standard_EXPORT static Handle(Graphic3d_Text) Draw (const Handle(Graphic3d_Group)& theGroup,
+                                                      const Handle(Prs3d_TextAspect)& theAspect,
+                                                      const TCollection_ExtendedString& theText,
+                                                      const gp_Pnt& theAttachmentPoint);
 
   //! Draws the text label.
   //! @param theGroup       group to add primitives
@@ -48,11 +49,12 @@ public:
   //! @param theText        text to draw
   //! @param theOrientation location and orientation specified in the model 3D space
   //! @param theHasOwnAnchor 
-  Standard_EXPORT static void Draw (const Handle(Graphic3d_Group)&    theGroup,
-                                    const Handle(Prs3d_TextAspect)&   theAspect,
-                                    const TCollection_ExtendedString& theText,
-                                    const gp_Ax2&                     theOrientation,
-                                    const Standard_Boolean            theHasOwnAnchor = Standard_True);
+  //! @return text to draw
+  Standard_EXPORT static Handle(Graphic3d_Text) Draw (const Handle(Graphic3d_Group)&    theGroup,
+                                                      const Handle(Prs3d_TextAspect)&   theAspect,
+                                                      const TCollection_ExtendedString& theText,
+                                                      const gp_Ax2&                     theOrientation,
+                                                      const Standard_Boolean            theHasOwnAnchor = Standard_True);
 
 public:
 
index 4ba004b..2554414 100644 (file)
 
 #include <StdPrs_BRepTextBuilder.hxx>
 
+#include <Font_TextFormatter.hxx>
+
 // =======================================================================
 // Function : Perfrom
 // Purpose  :
 // =======================================================================
 TopoDS_Shape StdPrs_BRepTextBuilder::Perform (StdPrs_BRepFont&          theFont,
-                                              const Font_TextFormatter& theFormatter,
+                                              const Handle(Font_TextFormatter)& theFormatter,
                                               const gp_Ax3&             thePenLoc)
 {
   gp_Trsf          aTrsf;
@@ -31,34 +33,20 @@ TopoDS_Shape StdPrs_BRepTextBuilder::Perform (StdPrs_BRepFont&          theFont,
 
   myBuilder.MakeCompound (aResult);
 
-  Standard_Integer aSymbolCounter = 0;
-  Standard_Real    aScaleUnits    = theFont.Scale();
-  for (NCollection_Utf8Iter anIter = theFormatter.String().Iterator(); *anIter != 0; ++anIter)
+  Standard_Real aScaleUnits    = theFont.Scale();
+  for (Font_TextFormatter::Iterator aFormatterIt (*theFormatter, Font_TextFormatter::IterationFilter_ExcludeInvisible);
+       aFormatterIt.More(); aFormatterIt.Next())
   {
-    const Standard_Utf32Char aCharCurr = *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)
-     || aCharCurr == ' '
-     || aCharCurr == '\t'
-     || aCharCurr == '\n')
-    {
-      continue; // skip unsupported carriage control codes
-    }
+    const NCollection_Vec2<Standard_ShortReal>& aCorner = theFormatter->BottomLeft (aFormatterIt.SymbolPosition());
 
-    const NCollection_Vec2<Standard_ShortReal>& aCorner = theFormatter.TopLeft (aSymbolCounter);
     aPen.SetCoord (aCorner.x() * aScaleUnits, aCorner.y() * aScaleUnits, 0.0);
-    aGlyphShape = theFont.RenderGlyph (aCharCurr);
+    aGlyphShape = theFont.RenderGlyph (aFormatterIt.Symbol());
     if (!aGlyphShape.IsNull())
     {
       aTrsf.SetTranslation (gp_Vec (aPen));
       aGlyphShape.Move (aTrsf);
       myBuilder.Add (aResult, aGlyphShape);
     }
-
-    ++aSymbolCounter;
   }
 
   aTrsf.SetTransformation (thePenLoc, gp_Ax3 (gp::XOY()));
@@ -77,13 +65,13 @@ TopoDS_Shape StdPrs_BRepTextBuilder::Perform (StdPrs_BRepFont&
                                               const Graphic3d_HorizontalTextAlignment theHAlign,
                                               const Graphic3d_VerticalTextAlignment   theVAlign)
 {
-  Font_TextFormatter aFormatter;
+  Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
 
-  aFormatter.Reset();
-  aFormatter.SetupAlignment (theHAlign, theVAlign);
+  aFormatter->Reset();
+  aFormatter->SetupAlignment (theHAlign, theVAlign);
 
-  aFormatter.Append (theString, *(reinterpret_cast<Font_FTFont*> (&theFont)));
-  aFormatter.Format();
+  aFormatter->Append (theString, *(reinterpret_cast<Font_FTFont*> (&theFont)));
+  aFormatter->Format();
 
   return Perform (theFont, aFormatter, thePenLoc);
 }
index 4e6b60a..5c003a1 100644 (file)
@@ -25,13 +25,12 @@ class StdPrs_BRepTextBuilder
 {
 public:
   //! Render text as BRep shape.
-  //! @param theString text in UTF-8 encoding
+  //! @param theFormatter formatter which defines aligned text
   //! @param thePenLoc start position and orientation on the baseline
-  //! @param theFormatter formatter which defines alignment for the text
   //! @return result shape with pen transformation applied as shape location
-  Standard_EXPORT TopoDS_Shape Perform (StdPrs_BRepFont&          theFont,
-                                        const Font_TextFormatter& theFormatter,
-                                        const gp_Ax3&             thePenLoc = gp_Ax3());
+  Standard_EXPORT TopoDS_Shape Perform (StdPrs_BRepFont&                  theFont,
+                                        const Handle(Font_TextFormatter)& theFormatter,
+                                        const gp_Ax3&                     thePenLoc = gp_Ax3());
   //! Render text as BRep shape.
   //! @param theString text in UTF-8 encoding
   //! @param thePenLoc start position and orientation on the baseline
index b8dec84..2fc6857 100644 (file)
@@ -2390,6 +2390,8 @@ static int VDrawText (Draw_Interpretor& theDI,
   gp_Dir           aDirection;
   gp_Pnt           aPos;
 
+
+  Handle(Font_TextFormatter) aTextFormatter;
   for (; anArgIt < theArgsNb; ++anArgIt)
   {
     TCollection_AsciiString aParam (theArgVec[anArgIt]);
@@ -2517,6 +2519,20 @@ static int VDrawText (Draw_Interpretor& theDI,
 
       aTextPrs->SetHeight (Draw::Atof(theArgVec[anArgIt]));
     }
+    else if (aParam == "-wrapping")
+    {
+      if (++anArgIt >= theArgsNb)
+      {
+        Message::SendFail() << "Syntax error: wrong number of values for parameter '" << aParam << "'";
+        return 1;
+      }
+
+      if (aTextFormatter.IsNull())
+      {
+        aTextFormatter = new Font_TextFormatter();
+      }
+      aTextFormatter->SetWrapping ((Standard_ShortReal)Draw::Atof(theArgVec[anArgIt]));
+    }
     else if (aParam == "-aspect")
     {
       if (++anArgIt >= theArgsNb)
@@ -2662,6 +2678,8 @@ static int VDrawText (Draw_Interpretor& theDI,
     }
   }
 
+  aTextPrs->SetTextFormatter (aTextFormatter);
+
   if (aHasPlane)
   {
     aTextPrs->SetOrientation3D (gp_Ax2 (aPos, aNormal, aDirection));
@@ -6628,6 +6646,7 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
                    "\n\t\t: [-angle angle=0]"
                    "\n\t\t: [-zoom {0|1}=0]"
                    "\n\t\t: [-height height=16]"
+                   "\n\t\t: [-wrapping width=40]"
                    "\n\t\t: [-aspect {regular|bold|italic|boldItalic}=regular]"
                    "\n\t\t: [-font font=Times]"
                    "\n\t\t: [-2d]"
diff --git a/tests/3rdparty/text3d/text_wrapped b/tests/3rdparty/text3d/text_wrapped
new file mode 100644 (file)
index 0000000..3063a2e
--- /dev/null
@@ -0,0 +1,27 @@
+puts "==========="
+puts "0030537: Visualization - wrapping text in font text formatter"
+puts ""
+puts "==========="
+
+pload MODELING VISUALIZATION
+vinit View1
+vclear
+vaxo
+
+box b1 10 0 360 10 180 40
+vdisplay b1
+vdrawtext t1 "Top text on plane yOz\n(not wrapped)" -pos 10 5 400 -color green -plane 1 0 0 0 1 0 -valign top -font SansFont -zoom 1
+
+box b2 10 0 240 10 130 60
+vdisplay b2
+vdrawtext t2 "Top text on plane yOz\n(wrapping=120)" -pos 10 5 300 -color green -wrapping 120 -plane 1 0 0 0 1 0 -valign top -font SansFont -zoom 1
+
+box b3 10 0 60 10 60 150
+vdisplay b3
+vdrawtext t3 "Top text on plane yOz\n(wrapping=50)" -pos 10 5 200 -color green -wrapping 50 -plane 1 0 0 0 1 0 -valign top -font SansFont -zoom 1
+
+vright
+vfit
+vzoom 0.9
+
+vdump $imagedir/${casename}.png