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