Redirection of generation reference documentation from source files
[occt.git] / src / AIS / AIS_AngleDimension.cxx
... / ...
CommitLineData
1// Created on: 1996-12-05
2// Created by: Arnaud BOUZY/Odile Olivier
3// Copyright (c) 1996-1999 Matra Datavision
4// Copyright (c) 1999-2014 OPEN CASCADE SAS
5//
6// This file is part of Open CASCADE Technology software library.
7//
8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
13//
14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
16
17#include <AIS_AngleDimension.hxx>
18
19#include <AIS.hxx>
20#include <BRepBuilderAPI_MakeFace.hxx>
21#include <BRepAdaptor_Curve.hxx>
22#include <BRepAdaptor_Surface.hxx>
23#include <BRepLib_MakeVertex.hxx>
24#include <BRep_Tool.hxx>
25#include <ElCLib.hxx>
26#include <GCPnts_UniformAbscissa.hxx>
27#include <GC_MakeArcOfCircle.hxx>
28#include <gce_MakeLin2d.hxx>
29#include <gce_MakeLin.hxx>
30#include <gce_MakeCirc.hxx>
31#include <gce_MakeCone.hxx>
32#include <gce_MakePln.hxx>
33#include <gce_MakeDir.hxx>
34#include <Geom_Circle.hxx>
35#include <Geom_TrimmedCurve.hxx>
36#include <Geom_ConicalSurface.hxx>
37#include <Geom_SurfaceOfRevolution.hxx>
38#include <Geom_OffsetSurface.hxx>
39#include <Graphic3d_ArrayOfSegments.hxx>
40#include <Graphic3d_Group.hxx>
41#include <Graphic3d_ArrayOfPolylines.hxx>
42#include <IntAna2d_AnaIntersection.hxx>
43#include <ProjLib.hxx>
44#include <Prs3d_Root.hxx>
45#include <Prs3d_ShadingAspect.hxx>
46#include <PrsMgr_PresentationManager3d.hxx>
47#include <Select3D_SensitiveGroup.hxx>
48#include <Select3D_SensitiveSegment.hxx>
49#include <SelectMgr_Selection.hxx>
50#include <Standard_ProgramError.hxx>
51#include <UnitsAPI.hxx>
52#include <Geom_Line.hxx>
53#include <Geom_Plane.hxx>
54
55
56namespace
57{
58 static const TCollection_ExtendedString THE_EMPTY_LABEL_STRING;
59 static const Standard_Real THE_EMPTY_LABEL_WIDTH = 0.0;
60 static const Standard_ExtCharacter THE_DEGREE_SYMBOL (0x00B0);
61 static const Standard_Real THE_3D_TEXT_MARGIN = 0.1;
62};
63
64//=======================================================================
65//function : Constructor
66//purpose :
67//=======================================================================
68AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Edge& theFirstEdge,
69 const TopoDS_Edge& theSecondEdge)
70: AIS_Dimension (AIS_KOD_PLANEANGLE)
71{
72 Init();
73 SetMeasuredGeometry (theFirstEdge, theSecondEdge);
74}
75
76//=======================================================================
77//function : Constructor
78//purpose :
79//=======================================================================
80AIS_AngleDimension::AIS_AngleDimension (const gp_Pnt& theFirstPoint,
81 const gp_Pnt& theSecondPoint,
82 const gp_Pnt& theThirdPoint)
83: AIS_Dimension (AIS_KOD_PLANEANGLE)
84{
85 Init();
86 SetMeasuredGeometry (theFirstPoint, theSecondPoint, theThirdPoint);
87}
88
89//=======================================================================
90//function : Constructor
91//purpose :
92//=======================================================================
93AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Vertex& theFirstVertex,
94 const TopoDS_Vertex& theSecondVertex,
95 const TopoDS_Vertex& theThirdVertex)
96: AIS_Dimension (AIS_KOD_PLANEANGLE)
97{
98 Init();
99 SetMeasuredGeometry (theFirstVertex, theSecondVertex, theThirdVertex);
100}
101
102//=======================================================================
103//function : Constructor
104//purpose :
105//=======================================================================
106AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theCone)
107: AIS_Dimension (AIS_KOD_PLANEANGLE)
108{
109 Init();
110 SetMeasuredGeometry (theCone);
111}
112
113//=======================================================================
114//function : Constructor
115//purpose :
116//=======================================================================
117AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
118 const TopoDS_Face& theSecondFace)
119: AIS_Dimension (AIS_KOD_PLANEANGLE)
120{
121 Init();
122 SetMeasuredGeometry (theFirstFace, theSecondFace);
123}
124
125//=======================================================================
126//function : Constructor
127//purpose :
128//=======================================================================
129AIS_AngleDimension::AIS_AngleDimension (const TopoDS_Face& theFirstFace,
130 const TopoDS_Face& theSecondFace,
131 const gp_Pnt& thePoint)
132: AIS_Dimension (AIS_KOD_PLANEANGLE)
133{
134 Init();
135 SetMeasuredGeometry (theFirstFace, theSecondFace, thePoint);
136}
137
138//=======================================================================
139//function : SetMeasuredGeometry
140//purpose :
141//=======================================================================
142void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Edge& theFirstEdge,
143 const TopoDS_Edge& theSecondEdge)
144{
145 gp_Pln aComputedPlane;
146
147 myFirstShape = theFirstEdge;
148 mySecondShape = theSecondEdge;
149 myThirdShape = TopoDS_Shape();
150 myGeometryType = GeometryType_Edges;
151 myIsGeometryValid = InitTwoEdgesAngle (aComputedPlane);
152
153 if (myIsGeometryValid && !myIsPlaneCustom)
154 {
155 ComputePlane();
156 }
157
158 SetToUpdate();
159}
160
161//=======================================================================
162//function : SetMeasuredGeometry
163//purpose :
164//=======================================================================
165void AIS_AngleDimension::SetMeasuredGeometry (const gp_Pnt& theFirstPoint,
166 const gp_Pnt& theSecondPoint,
167 const gp_Pnt& theThirdPoint)
168{
169 myFirstPoint = theFirstPoint;
170 myCenterPoint = theSecondPoint;
171 mySecondPoint = theThirdPoint;
172 myFirstShape = BRepLib_MakeVertex (myFirstPoint);
173 mySecondShape = BRepLib_MakeVertex (myCenterPoint);
174 myThirdShape = BRepLib_MakeVertex (mySecondPoint);
175 myGeometryType = GeometryType_Points;
176 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
177
178 if (myIsGeometryValid && !myIsPlaneCustom)
179 {
180 ComputePlane();
181 }
182
183 SetToUpdate();
184}
185
186//=======================================================================
187//function : SetMeasuredGeometry
188//purpose :
189//=======================================================================
190void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Vertex& theFirstVertex,
191 const TopoDS_Vertex& theSecondVertex,
192 const TopoDS_Vertex& theThirdVertex)
193{
194 myFirstShape = theFirstVertex;
195 mySecondShape = theSecondVertex;
196 myThirdShape = theThirdVertex;
197 myFirstPoint = BRep_Tool::Pnt (theFirstVertex);
198 myCenterPoint = BRep_Tool::Pnt (theSecondVertex);
199 mySecondPoint = BRep_Tool::Pnt (theThirdVertex);
200 myGeometryType = GeometryType_Points;
201 myIsGeometryValid = IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
202
203 if (myIsGeometryValid && !myIsPlaneCustom)
204 {
205 ComputePlane();
206 }
207
208 SetToUpdate();
209}
210
211//=======================================================================
212//function : SetMeasuredGeometry
213//purpose :
214//=======================================================================
215void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theCone)
216{
217 myFirstShape = theCone;
218 mySecondShape = TopoDS_Shape();
219 myThirdShape = TopoDS_Shape();
220 myGeometryType = GeometryType_Face;
221 myIsGeometryValid = InitConeAngle();
222
223 if (myIsGeometryValid && !myIsPlaneCustom)
224 {
225 ComputePlane();
226 }
227
228 SetToUpdate();
229}
230
231//=======================================================================
232//function : SetMeasuredGeometry
233//purpose :
234//=======================================================================
235void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
236 const TopoDS_Face& theSecondFace)
237{
238 myFirstShape = theFirstFace;
239 mySecondShape = theSecondFace;
240 myThirdShape = TopoDS_Shape();
241 myGeometryType = GeometryType_Faces;
242 myIsGeometryValid = InitTwoFacesAngle();
243
244 if (myIsGeometryValid && !myIsPlaneCustom)
245 {
246 ComputePlane();
247 }
248
249 SetToUpdate();
250}
251
252//=======================================================================
253//function : SetMeasuredGeometry
254//purpose :
255//=======================================================================
256void AIS_AngleDimension::SetMeasuredGeometry (const TopoDS_Face& theFirstFace,
257 const TopoDS_Face& theSecondFace,
258 const gp_Pnt& thePoint)
259{
260 myFirstShape = theFirstFace;
261 mySecondShape = theSecondFace;
262 myThirdShape = TopoDS_Shape();
263 myGeometryType = GeometryType_Faces;
264 myIsGeometryValid = InitTwoFacesAngle (thePoint);
265
266 if (myIsGeometryValid && !myIsPlaneCustom)
267 {
268 ComputePlane();
269 }
270
271 SetToUpdate();
272}
273
274//=======================================================================
275//function : Init
276//purpose :
277//=======================================================================
278void AIS_AngleDimension::Init()
279{
280 SetSpecialSymbol (THE_DEGREE_SYMBOL);
281 SetDisplaySpecialSymbol (AIS_DSS_After);
282 SetFlyout (15.0);
283}
284
285//=======================================================================
286//function: GetCenterOnArc
287//purpose :
288//=======================================================================
289gp_Pnt AIS_AngleDimension::GetCenterOnArc (const gp_Pnt& theFirstAttach,
290 const gp_Pnt& theSecondAttach,
291 const gp_Pnt& theCenter) const
292{
293 // construct plane where the circle and the arc are located
294 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
295 if (!aConstructPlane.IsDone())
296 {
297 return gp::Origin();
298 }
299
300 gp_Pln aPlane = aConstructPlane.Value();
301
302 Standard_Real aRadius = theFirstAttach.Distance (theCenter);
303
304 // construct circle forming the arc
305 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
306 if (!aConstructCircle.IsDone())
307 {
308 return gp::Origin();
309 }
310
311 gp_Circ aCircle = aConstructCircle.Value();
312
313 // compute angle parameters of arc end-points on circle
314 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
315 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
316 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
317
318 return ElCLib::Value ((aParamBeg + aParamEnd) * 0.5, aCircle);
319}
320
321//=======================================================================
322//function : DrawArc
323//purpose : draws the arc between two attach points
324//=======================================================================
325void AIS_AngleDimension::DrawArc (const Handle(Prs3d_Presentation)& thePresentation,
326 const gp_Pnt& theFirstAttach,
327 const gp_Pnt& theSecondAttach,
328 const gp_Pnt& theCenter,
329 const Standard_Real theRadius,
330 const Standard_Integer theMode)
331{
332 // construct plane where the circle and the arc are located
333 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
334 if (!aConstructPlane.IsDone())
335 {
336 return;
337 }
338
339 gp_Pln aPlane = aConstructPlane.Value();
340
341 // construct circle forming the arc
342 gce_MakeCirc aConstructCircle (theCenter, aPlane, theRadius);
343 if (!aConstructCircle.IsDone())
344 {
345 return;
346 }
347
348 gp_Circ aCircle = aConstructCircle.Value();
349
350 // construct the arc
351 GC_MakeArcOfCircle aConstructArc (aCircle, theFirstAttach, theSecondAttach, Standard_True);
352 if (!aConstructArc.IsDone())
353 {
354 return;
355 }
356
357 // generate points with specified deflection
358 const Handle(Geom_TrimmedCurve)& anArcCurve = aConstructArc.Value();
359
360 GeomAdaptor_Curve anArcAdaptor (anArcCurve, anArcCurve->FirstParameter(), anArcCurve->LastParameter());
361
362 // compute number of discretization elements in old-fanshioned way
363 gp_Vec aCenterToFirstVec (theCenter, theFirstAttach);
364 gp_Vec aCenterToSecondVec (theCenter, theSecondAttach);
365 const Standard_Real anAngle = aCenterToFirstVec.Angle (aCenterToSecondVec);
366 const Standard_Integer aNbPoints = Max (4, Standard_Integer (50.0 * anAngle / M_PI));
367
368 GCPnts_UniformAbscissa aMakePnts (anArcAdaptor, aNbPoints);
369 if (!aMakePnts.IsDone())
370 {
371 return;
372 }
373
374 // init data arrays for graphical and selection primitives
375 Handle(Graphic3d_ArrayOfPolylines) aPrimSegments = new Graphic3d_ArrayOfPolylines (aNbPoints);
376
377 SelectionGeometry::Curve& aSensitiveCurve = mySelectionGeom.NewCurve();
378
379 // load data into arrays
380 for (Standard_Integer aPntIt = 1; aPntIt <= aMakePnts.NbPoints(); ++aPntIt)
381 {
382 gp_Pnt aPnt = anArcAdaptor.Value (aMakePnts.Parameter (aPntIt));
383
384 aPrimSegments->AddVertex (aPnt);
385
386 aSensitiveCurve.Append (aPnt);
387 }
388
389 // add display presentation
390 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
391 {
392 Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_True);
393 }
394 Handle(Graphic3d_AspectLine3d) aDimensionLineStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
395 Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aDimensionLineStyle);
396 Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
397 if (!myDrawer->DimensionAspect()->IsText3d() && theMode == ComputeMode_All)
398 {
399 Prs3d_Root::CurrentGroup (thePresentation)->SetStencilTestOptions (Standard_False);
400 }
401}
402
403//=======================================================================
404//function: DrawArcWithText
405//purpose :
406//=======================================================================
407void AIS_AngleDimension::DrawArcWithText (const Handle(Prs3d_Presentation)& thePresentation,
408 const gp_Pnt& theFirstAttach,
409 const gp_Pnt& theSecondAttach,
410 const gp_Pnt& theCenter,
411 const TCollection_ExtendedString& theText,
412 const Standard_Real theTextWidth,
413 const Standard_Integer theMode,
414 const Standard_Integer theLabelPosition)
415{
416 // construct plane where the circle and the arc are located
417 gce_MakePln aConstructPlane (theFirstAttach, theSecondAttach, theCenter);
418 if (!aConstructPlane.IsDone())
419 {
420 return;
421 }
422
423 gp_Pln aPlane = aConstructPlane.Value();
424
425 Standard_Real aRadius = theFirstAttach.Distance (myCenterPoint);
426
427 // construct circle forming the arc
428 gce_MakeCirc aConstructCircle (theCenter, aPlane, aRadius);
429 if (!aConstructCircle.IsDone())
430 {
431 return;
432 }
433
434 gp_Circ aCircle = aConstructCircle.Value();
435
436 // compute angle parameters of arc end-points on circle
437 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, theFirstAttach);
438 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, theSecondAttach);
439 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
440
441 // middle point of arc parameter on circle
442 Standard_Real aParamMid = (aParamBeg + aParamEnd) * 0.5;
443
444 // add text graphical primitives
445 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
446 {
447 gp_Pnt aTextPos = ElCLib::Value (aParamMid, aCircle);
448 gp_Dir aTextDir = gce_MakeDir (theFirstAttach, theSecondAttach);
449
450 // Drawing text
451 DrawText (thePresentation,
452 aTextPos,
453 aTextDir,
454 theText,
455 theLabelPosition);
456 }
457
458 if (theMode != ComputeMode_All && theMode != ComputeMode_Line)
459 {
460 return;
461 }
462
463 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
464
465 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
466 && aDimensionAspect->IsText3d();
467
468 if (isLineBreak)
469 {
470 // compute gap for label as parameteric size of sector on circle segment
471 Standard_Real aSectorOnCircle = theTextWidth / aRadius;
472
473 gp_Pnt aTextPntBeg = ElCLib::Value (aParamMid - aSectorOnCircle * 0.5, aCircle);
474 gp_Pnt aTextPntEnd = ElCLib::Value (aParamMid + aSectorOnCircle * 0.5, aCircle);
475
476 // Drawing arcs
477 DrawArc (thePresentation, theFirstAttach, aTextPntBeg, theCenter, aRadius, theMode);
478 DrawArc (thePresentation, theSecondAttach, aTextPntEnd, theCenter, aRadius, theMode);
479 }
480 else
481 {
482 DrawArc (thePresentation, theFirstAttach, theSecondAttach, theCenter, aRadius, theMode);
483 }
484}
485
486//=======================================================================
487//function : CheckPlane
488//purpose :
489//=======================================================================
490Standard_Boolean AIS_AngleDimension::CheckPlane (const gp_Pln& thePlane)const
491{
492 if (!thePlane.Contains (myFirstPoint, Precision::Confusion()) &&
493 !thePlane.Contains (mySecondPoint, Precision::Confusion()) &&
494 !thePlane.Contains (myCenterPoint, Precision::Confusion()))
495 {
496 return Standard_False;
497 }
498
499 return Standard_True;
500}
501
502//=======================================================================
503//function : ComputePlane
504//purpose :
505//=======================================================================
506void AIS_AngleDimension::ComputePlane()
507{
508 if (!myIsGeometryValid)
509 {
510 return;
511 }
512
513 gp_Vec aFirstVec = gp_Vec (myCenterPoint, myFirstPoint).Normalized();
514 gp_Vec aSecondVec = gp_Vec (myCenterPoint, mySecondPoint).Normalized();
515 gp_Vec aDirectionN = aSecondVec.Crossed (aFirstVec).Normalized();
516 gp_Vec aDirectionY = (aFirstVec + aSecondVec).Normalized();
517 gp_Vec aDirectionX = aDirectionY.Crossed (aDirectionN).Normalized();
518
519 myPlane = gp_Pln (gp_Ax3 (myCenterPoint, gp_Dir (aDirectionN), gp_Dir (aDirectionX)));
520}
521
522//=======================================================================
523//function : GetModelUnits
524//purpose :
525//=======================================================================
526const TCollection_AsciiString& AIS_AngleDimension::GetModelUnits() const
527{
528 return myDrawer->DimAngleModelUnits();
529}
530
531//=======================================================================
532//function : GetDisplayUnits
533//purpose :
534//=======================================================================
535const TCollection_AsciiString& AIS_AngleDimension::GetDisplayUnits() const
536{
537 return myDrawer->DimAngleDisplayUnits();
538}
539
540//=======================================================================
541//function : SetModelUnits
542//purpose :
543//=======================================================================
544void AIS_AngleDimension::SetModelUnits (const TCollection_AsciiString& theUnits)
545{
546 myDrawer->SetDimAngleModelUnits (theUnits);
547}
548
549//=======================================================================
550//function : SetDisplayUnits
551//purpose :
552//=======================================================================
553void AIS_AngleDimension::SetDisplayUnits (const TCollection_AsciiString& theUnits)
554{
555 myDrawer->SetDimAngleDisplayUnits (theUnits);
556}
557
558//=======================================================================
559//function : ComputeValue
560//purpose :
561//=======================================================================
562Standard_Real AIS_AngleDimension::ComputeValue() const
563{
564 if (!IsValid())
565 {
566 return 0.0;
567 }
568
569 gp_Vec aVec1 (myCenterPoint, myFirstPoint);
570 gp_Vec aVec2 (myCenterPoint, mySecondPoint);
571
572 Standard_Real anAngle = aVec2.AngleWithRef (aVec1, GetPlane().Axis().Direction());
573
574 return anAngle > 0.0 ? anAngle : (2.0 * M_PI + anAngle);
575}
576
577//=======================================================================
578//function : Compute
579//purpose : Having three gp_Pnt points compute presentation
580//=======================================================================
581void AIS_AngleDimension::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePM*/,
582 const Handle(Prs3d_Presentation)& thePresentation,
583 const Standard_Integer theMode)
584{
585 thePresentation->Clear();
586 mySelectionGeom.Clear (theMode);
587
588 if (!IsValid())
589 {
590 return;
591 }
592
593 // Parameters for presentation
594 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
595
596 Prs3d_Root::CurrentGroup(thePresentation)->SetPrimitivesAspect (aDimensionAspect->LineAspect()->Aspect());
597
598 Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
599
600 // prepare label string and compute its geometrical width
601 Standard_Real aLabelWidth;
602 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
603
604 // add margins to label width
605 if (aDimensionAspect->IsText3d())
606 {
607 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
608 }
609
610 // Get parameters from aspect or adjust it according with custom text position
611 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
612 Prs3d_DimensionTextHorizontalPosition aHorisontalTextPos = aDimensionAspect->TextHorizontalPosition();
613
614 if (IsTextPositionCustom())
615 {
616 AdjustParameters (myFixedTextPosition,anExtensionSize, aHorisontalTextPos, myFlyout);
617 }
618
619 // Handle user-defined and automatic arrow placement
620 Standard_Boolean isArrowsExternal = Standard_False;
621 Standard_Integer aLabelPosition = LabelPosition_None;
622
623 FitTextAlignment (aHorisontalTextPos, aLabelPosition, isArrowsExternal);
624
625 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
626 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
627
628 //Arrows positions and directions
629 gp_Vec aWPDir = gp_Vec (GetPlane().Axis().Direction());
630
631 gp_Dir aFirstExtensionDir = aWPDir ^ gp_Vec (myCenterPoint, aFirstAttach);
632 gp_Dir aSecondExtensionDir = aWPDir.Reversed() ^ gp_Vec (myCenterPoint, aSecondAttach);
633
634 gp_Vec aFirstArrowVec = gp_Vec (aFirstExtensionDir) * anArrowLength;
635 gp_Vec aSecondArrowVec = gp_Vec (aSecondExtensionDir) * anArrowLength;
636
637 gp_Pnt aFirstArrowBegin (0.0, 0.0, 0.0);
638 gp_Pnt aFirstArrowEnd (0.0, 0.0, 0.0);
639 gp_Pnt aSecondArrowBegin (0.0, 0.0, 0.0);
640 gp_Pnt aSecondArrowEnd (0.0, 0.0, 0.0);
641
642 if (isArrowsExternal)
643 {
644 aFirstArrowVec.Reverse();
645 aSecondArrowVec.Reverse();
646 }
647
648 aFirstArrowBegin = aFirstAttach;
649 aSecondArrowBegin = aSecondAttach;
650 aFirstArrowEnd = aFirstAttach.Translated (-aFirstArrowVec);
651 aSecondArrowEnd = aSecondAttach.Translated (-aSecondArrowVec);
652
653 // Group1: stenciling text and the angle dimension arc
654 Prs3d_Root::NewGroup (thePresentation);
655
656 Standard_Integer aHPosition = aLabelPosition & LabelPosition_HMask;
657
658 // draw text label
659 switch (aHPosition)
660 {
661 case LabelPosition_HCenter :
662 {
663 Standard_Boolean isLineBreak = aDimensionAspect->TextVerticalPosition() == Prs3d_DTVP_Center
664 && aDimensionAspect->IsText3d();
665
666 if (isLineBreak)
667 {
668 DrawArcWithText (thePresentation,
669 aFirstAttach,
670 aSecondAttach,
671 myCenterPoint,
672 aLabelString,
673 aLabelWidth,
674 theMode,
675 aLabelPosition);
676 break;
677 }
678
679 // compute text primitives
680 if (theMode == ComputeMode_All || theMode == ComputeMode_Text)
681 {
682 gp_Vec aDimensionDir (aFirstAttach, aSecondAttach);
683 gp_Pnt aTextPos = IsTextPositionCustom() ? myFixedTextPosition
684 : GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
685 gp_Dir aTextDir = aDimensionDir;
686
687 DrawText (thePresentation,
688 aTextPos,
689 aTextDir,
690 aLabelString,
691 aLabelPosition);
692 }
693
694 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
695 {
696 DrawArc (thePresentation,
697 isArrowsExternal ? aFirstAttach : aFirstArrowEnd,
698 isArrowsExternal ? aSecondAttach : aSecondArrowEnd,
699 myCenterPoint,
700 Abs (GetFlyout()),
701 theMode);
702 }
703 }
704 break;
705
706 case LabelPosition_Left :
707 {
708 DrawExtension (thePresentation,
709 anExtensionSize,
710 isArrowsExternal ? aFirstArrowEnd : aFirstAttach,
711 aFirstExtensionDir,
712 aLabelString,
713 aLabelWidth,
714 theMode,
715 aLabelPosition);
716 }
717 break;
718
719 case LabelPosition_Right :
720 {
721 DrawExtension (thePresentation,
722 anExtensionSize,
723 isArrowsExternal ? aSecondArrowEnd : aSecondAttach,
724 aSecondExtensionDir,
725 aLabelString,
726 aLabelWidth,
727 theMode,
728 aLabelPosition);
729 }
730 break;
731 }
732
733 // dimension arc without text
734 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && aHPosition != LabelPosition_HCenter)
735 {
736 Prs3d_Root::NewGroup (thePresentation);
737
738 DrawArc (thePresentation,
739 isArrowsExternal ? aFirstAttach : aFirstArrowEnd,
740 isArrowsExternal ? aSecondAttach : aSecondArrowEnd,
741 myCenterPoint,
742 Abs(GetFlyout ()),
743 theMode);
744 }
745
746 // arrows and arrow extensions
747 if (theMode == ComputeMode_All || theMode == ComputeMode_Line)
748 {
749 Prs3d_Root::NewGroup (thePresentation);
750
751 DrawArrow (thePresentation, aFirstArrowBegin, gp_Dir (aFirstArrowVec));
752 DrawArrow (thePresentation, aSecondArrowBegin, gp_Dir (aSecondArrowVec));
753 }
754
755 if ((theMode == ComputeMode_All || theMode == ComputeMode_Line) && isArrowsExternal)
756 {
757 Prs3d_Root::NewGroup (thePresentation);
758
759 if (aHPosition != LabelPosition_Left)
760 {
761 DrawExtension (thePresentation,
762 aDimensionAspect->ArrowTailSize(),
763 aFirstArrowEnd,
764 aFirstExtensionDir,
765 THE_EMPTY_LABEL_STRING,
766 THE_EMPTY_LABEL_WIDTH,
767 theMode,
768 LabelPosition_None);
769 }
770
771 if (aHPosition != LabelPosition_Right)
772 {
773 DrawExtension (thePresentation,
774 aDimensionAspect->ArrowTailSize(),
775 aSecondArrowEnd,
776 aSecondExtensionDir,
777 THE_EMPTY_LABEL_STRING,
778 THE_EMPTY_LABEL_WIDTH,
779 theMode,
780 LabelPosition_None);
781 }
782 }
783
784 // flyouts
785 if (theMode == ComputeMode_All)
786 {
787 Prs3d_Root::NewGroup (thePresentation);
788
789 Handle(Graphic3d_ArrayOfSegments) aPrimSegments = new Graphic3d_ArrayOfSegments (4);
790 aPrimSegments->AddVertex (myCenterPoint);
791 aPrimSegments->AddVertex (aFirstAttach);
792 aPrimSegments->AddVertex (myCenterPoint);
793 aPrimSegments->AddVertex (aSecondAttach);
794
795 Handle(Graphic3d_AspectLine3d) aFlyoutStyle = myDrawer->DimensionAspect()->LineAspect()->Aspect();
796 Prs3d_Root::CurrentGroup (thePresentation)->SetPrimitivesAspect (aFlyoutStyle);
797 Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPrimSegments);
798 }
799
800 mySelectionGeom.IsComputed = Standard_True;
801}
802
803//=======================================================================
804//function : ComputeFlyoutSelection
805//purpose : computes selection for flyouts
806//=======================================================================
807void AIS_AngleDimension::ComputeFlyoutSelection (const Handle(SelectMgr_Selection)& theSelection,
808 const Handle(SelectMgr_EntityOwner)& theOwner)
809{
810 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
811 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
812
813 Handle(Select3D_SensitiveGroup) aSensitiveEntity = new Select3D_SensitiveGroup (theOwner);
814 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aFirstAttach));
815 aSensitiveEntity->Add (new Select3D_SensitiveSegment (theOwner, myCenterPoint, aSecondAttach));
816
817 theSelection->Add (aSensitiveEntity);
818}
819
820//=======================================================================
821//function : InitTwoEdgesAngle
822//purpose :
823//=======================================================================
824Standard_Boolean AIS_AngleDimension::InitTwoEdgesAngle (gp_Pln& theComputedPlane)
825{
826 TopoDS_Edge aFirstEdge = TopoDS::Edge (myFirstShape);
827 TopoDS_Edge aSecondEdge = TopoDS::Edge (mySecondShape);
828
829 BRepAdaptor_Curve aMakeFirstLine (aFirstEdge);
830 BRepAdaptor_Curve aMakeSecondLine (aSecondEdge);
831
832 if (aMakeFirstLine.GetType() != GeomAbs_Line || aMakeSecondLine.GetType() != GeomAbs_Line)
833 {
834 return Standard_False;
835 }
836
837 Handle(Geom_Line) aFirstLine = new Geom_Line (aMakeFirstLine.Line());
838 Handle(Geom_Line) aSecondLine = new Geom_Line (aMakeSecondLine.Line());
839
840 gp_Lin aFirstLin = aFirstLine->Lin();
841 gp_Lin aSecondLin = aSecondLine->Lin();
842
843 Standard_Boolean isParallelLines = Abs (aFirstLin.Angle (aSecondLin) - M_PI) <= Precision::Angular();
844
845 gp_Pnt aPoint = aFirstLine->Value (0.0);
846 gp_Dir aNormal = isParallelLines
847 ? gp_Vec (aSecondLin.Normal (aPoint).Direction()) ^ gp_Vec (aSecondLin.Direction())
848 : gp_Vec (aFirstLin.Direction()) ^ gp_Vec (aSecondLin.Direction());
849
850 theComputedPlane = gp_Pln (aPoint, aNormal);
851
852 // Compute geometry for this plane and edges
853 Standard_Boolean isInfinite1,isInfinite2;
854 gp_Pnt aFirstPoint1, aLastPoint1, aFirstPoint2, aLastPoint2;
855
856 if (!AIS::ComputeGeometry (aFirstEdge, aSecondEdge,
857 aFirstLine, aSecondLine,
858 aFirstPoint1, aLastPoint1,
859 aFirstPoint2, aLastPoint2,
860 isInfinite1, isInfinite2))
861 {
862 return Standard_False;
863 }
864
865 if (aFirstLin.Direction().IsParallel (aSecondLin.Direction(), Precision::Angular()))
866 {
867 myFirstPoint = aFirstLin.Location();
868 mySecondPoint = ElCLib::Value (ElCLib::Parameter (aFirstLin, myFirstPoint), aSecondLin);
869
870 if (mySecondPoint.Distance (myFirstPoint) <= Precision::Confusion())
871 {
872 mySecondPoint.Translate (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
873 }
874
875 myCenterPoint.SetXYZ ((myFirstPoint.XYZ() + mySecondPoint.XYZ()) / 2.0);
876 }
877 else
878 {
879 // Find intersection
880 gp_Lin2d aFirstLin2d = ProjLib::Project (theComputedPlane, aFirstLin);
881 gp_Lin2d aSecondLin2d = ProjLib::Project (theComputedPlane, aSecondLin);
882
883 IntAna2d_AnaIntersection anInt2d (aFirstLin2d, aSecondLin2d);
884 gp_Pnt2d anIntersectPoint;
885 if (!anInt2d.IsDone() || anInt2d.IsEmpty())
886 {
887 return Standard_False;
888 }
889
890 anIntersectPoint = gp_Pnt2d (anInt2d.Point(1).Value());
891 myCenterPoint = ElCLib::To3d (theComputedPlane.Position().Ax2(), anIntersectPoint);
892
893 if (isInfinite1 || isInfinite2)
894 {
895 myFirstPoint = myCenterPoint.Translated (gp_Vec (aFirstLin.Direction()) * Abs (GetFlyout()));
896 mySecondPoint = myCenterPoint.Translated (gp_Vec (aSecondLin.Direction()) * Abs (GetFlyout()));
897
898 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
899 }
900
901 // |
902 // | <- dimension should be here
903 // *----
904 myFirstPoint = myCenterPoint.Distance (aFirstPoint1) > myCenterPoint.Distance (aLastPoint1)
905 ? aFirstPoint1
906 : aLastPoint1;
907
908 mySecondPoint = myCenterPoint.Distance (aFirstPoint2) > myCenterPoint.Distance (aLastPoint2)
909 ? aFirstPoint2
910 : aLastPoint2;
911 }
912
913 return IsValidPoints (myFirstPoint, myCenterPoint, mySecondPoint);
914}
915
916//=======================================================================
917//function : InitTwoFacesAngle
918//purpose : initialization of angle dimension between two faces
919//=======================================================================
920Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle()
921{
922 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
923 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
924
925 gp_Dir aFirstDir, aSecondDir;
926 gp_Pln aFirstPln, aSecondPln;
927 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
928 AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
929 Standard_Real aFirstOffset, aSecondOffset;
930
931 AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
932 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
933
934 AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
935 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
936
937 if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
938 {
939 //Planar faces angle
940 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
941 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
942 return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
943 aSecondFace,
944 myCenterPoint,
945 myFirstPoint,
946 mySecondPoint)
947 && IsValidPoints (myFirstPoint,
948 myCenterPoint,
949 mySecondPoint);
950 }
951 else
952 {
953 // Curvilinear faces angle
954 return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
955 aSecondFace,
956 aFirstSurfType,
957 aSecondSurfType,
958 myCenterPoint,
959 myFirstPoint,
960 mySecondPoint)
961 && IsValidPoints (myFirstPoint,
962 myCenterPoint,
963 mySecondPoint);
964 }
965}
966
967//=======================================================================
968//function : InitTwoFacesAngle
969//purpose : initialization of angle dimension between two faces
970//=======================================================================
971Standard_Boolean AIS_AngleDimension::InitTwoFacesAngle (const gp_Pnt thePointOnFirstFace)
972{
973 TopoDS_Face aFirstFace = TopoDS::Face (myFirstShape);
974 TopoDS_Face aSecondFace = TopoDS::Face (mySecondShape);
975
976 gp_Dir aFirstDir, aSecondDir;
977 gp_Pln aFirstPln, aSecondPln;
978 Handle(Geom_Surface) aFirstBasisSurf, aSecondBasisSurf;
979 AIS_KindOfSurface aFirstSurfType, aSecondSurfType;
980 Standard_Real aFirstOffset, aSecondOffset;
981
982 AIS::GetPlaneFromFace (aFirstFace, aFirstPln,
983 aFirstBasisSurf,aFirstSurfType,aFirstOffset);
984
985 AIS::GetPlaneFromFace (aSecondFace, aSecondPln,
986 aSecondBasisSurf, aSecondSurfType, aSecondOffset);
987
988 myFirstPoint = thePointOnFirstFace;
989 if (aFirstSurfType == AIS_KOS_Plane && aSecondSurfType == AIS_KOS_Plane)
990 {
991 //Planar faces angle
992 Handle(Geom_Plane) aFirstPlane = Handle(Geom_Plane)::DownCast (aFirstBasisSurf);
993 Handle(Geom_Plane) aSecondPlane = Handle(Geom_Plane)::DownCast (aSecondBasisSurf);
994 return AIS::InitAngleBetweenPlanarFaces (aFirstFace,
995 aSecondFace,
996 myCenterPoint,
997 myFirstPoint,
998 mySecondPoint,
999 Standard_True)
1000 && IsValidPoints (myFirstPoint,
1001 myCenterPoint,
1002 mySecondPoint);
1003 }
1004 else
1005 {
1006 // Curvilinear faces angle
1007 return AIS::InitAngleBetweenCurvilinearFaces (aFirstFace,
1008 aSecondFace,
1009 aFirstSurfType,
1010 aSecondSurfType,
1011 myCenterPoint,
1012 myFirstPoint,
1013 mySecondPoint,
1014 Standard_True)
1015 && IsValidPoints (myFirstPoint,
1016 myCenterPoint,
1017 mySecondPoint);
1018 }
1019}
1020
1021//=======================================================================
1022//function : InitConeAngle
1023//purpose : initialization of the cone angle
1024//=======================================================================
1025Standard_Boolean AIS_AngleDimension::InitConeAngle()
1026{
1027 if (myFirstShape.IsNull())
1028 {
1029 return Standard_False;
1030 }
1031
1032 TopoDS_Face aConeShape = TopoDS::Face (myFirstShape);
1033 gp_Pln aPln;
1034 gp_Cone aCone;
1035 gp_Circ aCircle;
1036 // A surface from the Face
1037 Handle(Geom_Surface) aSurf;
1038 Handle(Geom_OffsetSurface) aOffsetSurf;
1039 Handle(Geom_ConicalSurface) aConicalSurf;
1040 Handle(Geom_SurfaceOfRevolution) aRevSurf;
1041 Handle(Geom_Line) aLine;
1042 BRepAdaptor_Surface aConeAdaptor (aConeShape);
1043 TopoDS_Face aFace;
1044 AIS_KindOfSurface aSurfType;
1045 Standard_Real anOffset = 0.;
1046 Handle(Standard_Type) aType;
1047
1048 Standard_Real aMaxV = aConeAdaptor.FirstVParameter();
1049 Standard_Real aMinV = aConeAdaptor.LastVParameter();
1050
1051 AIS::GetPlaneFromFace (aConeShape, aPln, aSurf, aSurfType, anOffset);
1052
1053 if (aSurfType == AIS_KOS_Revolution)
1054 {
1055 // Surface of revolution
1056 aRevSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(aSurf);
1057 gp_Lin aLin (aRevSurf->Axis());
1058 Handle(Geom_Curve) aBasisCurve = aRevSurf->BasisCurve();
1059 //Must be a part of line (basis curve should be linear)
1060 if (aBasisCurve ->DynamicType() != STANDARD_TYPE(Geom_Line))
1061 return Standard_False;
1062
1063 gp_Pnt aFirst1 = aConeAdaptor.Value (0., aMinV);
1064 gp_Pnt aLast1 = aConeAdaptor.Value (0., aMaxV);
1065 gp_Vec aVec1 (aFirst1, aLast1);
1066
1067 //Projection <aFirst> on <aLin>
1068 gp_Pnt aFirst2 = ElCLib::Value (ElCLib::Parameter (aLin, aFirst1), aLin);
1069 // Projection <aLast> on <aLin>
1070 gp_Pnt aLast2 = ElCLib::Value (ElCLib::Parameter (aLin, aLast1), aLin);
1071
1072 gp_Vec aVec2 (aFirst2, aLast2);
1073
1074 // Check if two parts of revolution are parallel (it's a cylinder) or normal (it's a circle).
1075 if (aVec1.IsParallel (aVec2, Precision::Angular())
1076 || aVec1.IsNormal (aVec2,Precision::Angular()))
1077 return Standard_False;
1078
1079 gce_MakeCone aMkCone (aRevSurf->Axis(), aFirst1, aLast1);
1080 aCone = aMkCone.Value();
1081 myCenterPoint = aCone.Apex();
1082 }
1083 else
1084 {
1085 aType = aSurf->DynamicType();
1086 if (aType == STANDARD_TYPE(Geom_OffsetSurface) || anOffset > 0.01)
1087 {
1088 // Offset surface
1089 aOffsetSurf = new Geom_OffsetSurface (aSurf, anOffset);
1090 aSurf = aOffsetSurf->Surface();
1091 BRepBuilderAPI_MakeFace aMkFace(aSurf, Precision::Confusion());
1092 aMkFace.Build();
1093 if (!aMkFace.IsDone())
1094 return Standard_False;
1095 aConeAdaptor.Initialize (aMkFace.Face());
1096 }
1097 aCone = aConeAdaptor.Cone();
1098 aConicalSurf = Handle(Geom_ConicalSurface)::DownCast (aSurf);
1099 myCenterPoint = aConicalSurf->Apex();
1100 }
1101
1102 // A circle where the angle is drawn
1103 Handle(Geom_Curve) aCurve;
1104 Standard_Real aMidV = ( aMinV + aMaxV ) / 2.5;
1105 aCurve = aSurf->VIso (aMidV);
1106 aCircle = Handle(Geom_Circle)::DownCast (aCurve)->Circ();
1107
1108 aCurve = aSurf->VIso(aMaxV);
1109 gp_Circ aCircVmax = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1110 aCurve = aSurf->VIso(aMinV);
1111 gp_Circ aCircVmin = Handle(Geom_Circle)::DownCast(aCurve)->Circ();
1112
1113 if (aCircVmax.Radius() < aCircVmin.Radius())
1114 {
1115 gp_Circ aTmpCirc = aCircVmax;
1116 aCircVmax = aCircVmin;
1117 aCircVmin = aTmpCirc;
1118 }
1119
1120 myFirstPoint = ElCLib::Value (0, aCircle);
1121 mySecondPoint = ElCLib::Value (M_PI, aCircle);
1122 return Standard_True;
1123}
1124
1125//=======================================================================
1126//function : IsValidPoints
1127//purpose :
1128//=======================================================================
1129Standard_Boolean AIS_AngleDimension::IsValidPoints (const gp_Pnt& theFirstPoint,
1130 const gp_Pnt& theCenterPoint,
1131 const gp_Pnt& theSecondPoint) const
1132{
1133 return theFirstPoint.Distance (theCenterPoint) > Precision::Confusion()
1134 && theSecondPoint.Distance (theCenterPoint) > Precision::Confusion()
1135 && gp_Vec (theCenterPoint, theFirstPoint).Angle (
1136 gp_Vec (theCenterPoint, theSecondPoint)) > Precision::Angular();
1137}
1138
1139//=======================================================================
1140//function : GetTextPosition
1141//purpose :
1142//=======================================================================
1143const gp_Pnt AIS_AngleDimension::GetTextPosition() const
1144{
1145 if (!IsValid())
1146 {
1147 return gp::Origin();
1148 }
1149
1150 if (IsTextPositionCustom())
1151 {
1152 return myFixedTextPosition;
1153 }
1154
1155 // Counts text position according to the dimension parameters
1156 gp_Pnt aTextPosition (gp::Origin());
1157
1158 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1159
1160 // Prepare label string and compute its geometrical width
1161 Standard_Real aLabelWidth;
1162 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1163
1164 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1165 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec(myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1166
1167 // Handle user-defined and automatic arrow placement
1168 Standard_Boolean isArrowsExternal = Standard_False;
1169 Standard_Integer aLabelPosition = LabelPosition_None;
1170 FitTextAlignment (aDimensionAspect->TextHorizontalPosition(),
1171 aLabelPosition, isArrowsExternal);
1172
1173 // Get text position
1174 switch (aLabelPosition & LabelPosition_HMask)
1175 {
1176 case LabelPosition_HCenter:
1177 {
1178 aTextPosition = GetCenterOnArc (aFirstAttach, aSecondAttach, myCenterPoint);
1179 }
1180 break;
1181 case LabelPosition_Left:
1182 {
1183 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1184 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aFirstAttach);
1185 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1186 Standard_Real anOffset = isArrowsExternal
1187 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1188 : anExtensionSize;
1189 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * -anOffset;
1190 aTextPosition = aFirstAttach.Translated (anExtensionVec);
1191 }
1192 break;
1193 case LabelPosition_Right:
1194 {
1195 gp_Dir aPlaneNormal = gp_Vec (aFirstAttach, aSecondAttach) ^ gp_Vec (myCenterPoint, aFirstAttach);
1196 gp_Dir anExtensionDir = aPlaneNormal ^ gp_Vec (myCenterPoint, aSecondAttach);
1197 Standard_Real anExtensionSize = aDimensionAspect->ExtensionSize();
1198 Standard_Real anOffset = isArrowsExternal
1199 ? anExtensionSize + aDimensionAspect->ArrowAspect()->Length()
1200 : anExtensionSize;
1201 gp_Vec anExtensionVec = gp_Vec (anExtensionDir) * anOffset;
1202 aTextPosition = aSecondAttach.Translated (anExtensionVec);
1203 }
1204 break;
1205 }
1206
1207 return aTextPosition;
1208}
1209
1210//=======================================================================
1211//function : SetTextPosition
1212//purpose :
1213//=======================================================================
1214void AIS_AngleDimension::SetTextPosition (const gp_Pnt& theTextPos)
1215{
1216 if (!IsValid())
1217 {
1218 return;
1219 }
1220
1221 // The text position point for angle dimension should belong to the working plane.
1222 if (!GetPlane().Contains (theTextPos, Precision::Confusion()))
1223 {
1224 Standard_ProgramError::Raise ("The text position point for angle dimension doesn't belong to the working plane.");
1225 }
1226
1227 myIsTextPositionFixed = Standard_True;
1228 myFixedTextPosition = theTextPos;
1229}
1230
1231//=======================================================================
1232//function : AdjustParameters
1233//purpose :
1234//=======================================================================
1235void AIS_AngleDimension::AdjustParameters (const gp_Pnt& theTextPos,
1236 Standard_Real& theExtensionSize,
1237 Prs3d_DimensionTextHorizontalPosition& theAlignment,
1238 Standard_Real& theFlyout) const
1239{
1240 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1241 Standard_Real anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1242
1243 // Build circle with radius that is equal to distance from text position to the center point.
1244 Standard_Real aRadius = gp_Vec (myCenterPoint, theTextPos).Magnitude();
1245
1246 // Set attach points in positive direction of the flyout.
1247 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * aRadius);
1248 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * aRadius);
1249
1250 gce_MakeCirc aConstructCircle (myCenterPoint, GetPlane(), aRadius);
1251 if (!aConstructCircle.IsDone())
1252 {
1253 return;
1254 }
1255 gp_Circ aCircle = aConstructCircle.Value();
1256
1257 // Default values
1258 theExtensionSize = aDimensionAspect->ArrowAspect()->Length();
1259 theAlignment = Prs3d_DTHP_Center;
1260
1261 Standard_Real aParamBeg = ElCLib::Parameter (aCircle, aFirstAttach);
1262 Standard_Real aParamEnd = ElCLib::Parameter (aCircle, aSecondAttach);
1263 if (aParamEnd < aParamBeg)
1264 {
1265 Standard_Real aParam = aParamEnd;
1266 aParamEnd = aParamBeg;
1267 aParamBeg = aParam;
1268 }
1269
1270 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1271 Standard_Real aTextPar = ElCLib::Parameter (aCircle , theTextPos);
1272
1273 // Horizontal center
1274 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1275 {
1276 theFlyout = aRadius;
1277 return;
1278 }
1279
1280 aParamBeg += M_PI;
1281 aParamEnd += M_PI;
1282 ElCLib::AdjustPeriodic (0.0, M_PI * 2, Precision::PConfusion(), aParamBeg, aParamEnd);
1283
1284 if (aTextPar > aParamBeg && aTextPar < aParamEnd)
1285 {
1286 theFlyout = -aRadius;
1287 return;
1288 }
1289
1290 // Text on the extensions
1291 gp_Lin aFirstLine = gce_MakeLin (myCenterPoint, myFirstPoint);
1292 gp_Lin aSecondLine = gce_MakeLin (myCenterPoint, mySecondPoint);
1293 gp_Pnt aFirstTextProj = AIS::Nearest (aFirstLine, theTextPos);
1294 gp_Pnt aSecondTextProj = AIS::Nearest (aSecondLine, theTextPos);
1295 Standard_Real aFirstDist = aFirstTextProj.Distance (theTextPos);
1296 Standard_Real aSecondDist = aSecondTextProj.Distance (theTextPos);
1297
1298 if (aFirstDist <= aSecondDist)
1299 {
1300 aRadius = myCenterPoint.Distance (aFirstTextProj);
1301 Standard_Real aNewExtensionSize = aFirstDist - anArrowLength;
1302 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1303
1304 theAlignment = Prs3d_DTHP_Left;
1305
1306 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, myFirstPoint).Normalized().Scaled (aRadius);
1307
1308 theFlyout = aFirstTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1309 ? -aRadius : aRadius;
1310 }
1311 else
1312 {
1313 aRadius = myCenterPoint.Distance (aSecondTextProj);
1314
1315 Standard_Real aNewExtensionSize = aSecondDist - anArrowLength;
1316
1317 theExtensionSize = aNewExtensionSize < 0.0 ? 0.0 : aNewExtensionSize;
1318
1319 theAlignment = Prs3d_DTHP_Right;
1320
1321 gp_Vec aPosFlyoutDir = gp_Vec (myCenterPoint, mySecondPoint).Normalized().Scaled (aRadius);
1322
1323 theFlyout = aSecondTextProj.Distance (myCenterPoint.Translated (aPosFlyoutDir)) > Precision::Confusion()
1324 ? -aRadius : aRadius;
1325 }
1326}
1327
1328//=======================================================================
1329//function : FitTextAlignment
1330//purpose :
1331//=======================================================================
1332void AIS_AngleDimension::FitTextAlignment (const Prs3d_DimensionTextHorizontalPosition& theHorizontalTextPos,
1333 Standard_Integer& theLabelPosition,
1334 Standard_Boolean& theIsArrowsExternal) const
1335{
1336 Handle(Prs3d_DimensionAspect) aDimensionAspect = myDrawer->DimensionAspect();
1337
1338 Quantity_Length anArrowLength = aDimensionAspect->ArrowAspect()->Length();
1339
1340 // Prepare label string and compute its geometrical width
1341 Standard_Real aLabelWidth;
1342 TCollection_ExtendedString aLabelString = GetValueString (aLabelWidth);
1343
1344 // add margins to label width
1345 if (aDimensionAspect->IsText3d())
1346 {
1347 aLabelWidth += aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN * 2.0;
1348 }
1349
1350 gp_Pnt aFirstAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, myFirstPoint).Normalized() * GetFlyout());
1351 gp_Pnt aSecondAttach = myCenterPoint.Translated (gp_Vec (myCenterPoint, mySecondPoint).Normalized() * GetFlyout());
1352
1353 // Handle user-defined and automatic arrow placement
1354 switch (aDimensionAspect->ArrowOrientation())
1355 {
1356 case Prs3d_DAO_External: theIsArrowsExternal = true; break;
1357 case Prs3d_DAO_Internal: theIsArrowsExternal = false; break;
1358 case Prs3d_DAO_Fit:
1359 {
1360 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1361 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1362
1363 // Add margin to ensure a small tail between text and arrow
1364 Standard_Real anArrowMargin = aDimensionAspect->IsText3d()
1365 ? aDimensionAspect->TextAspect()->Height() * THE_3D_TEXT_MARGIN
1366 : 0.0;
1367
1368 Standard_Real anArrowsWidth = (anArrowLength + anArrowMargin) * 2.0;
1369
1370 theIsArrowsExternal = aDimensionWidth < aLabelWidth + anArrowsWidth;
1371 break;
1372 }
1373 }
1374
1375 // Handle user-defined and automatic text placement
1376 switch (theHorizontalTextPos)
1377 {
1378 case Prs3d_DTHP_Left : theLabelPosition |= LabelPosition_Left; break;
1379 case Prs3d_DTHP_Right : theLabelPosition |= LabelPosition_Right; break;
1380 case Prs3d_DTHP_Center: theLabelPosition |= LabelPosition_HCenter; break;
1381 case Prs3d_DTHP_Fit:
1382 {
1383 gp_Vec anAttachVector (aFirstAttach, aSecondAttach);
1384 Standard_Real aDimensionWidth = anAttachVector.Magnitude();
1385 Standard_Real anArrowsWidth = anArrowLength * 2.0;
1386 Standard_Real aContentWidth = theIsArrowsExternal ? aLabelWidth : aLabelWidth + anArrowsWidth;
1387
1388 theLabelPosition |= aDimensionWidth < aContentWidth ? LabelPosition_Left : LabelPosition_HCenter;
1389 break;
1390 }
1391 }
1392
1393 switch (aDimensionAspect->TextVerticalPosition())
1394 {
1395 case Prs3d_DTVP_Above : theLabelPosition |= LabelPosition_Above; break;
1396 case Prs3d_DTVP_Below : theLabelPosition |= LabelPosition_Below; break;
1397 case Prs3d_DTVP_Center : theLabelPosition |= LabelPosition_VCenter; break;
1398 }
1399}