Salome HOME
Issue #555 - Make a number of shifted/rotated copies - selected object does not appea...
[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 (myImpl) {
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 = (Handle(AIS_InteractiveObject)*)myImpl;
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     setImpl(new Handle(AIS_InteractiveObject)(new AIS_Shape(aTDS)));
76 }
77
78 void GeomAPI_AISObject::createDistance(std::shared_ptr<GeomAPI_Pnt> theStartPoint,
79                                        std::shared_ptr<GeomAPI_Pnt> theEndPoint,
80                                        std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
81                                        std::shared_ptr<GeomAPI_Pln> thePlane, double theDistance)
82 {
83   double aFlyout = 0;
84   if (theFlyoutPoint) {
85     double aDist = 0.0;
86     if (theStartPoint->distance(theEndPoint) < tolerance)
87       aDist = theStartPoint->distance(theFlyoutPoint);
88     else {
89       std::shared_ptr<GeomAPI_Lin> aLine = std::shared_ptr<GeomAPI_Lin>(
90           new GeomAPI_Lin(theStartPoint, theEndPoint));
91       aDist = aLine->distance(theFlyoutPoint);
92     }
93
94     std::shared_ptr<GeomAPI_XYZ> aLineDir = theEndPoint->xyz()->decreased(theStartPoint->xyz());
95     std::shared_ptr<GeomAPI_XYZ> aFOutDir = theFlyoutPoint->xyz()->decreased(
96         theStartPoint->xyz());
97     std::shared_ptr<GeomAPI_XYZ> aNorm = thePlane->direction()->xyz();
98     if (aLineDir->cross(aFOutDir)->dot(aNorm) < 0)
99       aDist = -aDist;
100     aFlyout = aDist;
101   }
102
103   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
104   if (anAIS.IsNull()) {
105     Handle(AIS_LengthDimension) aDimAIS = new AIS_LengthDimension(theStartPoint->impl<gp_Pnt>(),
106                                                                   theEndPoint->impl<gp_Pnt>(),
107                                                                   thePlane->impl<gp_Pln>());
108     aDimAIS->SetCustomValue(theDistance);
109
110     Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect();
111     anAspect->MakeArrows3d(Standard_False);
112     anAspect->MakeText3d(Standard_False);
113     anAspect->TextAspect()->SetHeight(CONSTRAINT_TEXT_HEIGHT);
114     anAspect->MakeTextShaded(Standard_True);
115     anAspect->ArrowAspect()->SetLength(theDistance / 10.);
116     aDimAIS->DimensionAspect()->MakeUnitsDisplayed(false);
117     aDimAIS->SetDimensionAspect(anAspect);
118     aDimAIS->SetSelToleranceForText2d(CONSTRAINT_TEXT_SELECTION_TOLERANCE);
119     aDimAIS->SetFlyout(aFlyout);
120
121     setImpl(new Handle(AIS_InteractiveObject)(aDimAIS));
122   } else {
123     // update presentation
124     Handle(AIS_LengthDimension) aDimAIS = Handle(AIS_LengthDimension)::DownCast(anAIS);
125     if (!aDimAIS.IsNull()) {
126       aDimAIS->SetMeasuredGeometry(theStartPoint->impl<gp_Pnt>(), theEndPoint->impl<gp_Pnt>(),
127                                    thePlane->impl<gp_Pln>());
128       aDimAIS->SetCustomValue(theDistance);
129       aDimAIS->SetFlyout(aFlyout);
130
131       aDimAIS->Redisplay(Standard_True);
132     }
133   }
134 }
135
136 void GeomAPI_AISObject::createRadius(std::shared_ptr<GeomAPI_Circ> theCircle,
137                                      std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
138                                      double theRadius)
139 {
140   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
141
142   // TODO: a bug in AIS_RadiusDimension:
143   // The anchor point can't be myCirc.Location() - an exception is raised.
144   // But we need exactly this case...
145   // We want to show a radius dimension starting from the circle centre and 
146   // ending at the user-defined point.
147   // Also, if anchor point coincides with myP2, the radius dimension is not displayed at all.
148   std::shared_ptr<GeomAPI_Pnt> anAnchor = theCircle->project(theFlyoutPoint);
149   std::shared_ptr<GeomAPI_XYZ> anAnchorXYZ = anAnchor->xyz();
150   anAnchorXYZ = anAnchorXYZ->decreased(aCenter->xyz());
151   std::shared_ptr<GeomAPI_Dir> aDeltaDir(new GeomAPI_Dir(anAnchorXYZ));
152   const double aDelta = 1e-3;
153   anAnchor->setX(anAnchor->x() + aDelta * aDeltaDir->x());
154   anAnchor->setY(anAnchor->y() + aDelta * aDeltaDir->y());
155   anAnchor->setZ(anAnchor->z() + aDelta * aDeltaDir->z());
156
157   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
158   if (anAIS.IsNull()) {
159     Handle(AIS_RadiusDimension) aDimAIS = new AIS_RadiusDimension(theCircle->impl<gp_Circ>(),
160                                                                   anAnchor->impl<gp_Pnt>());
161     aDimAIS->SetCustomValue(theRadius);
162
163     Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect();
164     anAspect->MakeArrows3d(Standard_False);
165     anAspect->MakeText3d(false);
166     anAspect->TextAspect()->SetHeight(CONSTRAINT_TEXT_HEIGHT);
167     anAspect->ArrowAspect()->SetLength(theRadius / 5.);
168     anAspect->MakeTextShaded(false);
169     aDimAIS->DimensionAspect()->MakeUnitsDisplayed(false);
170     aDimAIS->SetDimensionAspect(anAspect);
171     aDimAIS->SetSelToleranceForText2d(CONSTRAINT_TEXT_SELECTION_TOLERANCE);
172
173     setImpl(new Handle(AIS_InteractiveObject)(aDimAIS));
174   } else {
175     // update presentation
176     Handle(AIS_RadiusDimension) aDimAIS = Handle(AIS_RadiusDimension)::DownCast(anAIS);
177     if (!aDimAIS.IsNull()) {
178       aDimAIS->SetMeasuredGeometry(theCircle->impl<gp_Circ>(), anAnchor->impl<gp_Pnt>());
179       aDimAIS->SetCustomValue(theRadius);
180       aDimAIS->Redisplay(Standard_True);
181     }
182   }
183 }
184
185 void GeomAPI_AISObject::createParallel(std::shared_ptr<GeomAPI_Shape> theLine1,
186                                        std::shared_ptr<GeomAPI_Shape> theLine2,
187                                        std::shared_ptr<GeomAPI_Pnt> theFlyoutPoint,
188                                        std::shared_ptr<GeomAPI_Pln> thePlane)
189 {
190   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
191   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
192   if (anAIS.IsNull()) {
193     Handle(AIS_ParallelRelation) aParallel = new AIS_ParallelRelation(
194         theLine1->impl<TopoDS_Shape>(), theLine2->impl<TopoDS_Shape>(), aPlane);
195     if (theFlyoutPoint)
196       aParallel->SetPosition(theFlyoutPoint->impl<gp_Pnt>());
197
198     setImpl(new Handle(AIS_InteractiveObject)(aParallel));
199   } else {
200     Handle(AIS_ParallelRelation) aParallel = Handle(AIS_ParallelRelation)::DownCast(anAIS);
201     if (!aParallel.IsNull()) {
202       aParallel->SetFirstShape(theLine1->impl<TopoDS_Shape>());
203       aParallel->SetSecondShape(theLine2->impl<TopoDS_Shape>());
204       aParallel->SetPlane(aPlane);
205       if (theFlyoutPoint)
206         aParallel->SetPosition(theFlyoutPoint->impl<gp_Pnt>());
207       aParallel->Redisplay(Standard_True);
208     }
209   }
210 }
211
212 void GeomAPI_AISObject::createPerpendicular(std::shared_ptr<GeomAPI_Shape> theLine1,
213                                             std::shared_ptr<GeomAPI_Shape> theLine2,
214                                             std::shared_ptr<GeomAPI_Pln> thePlane)
215 {
216   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
217   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
218   if (anAIS.IsNull()) {
219     Handle(AIS_PerpendicularRelation) aPerpendicular = new AIS_PerpendicularRelation(
220         theLine1->impl<TopoDS_Shape>(), theLine2->impl<TopoDS_Shape>(), aPlane);
221
222     setImpl(new Handle(AIS_InteractiveObject)(aPerpendicular));
223   } else {
224     Handle(AIS_PerpendicularRelation) aPerpendicular = Handle(AIS_PerpendicularRelation)::DownCast(
225         anAIS);
226     if (!aPerpendicular.IsNull()) {
227       aPerpendicular->SetFirstShape(theLine1->impl<TopoDS_Shape>());
228       aPerpendicular->SetSecondShape(theLine2->impl<TopoDS_Shape>());
229       aPerpendicular->SetPlane(aPlane);
230       aPerpendicular->Redisplay(Standard_True);
231     }
232   }
233 }
234
235
236 void GeomAPI_AISObject::createFixed(std::shared_ptr<GeomAPI_Shape> theShape,
237                                     std::shared_ptr<GeomAPI_Pln> thePlane)
238 {
239   Handle(Geom_Plane) aPlane = new Geom_Plane(thePlane->impl<gp_Pln>());
240   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
241   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
242   Handle(AIS_FixRelation) aFixPrs;
243   if (anAIS.IsNull()) {
244     aFixPrs = new AIS_FixRelation(aShape, aPlane);
245
246     setImpl(new Handle(AIS_InteractiveObject)(aFixPrs));
247   } else {
248     aFixPrs = Handle(AIS_FixRelation)::DownCast(anAIS);
249     if (!aFixPrs.IsNull()) {
250       aFixPrs->SetFirstShape(aShape);
251       aFixPrs->SetPlane(aPlane);
252       aFixPrs->Redisplay(Standard_True);
253     }
254   }
255   if (!aFixPrs.IsNull()) {
256     Bnd_Box aBox;
257     BRepBndLib::Add(aShape, aBox);
258     double aXmin, aXmax, aYmin, aYmax, aZmin, aZmax;
259     aBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
260     gp_Pnt aXYZ1(aXmin, aXmax, aYmin);
261     gp_Pnt aXYZ2(aXmax, aYmax, aZmax);
262     double aDist = aXYZ1.Distance(aXYZ2);
263     if (aDist > Precision::Confusion()) {
264       aFixPrs->SetArrowSize(aDist/8.);
265     }
266   }
267 }
268
269 void GeomAPI_AISObject::setColor(const int& theColor)
270 {
271   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
272   if (anAIS.IsNull())
273     return;
274   Quantity_Color aColor((Quantity_NameOfColor) theColor);
275   anAIS->SetColor(aColor);
276   Handle(AIS_Dimension) aDimAIS = Handle(AIS_Dimension)::DownCast(anAIS);
277   if (!aDimAIS.IsNull()) {
278     aDimAIS->DimensionAspect()->SetCommonColor(aColor);
279   }
280   Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
281   aContext->SetColor(anAIS, aColor, false);
282 }
283
284 bool GeomAPI_AISObject::setWidth(const double& theWidth)
285 {
286   bool isChanged = false;
287   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
288   if (!anAIS.IsNull()) {
289     isChanged = anAIS->Width() != theWidth;
290     if (isChanged)
291       anAIS->SetWidth(theWidth);
292   }
293   return isChanged;
294 }
295
296 bool GeomAPI_AISObject::setColor(int theR, int theG, int theB)
297 {
298   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
299   if (anAIS.IsNull())
300     return false;
301   Quantity_Color aColor(theR / 255., theG / 255., theB / 255., Quantity_TOC_RGB);
302   Quantity_Color aCurrentColor;
303   anAIS->Color(aCurrentColor);
304   // do not set the same color to the presentation
305   if (aColor.IsEqual(aCurrentColor))
306     return false;
307
308   anAIS->SetColor(aColor);
309   Handle(AIS_Dimension) aDimAIS = Handle(AIS_Dimension)::DownCast(anAIS);
310   if (!aDimAIS.IsNull()) {
311     aDimAIS->DimensionAspect()->SetCommonColor(aColor);
312   }
313   Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
314   aContext->SetColor(anAIS, aColor, false);
315   return true;
316 }
317
318 void GeomAPI_AISObject::getColor(int& theR, int& theG, int& theB)
319 {
320   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
321   if (anAIS.IsNull())
322     return;
323
324   Quantity_Color aColor = anAIS->Color();
325   theR = (int)(aColor.Red()*255.);
326   theG = (int)(aColor.Green()*255.);
327   theB = (int)(aColor.Blue()*255.);
328 }
329
330 bool GeomAPI_AISObject::empty() const
331 {
332   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
333       ->impl<Handle(AIS_InteractiveObject)>();
334   if (anAIS.IsNull())
335     return true;
336   return false;
337 }
338
339 int GeomAPI_AISObject::getShapeType() const
340 {
341   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
342       ->impl<Handle(AIS_InteractiveObject)>();
343   if (!anAIS.IsNull()) {
344     Handle(AIS_Shape) aAISShape = Handle(AIS_Shape)::DownCast(anAIS);
345     if (!aAISShape.IsNull()) {
346       return aAISShape->Shape().ShapeType();
347     }
348   }
349   return -1;
350 }
351
352 void GeomAPI_AISObject::setPointMarker(int theType, double theScale)
353 {
354   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
355   if (!anAIS.IsNull()) {
356     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
357     if (aDrawer->HasOwnPointAspect()) {
358       Handle(Prs3d_PointAspect) aPA = aDrawer->PointAspect();
359       aPA->SetTypeOfMarker((Aspect_TypeOfMarker)theType);
360       aPA->SetScale(theScale);
361     } else {
362       Quantity_NameOfColor aCol = Quantity_NOC_YELLOW;
363       aDrawer->SetPointAspect(new Prs3d_PointAspect((Aspect_TypeOfMarker)theType, aCol, theScale));
364     }
365   }
366 }
367
368 bool GeomAPI_AISObject::setLineStyle(int theStyle)
369 {
370   bool isChanged = false;
371   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
372   if (!anAIS.IsNull()) {
373     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
374     Handle(Prs3d_LineAspect) aLineAspect;
375
376     Aspect_TypeOfLine aType = (Aspect_TypeOfLine)theStyle;
377     if (aDrawer->HasOwnLineAspect()) {
378       aLineAspect = aDrawer->LineAspect();
379     }
380     if (aDrawer->HasOwnWireAspect()) {
381       aLineAspect = aDrawer->WireAspect();
382     }
383     Quantity_Color aCurrentColor;
384     Aspect_TypeOfLine aCurrentType;
385     Standard_Real aCurrentWidth;
386     aLineAspect->Aspect()->Values(aCurrentColor, aCurrentType, aCurrentWidth);
387     isChanged = aType != aCurrentType;
388     if (isChanged) {
389       aLineAspect->SetTypeOfLine(aType);
390     }
391   }
392   return isChanged;
393 }
394
395 bool GeomAPI_AISObject::setTransparensy(double theVal)
396 {
397   bool isChanged = false;
398   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
399   if (!anAIS.IsNull()) {
400     Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
401     if (!aContext.IsNull()) {
402       double aCurrentValue = anAIS->Transparency();
403       isChanged = aCurrentValue != theVal;
404       if (isChanged)
405         aContext->SetTransparency(anAIS, theVal, false);
406     }
407   }
408  return isChanged;
409 }