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