#include <Font_BRepTextBuilder.hxx>
+#include <Font_TextFormatter.hxx>
+
// =======================================================================
// Function : Perfrom
// Purpose :
// =======================================================================
TopoDS_Shape Font_BRepTextBuilder::Perform (Font_BRepFont& theFont,
- const Font_TextFormatter& theFormatter,
+ const Handle(Font_TextFormatter)& theFormatter,
const gp_Ax3& thePenLoc)
{
gp_Trsf aTrsf;
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()));
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);
}
#define Font_BRepTextBuilder_Header
#include <Font_BRepFont.hxx>
-#include <Font_TextFormatter.hxx>
#include <gp_Ax3.hxx>
+class Font_TextFormatter;
+
//! Represents class for applying text formatting.
class Font_BRepTextBuilder
{
//! @param theFormatter formatter which defines alignment for the text
//! @return result shape with pen transformation applied as shape location
Standard_EXPORT TopoDS_Shape Perform (Font_BRepFont& theFont,
- const Font_TextFormatter& theFormatter,
+ const Handle(Font_TextFormatter)& theFormatter,
const gp_Ax3& thePenLoc = gp_Ax3());
//! Render text as BRep shape.
//! @param theString text in UTF-8 encoding
const Graphic3d_HorizontalTextAlignment theAlignX,
const Graphic3d_VerticalTextAlignment theAlignY)
{
- Font_TextFormatter aFormatter;
- aFormatter.SetupAlignment (theAlignX, theAlignY);
- aFormatter.Reset();
+ Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
+ aFormatter->SetupAlignment (theAlignX, theAlignY);
+ aFormatter->Reset();
- aFormatter.Append (theString, *this);
- aFormatter.Format();
+ aFormatter->Append (theString, *this);
+ aFormatter->Format();
Font_Rect aBndBox;
- aFormatter.BndBox (aBndBox);
+ aFormatter->BndBox (aBndBox);
return aBndBox;
}
#include <Font_FTFont.hxx>
+#include <Precision.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
+
namespace
{
typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
: 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),
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;
}
// =======================================================================
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;)
+ Handle(Font_TextFormatter) aFormatter (this);
+ Standard_Utf32Char aCharThis;
+ for (Font_TextFormatter::Iterator aFormatterIt (aFormatter); 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)
+ aCharThis = aFormatterIt.Symbol();
+ const Standard_Utf32Char aCharNext = aFormatterIt.SymbolNext();
+
+ Standard_ShortReal anAdvanceX = 0;
+ if (Font_TextFormatter::IsCommandSymbol (aCharThis))
{
continue; // skip unsupported carriage control codes
}
{
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 >= getRectsNb())
{
++myLinesNb;
myPenCurrLine -= myLineSpacing;
return;
}
+ Standard_ShortReal aXMin = BottomLeft (aFirstCornerId).x();
+ Font_Rect aBndBox;
+ BndBox (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;
- 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;
- }
+ case Graphic3d_HTA_LEFT: myMoveVec.x() = -aXMin; break;
+ case Graphic3d_HTA_RIGHT: myMoveVec.x() = -aXMin + (theMaxLineWidth - (aXMax - aXMin)); break;
+ case Graphic3d_HTA_CENTER: myMoveVec.x() = -aXMin + 0.5f * (theMaxLineWidth - (aXMax - aXMin)); break;
}
move (myCorners, myMoveVec, myRectLineStart, theLastRect);
++myLinesNb;
myPenCurrLine -= myLineSpacing;
- myRectLineStart = myRectWordStart = theLastRect + 1;
+ myRectLineStart = theLastRect + 1;
}
// =======================================================================
// =======================================================================
void Font_TextFormatter::Format()
{
- if (myRectsNb == 0 || myIsFormatted)
+ if (getRectsNb() == 0 || myIsFormatted)
{
return;
}
myIsFormatted = true;
- myLinesNb = myRectLineStart = myRectWordStart = 0;
+ myLinesNb = myRectLineStart = 0;
myBndTop = 0.0f;
myBndWidth = 0.0f;
myMoveVec.x() = myMoveVec.y() = 0.0f;
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())
+ {
+ aMaxLineWidth = Max (aMaxLineWidth, MaximumSymbolWidth()); // it is not possible to wrap less than symbol width
+ }
+ else
{
- 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)
+ if (myNewLines.IsEmpty()) // If only one line
+ aMaxLineWidth = myPen.x();
+ else
{
- continue; // skip unsupported carriage control codes
+ for (int aLineIt = 0; aLineIt < myLinesNb; aLineIt++)
+ aMaxLineWidth = Max (aMaxLineWidth, getLineWidth (aLineIt));
}
- 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));
- }
+ }
+
+ Handle(Font_TextFormatter) aFormatter (this);
+ for (Font_TextFormatter::Iterator aFormatterIt (aFormatter);
+ 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;
+ BndBox (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 (getRectsNb() - 1, aMaxLineWidth);
// apply vertical alignment style
if (myAlignY == Graphic3d_VTA_BOTTOM)
if (myAlignY != Graphic3d_VTA_TOP)
{
- moveY (myCorners, myBndTop, 0, myRectsNb - 1);
+ moveY (myCorners, myBndTop, 0, getRectsNb() - 1);
+ }
+}
+
+// =======================================================================
+// function : BndBox
+// purpose :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::BndBox (const Standard_Integer theIndex, Font_Rect& theBndBox) const
+{
+ if (theIndex < 0 || theIndex >= GetCorners().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())
+ {
+ theBndBox.Right = aNextLeftCorner.x();
+ }
+ else
+ {
+ // the next symbol is on the next row either by '\n' or by wrapping
+ Standard_ShortReal aLineWidth = getLineWidth (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 : LastLFBndBox
+// purpose :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::LastLFBndBox (Font_Rect& theBndBox) const
+{
+ if (GetCorners().Length() == 0 || myLastSymbolWidth > 0.0f)
+ return Standard_False;
+
+ const NCollection_Vec2<Standard_ShortReal>& aLastCorner = BottomLeft (GetCorners().Length() -1);
+
+ theBndBox.Top = aLastCorner.y();
+ theBndBox.Bottom = theBndBox.Top - myLineSpacing;
+ switch (myAlignX)
+ {
+ case Graphic3d_HTA_LEFT: theBndBox.Left = theBndBox.Right = 0; break;
+ case Graphic3d_HTA_RIGHT: theBndBox.Left = theBndBox.Right = myBndWidth; break;
+ case Graphic3d_HTA_CENTER: theBndBox.Left = theBndBox.Right = 0.5f * myBndWidth; break;
+ }
+ return Standard_True;
+}
+
+// =======================================================================
+// 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() + myLineSpacing) / myLineSpacing);
+}
+
+// =======================================================================
+// function : IsCommandSymbol
+// purpose :
+// =======================================================================
+Standard_Boolean Font_TextFormatter::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;
+}
+
+// =======================================================================
+// function : getLineWidth
+// purpose :
+// =======================================================================
+Standard_ShortReal Font_TextFormatter::getLineWidth (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 myPen.x() - getLineWidth (theIndex - 1);
+
+ return 0;
}
class Font_FTFont;
+DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
+
//! This class intended to prepare formatted text.
-class Font_TextFormatter
+//! Case of the formatter using:
+//! Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
+//! aFormatter->Append(text_1, aFont1);
+//! aFormatter->Append(text_2, aFont2);
+//! aFormatter->Format();
+//!
+//! Example of corners indices for the text:
+//! "row_1\n" - 0-5
+//! "\n" - 6
+//! "\n" - 7
+//! "row_2\n" - 8-13
+//! Processing of \n symbol:
+//! - it is placed on the row where it appears
+//! - BndBox for \n has zero width
+//! - if the last symbol is \n, use LastBndBox() to get position on the next row
+//!
+//! Pay attention that fonts should have the same LineSpacing value
+//!
+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 light sources.
+ class Iterator
+ {
+ public:
+ //! Constructor with initialization.
+ Iterator (const Handle(Font_TextFormatter)& theFormatter,
+ IterationFilter theFilter = IterationFilter_None)
+ : myFormatter (theFormatter), myFilter (theFilter), myIter (theFormatter->myString.Iterator())
+ {
+ 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.
+ const Standard_Utf32Char& Symbol() const { return mySymbolChar; }
+
+ //! Returns the next symbol if exists.
+ const Standard_Utf32Char& SymbolNext() const { return mySymbolCharNext; }
+
+ //! Returns current symbol position.
+ const Standard_Integer& SymbolPosition() const { return mySymbolPosition; }
+
+ //! Returns the next symbol position.
+ const Standard_Integer& SymbolPositionNext() const { return mySymbolNext; }
+
+ //! Moves to the next item.
+ void Next()
+ {
+ mySymbolPosition = mySymbolNext;
+ mySymbolChar = mySymbolCharNext;
+ mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
+ }
+
+ protected:
+ Standard_Integer readNextSymbol (const Standard_Integer aSymbolStartingFrom, Standard_Utf32Char& theSymbolChar)
+ {
+ Standard_Integer aNextSymbol = aSymbolStartingFrom;
+ 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:
+ Handle(Font_TextFormatter) myFormatter; //!< source class for iterating
+ 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();
Standard_EXPORT void Format();
//! Returns specific glyph rectangle.
- inline const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
+ inline const NCollection_Vec2<Standard_ShortReal>& BottomLeft (const Standard_Integer theIndex) const
{
return myCorners.Value (theIndex);
}
+ //! Returns symbol bounding box
+ //! @param bounding box.
+ Standard_EXPORT Standard_Boolean BndBox (const Standard_Integer theIndex, Font_Rect& theBndBox) const;
+
+ //! Returns true if the last symbol is caret. Creates bounding box of the next row symbol position
+ Standard_EXPORT Standard_Boolean LastLFBndBox (Font_Rect& theBndBox) 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 current rendering string.
- inline const NCollection_String& String() const
- {
- return myString;
- }
+ //! Obsolete method, please use Iterator to get the string characters
+ //inline const NCollection_String& String() const
+ //{
+ // return myString;
+ //}
//! 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
{
return myLineSpacing * Standard_ShortReal(myLinesNb);
}
+ //!< @return maximum width of the text symbol
+ inline Standard_ShortReal MaximumSymbolWidth() const { return myMaxSymbolWidth; }
+
//! @param bounding box.
inline void BndBox (Font_Rect& theBndBox) const
{
case Graphic3d_HTA_RIGHT: theBndBox.Right = -myBndWidth; break;
case Graphic3d_HTA_CENTER:
{
- theBndBox.Left = -0.5f * myBndWidth;
+ theBndBox.Left = -0.5f * myBndWidth;
theBndBox.Right = 0.5f * myBndWidth;
break;
}
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> >& GetCorners() const { return myCorners; }
+
+ const NCollection_Vector<Standard_ShortReal>& GetNewLines() const { return myNewLines; }
+
+ //!< Returns true if the symbol is CR, BEL, FF, NP, BS or VT
+ Standard_EXPORT static Standard_Boolean IsCommandSymbol (const Standard_Utf32Char& theSymbol);
+
+protected:
+ //!< Returns width of a line
+ Standard_ShortReal getLineWidth (const Standard_Integer theIndex) const;
+
+ 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);
+
+ //!< Returns rectangle number
+ Standard_Integer getRectsNb() { return myCorners.Length(); }
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 it is 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
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_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 myBndWidth;
NCollection_Vec2<Standard_ShortReal>
myMoveVec; //!< local variable
+
+ friend Iterator;
};
#endif // Font_TextFormatter_Header
#include <gp_Ax2.hxx>
#include <gp_Pnt.hxx>
+#include <Font_TextFormatter.hxx>
#include <Graphic3d_ArrayOfPoints.hxx>
#include <Graphic3d_ArrayOfPrimitives.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
Update();
}
+// =======================================================================
+// function : Text
+// purpose :
+// =======================================================================
+void Graphic3d_Group::Text (const Handle(Font_TextFormatter)& theTextFormatter,
+ const gp_Ax2& theOrientation,
+ const Standard_Real theHeight,
+ const Standard_Real theAngle,
+ const Graphic3d_TextPath theTp,
+ const Standard_Boolean theToEvalMinMax,
+ const Standard_Boolean theHasOwnAnchor)
+{
+
+ Text ("", //theTextFormatter->String().ToCString(),
+ theOrientation,
+ theHeight,
+ theAngle,
+ theTp,
+ theTextFormatter->HorizontalTextAlignment(),
+ theTextFormatter->VerticalTextAlignment(),
+ theToEvalMinMax,
+ theHasOwnAnchor);
+}
+
// =======================================================================
// function : Text
// purpose :
#include <Graphic3d_TypeOfPrimitiveArray.hxx>
#include <Graphic3d_Vertex.hxx>
#include <Graphic3d_VerticalTextAlignment.hxx>
+
#include <Standard_Transient.hxx>
#include <Standard.hxx>
#include <Standard_Address.hxx>
#include <TCollection_ExtendedString.hxx>
#include <gp_Ax2.hxx>
+class Font_TextFormatter;
class Graphic3d_Structure;
class Graphic3d_ArrayOfPrimitives;
const Standard_Boolean theToEvalMinMax = Standard_True,
const Standard_Boolean theHasOwnAnchor = Standard_True);
+ //! Add text element in 3D space.
+ Standard_EXPORT virtual void Text (const Handle(Font_TextFormatter)& theTextFormatter,
+ const gp_Ax2& theOrientation,
+ const Standard_Real theHeight,
+ const Standard_Real theAngle,
+ const Graphic3d_TextPath theTp,
+ const Standard_Boolean theToEvalMinMax,
+ const Standard_Boolean theHasOwnAnchor = Standard_True);
+
//! Adds an array of primitives for display
Standard_EXPORT virtual void AddPrimitiveArray (const Graphic3d_TypeOfPrimitiveArray theType, const Handle(Graphic3d_IndexBuffer)& theIndices, const Handle(Graphic3d_Buffer)& theAttribs, const Handle(Graphic3d_BoundBuffer)& theBounds, const Standard_Boolean theToEvalMinMax = Standard_True);
#include <OpenGl_Text.hxx>
#include <OpenGl_Workspace.hxx>
+#include <Font_TextFormatter.hxx>
+
#include <Graphic3d_ArrayOfPrimitives.hxx>
#include <Graphic3d_GroupDefinitionError.hxx>
}
+// =======================================================================
+// function : SetFlippingOptions
+// purpose :
+// =======================================================================
+void OpenGl_Group::Text (const Handle(Font_TextFormatter)& theTextFormatter,
+ const gp_Ax2& theOrientation,
+ const Standard_Real theHeight,
+ const Standard_Real theAngle,
+ const Graphic3d_TextPath theTp,
+ const Standard_Boolean theToEvalMinMax,
+ const Standard_Boolean theHasOwnAnchor)
+{
+ if (IsDeleted())
+ {
+ return;
+ }
+
+ OpenGl_TextParam aParams;
+ OpenGl_Structure* aStruct = GlStruct();
+
+ aParams.Height = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
+
+ Handle(OpenGl_Text) aText = new OpenGl_Text ("", theOrientation, aParams, theHasOwnAnchor != Standard_False);
+ aText->SetTextFormatter (theTextFormatter);
+
+ AddElement (aText);
+
+ Graphic3d_Group::Text ("", theOrientation, theHeight, theAngle,
+ theTp, theTextFormatter->HorizontalTextAlignment(), theTextFormatter->VerticalTextAlignment(),
+ theToEvalMinMax, theHasOwnAnchor);
+}
+
// =======================================================================
// function : SetFlippingOptions
// purpose :
#include <OpenGl_CappingPlaneResource.hxx>
#include <OpenGl_Element.hxx>
+class Font_TextFormatter;
+
class OpenGl_Group;
class OpenGl_CappingPlaneResource;
class OpenGl_Structure;
const Standard_Boolean theToEvalMinMax,
const Standard_Boolean theHasOwnAnchor = Standard_True) Standard_OVERRIDE;
+ //! Add text element in 3D space.
+ Standard_EXPORT virtual void Text (const Handle(Font_TextFormatter)& theTextFormatter,
+ const gp_Ax2& theOrientation,
+ const Standard_Real theHeight,
+ const Standard_Real theAngle,
+ const Graphic3d_TextPath theTp,
+ const Standard_Boolean theToEvalMinMax,
+ const Standard_Boolean theHasOwnAnchor = Standard_True) Standard_OVERRIDE;
+
//! Add flipping element
Standard_EXPORT virtual void SetFlippingOptions (const Standard_Boolean theIsEnabled,
const gp_Ax2& theRefPlane) Standard_OVERRIDE;
#include <Font_FontMgr.hxx>
#include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
#include <Graphic3d_TransformUtils.hxx>
#include <TCollection_HAsciiString.hxx>
const OpenGl_Vec4& theColorSubs,
const unsigned int theResolution) const
{
- if (myString.IsEmpty())
+ if (myString.IsEmpty() && myFormatter.IsNull())
{
return;
}
if (myTextures.IsEmpty())
{
- Font_TextFormatter aFormatter;
- aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
- aFormatter.Reset();
+ Handle(Font_TextFormatter) aFormatter = myFormatter;
+ if (myFormatter.IsNull())
+ {
+ aFormatter = new Font_TextFormatter();
+ aFormatter->SetupAlignment (myParams.HAlign, myParams.VAlign);
+ aFormatter->Reset();
- aFormatter.Append (myString, *myFont->FTFont().operator->());
- aFormatter.Format();
+ aFormatter->Append (myString, *myFont->FTFont().operator->());
+ aFormatter->Format();
+ }
OpenGl_TextBuilder aBuilder;
aBuilder.Perform (aFormatter,
myVertsVbo,
myTCrdsVbo);
- aFormatter.BndBox (myBndBox);
+ aFormatter->BndBox (myBndBox);
if (!myBndVertsVbo.IsNull())
{
myBndVertsVbo->Release (theCtx.get());
#include <OpenGl_Element.hxx>
+#include <NCollection_String.hxx>
+
#include <OpenGl_AspectText.hxx>
#include <OpenGl_TextParam.hxx>
#include <OpenGl_TextBuilder.hxx>
#include <gp_Ax2.hxx>
+class Font_TextFormatter;
+
//! Text rendering
class OpenGl_Text : public OpenGl_Element
{
const OpenGl_Vec3& thePoint,
const OpenGl_TextParam& theParams);
+ //! Setup text formatter
+ Standard_EXPORT void SetTextFormatter (const Handle(Font_TextFormatter)& theFormatter) { myFormatter = theFormatter; }
+
//! Setup new position
Standard_EXPORT void SetPosition (const OpenGl_Vec3& thePoint);
bool myHasPlane; //!< Check if text have orientation in 3D space.
bool myHasAnchorPoint; //!< Shows if it has own attach point
+ Handle(Font_TextFormatter) myFormatter; //!< Text formatter, an alternative to text params
+
public:
DEFINE_STANDARD_ALLOC
#include <OpenGl_VertexBufferCompat.hxx>
#include <Font_FTFont.hxx>
+#include <Font_TextFormatter.hxx>
namespace
{
// 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,
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;
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,
+void OpenGl_TextBuilder::Perform (const Handle(Font_TextFormatter)& theFormatter,
const Handle(OpenGl_Context)& theCtx,
OpenGl_Font& theFont,
NCollection_Vector<GLuint>& theTextures,
#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 <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
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,
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,
#include <AIS_Trihedron.hxx>
#include <BRep_Builder.hxx>
#include <Geom_Axis2Placement.hxx>
+#include <Prs3d_PointAspect.hxx>
#include <TopoDS_Compound.hxx>
#include <inspector/TreeModel_ColumnType.hxx>
if (myPreviewPresentation.IsNull())
{
+ Quantity_Color aColor(Quantity_NOC_TOMATO);//Quantity_NOC_GREENYELLOW));//Quantity_NOC_BLUE1));
+
myPreviewPresentation = new AIS_Shape (aCompound);
- myPreviewPresentation->SetColor (Quantity_Color (Quantity_NOC_TOMATO));//Quantity_NOC_GREENYELLOW));//Quantity_NOC_BLUE1));
+ myPreviewPresentation->Attributes()->SetPointAspect (new Prs3d_PointAspect (Aspect_TOM_O_PLUS, aColor, 3.0));
+ myPreviewPresentation->SetColor (aColor);
myPreviewPresentation->SetZLayer (Graphic3d_ZLayerId_Topmost);
myPreviewPresentation->SetTransformPersistence(thePersistent);