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