From: san Date: Thu, 24 Sep 2015 15:47:34 +0000 (+0300) Subject: 0026507: Visualization - Improved presentations of dimensions X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=435e8993508afcaac05c8d9094529b663b27c054;p=occt-copy.git 0026507: Visualization - Improved presentations of dimensions --- diff --git a/src/AIS/AIS_AngleDimension.cxx b/src/AIS/AIS_AngleDimension.cxx index 2767e03107..6b81661445 100644 --- a/src/AIS/AIS_AngleDimension.cxx +++ b/src/AIS/AIS_AngleDimension.cxx @@ -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()) diff --git a/src/AIS/AIS_DiameterDimension.cxx b/src/AIS/AIS_DiameterDimension.cxx index 244f46e62c..66abc06ff4 100644 --- a/src/AIS/AIS_DiameterDimension.cxx +++ b/src/AIS/AIS_DiameterDimension.cxx @@ -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); } //======================================================================= diff --git a/src/AIS/AIS_DiameterDimension.hxx b/src/AIS/AIS_DiameterDimension.hxx index de17879e61..8b12a1dc1f 100644 --- a/src/AIS/AIS_DiameterDimension.hxx +++ b/src/AIS/AIS_DiameterDimension.hxx @@ -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 diff --git a/src/AIS/AIS_Dimension.cxx b/src/AIS/AIS_Dimension.cxx index a09e1a1da2..de8af43683 100755 --- a/src/AIS/AIS_Dimension.cxx +++ b/src/AIS/AIS_Dimension.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -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 (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(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; } } diff --git a/src/AIS/AIS_Dimension.hxx b/src/AIS/AIS_Dimension.hxx index 6992339ff9..3b8c32e1e1 100755 --- a/src/AIS/AIS_Dimension.hxx +++ b/src/AIS/AIS_Dimension.hxx @@ -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: diff --git a/src/AIS/AIS_RadiusDimension.cxx b/src/AIS/AIS_RadiusDimension.cxx index 265201117f..0319b56961 100644 --- a/src/AIS/AIS_RadiusDimension.cxx +++ b/src/AIS/AIS_RadiusDimension.cxx @@ -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); } //======================================================================= diff --git a/src/AIS/AIS_RadiusDimension.hxx b/src/AIS/AIS_RadiusDimension.hxx index 991c4a28aa..e9b896193d 100644 --- a/src/AIS/AIS_RadiusDimension.hxx +++ b/src/AIS/AIS_RadiusDimension.hxx @@ -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: diff --git a/src/Font/FILES b/src/Font/FILES index ad2c3280a2..2aa2c0b149 100644 --- a/src/Font/FILES +++ b/src/Font/FILES @@ -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 diff --git a/src/Font/Font_BRepFont.cxx b/src/Font/Font_BRepFont.cxx index 4d20aaa2dd..636bd29540 100755 --- a/src/Font/Font_BRepFont.cxx +++ b/src/Font/Font_BRepFont.cxx @@ -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 (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 (aCurrWidth)); + aCurrWidth = 0; + ++aLine; + continue; + } + + aCurrWidth += AdvanceX (aCharCurr, aCharNext); + } + + aBox.Right = Max (aBox.Right, static_cast (aCurrWidth)); + aBox.Bottom = aBox.Top - static_cast (LineSpacing() * Standard_Real (aLine + 1)); + + return aBox; +} diff --git a/src/Font/Font_BRepFont.hxx b/src/Font/Font_BRepFont.hxx index 71bd0a2af0..df13223c8c 100755 --- a/src/Font/Font_BRepFont.hxx +++ b/src/Font/Font_BRepFont.hxx @@ -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. diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx index 684a831185..b0f422ccbe 100755 --- a/src/Font/Font_FTFont.cxx +++ b/src/Font/Font_FTFont.cxx @@ -15,6 +15,8 @@ #include #include +#include + #include #include @@ -257,3 +259,25 @@ float Font_FTFont::AdvanceY (const Standard_Utf32Char theUCharNext) } return fromFTPoints (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; +} diff --git a/src/Font/Font_FTFont.hxx b/src/Font/Font_FTFont.hxx index f4ba85ca8a..5c425494c6 100755 --- a/src/Font/Font_FTFont.hxx +++ b/src/Font/Font_FTFont.hxx @@ -16,11 +16,13 @@ #ifndef _Font_FTFont_H__ #define _Font_FTFont_H__ -#include -#include +#include #include +#include +#include #include -#include +#include +#include //! 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 TopLeft() const + { + return NCollection_Vec2 (Left, Top); + } + NCollection_Vec2& TopLeft (NCollection_Vec2& 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 index 0000000000..61b15446a6 --- /dev/null +++ b/src/Font/Font_TextFormatter.cxx @@ -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 + +namespace +{ + typedef NCollection_Vec2 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& 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 index 0000000000..2ce2b23a3c --- /dev/null +++ b/src/Font/Font_TextFormatter.hxx @@ -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 +#include +#include + +//! 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& 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 + myPen; //!< current pen position + NCollection_Vector < NCollection_Vec2 > + myCorners; //!< The top left corners of a formatted rectangles. + Standard_Integer myRectsNb; //!< rectangles number + NCollection_Vector + 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 + myMoveVec; //!< local variable + +public: + + DEFINE_STANDARD_RTTI(Font_TextFormatter) // Type definition + +}; + +DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient) + +#endif // Font_TextFormatter_Header diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 37d3e63a1f..de9014dd12 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -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 diff --git a/src/OpenGl/OpenGl_Font.cxx b/src/OpenGl/OpenGl_Font.cxx index 1a17c604ab..114bb0d156 100755 --- a/src/OpenGl/OpenGl_Font.cxx +++ b/src/OpenGl/OpenGl_Font.cxx @@ -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; } diff --git a/src/OpenGl/OpenGl_Font.hxx b/src/OpenGl/OpenGl_Font.hxx index fd95912d1d..7e8f7149bd 100755 --- a/src/OpenGl/OpenGl_Font.hxx +++ b/src/OpenGl/OpenGl_Font.hxx @@ -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: diff --git a/src/OpenGl/OpenGl_Text.cxx b/src/OpenGl/OpenGl_Text.cxx index a67ea82ed6..6acc096456 100644 --- a/src/OpenGl/OpenGl_Text.cxx +++ b/src/OpenGl/OpenGl_Text.cxx @@ -464,8 +464,7 @@ void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx, anObjZ); OpenGl_Utils::Translate (aModViewMat, anObjX, anObjY, anObjZ); - OpenGl_Utils::Rotate (aModViewMat, theTextAspect.Angle(), 0.0, 0.0, 1.0); - + OpenGl_Utils::Rotate (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); } diff --git a/src/OpenGl/OpenGl_Text.hxx b/src/OpenGl/OpenGl_Text.hxx index 68d8514a51..71200ee30a 100755 --- a/src/OpenGl/OpenGl_Text.hxx +++ b/src/OpenGl/OpenGl_Text.hxx @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/src/OpenGl/OpenGl_TextBuilder.cxx b/src/OpenGl/OpenGl_TextBuilder.cxx new file mode 100644 index 0000000000..c814e24108 --- /dev/null +++ b/src/OpenGl/OpenGl_TextBuilder.cxx @@ -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 +#include + +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& theTextures, + NCollection_Vector > >& theVertsPerTexture, + NCollection_Vector > >& 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()); + theTCrdsPerTexture.Append (new NCollection_Vector()); + } + + NCollection_Vector& aVerts = *theVertsPerTexture.ChangeValue (aListId); + NCollection_Vector& 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& theTextures, + NCollection_Vector& theVertsPerTexture, + NCollection_Vector& theTCrdsPerTexture) +{ + NCollection_Vector< NCollection_Handle > > aVertsPerTexture; + NCollection_Vector< NCollection_Handle > > 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& 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& 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 index 0000000000..016e518267 --- /dev/null +++ b/src/OpenGl/OpenGl_TextBuilder.hxx @@ -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 + +#include +#include +#include +#include +#include + +#include +#include + + +//! 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& theTextures, + NCollection_Vector& theVertsPerTexture, + NCollection_Vector& theTCrdsPerTexture); + +protected: //! @name class auxillary methods + + Standard_EXPORT void createGlyphs (const Font_TextFormatter& theFormatter, + const Handle(OpenGl_Context)& theCtx, + OpenGl_Font& theFont, + NCollection_Vector& theTextures, + NCollection_Vector< NCollection_Handle < NCollection_Vector > >& theVertsPerTexture, + NCollection_Vector< NCollection_Handle < NCollection_Vector > >& theTCrdsPerTexture); + +protected: //! @name class auxillary fields + + NCollection_Vector myTileRects; + OpenGl_VertexBufferEditor myVboEditor; +}; + +#endif // OpenGl_TextBuilder_Header diff --git a/src/Prs3d/Prs3d.cdl b/src/Prs3d/Prs3d.cdl index da879ef8e3..2ebe681816 100644 --- a/src/Prs3d/Prs3d.cdl +++ b/src/Prs3d/Prs3d.cdl @@ -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; diff --git a/src/ViewerTest/ViewerTest_RelationCommands.cxx b/src/ViewerTest/ViewerTest_RelationCommands.cxx index d15dafe84f..7a8bdff5f3 100644 --- a/src/ViewerTest/ViewerTest_RelationCommands.cxx +++ b/src/ViewerTest/ViewerTest_RelationCommands.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -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& theRealParams, NCollection_DataMap& theStringParams, + NCollection_DataMap& theBooleanParams, + Standard_Boolean& theIsTextAligned, gp_Dir& theTextDir, NCollection_List* 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& theRealParams, - const NCollection_DataMap& theStringParams) + const NCollection_DataMap& theStringParams, + const NCollection_DataMap& 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 aRealParams; NCollection_DataMap aStringParams; + NCollection_DataMap 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 aRealParams; NCollection_DataMap aStringParams; + NCollection_DataMap 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 index 0000000000..8162e91e73 --- /dev/null +++ b/tests/bugs/vis/bug26507_1 @@ -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 index 0000000000..d3e464b1b1 --- /dev/null +++ b/tests/bugs/vis/bug26507_2 @@ -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 index 0000000000..82cde88192 --- /dev/null +++ b/tests/bugs/vis/bug26507_3 @@ -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 index 0000000000..1a82836c47 --- /dev/null +++ b/tests/bugs/vis/bug26507_4 @@ -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 index 0000000000..ab823f3408 --- /dev/null +++ b/tests/bugs/vis/bug26507_5 @@ -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