0031458: Visualization - refine classes across Prs3d and StdPrs packages
[occt.git] / src / PrsDim / PrsDim_Dimension.cxx
1 // Created on: 2013-11-11
2 // Created by: Anastasia BORISOVA
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <PrsDim_Dimension.hxx>
17
18 #include <PrsDim.hxx>
19 #include <PrsDim_DimensionOwner.hxx>
20 #include <Adaptor3d_HCurve.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepBndLib.hxx>
24 #include <Bnd_Box.hxx>
25 #include <ElCLib.hxx>
26 #include <Font_BRepFont.hxx>
27 #include <Font_BRepTextBuilder.hxx>
28 #include <GC_MakeCircle.hxx>
29 #include <Geom_Line.hxx>
30 #include <GeomAdaptor_Curve.hxx>
31 #include <Geom_TrimmedCurve.hxx>
32 #include <gce_MakeDir.hxx>
33 #include <gce_MakeLin.hxx>
34 #include <gce_MakePln.hxx>
35 #include <Graphic3d_ArrayOfSegments.hxx>
36 #include <Graphic3d_ArrayOfTriangles.hxx>
37 #include <Graphic3d_AspectLine3d.hxx>
38 #include <Graphic3d_AspectFillArea3d.hxx>
39 #include <Graphic3d_AspectText3d.hxx>
40 #include <Graphic3d_Group.hxx>
41 #include <PrsMgr_PresentationManager3d.hxx>
42 #include <Prs3d_Arrow.hxx>
43 #include <Prs3d_ArrowAspect.hxx>
44 #include <Prs3d_Drawer.hxx>
45 #include <Prs3d_LineAspect.hxx>
46 #include <Prs3d_Presentation.hxx>
47 #include <Prs3d_Root.hxx>
48 #include <Prs3d_ShadingAspect.hxx>
49 #include <Prs3d_Text.hxx>
50 #include <SelectMgr_EntityOwner.hxx>
51 #include <SelectMgr_Selection.hxx>
52 #include <SelectMgr_SequenceOfOwner.hxx>
53 #include <Select3D_SensitiveCircle.hxx>
54 #include <Select3D_SensitiveGroup.hxx>
55 #include <Select3D_SensitiveCurve.hxx>
56 #include <Select3D_SensitiveSegment.hxx>
57 #include <Select3D_SensitiveTriangle.hxx>
58 #include <Select3D_SensitiveTriangulation.hxx>
59 #include <Poly_Array1OfTriangle.hxx>
60 #include <Poly_Triangulation.hxx>
61 #include <Standard_CString.hxx>
62 #include <Standard_ProgramError.hxx>
63 #include <StdPrs_ShadedShape.hxx>
64 #include <StdPrs_WFShape.hxx>
65 #include <TCollection_AsciiString.hxx>
66 #include <TCollection_ExtendedString.hxx>
67 #include <TopExp_Explorer.hxx>
68 #include <TopoDS.hxx>
69 #include <TopoDS_Edge.hxx>
70 #include <TopoDS_Vertex.hxx>
71 #include <Units.hxx>
72 #include <Units_UnitsDictionary.hxx>
73 #include <UnitsAPI.hxx>
74 #include <UnitsAPI_SystemUnits.hxx>
75
76 IMPLEMENT_STANDARD_RTTIEXT(PrsDim_Dimension, AIS_InteractiveObject)
77
78 namespace
79 {
80   // default text strings
81   static const TCollection_ExtendedString THE_EMPTY_LABEL;
82   static const TCollection_AsciiString    THE_UNDEFINED_UNITS;
83
84   // default text margin and resolution
85   static const Standard_Real THE_3D_TEXT_MARGIN    = 0.1;
86   static const unsigned int  THE_2D_TEXT_RESOLUTION = 72;
87
88   // default selection priorities
89   static const Standard_Integer THE_NEUTRAL_SEL_PRIORITY = 5;
90   static const Standard_Integer THE_LOCAL_SEL_PRIORITY   = 6;
91 }
92
93 //=======================================================================
94 //function : Constructor
95 //purpose  : 
96 //=======================================================================
97 PrsDim_Dimension::PrsDim_Dimension (const PrsDim_KindOfDimension theType)
98 : AIS_InteractiveObject  (),
99   mySelToleranceForText2d(0.0),
100   myValueType            (ValueType_Computed),
101   myCustomValue          (0.0),
102   myCustomStringValue    (),
103   myIsTextPositionFixed  (Standard_False), 
104   mySpecialSymbol        (' '),
105   myDisplaySpecialSymbol (PrsDim_DisplaySpecialSymbol_No),
106   myGeometryType         (GeometryType_UndefShapes),
107   myIsPlaneCustom        (Standard_False),
108   myFlyout               (0.0),
109   myIsGeometryValid      (Standard_False),
110   myKindOfDimension      (theType)
111 {
112 }
113
114 //=======================================================================
115 //function : SetCustomValue
116 //purpose  : 
117 //=======================================================================
118 void PrsDim_Dimension::SetCustomValue (const Standard_Real theValue)
119 {
120   if (myValueType == ValueType_CustomReal && myCustomValue == theValue)
121   {
122     return;
123   }
124
125   myValueType = ValueType_CustomReal;
126   myCustomValue = theValue;
127
128   SetToUpdate();
129 }
130
131 //=======================================================================
132 //function : SetCustomValue
133 //purpose  : 
134 //=======================================================================
135 void PrsDim_Dimension::SetCustomValue (const TCollection_ExtendedString& theValue)
136 {
137   if (myValueType == ValueType_CustomText && myCustomStringValue == theValue)
138   {
139     return;
140   }
141
142   myValueType = ValueType_CustomText;
143   myCustomStringValue = theValue;
144
145   SetToUpdate();
146 }
147
148 //=======================================================================
149 //function : SetUserPlane
150 //purpose  : 
151 //=======================================================================
152 void PrsDim_Dimension::SetCustomPlane (const gp_Pln& thePlane)
153 {
154   myPlane = thePlane;
155   myIsPlaneCustom = Standard_True;
156
157   // Disable fixed (custom) text position
158   UnsetFixedTextPosition();
159
160   // Check validity if geometry has been set already.
161   if (IsValid())
162   {
163     SetToUpdate();
164   }
165 }
166
167 //=======================================================================
168 //function : SetDimensionAspect
169 //purpose  :
170 //=======================================================================
171 void PrsDim_Dimension::SetDimensionAspect (const Handle(Prs3d_DimensionAspect)& theDimensionAspect)
172 {
173   myDrawer->SetDimensionAspect (theDimensionAspect);
174
175   SetToUpdate();
176 }
177
178 //=======================================================================
179 //function : SetDisplaySpecialSymbol
180 //purpose  :
181 //=======================================================================
182 void PrsDim_Dimension::SetDisplaySpecialSymbol (const PrsDim_DisplaySpecialSymbol theDisplaySpecSymbol)
183 {
184   if (myDisplaySpecialSymbol == theDisplaySpecSymbol)
185   {
186     return;
187   }
188
189   myDisplaySpecialSymbol = theDisplaySpecSymbol;
190
191   SetToUpdate();
192 }
193
194 //=======================================================================
195 //function : SetSpecialSymbol
196 //purpose  :
197 //=======================================================================
198 void PrsDim_Dimension::SetSpecialSymbol (const Standard_ExtCharacter theSpecialSymbol)
199 {
200   if (mySpecialSymbol == theSpecialSymbol)
201   {
202     return;
203   }
204
205   mySpecialSymbol = theSpecialSymbol;
206
207   SetToUpdate();
208 }
209
210 //=======================================================================
211 //function : SetSelToleranceForText2d
212 //purpose  :
213 //=======================================================================
214 void PrsDim_Dimension::SetSelToleranceForText2d (const Standard_Real theTol)
215 {
216   if (mySelToleranceForText2d == theTol)
217   {
218     return;
219   }
220
221   mySelToleranceForText2d = theTol;
222
223   SetToUpdate();
224 }
225
226 //=======================================================================
227 //function : SetFlyout
228 //purpose  :
229 //=======================================================================
230 void PrsDim_Dimension::SetFlyout (const Standard_Real theFlyout)
231 {
232   if (myFlyout == theFlyout)
233   {
234     return;
235   }
236
237   myFlyout = theFlyout;
238
239   // Disable fixed text position
240   UnsetFixedTextPosition();
241
242   SetToUpdate();
243 }
244
245 //=======================================================================
246 //function : GetDisplayUnits
247 //purpose  :
248 //=======================================================================
249 const TCollection_AsciiString& PrsDim_Dimension::GetDisplayUnits() const
250 {
251   return THE_UNDEFINED_UNITS;
252 }
253
254 //=======================================================================
255 //function : GetModelUnits
256 //purpose  :
257 //=======================================================================
258 const TCollection_AsciiString& PrsDim_Dimension::GetModelUnits() const
259 {
260   return THE_UNDEFINED_UNITS;
261 }
262
263 //=======================================================================
264 //function : ValueToDisplayUnits
265 //purpose  :
266 //=======================================================================
267 Standard_Real PrsDim_Dimension::ValueToDisplayUnits() const
268 {
269   return UnitsAPI::AnyToAny (GetValue(),
270                              GetModelUnits().ToCString(),
271                              GetDisplayUnits().ToCString());
272 }
273
274 //=======================================================================
275 //function : GetValueString
276 //purpose  : 
277 //=======================================================================
278 TCollection_ExtendedString PrsDim_Dimension::GetValueString (Standard_Real& theWidth) const
279 {
280   TCollection_ExtendedString aValueStr;
281   if (myValueType == ValueType_CustomText)
282   {
283     aValueStr = myCustomStringValue;
284   }
285   else
286   {
287     // format value string using "sprintf"
288     TCollection_AsciiString aFormatStr = myDrawer->DimensionAspect()->ValueStringFormat();
289
290     char aFmtBuffer[256];
291     sprintf (aFmtBuffer, aFormatStr.ToCString(), ValueToDisplayUnits());
292     aValueStr = TCollection_ExtendedString (aFmtBuffer);
293   }
294
295   // add units to values string
296   if (myDrawer->DimensionAspect()->IsUnitsDisplayed())
297   {
298     aValueStr += " ";
299     aValueStr += TCollection_ExtendedString (GetDisplayUnits());
300   }
301
302   switch (myDisplaySpecialSymbol)
303   {
304     case PrsDim_DisplaySpecialSymbol_Before: aValueStr.Insert (1, mySpecialSymbol); break;
305     case PrsDim_DisplaySpecialSymbol_After:  aValueStr.Insert (aValueStr.Length() + 1, mySpecialSymbol); break;
306     case PrsDim_DisplaySpecialSymbol_No: break;
307   }
308
309   // Get text style parameters
310   Handle(Prs3d_TextAspect) aTextAspect = myDrawer->DimensionAspect()->TextAspect();
311   NCollection_Utf8String anUTFString (aValueStr.ToExtString());
312
313   theWidth = 0.0;
314
315   if (myDrawer->DimensionAspect()->IsText3d())
316   {
317     // text width produced by BRepFont
318     Font_BRepFont aFont;
319     if (aFont.FindAndInit (aTextAspect->Aspect()->Font(), aTextAspect->Aspect()->GetTextFontAspect(), aTextAspect->Height(), Font_StrictLevel_Any))
320     {
321       for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
322       {
323         Standard_Utf32Char aCurrChar = *anIter;
324         Standard_Utf32Char aNextChar = *(++anIter);
325         theWidth += aFont.AdvanceX (aCurrChar, aNextChar);
326       }
327     }
328   }
329   else
330   {
331     // Text width for 1:1 scale 2D case
332     Font_FTFontParams aFontParams;
333     aFontParams.PointSize  = (unsigned int )aTextAspect->Height();
334     aFontParams.Resolution = THE_2D_TEXT_RESOLUTION;
335     if (Handle(Font_FTFont) aFont = Font_FTFont::FindAndCreate (aTextAspect->Aspect()->Font(), aTextAspect->Aspect()->GetTextFontAspect(), aFontParams, Font_StrictLevel_Any))
336     {
337       for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
338       {
339         Standard_Utf32Char aCurrChar = *anIter;
340         Standard_Utf32Char aNextChar = *(++anIter);
341         theWidth += (Standard_Real) aFont->AdvanceX (aCurrChar, aNextChar);
342       }
343     }
344   }
345
346   return aValueStr;
347 }
348
349 //=======================================================================
350 //function : DrawArrow
351 //purpose  : 
352 //=======================================================================
353 void PrsDim_Dimension::DrawArrow (const Handle(Prs3d_Presentation)& thePresentation,
354                                   const gp_Pnt& theLocation,
355                                   const gp_Dir& theDirection)
356 {
357   Handle(Graphic3d_Group) aGroup = Prs3d_Root::NewGroup (thePresentation);
358
359   Standard_Real aLength = myDrawer->DimensionAspect()->ArrowAspect()->Length();
360   Standard_Real anAngle = myDrawer->DimensionAspect()->ArrowAspect()->Angle();
361
362   if (myDrawer->DimensionAspect()->IsArrows3d())
363   {
364     Prs3d_Arrow::Draw (aGroup,
365                        theLocation,
366                        theDirection,
367                        anAngle,
368                        aLength);
369     aGroup->SetGroupPrimitivesAspect (myDrawer->DimensionAspect()->ArrowAspect()->Aspect());
370   }
371   else
372   {
373     gp_Pnt aLeftPoint (gp::Origin());
374     gp_Pnt aRightPoint (gp::Origin());
375     const gp_Dir& aPlane = GetPlane().Axis().Direction();
376
377     PointsForArrow (theLocation, theDirection, aPlane, aLength, anAngle, aLeftPoint, aRightPoint);
378
379     Handle(Graphic3d_ArrayOfTriangles) anArrow = new Graphic3d_ArrayOfTriangles(3);
380
381     anArrow->AddVertex (aLeftPoint);
382     anArrow->AddVertex (theLocation);
383     anArrow->AddVertex (aRightPoint);
384
385     // Set aspect for arrow triangles
386     Graphic3d_PolygonOffset aPolOffset;
387     aPolOffset.Mode = Aspect_POM_Off;
388     aPolOffset.Factor = 0.0f;
389     aPolOffset.Units  = 0.0f;
390     Handle(Graphic3d_AspectFillArea3d) aShadingStyle = new Graphic3d_AspectFillArea3d();
391     aShadingStyle->SetInteriorStyle (Aspect_IS_SOLID);
392     aShadingStyle->SetColor (myDrawer->DimensionAspect()->ArrowAspect()->Aspect()->Color());
393     aShadingStyle->SetShadingModel (Graphic3d_TOSM_UNLIT);
394     aShadingStyle->SetPolygonOffset (aPolOffset);
395
396     aGroup->SetPrimitivesAspect (aShadingStyle);
397     aGroup->AddPrimitiveArray (anArrow);
398   }
399
400   SelectionGeometry::Arrow& aSensitiveArrow = mySelectionGeom.NewArrow();
401   aSensitiveArrow.Position  = theLocation;
402   aSensitiveArrow.Direction = theDirection;
403 }
404
405 //=======================================================================
406 //function : drawText
407 //purpose  :
408 //=======================================================================
409 void PrsDim_Dimension::drawText (const Handle(Prs3d_Presentation)& thePresentation,
410                                  const gp_Pnt& theTextPos,
411                                  const gp_Dir& theTextDir,
412                                  const TCollection_ExtendedString& theText,
413                                  const Standard_Integer theLabelPosition)
414 {
415   Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
416   if (myDrawer->DimensionAspect()->IsText3d())
417   {
418     // getting font parameters
419     Handle(Prs3d_TextAspect) aTextAspect = myDrawer->DimensionAspect()->TextAspect();
420     Quantity_Color  aColor      = aTextAspect->Aspect()->Color();
421     Font_FontAspect aFontAspect = aTextAspect->Aspect()->GetTextFontAspect();
422     Standard_Real   aFontHeight = aTextAspect->Height();
423
424     // creating TopoDS_Shape for text
425     Font_BRepFont aFont (aTextAspect->Aspect()->Font().ToCString(),
426                          aFontAspect, aFontHeight);
427     NCollection_Utf8String anUTFString (theText.ToExtString());
428
429     Font_BRepTextBuilder aBuilder;
430     TopoDS_Shape aTextShape = aBuilder.Perform (aFont, anUTFString);
431
432     // compute text width with kerning
433     Standard_Real aTextWidth  = 0.0;
434     Standard_Real aTextHeight = aFont.Ascender() + aFont.Descender();
435
436     for (NCollection_Utf8Iter anIter = anUTFString.Iterator(); *anIter != 0; )
437     {
438       Standard_Utf32Char aCurrChar = *anIter;
439       Standard_Utf32Char aNextChar = *(++anIter);
440       aTextWidth += aFont.AdvanceX (aCurrChar, aNextChar);
441     }
442
443     // formating text position in XOY plane
444     Standard_Integer aHLabelPos = theLabelPosition & LabelPosition_HMask;
445     Standard_Integer aVLabelPos = theLabelPosition & LabelPosition_VMask;
446
447     gp_Dir aTextDir (aHLabelPos == LabelPosition_Left ? -theTextDir : theTextDir);
448
449     // compute label offsets
450     Standard_Real aMarginSize    = aFontHeight * THE_3D_TEXT_MARGIN;
451     Standard_Real aCenterHOffset = 0.0;
452     Standard_Real aCenterVOffset = 0.0;
453     switch (aHLabelPos)
454     {
455       case LabelPosition_HCenter : aCenterHOffset =  0.0; break;
456       case LabelPosition_Right   : aCenterHOffset =  aTextWidth / 2.0 + aMarginSize; break;
457       case LabelPosition_Left    : aCenterHOffset = -aTextWidth / 2.0 - aMarginSize; break;
458     }
459     switch (aVLabelPos)
460     {
461       case LabelPosition_VCenter : aCenterVOffset =  0.0; break;
462       case LabelPosition_Above   : aCenterVOffset =  aTextHeight / 2.0 + aMarginSize; break;
463       case LabelPosition_Below   : aCenterVOffset = -aTextHeight / 2.0 - aMarginSize; break;
464     }
465
466     // compute shape offset transformation
467     Standard_Real aShapeHOffset = aCenterHOffset - aTextWidth / 2.0;
468     Standard_Real aShapeVOffset = aCenterVOffset - aTextHeight / 2.0;
469
470     // center shape in its bounding box (suppress border spacing added by FT_Font)
471     Bnd_Box aShapeBnd;
472     BRepBndLib::AddClose (aTextShape, aShapeBnd);
473
474     Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
475     aShapeBnd.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
476
477     Standard_Real aXalign = aTextWidth  * 0.5 - (aXmax + aXmin) * 0.5;
478     Standard_Real aYalign = aTextHeight * 0.5 - (aYmax + aYmin) * 0.5;
479     aShapeHOffset += aXalign;
480     aShapeVOffset += aYalign;
481
482     gp_Trsf anOffsetTrsf;
483     anOffsetTrsf.SetTranslation (gp::Origin(), gp_Pnt (aShapeHOffset, aShapeVOffset, 0.0));
484     aTextShape.Move (anOffsetTrsf);
485
486     // transform text to myWorkingPlane coordinate system
487     gp_Ax3 aTextCoordSystem (theTextPos, GetPlane().Axis().Direction(), aTextDir);
488     gp_Trsf aTextPlaneTrsf;
489     aTextPlaneTrsf.SetTransformation (aTextCoordSystem, gp_Ax3 (gp::XOY()));
490     aTextShape.Move (aTextPlaneTrsf);
491
492     // set text flipping anchors
493     gp_Trsf aCenterOffsetTrsf;
494     gp_Pnt aCenterOffset (aCenterHOffset, aCenterVOffset, 0.0);
495     aCenterOffsetTrsf.SetTranslation (gp::Origin(), aCenterOffset);
496
497     gp_Pnt aCenterOfLabel (gp::Origin());
498     aCenterOfLabel.Transform (aCenterOffsetTrsf);
499     aCenterOfLabel.Transform (aTextPlaneTrsf);
500
501     gp_Ax2 aFlippingAxes (aCenterOfLabel, GetPlane().Axis().Direction(), aTextDir);
502     aGroup->SetFlippingOptions (Standard_True, aFlippingAxes);
503
504     // draw text
505     if (myDrawer->DimensionAspect()->IsTextShaded())
506     {
507       // Setting text shading and color parameters
508       if (!myDrawer->HasOwnShadingAspect())
509       {
510         myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
511       }
512
513       Graphic3d_MaterialAspect aShadeMat (Graphic3d_NOM_DEFAULT);
514       aShadeMat.SetAmbientColor (Quantity_NOC_BLACK);
515       aShadeMat.SetDiffuseColor (Quantity_NOC_BLACK);
516       aShadeMat.SetSpecularColor(Quantity_NOC_BLACK);
517       myDrawer->ShadingAspect()->Aspect()->SetInteriorColor (aColor);
518       myDrawer->ShadingAspect()->Aspect()->SetBackInteriorColor (aColor);
519       myDrawer->ShadingAspect()->SetMaterial (aShadeMat);
520
521       // drawing text
522       StdPrs_ShadedShape::Add (thePresentation, aTextShape, myDrawer);
523     }
524     else
525     {
526       // Setting color for text
527       if (!myDrawer->HasOwnFreeBoundaryAspect())
528       {
529         myDrawer->SetFreeBoundaryAspect (new Prs3d_LineAspect (aColor, Aspect_TOL_SOLID, 1.0));
530       }
531       myDrawer->FreeBoundaryAspect()->Aspect()->SetColor (aColor);
532
533       // drawing text
534       if (Handle(Graphic3d_ArrayOfPrimitives) anEdges = StdPrs_WFShape::AddAllEdges (aTextShape, myDrawer))
535       {
536         aGroup->SetGroupPrimitivesAspect (myDrawer->FreeBoundaryAspect()->Aspect());
537         aGroup->AddPrimitiveArray (anEdges);
538       }
539     }
540     Prs3d_Root::CurrentGroup (thePresentation)->SetFlippingOptions (Standard_False, gp_Ax2());
541
542     mySelectionGeom.TextPos    = aCenterOfLabel;
543     mySelectionGeom.TextDir    = aTextDir;
544     mySelectionGeom.TextWidth  = aTextWidth + aMarginSize * 2.0;
545     mySelectionGeom.TextHeight = aTextHeight;
546
547     return;
548   }
549
550   // generate primitives for 2D text
551   myDrawer->DimensionAspect()->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_DIMENSION);
552
553   Prs3d_Text::Draw (aGroup,
554                     myDrawer->DimensionAspect()->TextAspect(),
555                     theText,
556                     theTextPos);
557
558   mySelectionGeom.TextPos    = theTextPos;
559   mySelectionGeom.TextDir    = theTextDir;
560   mySelectionGeom.TextWidth  = 0.0;
561   mySelectionGeom.TextHeight = 0.0;
562 }
563
564 //=======================================================================
565 //function : DrawExtension
566 //purpose  : 
567 //=======================================================================
568 void PrsDim_Dimension::DrawExtension (const Handle(Prs3d_Presentation)& thePresentation,
569                                       const Standard_Real theExtensionSize,
570                                       const gp_Pnt& theExtensionStart,
571                                       const gp_Dir& theExtensionDir,
572                                       const TCollection_ExtendedString& theLabelString,
573                                       const Standard_Real theLabelWidth,
574                                       const Standard_Integer theMode,
575                                       const Standard_Integer theLabelPosition)
576 {
577   // reference line for extension starting at its connection point
578   gp_Lin anExtensionLine (theExtensionStart, theExtensionDir);
579
580   Standard_Boolean hasLabel = theLabelString.Length() > 0;
581   if (hasLabel && (theMode == ComputeMode_All || theMode == ComputeMode_Text))
582   {
583     // compute text primitives; get its model width
584     gp_Pnt aTextPos = ElCLib::Value (theExtensionSize, anExtensionLine);
585     gp_Dir aTextDir = theExtensionDir;
586
587     Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
588     drawText (thePresentation,
589               aTextPos,
590               aTextDir,
591               theLabelString,
592               theLabelPosition);
593   }
594
595   if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
596   {
597     return;
598   }
599
600   Standard_Boolean isShortLine =  !myDrawer->DimensionAspect()->IsText3d()
601                                || theLabelPosition & LabelPosition_VCenter;
602
603   // compute graphical primitives and sensitives for extension line
604   gp_Pnt anExtStart = theExtensionStart;
605   gp_Pnt anExtEnd   = !hasLabel || isShortLine
606     ? ElCLib::Value (theExtensionSize, anExtensionLine)
607     : ElCLib::Value (theExtensionSize + theLabelWidth, anExtensionLine);
608
609   // add graphical primitives
610   Handle(Graphic3d_ArrayOfSegments) anExtPrimitive = new Graphic3d_ArrayOfSegments (2);
611   anExtPrimitive->AddVertex (anExtStart);
612   anExtPrimitive->AddVertex (anExtEnd);
613
614   // add selection primitives
615   SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
616   aSensitiveCurve.Append (anExtStart);
617   aSensitiveCurve.Append (anExtEnd);
618
619   Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
620   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
621   {
622     aGroup->SetStencilTestOptions (Standard_True);
623   }
624   Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
625   aGroup->SetPrimitivesAspect (aDimensionLineStyle);
626   aGroup->AddPrimitiveArray (anExtPrimitive);
627   if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
628   {
629     aGroup->SetStencilTestOptions (Standard_False);
630   }
631 }
632
633 //=======================================================================
634 //function : DrawLinearDimension
635 //purpose  : 
636 //=======================================================================
637 void PrsDim_Dimension::DrawLinearDimension (const Handle(Prs3d_Presentation)& thePresentation,
638                                             const Standard_Integer theMode,
639                                             const gp_Pnt& theFirstPoint,
640                                             const gp_Pnt& theSecondPoint,
641                                             const Standard_Boolean theIsOneSide)
642 {
643   // do not build any dimension for equal points
644   if (theFirstPoint.IsEqual (theSecondPoint, Precision::Confusion()))
645   {
646     throw Standard_ProgramError("Can not build presentation for equal points.");
647   }
648
649   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
650
651   // For extensions we need to know arrow size, text size and extension size: get it from aspect
652   Standard_Real anArrowLength   = aDimensionAspect->ArrowAspect()->Length();
653   Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
654   // prepare label string and compute its geometrical width
655   Standard_Real aLabelWidth;
656   TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
657
658   // add margins to cut dimension lines for 3d text
659   if (aDimensionAspect->IsText3d())
660   {
661     aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
662   }
663
664   // handle user-defined and automatic arrow placement
665   Standard_Boolean isArrowsExternal = Standard_False;
666   Standard_Integer aLabelPosition = LabelPosition_None;
667
668   Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
669   if (IsTextPositionCustom())
670   {
671     if (!AdjustParametersForLinear (myFixedTextPosition, theFirstPoint, theSecondPoint,
672                                     anExtensionSize, aHorisontalTextPos, myFlyout, myPlane, myIsPlaneCustom))
673     {
674       throw Standard_ProgramError("Can not adjust plane to the custom label position.");
675     }
676   }
677
678   FitTextAlignmentForLinear (theFirstPoint, theSecondPoint, theIsOneSide, aHorisontalTextPos,
679                              aLabelPosition, isArrowsExternal);
680
681   // compute dimension line points
682   gp_Pnt aLineBegPoint, aLineEndPoint;
683   ComputeFlyoutLinePoints (theFirstPoint, theSecondPoint, aLineBegPoint, aLineEndPoint);
684   gp_Lin aDimensionLine = gce_MakeLin (aLineBegPoint, aLineEndPoint);
685
686   // compute arrows positions and directions
687   gp_Dir aFirstArrowDir       = aDimensionLine.Direction().Reversed();
688   gp_Dir aSecondArrowDir      = aDimensionLine.Direction();
689   gp_Dir aFirstExtensionDir   = aDimensionLine.Direction().Reversed();
690   gp_Dir aSecondExtensionDir  = aDimensionLine.Direction();
691
692   gp_Pnt aFirstArrowBegin  (0.0, 0.0, 0.0);
693   gp_Pnt aFirstArrowEnd    (0.0, 0.0, 0.0);
694   gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
695   gp_Pnt aSecondArrowEnd   (0.0, 0.0, 0.0);
696
697   if (isArrowsExternal)
698   {
699     aFirstArrowDir.Reverse();
700     aSecondArrowDir.Reverse();
701   }
702
703   aFirstArrowBegin  = aLineBegPoint;
704   aSecondArrowBegin = aLineEndPoint;
705   aFirstArrowEnd    = aLineBegPoint.Translated (-gp_Vec (aFirstArrowDir).Scaled (anArrowLength));
706   aSecondArrowEnd   = aLineEndPoint.Translated (-gp_Vec (aSecondArrowDir).Scaled (anArrowLength));
707
708   gp_Pnt aCenterLineBegin = isArrowsExternal 
709     ? aLineBegPoint : aFirstArrowEnd;
710
711   gp_Pnt aCenterLineEnd = isArrowsExternal || theIsOneSide
712     ? aLineEndPoint : aSecondArrowEnd;
713
714
715   switch (aLabelPosition & LabelPosition_HMask)
716   {
717     // ------------------------------------------------------------------------ //
718     //                                CENTER                                    //
719     // -------------------------------------------------------------------------//
720     case LabelPosition_HCenter:
721     {
722       // add label on dimension or extension line to presentation
723       gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
724                                               : (aCenterLineBegin.XYZ() + aCenterLineEnd.XYZ()) * 0.5;
725       gp_Dir aTextDir = aDimensionLine.Direction();
726
727       // add text primitives
728       if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
729       {
730         thePresentation->NewGroup();
731         drawText (thePresentation,
732                   aTextPos,
733                   aTextDir,
734                   aLabelString,
735                   aLabelPosition);
736       }
737
738       // add dimension line primitives
739       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
740       {
741         Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
742                                     && aDimensionAspect->IsText3d();
743
744         Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (isLineBreak ? 4 : 2);
745
746         // compute continuous or sectioned main line segments
747         if (isLineBreak)
748         {
749           Standard_Real aPTextPosition = ElCLib::Parameter (aDimensionLine, aTextPos);
750           gp_Pnt aSection1Beg = aCenterLineBegin;
751           gp_Pnt aSection1End = ElCLib::Value (aPTextPosition - (aLabelWidth * 0.5), aDimensionLine);
752           gp_Pnt aSection2Beg = ElCLib::Value (aPTextPosition + (aLabelWidth * 0.5), aDimensionLine);
753           gp_Pnt aSection2End = aCenterLineEnd;
754
755           aPrimSegments->AddVertex (aSection1Beg);
756           aPrimSegments->AddVertex (aSection1End);
757           aPrimSegments->AddVertex (aSection2Beg);
758           aPrimSegments->AddVertex (aSection2End);
759
760           SelectionGeometry::Curve& aLeftSensitiveCurve  = mySelectionGeom.NewCurve();
761           SelectionGeometry::Curve& aRightSensitiveCurve = mySelectionGeom.NewCurve();
762           aLeftSensitiveCurve.Append (aSection1Beg);
763           aLeftSensitiveCurve.Append (aSection1End);
764           aRightSensitiveCurve.Append (aSection2Beg);
765           aRightSensitiveCurve.Append (aSection2End);
766         }
767         else
768         {
769           aPrimSegments->AddVertex (aCenterLineBegin);
770           aPrimSegments->AddVertex (aCenterLineEnd);
771
772           SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
773           aSensitiveCurve.Append (aCenterLineBegin);
774           aSensitiveCurve.Append (aCenterLineEnd);
775         }
776
777         // set text label justification
778         Graphic3d_VerticalTextAlignment aTextJustificaton = Graphic3d_VTA_BOTTOM;
779         switch (aLabelPosition & LabelPosition_VMask)
780         {
781           case LabelPosition_Above   :
782           case LabelPosition_VCenter : aTextJustificaton = Graphic3d_VTA_BOTTOM; break;
783           case LabelPosition_Below   : aTextJustificaton = Graphic3d_VTA_TOP;    break;
784         }
785         aDimensionAspect->TextAspect()->SetVerticalJustification (aTextJustificaton);
786
787         // main dimension line, short extension
788         {
789           Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
790           if (!aDimensionAspect->IsText3d() && theMode == ComputeMode_All)
791           {
792             aGroup->SetStencilTestOptions (Standard_True);
793           }
794           aGroup->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
795           aGroup->AddPrimitiveArray (aPrimSegments);
796           if (!aDimensionAspect->IsText3d() && theMode == ComputeMode_All)
797           {
798             aGroup->SetStencilTestOptions (Standard_False);
799           }
800         }
801
802         // add arrows to presentation
803         {
804           Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
805           DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
806           if (!theIsOneSide)
807           {
808             DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
809           }
810         }
811
812         if (!isArrowsExternal)
813         {
814           break;
815         }
816
817         // add arrow extension lines to presentation
818         {
819           DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
820                          aFirstArrowEnd, aFirstExtensionDir,
821                          THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
822           if (!theIsOneSide)
823           {
824             DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
825                            aSecondArrowEnd, aSecondExtensionDir,
826                            THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
827           }
828         }
829       }
830       break;
831     }
832     // ------------------------------------------------------------------------ //
833     //                                LEFT                                      //
834     // -------------------------------------------------------------------------//
835
836     case LabelPosition_Left:
837     {
838       // add label on dimension or extension line to presentation
839       {
840         // Left extension with the text
841         DrawExtension (thePresentation, anExtensionSize,
842                        isArrowsExternal
843                          ? aFirstArrowEnd
844                          : aFirstArrowBegin,
845                        aFirstExtensionDir,
846                        aLabelString,
847                        aLabelWidth,
848                        theMode,
849                        aLabelPosition);
850       }
851
852       // add dimension line primitives
853       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
854       {
855         // add central dimension line
856         {
857           Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
858
859           // add graphical primitives
860           Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (2);
861           aPrimSegments->AddVertex (aCenterLineBegin);
862           aPrimSegments->AddVertex (aCenterLineEnd);
863
864           aGroup->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
865           aGroup->AddPrimitiveArray (aPrimSegments);
866
867           // add selection primitives
868           SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
869           aSensitiveCurve.Append (aCenterLineBegin);
870           aSensitiveCurve.Append (aCenterLineEnd);
871         }
872
873         // add arrows to presentation
874         {
875           Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
876           DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
877           if (!theIsOneSide)
878           {
879             DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
880           }
881         }
882
883         if (!isArrowsExternal || theIsOneSide)
884         {
885           break;
886         }
887
888         // add extension lines for external arrows
889         {
890           DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
891                          aSecondArrowEnd, aSecondExtensionDir,
892                          THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
893         }
894       }
895
896       break;
897     }
898     // ------------------------------------------------------------------------ //
899     //                                RIGHT                                     //
900     // -------------------------------------------------------------------------//
901
902     case LabelPosition_Right:
903     {
904       // add label on dimension or extension line to presentation
905
906       // Right extension with text
907       DrawExtension (thePresentation, anExtensionSize,
908                      isArrowsExternal
909                        ? aSecondArrowEnd
910                        : aSecondArrowBegin,
911                      aSecondExtensionDir,
912                      aLabelString, aLabelWidth,
913                      theMode,
914                      aLabelPosition);
915
916       if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
917       {
918         // add central dimension line
919         {
920           Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
921
922           // add graphical primitives
923           Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (2);
924           aPrimSegments->AddVertex (aCenterLineBegin);
925           aPrimSegments->AddVertex (aCenterLineEnd);
926           aGroup->SetGroupPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
927           aGroup->AddPrimitiveArray (aPrimSegments);
928
929           // add selection primitives
930           SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
931           aSensitiveCurve.Append (aCenterLineBegin);
932           aSensitiveCurve.Append (aCenterLineEnd);
933         }
934
935         // add arrows to presentation
936         {
937           thePresentation->NewGroup();
938           DrawArrow (thePresentation, aSecondArrowBegin, aSecondArrowDir);
939           if (!theIsOneSide)
940           {
941             DrawArrow (thePresentation, aFirstArrowBegin, aFirstArrowDir);
942           }
943         }
944
945         if (!isArrowsExternal || theIsOneSide)
946         {
947           break;
948         }
949
950         // add extension lines for external arrows
951         {
952           DrawExtension (thePresentation, aDimensionAspect->ArrowTailSize(),
953                          aFirstArrowEnd, aFirstExtensionDir,
954                          THE_EMPTY_LABEL, 0.0, theMode, LabelPosition_None);
955         }
956       }
957
958       break;
959     }
960   }
961
962   // add flyout lines to presentation
963   if (theMode == ComputeMode_All)
964   {
965     Handle(Graphic3d_Group) aGroup = thePresentation->NewGroup();
966
967     Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments(4);
968     aPrimSegments->AddVertex (theFirstPoint);
969     aPrimSegments->AddVertex (aLineBegPoint);
970
971     aPrimSegments->AddVertex (theSecondPoint);
972     aPrimSegments->AddVertex (aLineEndPoint);
973
974     aGroup->SetGroupPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
975     aGroup->AddPrimitiveArray (aPrimSegments);
976   }
977
978   mySelectionGeom.IsComputed = Standard_True;
979 }
980
981 //=======================================================================
982 //function : ComputeFlyoutLinePoints
983 //purpose  :
984 //=======================================================================
985 void PrsDim_Dimension::ComputeFlyoutLinePoints (const gp_Pnt& theFirstPoint, const gp_Pnt& theSecondPoint,
986                                                 gp_Pnt& theLineBegPoint, gp_Pnt& theLineEndPoint)
987 {
988   // compute dimension line points
989   gp_Ax1 aPlaneNormal = GetPlane().Axis();
990   // compute flyout direction vector
991   gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
992   gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
993   // create lines for layouts
994   gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
995   gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
996
997   // Get flyout end points
998   theLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
999   theLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
1000 }
1001
1002 //=======================================================================
1003 //function : ComputeLinearFlyouts
1004 //purpose  :
1005 //=======================================================================
1006 void PrsDim_Dimension::ComputeLinearFlyouts (const Handle(SelectMgr_Selection)& theSelection,
1007                                              const Handle(SelectMgr_EntityOwner)& theOwner,
1008                                              const gp_Pnt& theFirstPoint,
1009                                              const gp_Pnt& theSecondPoint)
1010 {
1011   // count flyout direction
1012   gp_Ax1 aPlaneNormal = GetPlane().Axis();
1013   gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
1014
1015   // count a flyout direction vector.
1016   gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
1017
1018   // create lines for layouts
1019   gp_Lin aLine1 (theFirstPoint,  aFlyoutVector);
1020   gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
1021
1022   // get flyout end points
1023   gp_Pnt aFlyoutEnd1 = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint) + GetFlyout(), aLine1);
1024   gp_Pnt aFlyoutEnd2 = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
1025
1026   // fill sensitive entity for flyouts
1027   Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
1028   aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, theFirstPoint, aFlyoutEnd1));
1029   aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, theSecondPoint, aFlyoutEnd2));
1030   theSelection->Add (aSensitiveEntity);
1031 }
1032
1033 //=======================================================================
1034 //function : CircleFromPlanarFace
1035 //purpose  : if possible computes circle from planar face
1036 //=======================================================================
1037 Standard_Boolean PrsDim_Dimension::CircleFromPlanarFace (const TopoDS_Face& theFace,
1038                                                          Handle(Geom_Curve)& theCurve,
1039                                                          gp_Pnt& theFirstPoint,
1040                                                          gp_Pnt& theLastPoint)
1041 {
1042   TopExp_Explorer anIt (theFace, TopAbs_EDGE);
1043   for ( ; anIt.More(); anIt.Next())
1044   {
1045     TopoDS_Edge aCurEdge =  TopoDS::Edge (anIt.Current());
1046     if (PrsDim::ComputeGeometry (aCurEdge, theCurve, theFirstPoint, theLastPoint))
1047     {
1048       if (theCurve->IsInstance (STANDARD_TYPE(Geom_Circle)))
1049       {
1050         return Standard_True;
1051       }
1052     }
1053   }
1054   return Standard_False;
1055 }
1056
1057 //=======================================================================
1058 //function : CircleFromEdge
1059 //purpose  : if possible computes circle from edge
1060 //=======================================================================
1061 Standard_Boolean PrsDim_Dimension::CircleFromEdge (const TopoDS_Edge& theEdge,
1062                                                    gp_Circ&           theCircle,
1063                                                    gp_Pnt&            theFirstPoint,
1064                                                    gp_Pnt&            theLastPoint)
1065 {
1066   BRepAdaptor_Curve anAdaptedCurve (theEdge);
1067   switch (anAdaptedCurve.GetType())
1068   {
1069     case GeomAbs_Circle:
1070     {
1071       theCircle = anAdaptedCurve.Circle();
1072       break;
1073     }
1074     case GeomAbs_Ellipse:
1075     {
1076       gp_Elips anEll = anAdaptedCurve.Ellipse();
1077       if ((anEll.MinorRadius() - anEll.MajorRadius()) >= Precision::Confusion())
1078       {
1079         return Standard_False;
1080       }
1081       theCircle = gp_Circ(anEll.Position(),anEll.MinorRadius());
1082       break;
1083     }
1084     case GeomAbs_Line:
1085     case GeomAbs_Hyperbola:
1086     case GeomAbs_Parabola:
1087     case GeomAbs_BezierCurve:
1088     case GeomAbs_BSplineCurve:
1089     case GeomAbs_OtherCurve:
1090     default:
1091       return Standard_False;
1092   }
1093
1094   theFirstPoint = anAdaptedCurve.Value (anAdaptedCurve.FirstParameter());
1095   theLastPoint  = anAdaptedCurve.Value (anAdaptedCurve.LastParameter());
1096   return Standard_True;
1097 }
1098
1099 //=======================================================================
1100 //function : InitCircularDimension
1101 //purpose  : 
1102 //=======================================================================
1103 Standard_Boolean PrsDim_Dimension::InitCircularDimension (const TopoDS_Shape& theShape,
1104                                                           gp_Circ& theCircle,
1105                                                           gp_Pnt& theMiddleArcPoint,
1106                                                           Standard_Boolean& theIsClosed)
1107 {
1108   gp_Pln aPln;
1109   Handle(Geom_Surface) aBasisSurf;
1110   PrsDim_KindOfSurface aSurfType = PrsDim_KOS_OtherSurface;
1111   gp_Pnt aFirstPoint, aLastPoint;
1112   Standard_Real anOffset    = 0.0;
1113   Standard_Real aFirstParam = 0.0;
1114   Standard_Real aLastParam  = 0.0;
1115
1116   // Discover circular geometry
1117   switch (theShape.ShapeType())
1118   {
1119     case TopAbs_FACE:
1120     {
1121       PrsDim::GetPlaneFromFace (TopoDS::Face (theShape), aPln, aBasisSurf, aSurfType, anOffset);
1122
1123       if (aSurfType == PrsDim_KOS_Plane)
1124       {
1125         Handle(Geom_Curve) aCurve;
1126         if (!CircleFromPlanarFace (TopoDS::Face (theShape), aCurve, aFirstPoint, aLastPoint))
1127         {
1128           return Standard_False;
1129         }
1130
1131         theCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1132       }
1133       else
1134       {
1135         gp_Pnt aCurPos;
1136         BRepAdaptor_Surface aSurf1 (TopoDS::Face (theShape));
1137         Standard_Real aFirstU = aSurf1.FirstUParameter();
1138         Standard_Real aLastU  = aSurf1.LastUParameter();
1139         Standard_Real aFirstV = aSurf1.FirstVParameter();
1140         Standard_Real aLastV  = aSurf1.LastVParameter();
1141         Standard_Real aMidU   = (aFirstU + aLastU) * 0.5;
1142         Standard_Real aMidV   = (aFirstV + aLastV) * 0.5;
1143         aSurf1.D0 (aMidU, aMidV, aCurPos);
1144         Handle (Adaptor3d_HCurve) aBasisCurve;
1145         Standard_Boolean isExpectedType = Standard_False;
1146         if (aSurfType == PrsDim_KOS_Cylinder)
1147         {
1148           isExpectedType = Standard_True;
1149         }
1150         else
1151         {
1152           if (aSurfType == PrsDim_KOS_Revolution)
1153           {
1154             aBasisCurve = aSurf1.BasisCurve();
1155             if (aBasisCurve->GetType() == GeomAbs_Line)
1156             {
1157               isExpectedType = Standard_True;
1158             }
1159           }
1160           else if (aSurfType == PrsDim_KOS_Extrusion)
1161           {
1162             aBasisCurve = aSurf1.BasisCurve();
1163             if (aBasisCurve->GetType() == GeomAbs_Circle)
1164             {
1165               isExpectedType = Standard_True;
1166             }
1167           }
1168         }
1169
1170         if (!isExpectedType)
1171         {
1172           return Standard_False;
1173         }
1174
1175         Handle(Geom_Curve) aCurve = aBasisSurf->VIso(aMidV);
1176         if (aCurve->DynamicType() == STANDARD_TYPE (Geom_Circle))
1177         {
1178           theCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1179         }
1180         else if (aCurve->DynamicType() == STANDARD_TYPE (Geom_TrimmedCurve))
1181         {
1182           Handle(Geom_TrimmedCurve) aTrimmedCurve = Handle(Geom_TrimmedCurve)::DownCast (aCurve);
1183           aFirstU = aTrimmedCurve->FirstParameter();
1184           aLastU  = aTrimmedCurve->LastParameter();
1185           if (aTrimmedCurve->BasisCurve()->DynamicType() == STANDARD_TYPE (Geom_Circle))
1186           {
1187             theCircle = Handle(Geom_Circle)::DownCast(aTrimmedCurve->BasisCurve())->Circ();
1188           }
1189         }
1190         else
1191         {
1192           // Compute a circle from 3 points on "aCurve"
1193           gp_Pnt aP1, aP2;
1194           aSurf1.D0 (aFirstU, aMidV, aP1);
1195           aSurf1.D0 (aLastU, aMidV, aP2);
1196           GC_MakeCircle aMkCirc (aP1, aCurPos, aP2);
1197           theCircle = aMkCirc.Value()->Circ();
1198         }
1199
1200         aFirstPoint = ElCLib::Value (aFirstU, theCircle);
1201         aLastPoint = ElCLib::Value (aLastU,  theCircle);
1202       }
1203       break;
1204     }
1205     case TopAbs_WIRE:
1206     {
1207       TopoDS_Edge anEdge;
1208       TopExp_Explorer anIt (theShape, TopAbs_EDGE);
1209       if (anIt.More())
1210       {
1211         anEdge = TopoDS::Edge (anIt.Current());
1212       }
1213       if (!PrsDim_Dimension::CircleFromEdge (anEdge, theCircle, aFirstPoint, aLastPoint))
1214       {
1215         return Standard_False;
1216       }
1217       break;
1218     }
1219     case TopAbs_EDGE:
1220     {
1221       TopoDS_Edge anEdge = TopoDS::Edge (theShape);
1222       if (!PrsDim_Dimension::CircleFromEdge (anEdge, theCircle, aFirstPoint, aLastPoint))
1223       {
1224         return Standard_False;
1225       }
1226       break;
1227     }
1228     case TopAbs_COMPOUND:
1229     case TopAbs_COMPSOLID:
1230     case TopAbs_SOLID:
1231     case TopAbs_SHELL:
1232     case TopAbs_VERTEX:
1233     case TopAbs_SHAPE:
1234     default:
1235       return Standard_False;
1236   }
1237
1238   theIsClosed = aFirstPoint.IsEqual (aLastPoint, Precision::Confusion());
1239
1240   gp_Pnt aCenter = theCircle.Location();
1241
1242   if (theIsClosed) // Circle
1243   {
1244     gp_Dir anXDir = theCircle.XAxis().Direction();
1245     theMiddleArcPoint = aCenter.Translated (gp_Vec (anXDir) * theCircle.Radius());
1246   }
1247   else // Arc
1248   {
1249     aFirstParam = ElCLib::Parameter (theCircle, aFirstPoint);
1250     aLastParam  = ElCLib::Parameter (theCircle, aLastPoint);
1251     if (aFirstParam > aLastParam)
1252     {
1253       aFirstParam -= 2.0 * M_PI;
1254     }
1255
1256     Standard_Real aParCurPos = (aFirstParam + aLastParam) * 0.5;
1257     gp_Vec aVec = gp_Vec (aCenter, ElCLib::Value (aParCurPos, theCircle)).Normalized () * theCircle.Radius ();
1258     theMiddleArcPoint = aCenter.Translated (aVec);
1259   }
1260
1261   return Standard_True;
1262 }
1263
1264 //=======================================================================
1265 //function : ComputeSelection
1266 //purpose  : 
1267 //=======================================================================
1268 void PrsDim_Dimension::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
1269                                          const Standard_Integer theMode)
1270 {
1271   if (!mySelectionGeom.IsComputed)
1272   {
1273     return;
1274   }
1275
1276   PrsDim_DimensionSelectionMode aSelectionMode = (PrsDim_DimensionSelectionMode)theMode;
1277
1278   // init appropriate entity owner
1279   Handle(SelectMgr_EntityOwner) aSensitiveOwner;
1280
1281   switch (aSelectionMode)
1282   {
1283     // neutral selection owner
1284     case PrsDim_DimensionSelectionMode_All:
1285       aSensitiveOwner = new SelectMgr_EntityOwner (this, THE_NEUTRAL_SEL_PRIORITY);
1286       break;
1287
1288     // local selection owners
1289     case PrsDim_DimensionSelectionMode_Line:
1290     case PrsDim_DimensionSelectionMode_Text:
1291       aSensitiveOwner = new PrsDim_DimensionOwner (this, aSelectionMode, THE_LOCAL_SEL_PRIORITY);
1292       break;
1293   }
1294
1295   if (aSelectionMode == PrsDim_DimensionSelectionMode_All || aSelectionMode == PrsDim_DimensionSelectionMode_Line)
1296   {
1297     // sensitives for dimension line segments
1298     Handle(Select3D_SensitiveGroup) aGroupOfSensitives = new Select3D_SensitiveGroup (aSensitiveOwner);
1299
1300     SelectionGeometry::SeqOfCurves::Iterator aCurveIt (mySelectionGeom.DimensionLine);
1301     for (; aCurveIt.More(); aCurveIt.Next())
1302     {
1303       const SelectionGeometry::HCurve& aCurveData = aCurveIt.Value();
1304
1305       TColgp_Array1OfPnt aSensitivePnts (1, aCurveData->Length());
1306       for (Standard_Integer aPntIt = 1; aPntIt <= aCurveData->Length(); ++aPntIt)
1307       {
1308         aSensitivePnts.ChangeValue (aPntIt) = aCurveData->Value (aPntIt);
1309       }
1310
1311       aGroupOfSensitives->Add (new Select3D_SensitiveCurve (aSensitiveOwner, aSensitivePnts));
1312     }
1313
1314     Standard_Real anArrowLength = myDrawer->DimensionAspect()->ArrowAspect()->Length();
1315     Standard_Real anArrowAngle  = myDrawer->DimensionAspect()->ArrowAspect()->Angle();
1316
1317     // sensitives for arrows
1318     SelectionGeometry::SeqOfArrows::Iterator anArrowIt (mySelectionGeom.Arrows);
1319     for (; anArrowIt.More(); anArrowIt.Next())
1320     {
1321       const SelectionGeometry::HArrow& anArrow = anArrowIt.Value();
1322
1323       gp_Pnt aSidePnt1 (gp::Origin());
1324       gp_Pnt aSidePnt2 (gp::Origin());
1325       const gp_Dir& aPlane = GetPlane().Axis().Direction();
1326       const gp_Pnt& aPeak  = anArrow->Position;
1327       const gp_Dir& aDir   = anArrow->Direction;
1328
1329       // compute points for arrow in plane
1330       PointsForArrow (aPeak, aDir, aPlane, anArrowLength, anArrowAngle, aSidePnt1, aSidePnt2);
1331
1332       aGroupOfSensitives->Add (new Select3D_SensitiveTriangle (aSensitiveOwner, aPeak, aSidePnt1, aSidePnt2));
1333
1334       if (!myDrawer->DimensionAspect()->IsArrows3d())
1335       {
1336         continue;
1337       }
1338
1339       // compute points for orthogonal sensitive plane
1340       gp_Dir anOrthoPlane = anArrow->Direction.Crossed (aPlane);
1341
1342       PointsForArrow (aPeak, aDir, anOrthoPlane, anArrowLength, anArrowAngle, aSidePnt1, aSidePnt2);
1343
1344       aGroupOfSensitives->Add (new Select3D_SensitiveTriangle (aSensitiveOwner, aPeak, aSidePnt1, aSidePnt2));
1345     }
1346
1347     theSelection->Add (aGroupOfSensitives);
1348   }
1349
1350   // sensitives for text element
1351   if (aSelectionMode == PrsDim_DimensionSelectionMode_All || aSelectionMode == PrsDim_DimensionSelectionMode_Text)
1352   {
1353     Handle(Select3D_SensitiveEntity) aTextSensitive;
1354
1355     gp_Ax2 aTextAxes (mySelectionGeom.TextPos,
1356                       GetPlane().Axis().Direction(),
1357                       mySelectionGeom.TextDir);
1358
1359     if (myDrawer->DimensionAspect()->IsText3d())
1360     {
1361       // sensitive planar rectangle for text
1362       Standard_Real aDx = mySelectionGeom.TextWidth  * 0.5;
1363       Standard_Real aDy = mySelectionGeom.TextHeight * 0.5;
1364
1365       gp_Trsf aLabelPlane;
1366       aLabelPlane.SetTransformation (aTextAxes, gp::XOY());
1367
1368       TColgp_Array1OfPnt aRectanglePoints(1, 4);
1369       aRectanglePoints.ChangeValue(1) = gp_Pnt (-aDx, -aDy, 0.0).Transformed (aLabelPlane);
1370       aRectanglePoints.ChangeValue(2) = gp_Pnt (-aDx,  aDy, 0.0).Transformed (aLabelPlane);
1371       aRectanglePoints.ChangeValue(3) = gp_Pnt ( aDx,  aDy, 0.0).Transformed (aLabelPlane);
1372       aRectanglePoints.ChangeValue(4) = gp_Pnt ( aDx, -aDy, 0.0).Transformed (aLabelPlane);
1373
1374       Poly_Array1OfTriangle aTriangles(1, 2);
1375       aTriangles.ChangeValue(1) = Poly_Triangle(1, 2, 3);
1376       aTriangles.ChangeValue(2) = Poly_Triangle(1, 3, 4);
1377
1378       Handle(Poly_Triangulation) aRectanglePoly = 
1379         new Poly_Triangulation(aRectanglePoints, aTriangles);
1380
1381       aTextSensitive =
1382         new Select3D_SensitiveTriangulation (aSensitiveOwner, aRectanglePoly, TopLoc_Location(), Standard_True);
1383     }
1384     else
1385     {
1386       gp_Circ aTextGeom (aTextAxes, mySelToleranceForText2d != 0.0 
1387                                       ? mySelToleranceForText2d : 1.0);
1388       aTextSensitive = new Select3D_SensitiveCircle (aSensitiveOwner, aTextGeom, Standard_True);
1389     }
1390
1391     theSelection->Add (aTextSensitive);
1392   }
1393
1394   // callback for flyout sensitive calculation
1395   if (aSelectionMode == PrsDim_DimensionSelectionMode_All)
1396   {
1397     ComputeFlyoutSelection (theSelection, aSensitiveOwner);
1398   }
1399 }
1400
1401 //=======================================================================
1402 //function : PointsForArrow
1403 //purpose  : 
1404 //=======================================================================
1405 void PrsDim_Dimension::PointsForArrow (const gp_Pnt& thePeakPnt,
1406                                        const gp_Dir& theDirection,
1407                                        const gp_Dir& thePlane,
1408                                        const Standard_Real theArrowLength,
1409                                        const Standard_Real theArrowAngle,
1410                                        gp_Pnt& theSidePnt1,
1411                                        gp_Pnt& theSidePnt2)
1412 {
1413   gp_Lin anArrowLin (thePeakPnt, theDirection.Reversed());
1414   gp_Pnt anArrowEnd = ElCLib::Value (theArrowLength, anArrowLin);
1415   gp_Lin anEdgeLin (anArrowEnd, theDirection.Crossed (thePlane));
1416
1417   Standard_Real anEdgeLength = Tan (theArrowAngle) * theArrowLength;
1418
1419   theSidePnt1 = ElCLib::Value ( anEdgeLength, anEdgeLin);
1420   theSidePnt2 = ElCLib::Value (-anEdgeLength, anEdgeLin);
1421 }
1422
1423 //=======================================================================
1424 //function : GetTextPositionForLinear
1425 //purpose  : 
1426 //=======================================================================
1427 gp_Pnt PrsDim_Dimension::GetTextPositionForLinear (const gp_Pnt& theFirstPoint,
1428                                                    const gp_Pnt& theSecondPoint,
1429                                                    const Standard_Boolean theIsOneSide) const
1430 {
1431   if (!IsValid())
1432   {
1433     return gp::Origin();
1434   }
1435
1436   gp_Pnt aTextPosition (gp::Origin());
1437
1438   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1439
1440   // Get label alignment and arrow orientation.
1441   Standard_Integer aLabelPosition = 0;
1442   Standard_Boolean isArrowsExternal = Standard_False;
1443   FitTextAlignmentForLinear (theFirstPoint, theSecondPoint, theIsOneSide,
1444                              aDimensionAspect->TextHorizontalPosition(),
1445                              aLabelPosition, isArrowsExternal);
1446
1447   // Compute dimension line points.
1448   gp_Dir aPlaneNormal = GetPlane().Axis().Direction();
1449   gp_Vec aTargetPointsVec (theFirstPoint, theSecondPoint);
1450
1451   // Compute flyout direction vector
1452   gp_Dir aFlyoutVector = aPlaneNormal ^ gp_Dir (aTargetPointsVec);
1453
1454   // create lines for layouts
1455   gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
1456   gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
1457   // Get flyout end points
1458   gp_Pnt aLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
1459   gp_Pnt aLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
1460
1461   // Get text position.
1462   switch (aLabelPosition & LabelPosition_HMask)
1463   {
1464   case LabelPosition_Left:
1465     {
1466       gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
1467       Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1468
1469       Standard_Real anOffset = isArrowsExternal
1470                                  ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1471                                  : anExtensionSize;
1472       gp_Vec anExtensionVec = gp_Vec (aTargetPointsDir) * -anOffset;
1473       aTextPosition = aLineEndPoint.Translated (anExtensionVec);
1474     }
1475     break;
1476   case LabelPosition_Right:
1477     {
1478       gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
1479       Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1480
1481       Standard_Real anOffset = isArrowsExternal
1482                                  ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1483                                  : anExtensionSize;
1484       gp_Vec anExtensionVec = gp_Vec (aTargetPointsDir) * anOffset;
1485       aTextPosition = aLineBegPoint.Translated (anExtensionVec);
1486     }
1487     break;
1488   case LabelPosition_HCenter:
1489     {
1490       aTextPosition = (aLineBegPoint.XYZ() + aLineEndPoint.XYZ()) * 0.5;
1491     }
1492     break;
1493   }
1494
1495   return aTextPosition;
1496 }
1497
1498 //=======================================================================
1499 //function : AdjustParametersForLinear
1500 //purpose  : 
1501 //=======================================================================
1502 Standard_Boolean PrsDim_Dimension::AdjustParametersForLinear (const gp_Pnt& theTextPos,
1503                                                               const gp_Pnt& theFirstPoint,
1504                                                               const gp_Pnt& theSecondPoint,
1505                                                               Standard_Real& theExtensionSize,
1506                                                               Prs3d_DimensionTextHorizontalPosition& theAlignment,
1507                                                               Standard_Real& theFlyout,
1508                                                               gp_Pln& thePlane,
1509                                                               Standard_Boolean& theIsPlaneOld) const
1510 {
1511   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1512   Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1513
1514   gp_Dir aTargetPointsDir = gce_MakeDir (theFirstPoint, theSecondPoint);
1515   gp_Vec aTargetPointsVec (theFirstPoint, theSecondPoint);
1516
1517   // Don't set new plane if the text position lies on the attachment points line.
1518   gp_Lin aTargetPointsLin (theFirstPoint, aTargetPointsDir);
1519   if (!aTargetPointsLin.Contains (theTextPos, Precision::Confusion()))
1520   {
1521     //Set new automatic plane.
1522     thePlane = gce_MakePln (theTextPos, theFirstPoint, theSecondPoint);
1523     theIsPlaneOld = Standard_False;
1524   }
1525
1526   // Compute flyout direction vector.
1527   gp_Dir aPlaneNormal = GetPlane().Axis().Direction();
1528   gp_Dir aPositiveFlyout = aPlaneNormal ^ aTargetPointsDir;
1529
1530   // Additional check of collinearity of the plane normal and attachment points vector.
1531   if (aPlaneNormal.IsParallel (aTargetPointsDir, Precision::Angular()))
1532   {
1533     return Standard_False;
1534   }
1535
1536   // Set flyout.
1537   gp_Vec aFirstToTextVec (theFirstPoint, theTextPos);
1538
1539   Standard_Real aCos = aFirstToTextVec.Normalized() * gp_Vec (aTargetPointsDir);
1540
1541   gp_Pnt aTextPosProj = theFirstPoint.Translated
1542     (gp_Vec (aTargetPointsDir) * aFirstToTextVec.Magnitude() * aCos);
1543
1544   // Compute flyout value and direction.
1545   gp_Vec aFlyoutVector = gp_Vec (aTextPosProj, theTextPos);
1546
1547   theFlyout = 0.0;
1548   if (aFlyoutVector.Magnitude() > Precision::Confusion())
1549   {
1550     theFlyout = gp_Dir (aFlyoutVector).IsOpposite (aPositiveFlyout, Precision::Angular())
1551                 ? -aFlyoutVector.Magnitude()
1552                 :  aFlyoutVector.Magnitude();
1553   }
1554   
1555   // Compute attach points (through which main dimension line passes).
1556   gp_Pnt aFirstAttach  = theFirstPoint.Translated (aFlyoutVector);
1557   gp_Pnt aSecondAttach = theSecondPoint.Translated (aFlyoutVector);
1558
1559   // Set horizontal text alignment.
1560   if (aCos < 0.0)
1561   {
1562     theAlignment = Prs3d_DTHP_Left;
1563
1564     Standard_Real aNewExtSize = theTextPos.Distance (aFirstAttach) - anArrowLength;
1565     theExtensionSize = aNewExtSize < 0.0 ? 0.0 : aNewExtSize;
1566   }
1567   else if (aTextPosProj.Distance (theFirstPoint) > theFirstPoint.Distance (theSecondPoint))
1568   {
1569     theAlignment = Prs3d_DTHP_Right;
1570
1571     Standard_Real aNewExtSize = theTextPos.Distance (aSecondAttach) - anArrowLength;
1572     theExtensionSize = aNewExtSize < 0.0 ? 0.0 : aNewExtSize;
1573   }
1574   else
1575   {
1576     theAlignment = Prs3d_DTHP_Center;
1577   }
1578   return Standard_True;
1579 }
1580
1581 //=======================================================================
1582 //function : FitTextAlignmentForLinear
1583 //purpose  : 
1584 //=======================================================================
1585 void PrsDim_Dimension::FitTextAlignmentForLinear (const gp_Pnt& theFirstPoint,
1586                                                   const gp_Pnt& theSecondPoint,
1587                                                   const Standard_Boolean theIsOneSide,
1588                                                   const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1589                                                   Standard_Integer& theLabelPosition,
1590                                                   Standard_Boolean& theIsArrowsExternal) const
1591 {
1592   theLabelPosition = LabelPosition_None;
1593   theIsArrowsExternal = Standard_False;
1594
1595   // Compute dimension line points
1596   gp_Ax1 aPlaneNormal = GetPlane().Axis();
1597   gp_Dir aTargetPointsVector = gce_MakeDir (theFirstPoint, theSecondPoint);
1598
1599   // compute flyout direction vector
1600   gp_Dir aFlyoutVector = aPlaneNormal.Direction() ^ aTargetPointsVector;
1601
1602   // create lines for layouts
1603   gp_Lin aLine1 (theFirstPoint, aFlyoutVector);
1604   gp_Lin aLine2 (theSecondPoint, aFlyoutVector);
1605
1606   // Get flyout end points
1607   gp_Pnt aLineBegPoint = ElCLib::Value (ElCLib::Parameter (aLine1, theFirstPoint)  + GetFlyout(), aLine1);
1608   gp_Pnt aLineEndPoint = ElCLib::Value (ElCLib::Parameter (aLine2, theSecondPoint) + GetFlyout(), aLine2);
1609
1610   Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1611
1612   // For extensions we need to know arrow size, text size and extension size: get it from aspect
1613   Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1614
1615   // prepare label string and compute its geometrical width
1616   Standard_Real aLabelWidth;
1617   TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1618
1619   // Add margins to cut dimension lines for 3d text
1620   if (aDimensionAspect->IsText3d())
1621   {
1622     aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1623   }
1624
1625   // Handle user-defined and automatic arrow placement
1626   switch (aDimensionAspect->ArrowOrientation())
1627   {
1628     case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1629     case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1630     case Prs3d_DAO_Fit:
1631     {
1632       // Add margin to ensure a small tail between text and arrow
1633       Standard_Real anArrowMargin   = aDimensionAspect->IsText3d() 
1634                                     ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1635                                     : 0.0;
1636
1637       Standard_Real aDimensionWidth = aLineBegPoint.Distance (aLineEndPoint);
1638       Standard_Real anArrowsWidth   = theIsOneSide 
1639                                       ?  anArrowLength + anArrowMargin
1640                                       : (anArrowLength + anArrowMargin) * 2.0;
1641
1642       theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1643       break;
1644     }
1645   }
1646
1647   // Handle user-defined and automatic text placement
1648   switch (theHorizontalTextPos)
1649   {
1650     case Prs3d_DTHP_Left  : theLabelPosition |= LabelPosition_Left; break;
1651     case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1652     case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1653     case Prs3d_DTHP_Fit:
1654     {
1655       Standard_Real aDimensionWidth = aLineBegPoint.Distance (aLineEndPoint);
1656       Standard_Real anArrowsWidth   = theIsOneSide ? anArrowLength : 2.0 * anArrowLength;
1657       Standard_Real aContentWidth   = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1658
1659       theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1660       break;
1661     }
1662   }
1663
1664   // Handle vertical text placement options
1665   switch (aDimensionAspect->TextVerticalPosition())
1666   {
1667     case Prs3d_DTVP_Above  : theLabelPosition |= LabelPosition_Above; break;
1668     case Prs3d_DTVP_Below  : theLabelPosition |= LabelPosition_Below; break;
1669     case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
1670   }
1671 }
1672
1673 //=======================================================================
1674 //function : UnsetFixedTextPosition
1675 //purpose  : 
1676 //=======================================================================
1677 void PrsDim_Dimension::UnsetFixedTextPosition()
1678 {
1679   myIsTextPositionFixed = Standard_False;
1680   myFixedTextPosition = gp::Origin();
1681 }