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