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