Salome HOME
Get rid of compilation warnings. Part I.
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroCircle.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SketchPlugin_MacroCircle.h"
21
22 #include "SketchPlugin_Circle.h"
23 #include "SketchPlugin_Point.h"
24 #include "SketchPlugin_Tools.h"
25 #include "SketchPlugin_MacroArcReentrantMessage.h"
26
27 #include <ModelAPI_AttributeDouble.h>
28 #include <ModelAPI_AttributeRefAttr.h>
29 #include <ModelAPI_AttributeString.h>
30 #include <ModelAPI_Session.h>
31 #include <ModelAPI_Validator.h>
32 #include <ModelAPI_Events.h>
33
34 #include <GeomDataAPI_Dir.h>
35 #include <GeomDataAPI_Point2D.h>
36
37 #include <GeomAPI_Circ2d.h>
38 #include <GeomAPI_Pnt2d.h>
39 #include <GeomAPI_Vertex.h>
40
41 #include <GeomAlgoAPI_Circ2dBuilder.h>
42 #include <GeomAlgoAPI_CompoundBuilder.h>
43 #include <GeomAlgoAPI_EdgeBuilder.h>
44 #include <GeomAlgoAPI_PointBuilder.h>
45
46
47 const double tolerance = 1e-7;
48
49 namespace {
50   static const std::string& POINT_ID(int theIndex)
51   {
52     switch (theIndex) {
53       case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
54       case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
55       case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
56     }
57
58     static const std::string DUMMY;
59     return DUMMY;
60   }
61 }
62
63
64 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
65 : SketchPlugin_SketchEntity(),
66   myRadius(0.0)
67 {
68 }
69
70 void SketchPlugin_MacroCircle::initAttributes()
71 {
72   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
73   data()->addAttribute(EDIT_CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
74
75   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
76   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
77   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
78   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
79
80   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
81   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
82   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
83   data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
84   data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
85   data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
86
87   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
88   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
89
90   string(EDIT_CIRCLE_TYPE())->setValue("");
91
92   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
93   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
94   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
95   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
96   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
97   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE());
98 }
99
100 void SketchPlugin_MacroCircle::execute()
101 {
102   FeaturePtr aCircle = createCircleFeature();
103
104   std::string aType = string(CIRCLE_TYPE())->value();
105   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
106     constraintsForCircleByCenterAndPassed(aCircle);
107   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
108     constraintsForCircleByThreePoints(aCircle);
109
110   // message to init reentrant operation
111   static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
112   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
113     <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
114
115   std::string anEditType = string(EDIT_CIRCLE_TYPE())->value();
116   aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
117   aMessage->setCreatedFeature(aCircle);
118   Events_Loop::loop()->send(aMessage);
119 }
120
121 // LCOV_EXCL_START
122 std::string SketchPlugin_MacroCircle::processEvent(
123                                               const std::shared_ptr<Events_Message>& theMessage)
124 {
125   std::string aFilledAttributeName;
126   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
127         std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
128   if (aReentrantMessage.get()) {
129     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
130     std::string aCircleType = aReentrantMessage->typeOfCreation();
131
132     string(CIRCLE_TYPE())->setValue(aCircleType);
133
134     aFilledAttributeName = CIRCLE_TYPE();
135     ObjectPtr anObject = aReentrantMessage->selectedObject();
136     AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
137     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
138
139     if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
140       std::string aReferenceAttributeName;
141       if (aCircleType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
142         aFilledAttributeName = CENTER_POINT_ID();
143         aReferenceAttributeName = CENTER_POINT_REF_ID();
144       }
145       else {
146         aFilledAttributeName = FIRST_POINT_ID();
147         aReferenceAttributeName = FIRST_POINT_REF_ID();
148       }
149       // fill 2d point attribute
150       AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
151                                                         attribute(aFilledAttributeName));
152       aPointAttr->setValue(aClickedPoint);
153       // fill reference attribute
154       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
155                                                         attribute(aReferenceAttributeName));
156       if (aRefAttr.get()) {
157         if (anAttribute.get()) {
158           if (!anAttribute->owner().get() || !anAttribute->owner()->data()->isValid()) {
159             FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
160             if (aCreatedFeature.get()) {
161               std::string anID = anAttribute->id();
162               std::string anArcID;
163               if (anID == CENTER_POINT_ID())
164                 anArcID = SketchPlugin_Circle::CENTER_ID();
165               anAttribute = aCreatedFeature->attribute(anArcID);
166             }
167           }
168           aRefAttr->setAttr(anAttribute);
169         }
170         else if (anObject.get()) {
171           // if attribute is NULL, only object is defined, it should be processed outside
172           // the feature because it might be an external feature, that will be
173           // removed/created again after restart operation
174           // #2468 - Crash when sketching circles successively on a repetition
175           aFilledAttributeName = CIRCLE_TYPE();
176         }
177       }
178     }
179     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
180   }
181   return aFilledAttributeName;
182 }
183 // LCOV_EXCL_STOP
184
185 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
186 {
187   // Create constraints.
188   SketchPlugin_Tools::createCoincidenceOrTangency(
189       this, CENTER_POINT_REF_ID(),
190       theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
191       ObjectPtr(), false);
192   SketchPlugin_Tools::createCoincidenceOrTangency(
193       this, PASSED_POINT_REF_ID(), AttributePtr(),
194       theCircleFeature->lastResult(), true);
195 }
196
197 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
198 {
199   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
200                                SECOND_POINT_REF_ID(),
201                                THIRD_POINT_REF_ID() };
202
203   // Create constraints.
204   ResultPtr aCircleResult = theCircleFeature->lastResult();
205   for (int i = 0; i < 3; ++i) {
206     SketchPlugin_Tools::createCoincidenceOrTangency(
207         this, aPointRef[i], AttributePtr(), aCircleResult, true);
208   }
209 }
210
211 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
212 {
213   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
214   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
215       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
216                                                                              myCenter->y());
217   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
218   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
219                 ->setValue(boolean(AUXILIARY_ID())->value());
220   aCircleFeature->execute();
221   return aCircleFeature;
222 }
223
224 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
225 {
226   AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
227   AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
228   if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
229     return;
230
231   // Calculate circle parameters
232   AttributeRefAttrPtr aCenterRef = refattr(CENTER_POINT_REF_ID());
233   std::shared_ptr<GeomAPI_Pnt2d> aCenter;
234   std::shared_ptr<GeomAPI_Shape> aCurve;
235   SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
236       aCenterRef, aCenterAttr, aCurve, aCenter);
237   if (!aCenter)
238     aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
239   AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
240   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
241   std::shared_ptr<GeomAPI_Shape> aTangentCurve;
242   SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
243       aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
244
245   // Build a circle
246   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
247   aCircBuilder.setCenter(aCenter);
248   if (aTangentCurve) {
249     aCircBuilder.addTangentCurve(aTangentCurve);
250
251     AttributePoint2DPtr aPassedPntAttr =
252         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
253     if (aPassedPntAttr)
254       aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
255   } else
256     aCircBuilder.addPassingPoint(aPassedPoint);
257
258   std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
259   if (aCircle) {
260     myCenter = aCircle->center();
261     myRadius = aCircle->radius();
262   }
263 }
264
265 void SketchPlugin_MacroCircle::fillByThreePoints()
266 {
267   std::string aPointAttr[3] = { FIRST_POINT_ID(),
268                                 SECOND_POINT_ID(),
269                                 THIRD_POINT_ID() };
270   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
271                                SECOND_POINT_REF_ID(),
272                                THIRD_POINT_REF_ID() };
273
274   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
275
276   for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
277     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
278     if (!aPassedAttr->isInitialized())
279       break;
280
281     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
282     // calculate circle parameters
283     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
284     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
285     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
286         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
287
288     if (aPassedPoint)
289       aCircBuilder.addPassingPoint(aPassedPoint);
290     else {
291       aCircBuilder.addTangentCurve(aTangentCurve);
292       AttributePoint2DPtr aPassedPoint =
293           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
294       if (aPassedPoint)
295         aCircBuilder.setClosestPoint(aPassedPoint->pnt());
296     }
297   }
298
299   std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
300   if (aCircle) {
301     myCenter = aCircle->center();
302     myRadius = aCircle->radius();
303   }
304 }
305
306 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
307 {
308   std::string aPointAttr[2] = { FIRST_POINT_ID(),
309                                 SECOND_POINT_ID() };
310   std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
311                                SECOND_POINT_REF_ID() };
312
313   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
314
315   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
316   bool hasTangentCurve = false;
317   int aPntIndex = 0;
318   for (; aPntIndex < 2; ++aPntIndex) {
319     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
320     if (!aPassedAttr->isInitialized())
321       break;
322
323     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
324     // calculate circle parameters
325     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
326     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
327     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
328         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
329
330     if (aPassedPoint) {
331       aCircBuilder.addPassingPoint(aPassedPoint);
332       aPassedPoints[aPntIndex] = aPassedPoint;
333     } else {
334       hasTangentCurve = true;
335       aCircBuilder.addTangentCurve(aTangentCurve);
336       // if the circle is tangent to any curve,
337       // the third point will be initialized by the tangent point
338       aCircBuilder.addPassingPoint(
339           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
340     }
341   }
342   if (aPntIndex <= 1)
343     return;
344
345   std::shared_ptr<GeomAPI_Circ2d> aCircle;
346
347   if (hasTangentCurve)
348     aCircle = aCircBuilder.circle();
349   else {
350     // the circle is defined by two points, calculate its parameters manually
351     std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
352         (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
353         (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
354     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
355   }
356
357   if (aCircle) {
358     myCenter = aCircle->center();
359     myRadius = aCircle->radius();
360   }
361 }
362
363 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
364 {
365   SketchPlugin_Sketch* aSketch = sketch();
366   if(!aSketch || !myCenter || myRadius == 0) {
367     return AISObjectPtr();
368   }
369
370   // Compute a circle in 3D view.
371   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
372   std::shared_ptr<GeomDataAPI_Dir> aNDir =
373       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
374           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
375   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
376   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
377   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
378   if(!aCircleShape.get() || !aCenterPointShape.get()) {
379     return AISObjectPtr();
380   }
381
382   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
383   aShapes.push_back(aCircleShape);
384   aShapes.push_back(aCenterPointShape);
385
386   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
387   AISObjectPtr anAIS = thePrevious;
388   if(!anAIS.get()) {
389     anAIS.reset(new GeomAPI_AISObject());
390   }
391   anAIS->createShape(aCompound);
392
393   // Modify attributes
394   SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
395
396   return anAIS;
397 }
398
399 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
400   // If circle type switched reset all attributes.
401   if(theID == CIRCLE_TYPE()) {
402     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
403     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
404     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
405     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
406     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
407     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
408     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
409     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
410     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
411     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
412   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
413             theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
414     fillByCenterAndPassed();
415   else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
416           theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
417           theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
418     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
419     int aNbInitialized = 0;
420     for(int i = 1; i <= 3; ++i) {
421       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
422           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
423       if(aCurPnt->isInitialized())
424         aPoints[aNbInitialized++] = aCurPnt->pnt();
425     }
426
427     if(aNbInitialized == 1)
428       return;
429     else if(aNbInitialized == 2)
430       fillByTwoPassedPoints();
431     else
432       fillByThreePoints();
433   }
434
435   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
436   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
437   if(myCenter.get()) {
438     // center attribute is used in processEvent() to set reference to reentrant arc
439     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))
440         ->setValue(myCenter);
441   }
442   aRadiusAttr->setValue(myRadius);
443   data()->blockSendAttributeUpdated(aWasBlocked, false);
444 }