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