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