Salome HOME
Improvement #1140: Display of replicated Sketch entities with thinner line
[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   aContext->SetColor(anAIS, aColor, false);
320 }
321
322 double GeomAPI_AISObject::width()
323 {
324   double aWidth = 0.0;
325   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
326   if (!anAIS.IsNull()) {
327     aWidth = anAIS->Width();
328   }
329   return aWidth;
330 }
331
332 bool GeomAPI_AISObject::setWidth(const double& theWidth)
333 {
334   bool isChanged = false;
335   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
336   if (!anAIS.IsNull()) {
337     isChanged = anAIS->Width() != theWidth;
338     if (isChanged)
339       anAIS->SetWidth(theWidth);
340   }
341   return isChanged;
342 }
343
344 bool GeomAPI_AISObject::setColor(int theR, int theG, int theB)
345 {
346   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
347   if (anAIS.IsNull())
348     return false;
349   Quantity_Color aColor(theR / 255., theG / 255., theB / 255., Quantity_TOC_RGB);
350   Quantity_Color aCurrentColor;
351   anAIS->Color(aCurrentColor);
352   // do not set the same color to the presentation
353   if (aColor.IsEqual(aCurrentColor))
354     return false;
355
356   Handle(AIS_Dimension) aDimAIS = Handle(AIS_Dimension)::DownCast(anAIS);
357   if (!aDimAIS.IsNull()) {
358     aDimAIS->DimensionAspect()->SetCommonColor(aColor);
359   }
360   Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
361   aContext->SetColor(anAIS, aColor, false);
362   return true;
363 }
364
365 void GeomAPI_AISObject::getColor(int& theR, int& theG, int& theB)
366 {
367   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
368   if (anAIS.IsNull())
369     return;
370
371   Quantity_Color aColor = anAIS->Color();
372   theR = (int)(aColor.Red()*255.);
373   theG = (int)(aColor.Green()*255.);
374   theB = (int)(aColor.Blue()*255.);
375 }
376
377 bool GeomAPI_AISObject::empty() const
378 {
379   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
380       ->impl<Handle(AIS_InteractiveObject)>();
381   if (anAIS.IsNull())
382     return true;
383   return false;
384 }
385
386 int GeomAPI_AISObject::getShapeType() const
387 {
388   Handle(AIS_InteractiveObject) anAIS = const_cast<GeomAPI_AISObject*>(this)
389       ->impl<Handle(AIS_InteractiveObject)>();
390   if (!anAIS.IsNull()) {
391     Handle(AIS_Shape) aAISShape = Handle(AIS_Shape)::DownCast(anAIS);
392     if (!aAISShape.IsNull()) {
393       const TopoDS_Shape aShape = aAISShape->Shape();
394       if (!aShape.IsNull())
395         return aShape.ShapeType();
396     }
397   }
398   return -1;
399 }
400
401 void GeomAPI_AISObject::setPointMarker(int theType, double theScale)
402 {
403   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
404   if (!anAIS.IsNull()) {
405     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
406     if (aDrawer->HasOwnPointAspect()) {
407       Handle(Prs3d_PointAspect) aPA = aDrawer->PointAspect();
408       aPA->SetTypeOfMarker((Aspect_TypeOfMarker)theType);
409       aPA->SetScale(theScale);
410     } else {
411       Quantity_NameOfColor aCol = Quantity_NOC_YELLOW;
412       aDrawer->SetPointAspect(new Prs3d_PointAspect((Aspect_TypeOfMarker)theType, aCol, theScale));
413     }
414   }
415 }
416
417 bool GeomAPI_AISObject::setLineStyle(int theStyle)
418 {
419   bool isChanged = false;
420   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
421   if (!anAIS.IsNull()) {
422     Handle(Prs3d_Drawer) aDrawer = anAIS->Attributes();
423     Handle(Prs3d_LineAspect) aLineAspect;
424
425     Aspect_TypeOfLine aType = (Aspect_TypeOfLine)theStyle;
426     if (aDrawer->HasOwnLineAspect()) {
427       aLineAspect = aDrawer->LineAspect();
428     }
429     if (aDrawer->HasOwnWireAspect()) {
430       aLineAspect = aDrawer->WireAspect();
431     }
432     Quantity_Color aCurrentColor;
433     Aspect_TypeOfLine aCurrentType;
434     Standard_Real aCurrentWidth;
435     aLineAspect->Aspect()->Values(aCurrentColor, aCurrentType, aCurrentWidth);
436     isChanged = aType != aCurrentType;
437     if (isChanged) {
438       aLineAspect->SetTypeOfLine(aType);
439     }
440   }
441   return isChanged;
442 }
443
444 bool GeomAPI_AISObject::setTransparensy(double theVal)
445 {
446   bool isChanged = false;
447   Handle(AIS_InteractiveObject) anAIS = impl<Handle(AIS_InteractiveObject)>();
448   if (!anAIS.IsNull()) {
449     Handle(AIS_InteractiveContext) aContext = anAIS->GetContext();
450     if (!aContext.IsNull()) {
451       double aCurrentValue = anAIS->Transparency();
452       isChanged = aCurrentValue != theVal;
453       if (isChanged)
454         aContext->SetTransparency(anAIS, theVal, false);
455     } else {
456       anAIS->SetTransparency(theVal);
457     }
458   }
459  return isChanged;
460 }