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