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