Salome HOME
1. Fix for crash on Debian
[modules/shaper.git] / src / GeomAPI / GeomAPI_AISObject.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        GeomAPI_AISObject.cpp
4 // Created:     25 Jun 2014
5 // Author:      Artem ZHIDKOV
6
7 #include <GeomAPI_AISObject.h>
8
9 #include <GeomAPI_Circ.h>
10 #include <GeomAPI_Dir.h>
11 #include <GeomAPI_Lin.h>
12 #include <GeomAPI_Pln.h>
13 #include <GeomAPI_Pnt.h>
14 #include <GeomAPI_Shape.h>
15 #include <GeomAPI_XYZ.h>
16
17 #include <Geom_Plane.hxx>
18 #include <TopoDS_Shape.hxx>
19 #include <Quantity_NameOfColor.hxx>
20 #include <BRepBndLib.hxx>
21
22 #include <AIS_InteractiveObject.hxx>
23 #include <AIS_InteractiveContext.hxx>
24 #include <AIS_LengthDimension.hxx>
25 #include <AIS_ParallelRelation.hxx>
26 #include <AIS_PerpendicularRelation.hxx>
27 #include <AIS_RadiusDimension.hxx>
28 #include <AIS_Shape.hxx>
29 #include <AIS_FixRelation.hxx>
30 #include <Prs3d_PointAspect.hxx>
31
32 #include <Graphic3d_AspectLine3d.hxx>
33
34 const double tolerance = 1e-7;
35
36 const int CONSTRAINT_TEXT_HEIGHT = 28;  /// the text height of the constraint
37 const int CONSTRAINT_TEXT_SELECTION_TOLERANCE = 20;  /// the text selection tolerance
38
39 GeomAPI_AISObject::GeomAPI_AISObject()
40     : GeomAPI_Interface(new Handle(AIS_InteractiveObject)())
41 {
42 }
43
44 GeomAPI_AISObject::~GeomAPI_AISObject()
45 {
46   if (!empty()) {
47     // This is necessary for correct deletion of Handle entity.
48     // Without this Handle does not decremented counter to 0
49     Handle(AIS_InteractiveObject) *anAIS = implPtr<Handle(AIS_InteractiveObject)>();
50     anAIS->Nullify();
51   }
52 }
53
54
55 void GeomAPI_AISObject::createShape(std::shared_ptr<GeomAPI_Shape> theShape)
56 {
57   const TopoDS_Shape& aTDS =
58       (theShape && theShape->implPtr<TopoDS_Shape>()) ?
59           theShape->impl<TopoDS_Shape>() : TopoDS_Shape();
60
61   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
62   if (!anAIS.IsNull()) {
63     Handle(AIS_Shape) aShapeAIS = Handle(AIS_Shape)::DownCast(anAIS);
64     if (aShapeAIS) {
65       // if the AIS object is displayed in the opened local context in some mode, additional
66       // AIS sub objects are created there. They should be rebuild for correct selecting.
67       // It is possible to correct it by closing local context before the shape set and opening
68       // after. Another workaround to thrown down the selection and reselecting the AIS.
69       // If there was a problem here, try the first solution with close/open local context.
70
71       aShapeAIS->Set(aTDS);
72       aShapeAIS->Redisplay(Standard_True);
73     }
74   } else {
75     // Set default point as a '+' symbol
76     Handle(AIS_Shape) aShape = new AIS_Shape(aTDS);
77     Handle(Prs3d_Drawer) aDrawer = aShape->Attributes();
78     if (aDrawer->HasOwnPointAspect())
79       aDrawer->PointAspect()->SetTypeOfMarker(Aspect_TOM_PLUS);
80     else
81       aDrawer->SetPointAspect(new Prs3d_PointAspect(Aspect_TOM_PLUS, Quantity_NOC_YELLOW, 1.));
82     setImpl(new Handle(AIS_InteractiveObject)(aShape));
83   }
84 }
85
86 std::shared_ptr<GeomAPI_Shape> GeomAPI_AISObject::getShape() const
87 {
88   std::shared_ptr<GeomAPI_Shape> aResult;
89
90   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
91   if (!anAIS.IsNull()) {
92     Handle(AIS_Shape) aShapeAIS = Handle(AIS_Shape)::DownCast(anAIS);
93     if (aShapeAIS) {
94       std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
95       aResult->setImpl(new TopoDS_Shape(aShapeAIS->Shape()));
96       return aResult;
97     }
98   }
99   return std::shared_ptr<GeomAPI_Shape>();
100 }
101
102 void GeomAPI_AISObject::createDistance(std::shared_ptr<GeomAPI_Pnt> theStartPoint,
103                                        std::shared_ptr<GeomAPI_Pnt> theEndPoint,
104                                        std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
105                                        std::shared_ptr<GeomAPI_Pln> thePlane, double theDistance)
106 {
107   double aFlyout = 0;
108   if (theFlyoutPoint) {
109     double aDist = 0.0;
110     if (theStartPoint->distance(theEndPoint) < tolerance)
111       aDist = theStartPoint->distance(theFlyoutPoint);
112     else {
113       std::shared_ptr<GeomAPI_Lin> aLine = std::shared_ptr<GeomAPI_Lin>(
114           new GeomAPI_Lin(theStartPoint, theEndPoint));
115       aDist = aLine->distance(theFlyoutPoint);
116     }
117
118     std::shared_ptr<GeomAPI_XYZ> aLineDir = theEndPoint->xyz()->decreased(theStartPoint->xyz());
119     std::shared_ptr<GeomAPI_XYZ> aFOutDir = theFlyoutPoint->xyz()->decreased(
120         theStartPoint->xyz());
121     std::shared_ptr<GeomAPI_XYZ> aNorm = thePlane->direction()->xyz();
122     if (aLineDir->cross(aFOutDir)->dot(aNorm) < 0)
123       aDist = -aDist;
124     aFlyout = aDist;
125   }
126
127   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
128   if (anAIS.IsNull()) {
129     Handle(AIS_LengthDimension) aDimAIS = new AIS_LengthDimension(theStartPoint->impl<gp_Pnt>(),
130                                                                   theEndPoint->impl<gp_Pnt>(),
131                                                                   thePlane->impl<gp_Pln>());
132     aDimAIS->SetCustomValue(theDistance);
133
134     Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect();
135     anAspect->MakeArrows3d(Standard_False);
136     anAspect->MakeText3d(Standard_False);
137     anAspect->TextAspect()->SetHeight(CONSTRAINT_TEXT_HEIGHT);
138     anAspect->MakeTextShaded(Standard_True);
139     anAspect->ArrowAspect()->SetLength(theDistance / 10.);
140     aDimAIS->DimensionAspect()->MakeUnitsDisplayed(false);
141     aDimAIS->SetDimensionAspect(anAspect);
142     aDimAIS->SetSelToleranceForText2d(CONSTRAINT_TEXT_SELECTION_TOLERANCE);
143     aDimAIS->SetFlyout(aFlyout);
144
145     setImpl(new Handle(AIS_InteractiveObject)(aDimAIS));
146   } else {
147     // update presentation
148     Handle(AIS_LengthDimension) aDimAIS = Handle(AIS_LengthDimension)::DownCast(anAIS);
149     if (!aDimAIS.IsNull()) {
150       aDimAIS->SetMeasuredGeometry(theStartPoint->impl<gp_Pnt>(), theEndPoint->impl<gp_Pnt>(),
151                                    thePlane->impl<gp_Pln>());
152       aDimAIS->SetCustomValue(theDistance);
153       aDimAIS->SetFlyout(aFlyout);
154
155       aDimAIS->Redisplay(Standard_True);
156     }
157   }
158 }
159
160 bool GeomAPI_AISObject::isEmptyDistanceGeometry()
161 {
162   bool anEmpty = false;
163
164   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
165   if (!anAIS.IsNull()) {
166     Handle(AIS_LengthDimension) aDimAIS = Handle(AIS_LengthDimension)::DownCast(anAIS);
167     if (!aDimAIS.IsNull()) {
168       anEmpty = !aDimAIS->IsValid();
169     }
170   }
171
172   return anEmpty;
173 }
174
175 void GeomAPI_AISObject::createRadius(std::shared_ptr<GeomAPI_Circ> theCircle,
176                                      std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
177                                      double theRadius)
178 {
179   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
180
181   // TODO: a bug in AIS_RadiusDimension:
182   // The anchor point can't be myCirc.Location() - an exception is raised.
183   // But we need exactly this case...
184   // We want to show a radius dimension starting from the circle centre and
185   // ending at the user-defined point.
186   // Also, if anchor point coincides with myP2, the radius dimension is not displayed at all.
187   std::shared_ptr<GeomAPI_Pnt> anAnchor = theCircle->project(theFlyoutPoint);
188   std::shared_ptr<GeomAPI_XYZ> anAnchorXYZ = anAnchor->xyz();
189   anAnchorXYZ = anAnchorXYZ->decreased(aCenter->xyz());
190   std::shared_ptr<GeomAPI_Dir> aDeltaDir(new GeomAPI_Dir(anAnchorXYZ));
191   const double aDelta = 1e-3;
192   anAnchor->setX(anAnchor->x() + aDelta * aDeltaDir->x());
193   anAnchor->setY(anAnchor->y() + aDelta * aDeltaDir->y());
194   anAnchor->setZ(anAnchor->z() + aDelta * aDeltaDir->z());
195
196   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
197   if (anAIS.IsNull()) {
198     Handle(AIS_RadiusDimension) aDimAIS = new AIS_RadiusDimension(theCircle->impl<gp_Circ>(),
199                                                                   anAnchor->impl<gp_Pnt>());
200     aDimAIS->SetCustomValue(theRadius);
201
202     Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect();
203     anAspect->MakeArrows3d(Standard_False);
204     anAspect->MakeText3d(false);
205     anAspect->TextAspect()->SetHeight(CONSTRAINT_TEXT_HEIGHT);
206     anAspect->ArrowAspect()->SetLength(theRadius / 5.);
207     anAspect->MakeTextShaded(false);
208     aDimAIS->DimensionAspect()->MakeUnitsDisplayed(false);
209     aDimAIS->SetDimensionAspect(anAspect);
210     aDimAIS->SetSelToleranceForText2d(CONSTRAINT_TEXT_SELECTION_TOLERANCE);
211
212     setImpl(new Handle(AIS_InteractiveObject)(aDimAIS));
213   } else {
214     // update presentation
215     Handle(AIS_RadiusDimension) aDimAIS = Handle(AIS_RadiusDimension)::DownCast(anAIS);
216     if (!aDimAIS.IsNull()) {
217       aDimAIS->SetMeasuredGeometry(theCircle->impl<gp_Circ>(), anAnchor->impl<gp_Pnt>());
218       aDimAIS->SetCustomValue(theRadius);
219       aDimAIS->Redisplay(Standard_True);
220     }
221   }
222 }
223
224 void GeomAPI_AISObject::createParallel(std::shared_ptr<GeomAPI_Shape> theLine1,
225                                        std::shared_ptr<GeomAPI_Shape> theLine2,
226                                        std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
227                                        std::shared_ptr<GeomAPI_Pln> thePlane)
228 {
229   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
230   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
231   if (anAIS.IsNull()) {
232     Handle(AIS_ParallelRelation) aParallel = new AIS_ParallelRelation(
233         theLine1->impl<TopoDS_Shape>(), theLine2->impl<TopoDS_Shape>(), aPlane);
234     if (theFlyoutPoint)
235       aParallel->SetPosition(theFlyoutPoint->impl<gp_Pnt>());
236
237     setImpl(new Handle(AIS_InteractiveObject)(aParallel));
238   } else {
239     Handle(AIS_ParallelRelation) aParallel = Handle(AIS_ParallelRelation)::DownCast(anAIS);
240     if (!aParallel.IsNull()) {
241       aParallel->SetFirstShape(theLine1->impl<TopoDS_Shape>());
242       aParallel->SetSecondShape(theLine2->impl<TopoDS_Shape>());
243       aParallel->SetPlane(aPlane);
244       if (theFlyoutPoint)
245         aParallel->SetPosition(theFlyoutPoint->impl<gp_Pnt>());
246       aParallel->Redisplay(Standard_True);
247     }
248   }
249 }
250
251 void GeomAPI_AISObject::createPerpendicular(std::shared_ptr<GeomAPI_Shape> theLine1,
252                                             std::shared_ptr<GeomAPI_Shape> theLine2,
253                                             std::shared_ptr<GeomAPI_Pln> thePlane)
254 {
255   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
256   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
257   if (anAIS.IsNull()) {
258     Handle(AIS_PerpendicularRelation) aPerpendicular = new AIS_PerpendicularRelation(
259         theLine1->impl<TopoDS_Shape>(), theLine2->impl<TopoDS_Shape>(), aPlane);
260
261     setImpl(new Handle(AIS_InteractiveObject)(aPerpendicular));
262   } else {
263     Handle(AIS_PerpendicularRelation) aPerpendicular = Handle(AIS_PerpendicularRelation)::DownCast(
264         anAIS);
265     if (!aPerpendicular.IsNull()) {
266       aPerpendicular->SetFirstShape(theLine1->impl<TopoDS_Shape>());
267       aPerpendicular->SetSecondShape(theLine2->impl<TopoDS_Shape>());
268       aPerpendicular->SetPlane(aPlane);
269       aPerpendicular->Redisplay(Standard_True);
270     }
271   }
272 }
273
274
275 void GeomAPI_AISObject::createFixed(std::shared_ptr<GeomAPI_Shape> theShape,
276                                     std::shared_ptr<GeomAPI_Pln> thePlane)
277 {
278   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
279   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
280   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
281   Handle(AIS_FixRelation) aFixPrs;
282   if (anAIS.IsNull()) {
283     aFixPrs = new AIS_FixRelation(aShape, aPlane);
284
285     setImpl(new Handle(AIS_InteractiveObject)(aFixPrs));
286   } else {
287     aFixPrs = Handle(AIS_FixRelation)::DownCast(anAIS);
288     if (!aFixPrs.IsNull()) {
289       aFixPrs->SetFirstShape(aShape);
290       aFixPrs->SetPlane(aPlane);
291       aFixPrs->Redisplay(Standard_True);
292     }
293   }
294   if (!aFixPrs.IsNull()) {
295     Bnd_Box aBox;
296     BRepBndLib::Add(aShape, aBox);
297     double aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
298     aBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
299     gp_Pnt aXYZ1(aXmin, aXmax, aYmin);
300     gp_Pnt aXYZ2(aXmax, aYmax, aZmax);
301     double aDist = aXYZ1.Distance(aXYZ2);
302     if (aDist > Precision::Confusion()) {
303       aFixPrs->SetArrowSize(aDist/8.);
304     }
305   }
306 }
307
308 void GeomAPI_AISObject::setColor(const int& theColor)
309 {
310   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
311   if (anAIS.IsNull())
312     return;
313   Quantity_Color aColor((Quantity_NameOfColor) theColor);
314   Handle(AIS_Dimension) aDimAIS = Handle(AIS_Dimension)::DownCast(anAIS);
315   if (!aDimAIS.IsNull()) {
316     aDimAIS->DimensionAspect()->SetCommonColor(aColor);
317   }
318   Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
319   if (!aContext.IsNull())
320     aContext->SetColor(anAIS, aColor, false);
321   else
322     anAIS->SetColor(aColor);
323 }
324
325 double GeomAPI_AISObject::width()
326 {
327   double aWidth = 0.0;
328   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
329   if (!anAIS.IsNull()) {
330     aWidth = anAIS->Width();
331   }
332   return aWidth;
333 }
334
335 bool GeomAPI_AISObject::setWidth(const double& theWidth)
336 {
337   bool isChanged = false;
338   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
339   if (!anAIS.IsNull()) {
340     isChanged = anAIS->Width() != theWidth;
341     if (isChanged)
342       anAIS->SetWidth(theWidth);
343   }
344   return isChanged;
345 }
346
347 bool GeomAPI_AISObject::setColor(int theR, int theG, int theB)
348 {
349   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
350   if (anAIS.IsNull())
351     return false;
352   Quantity_Color aColor(theR / 255., theG / 255., theB / 255., Quantity_TOC_RGB);
353   Quantity_Color aCurrentColor;
354   anAIS->Color(aCurrentColor);
355   // do not set the same color to the presentation
356   if (aColor.IsEqual(aCurrentColor))
357     return false;
358
359   Handle(AIS_Dimension) aDimAIS = Handle(AIS_Dimension)::DownCast(anAIS);
360   if (!aDimAIS.IsNull()) {
361     aDimAIS->DimensionAspect()->SetCommonColor(aColor);
362   }
363   Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
364   if (!aContext.IsNull())
365     aContext->SetColor(anAIS, aColor, false);
366   else
367     anAIS->SetColor(aColor);
368   return true;
369 }
370
371 void GeomAPI_AISObject::getColor(int& theR, int& theG, int& theB)
372 {
373   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
374   if (anAIS.IsNull())
375     return;
376
377   Quantity_Color aColor = anAIS->Color();
378   theR = (int)(aColor.Red()*255.);
379   theG = (int)(aColor.Green()*255.);
380   theB = (int)(aColor.Blue()*255.);
381 }
382
383 bool GeomAPI_AISObject::setDeflection(const double theDeflection)
384 {
385   bool isModified = false;
386   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
387   if (!anAIS.IsNull()) {
388     Handle(AIS_Shape) anAISShape = Handle(AIS_Shape)::DownCast(anAIS);
389     if (!anAISShape.IsNull()) {
390       Standard_Real aCoefficient, aPreviousCoefficient;
391       anAISShape->OwnDeviationCoefficient(aCoefficient, aPreviousCoefficient);
392       if (fabs(aCoefficient-theDeflection) > Precision::Confusion()) {
393         isModified = true;
394         anAISShape->SetOwnDeviationCoefficient(theDeflection);
395         // redisplay is necessary here to update presentation in all modes
396         // Standard True flag. Displayer uses Standard False flag. If it will be changed in
397         // displayer, redisplay here will not be necessary. But performance should be checked.
398         anAISShape->Redisplay(Standard_True);
399       }
400     }
401   }
402   return isModified;
403 }
404
405 double GeomAPI_AISObject::getDeflection() const
406 {
407   double aDeflection = -1;
408
409   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
410   if (!anAIS.IsNull()) {
411     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
412     aDeflection = aDrawer->DeviationCoefficient();
413   }
414   return aDeflection;
415 }
416
417
418 bool GeomAPI_AISObject::empty() const
419 {
420   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
421       ->impl<Handle(AIS_InteractiveObject)>();
422   if (anAIS.IsNull())
423     return true;
424   return false;
425 }
426
427 int GeomAPI_AISObject::getShapeType() const
428 {
429   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
430       ->impl<Handle(AIS_InteractiveObject)>();
431   if (!anAIS.IsNull()) {
432     Handle(AIS_Shape) aAISShape = Handle(AIS_Shape)::DownCast(anAIS);
433     if (!aAISShape.IsNull()) {
434       const TopoDS_Shape aShape = aAISShape->Shape();
435       if (!aShape.IsNull())
436         return aShape.ShapeType();
437     }
438   }
439   return -1;
440 }
441
442 void GeomAPI_AISObject::setPointMarker(int theType, double theScale)
443 {
444   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
445   if (!anAIS.IsNull()) {
446     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
447     if (aDrawer->HasOwnPointAspect()) {
448       Handle(Prs3d_PointAspect) aPA = aDrawer->PointAspect();
449       aPA->SetTypeOfMarker((Aspect_TypeOfMarker)theType);
450       aPA->SetScale(theScale);
451     } else {
452       Quantity_NameOfColor aCol = Quantity_NOC_YELLOW;
453       aDrawer->SetPointAspect(new Prs3d_PointAspect((Aspect_TypeOfMarker)theType, aCol, theScale));
454     }
455   }
456 }
457
458 bool GeomAPI_AISObject::setLineStyle(int theStyle)
459 {
460   bool isChanged = false;
461   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
462   if (!anAIS.IsNull()) {
463     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
464     Handle(Prs3d_LineAspect) aLineAspect;
465
466     Aspect_TypeOfLine aType = (Aspect_TypeOfLine)theStyle;
467     if (aDrawer->HasOwnLineAspect()) {
468       aLineAspect = aDrawer->LineAspect();
469     }
470     if (aDrawer->HasOwnWireAspect()) {
471       aLineAspect = aDrawer->WireAspect();
472     }
473     if (!aLineAspect.IsNull()) {
474       Handle(Graphic3d_AspectLine3d) aGraphicAspect = aLineAspect->Aspect();
475       Aspect_TypeOfLine aCurrentType = aGraphicAspect->Type();
476       isChanged = aType != aCurrentType;
477       if (isChanged) {
478         aLineAspect->SetTypeOfLine(aType);
479       }
480     }
481   }
482   return isChanged;
483 }
484
485 bool GeomAPI_AISObject::setTransparensy(double theVal)
486 {
487   bool isChanged = false;
488   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
489   if (!anAIS.IsNull()) {
490     Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
491     if (!aContext.IsNull()) {
492       double aCurrentValue = anAIS->Transparency();
493       isChanged = aCurrentValue != theVal;
494       if (isChanged)
495         aContext->SetTransparency(anAIS, theVal, false);
496     } else {
497       anAIS->SetTransparency(theVal);
498     }
499   }
500  return isChanged;
501 }