Salome HOME
Issue #2066: crash when create Circle with Origin of coordinate sustem selected as...
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroCircle.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_MacroCircle.cpp
4 // Created:     26 May 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_MacroCircle.h"
8
9 #include "SketchPlugin_Circle.h"
10 #include "SketchPlugin_Point.h"
11 #include "SketchPlugin_Tools.h"
12
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeRefAttr.h>
15 #include <ModelAPI_AttributeString.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
18
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point2D.h>
21
22 #include <GeomAPI_Circ2d.h>
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Vertex.h>
25
26 #include <GeomAlgoAPI_CompoundBuilder.h>
27 #include <GeomAlgoAPI_EdgeBuilder.h>
28 #include <GeomAlgoAPI_PointBuilder.h>
29
30
31 const double tolerance = 1e-7;
32
33 namespace {
34   static const std::string& POINT_ID(int theIndex)
35   {
36     switch (theIndex) {
37       case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
38       case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
39       case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
40     }
41
42     static const std::string DUMMY;
43     return DUMMY;
44   }
45 }
46
47
48 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
49 : SketchPlugin_SketchEntity()
50 {
51 }
52
53 void SketchPlugin_MacroCircle::initAttributes()
54 {
55   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
56
57   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
58   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
59   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
60   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
61
62   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
63   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
64   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
65   data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66   data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
67   data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
68
69   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
70   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
71
72   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
73   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
74   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
75   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
76   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
77 }
78
79 void SketchPlugin_MacroCircle::execute()
80 {
81   std::string aType = string(CIRCLE_TYPE())->value();
82   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
83     createCircleByCenterAndPassed();
84   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
85     createCircleByThreePoints();
86 }
87
88 void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
89 {
90   // Create circle feature.
91   std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByCenterAndPassed();
92   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
93
94   // Create constraints.
95   SketchPlugin_Tools::createConstraint(this,
96                                        CENTER_POINT_REF_ID(),
97                                        aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
98                                        ObjectPtr(),
99                                        false);
100   SketchPlugin_Tools::createConstraint(this,
101                                        PASSED_POINT_REF_ID(),
102                                        AttributePtr(),
103                                        aCircleFeature->lastResult(),
104                                        true);
105 }
106
107 void SketchPlugin_MacroCircle::createCircleByThreePoints()
108 {
109   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
110                                SECOND_POINT_REF_ID(),
111                                THIRD_POINT_REF_ID() };
112
113   // Create circle feature.
114   std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByThreePoints();
115   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
116   ResultPtr aCircleResult = aCircleFeature->lastResult();
117
118   // Create constraints.
119   for (int i = 0; i < 3; ++i)
120     SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
121 }
122
123 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
124     const std::shared_ptr<GeomAPI_Circ2d>& theCircle)
125 {
126   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
127   std::shared_ptr<GeomAPI_Pnt2d> aCenter = theCircle->center();
128   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
129       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCenter->x(),
130                                                                              aCenter->y());
131   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(theCircle->radius());
132   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
133                 ->setValue(boolean(AUXILIARY_ID())->value());
134   aCircleFeature->execute();
135   return aCircleFeature;
136 }
137
138 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByCenterAndPassed()
139 {
140   AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
141   AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
142   if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
143     return std::shared_ptr<GeomAPI_Circ2d>();
144
145   AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
146   // Calculate circle parameters
147   std::shared_ptr<GeomAPI_Pnt2d> aCenter =
148       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
149   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
150   std::shared_ptr<GeomAPI_Shape> aTangentCurve;
151   SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
152       aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
153
154   // Build a circle
155   std::shared_ptr<GeomAPI_Circ2d> aCircle;
156   if (aTangentCurve) {
157     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
158     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
159   } else
160     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
161   return aCircle;
162 }
163
164 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByThreePoints()
165 {
166   std::string aPointAttr[3] = { FIRST_POINT_ID(),
167                                 SECOND_POINT_ID(),
168                                 THIRD_POINT_ID() };
169   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
170                                SECOND_POINT_REF_ID(),
171                                THIRD_POINT_REF_ID() };
172   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
173   for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
174     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
175     if (!aPassedAttr->isInitialized())
176       break;
177
178     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
179     // calculate circle parameters
180     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
181     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
182     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
183         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
184
185     if (aPassedPoint)
186       aPassedEntities[aPntIndex] = aPassedPoint;
187     else
188       aPassedEntities[aPntIndex] = aTangentCurve;
189   }
190
191   std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
192   std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
193       new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
194   if (!aCircle->implPtr<char>())
195     return std::shared_ptr<GeomAPI_Circ2d>();
196   return aCircle;
197 }
198
199 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByTwoPassedPoints()
200 {
201   std::string aPointAttr[2] = { FIRST_POINT_ID(),
202                                 SECOND_POINT_ID() };
203   std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
204                                SECOND_POINT_REF_ID() };
205   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
206   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
207   int aPntIndex = 0;
208   for (; aPntIndex < 2; ++aPntIndex) {
209     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
210     if (!aPassedAttr->isInitialized())
211       break;
212
213     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
214     // calculate circle parameters
215     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
216     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
217     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
218         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
219
220     if (aPassedPoint) {
221       aPassedEntities[aPntIndex] = aPassedPoint;
222       aPassedPoints[aPntIndex] = aPassedPoint;
223     } else {
224       aPassedEntities[aPntIndex] = aTangentCurve;
225       // if the circle is tangent to any curve,
226       // the third point will be initialized by the tangent point
227       aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
228     }
229   }
230   if (aPntIndex <= 1)
231     return std::shared_ptr<GeomAPI_Circ2d>();
232
233   std::shared_ptr<GeomAPI_Circ2d> aCircle;
234   if (aPassedEntities[2]) {
235     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
236     aCircle = std::shared_ptr<GeomAPI_Circ2d>(
237         new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
238   } else {
239     // the circle is defined by two points, calculate its parameters manually
240     std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
241         (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
242         (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
243     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
244   }
245   if (!aCircle->implPtr<char>())
246     return std::shared_ptr<GeomAPI_Circ2d>();
247   return aCircle;
248 }
249
250 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
251 {
252   SketchPlugin_Sketch* aSketch = sketch();
253   if(!aSketch) {
254     return AISObjectPtr();
255   }
256
257   // Create circle on the sketch plane
258   std::shared_ptr<GeomAPI_Circ2d> aCircleOnSketch;
259   std::string aType = string(CIRCLE_TYPE())->value();
260   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
261     aCircleOnSketch = shapeByCenterAndPassed();
262   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
263     if (attribute(THIRD_POINT_ID())->isInitialized())
264       aCircleOnSketch = shapeByThreePoints();
265     else
266       aCircleOnSketch = shapeByTwoPassedPoints();
267   }
268
269   if (!aCircleOnSketch)
270     return AISObjectPtr();
271
272   std::shared_ptr<GeomAPI_Pnt2d> aCenter2D = aCircleOnSketch->center();
273   if(!aCenter2D.get())
274     return AISObjectPtr();
275   double aRadius = aCircleOnSketch->radius();
276
277   // Compute a circle in 3D view.
278   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenter2D->x(), aCenter2D->y()));
279   std::shared_ptr<GeomDataAPI_Dir> aNDir =
280       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
281           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
282   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
283   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius);
284   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
285   if(!aCircleShape.get() || !aCenterPointShape.get()) {
286     return AISObjectPtr();
287   }
288
289   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
290   aShapes.push_back(aCircleShape);
291   aShapes.push_back(aCenterPointShape);
292
293   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
294   AISObjectPtr anAIS = thePrevious;
295   if(!anAIS.get()) {
296     anAIS.reset(new GeomAPI_AISObject());
297   }
298   anAIS->createShape(aCompound);
299   return anAIS;
300 }
301
302 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
303   double aRadius = 0.0;
304   // If circle type switched reset all attributes.
305   if(theID == CIRCLE_TYPE()) {
306     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
307     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
308     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
309     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
310     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
311     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
312     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
313     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
314     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
315     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
316   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
317     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
318         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
319     if(!aCenterPointAttr->isInitialized()) {
320       return;
321     }
322     std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
323         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
324     if(!aPassedPointAttr->isInitialized()) {
325       return;
326     }
327
328     aRadius = aCenterPointAttr->pnt()->distance(aPassedPointAttr->pnt());
329   } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
330     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
331     int aNbInitialized = 0;
332     for(int i = 1; i <= 3; ++i) {
333       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
334           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
335       if(aCurPnt->isInitialized())
336         aPoints[aNbInitialized++] = aCurPnt->pnt();
337     }
338
339     std::shared_ptr<GeomAPI_Circ2d> aCircle;
340     if(aNbInitialized == 1)
341       return;
342     else if(aNbInitialized == 2)
343       aCircle = shapeByTwoPassedPoints();
344     else
345       aCircle = shapeByThreePoints();
346     if (aCircle)
347       aRadius = aCircle->radius();
348   }
349
350   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
351   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
352   aRadiusAttr->setValue(aRadius);
353   data()->blockSendAttributeUpdated(aWasBlocked, false);
354 }