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