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