Salome HOME
b865ec374d61420e52b206ee2984e08d2e79c00d
[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 #include "SketchPlugin_MacroArcReentrantMessage.h"
13
14 #include <ModelAPI_AttributeDouble.h>
15 #include <ModelAPI_AttributeRefAttr.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_Session.h>
18 #include <ModelAPI_Validator.h>
19 #include <ModelAPI_Events.h>
20
21 #include <GeomDataAPI_Dir.h>
22 #include <GeomDataAPI_Point2D.h>
23
24 #include <GeomAPI_Circ2d.h>
25 #include <GeomAPI_Pnt2d.h>
26 #include <GeomAPI_Vertex.h>
27
28 #include <GeomAlgoAPI_CompoundBuilder.h>
29 #include <GeomAlgoAPI_EdgeBuilder.h>
30 #include <GeomAlgoAPI_PointBuilder.h>
31
32
33 const double tolerance = 1e-7;
34
35 namespace {
36   static const std::string& POINT_ID(int theIndex)
37   {
38     switch (theIndex) {
39       case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
40       case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
41       case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
42     }
43
44     static const std::string DUMMY;
45     return DUMMY;
46   }
47 }
48
49
50 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
51 : SketchPlugin_SketchEntity(),
52   myRadius(0.0)
53 {
54 }
55
56 void SketchPlugin_MacroCircle::initAttributes()
57 {
58   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
59   data()->addAttribute(EDIT_CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
60
61   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
62   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
63   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
64   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
65
66   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
67   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
68   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
69   data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
70   data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71   data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72
73   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
74   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
75
76   string(EDIT_CIRCLE_TYPE())->setValue("");
77
78   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
79   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
80   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
82   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
83   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE());
84 }
85
86 void SketchPlugin_MacroCircle::execute()
87 {
88   FeaturePtr aCircle = createCircleFeature();
89
90   std::string aType = string(CIRCLE_TYPE())->value();
91   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
92     constraintsForCircleByCenterAndPassed(aCircle);
93   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
94     constraintsForCircleByThreePoints(aCircle);
95
96   // message to init reentrant operation
97   static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
98   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
99     <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, 0));
100
101   std::string anEditType = string(EDIT_CIRCLE_TYPE())->value();
102   aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
103   aMessage->setCreatedFeature(aCircle);
104   Events_Loop::loop()->send(aMessage);
105   Events_Loop::loop()->flush(anId);
106 }
107
108 std::string SketchPlugin_MacroCircle::processEvent(const std::shared_ptr<Events_Message>& theMessage)
109 {
110   std::string aFilledAttributeName;
111   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
112         std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
113   if (aReentrantMessage.get()) {
114     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
115     std::string aCircleType = aReentrantMessage->typeOfCreation();
116
117     string(CIRCLE_TYPE())->setValue(aCircleType);
118
119     aFilledAttributeName = CIRCLE_TYPE();
120     ObjectPtr anObject = aReentrantMessage->selectedObject();
121     AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
122     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
123
124     if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
125       std::string aReferenceAttributeName;
126       if (aCircleType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
127         aFilledAttributeName = CENTER_POINT_ID();
128         aReferenceAttributeName = CENTER_POINT_REF_ID();
129       }
130       else {
131         aFilledAttributeName = FIRST_POINT_ID();
132         aReferenceAttributeName = FIRST_POINT_REF_ID();
133       }
134       // fill 2d point attribute
135       AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
136                                                         attribute(aFilledAttributeName));
137       aPointAttr->setValue(aClickedPoint);
138       // fill reference attribute
139       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
140                                                         attribute(aReferenceAttributeName));
141       if (aRefAttr.get()) {
142         if (anAttribute.get())
143           aRefAttr->setAttr(anAttribute);
144         else if (anObject.get()) {
145           // if presentation of previous reentrant macro arc is used, the object is invalid,
146           // we should use result of previous feature of the message(Arc)
147           if (!anObject->data()->isValid()) {
148             FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
149             anObject = aCreatedFeature->lastResult();
150           }
151           aRefAttr->setObject(anObject);
152         }
153       }
154     }
155     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
156   }
157   return aFilledAttributeName;
158 }
159
160 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
161 {
162   // Create constraints.
163   SketchPlugin_Tools::createConstraint(
164       this, CENTER_POINT_REF_ID(),
165       theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
166       ObjectPtr(), false);
167   SketchPlugin_Tools::createConstraint(
168       this, PASSED_POINT_REF_ID(), AttributePtr(),
169       theCircleFeature->lastResult(), true);
170 }
171
172 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
173 {
174   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
175                                SECOND_POINT_REF_ID(),
176                                THIRD_POINT_REF_ID() };
177
178   // Create constraints.
179   ResultPtr aCircleResult = theCircleFeature->lastResult();
180   for (int i = 0; i < 3; ++i)
181     SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
182 }
183
184 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
185 {
186   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
187   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
188       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
189                                                                              myCenter->y());
190   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
191   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
192                 ->setValue(boolean(AUXILIARY_ID())->value());
193   aCircleFeature->execute();
194   return aCircleFeature;
195 }
196
197 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
198 {
199   AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
200   AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
201   if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
202     return;
203
204   AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
205   // Calculate circle parameters
206   std::shared_ptr<GeomAPI_Pnt2d> aCenter =
207       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
208   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
209   std::shared_ptr<GeomAPI_Shape> aTangentCurve;
210   SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
211       aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
212
213   // Build a circle
214   std::shared_ptr<GeomAPI_Circ2d> aCircle;
215   if (aTangentCurve) {
216     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
217     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
218   } else
219     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
220   if (aCircle->implPtr<char>()) {
221     myCenter = aCircle->center();
222     myRadius = aCircle->radius();
223   }
224 }
225
226 void SketchPlugin_MacroCircle::fillByThreePoints()
227 {
228   std::string aPointAttr[3] = { FIRST_POINT_ID(),
229                                 SECOND_POINT_ID(),
230                                 THIRD_POINT_ID() };
231   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
232                                SECOND_POINT_REF_ID(),
233                                THIRD_POINT_REF_ID() };
234   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
235   for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
236     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
237     if (!aPassedAttr->isInitialized())
238       break;
239
240     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
241     // calculate circle parameters
242     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
243     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
244     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
245         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
246
247     if (aPassedPoint)
248       aPassedEntities[aPntIndex] = aPassedPoint;
249     else
250       aPassedEntities[aPntIndex] = aTangentCurve;
251   }
252
253   std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
254   std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
255       new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
256   if (aCircle->implPtr<char>()) {
257     myCenter = aCircle->center();
258     myRadius = aCircle->radius();
259   }
260 }
261
262 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
263 {
264   std::string aPointAttr[2] = { FIRST_POINT_ID(),
265                                 SECOND_POINT_ID() };
266   std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
267                                SECOND_POINT_REF_ID() };
268   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
269   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
270   int aPntIndex = 0;
271   for (; aPntIndex < 2; ++aPntIndex) {
272     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
273     if (!aPassedAttr->isInitialized())
274       break;
275
276     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
277     // calculate circle parameters
278     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
279     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
280     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
281         aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
282
283     if (aPassedPoint) {
284       aPassedEntities[aPntIndex] = aPassedPoint;
285       aPassedPoints[aPntIndex] = aPassedPoint;
286     } else {
287       aPassedEntities[aPntIndex] = aTangentCurve;
288       // if the circle is tangent to any curve,
289       // the third point will be initialized by the tangent point
290       aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
291     }
292   }
293   if (aPntIndex <= 1)
294     return;
295
296   std::shared_ptr<GeomAPI_Circ2d> aCircle;
297   if (aPassedEntities[2]) {
298     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
299     aCircle = std::shared_ptr<GeomAPI_Circ2d>(
300         new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
301   } else {
302     // the circle is defined by two points, calculate its parameters manually
303     std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
304         (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
305         (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
306     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
307   }
308   if (aCircle->implPtr<char>()) {
309     myCenter = aCircle->center();
310     myRadius = aCircle->radius();
311   }
312 }
313
314 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
315 {
316   SketchPlugin_Sketch* aSketch = sketch();
317   if(!aSketch || !myCenter || myRadius == 0) {
318     return AISObjectPtr();
319   }
320
321   // Compute a circle in 3D view.
322   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
323   std::shared_ptr<GeomDataAPI_Dir> aNDir =
324       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
325           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
326   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
327   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
328   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
329   if(!aCircleShape.get() || !aCenterPointShape.get()) {
330     return AISObjectPtr();
331   }
332
333   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
334   aShapes.push_back(aCircleShape);
335   aShapes.push_back(aCenterPointShape);
336
337   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
338   AISObjectPtr anAIS = thePrevious;
339   if(!anAIS.get()) {
340     anAIS.reset(new GeomAPI_AISObject());
341   }
342   anAIS->createShape(aCompound);
343   return anAIS;
344 }
345
346 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
347   double aRadius = 0.0;
348   // If circle type switched reset all attributes.
349   if(theID == CIRCLE_TYPE()) {
350     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
351     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
352     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
353     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
354     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
355     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
356     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
357     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
358     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
359     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
360   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
361             theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
362     fillByCenterAndPassed();
363   else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
364           theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
365           theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
366     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
367     int aNbInitialized = 0;
368     for(int i = 1; i <= 3; ++i) {
369       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
370           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
371       if(aCurPnt->isInitialized())
372         aPoints[aNbInitialized++] = aCurPnt->pnt();
373     }
374
375     if(aNbInitialized == 1)
376       return;
377     else if(aNbInitialized == 2)
378       fillByTwoPassedPoints();
379     else
380       fillByThreePoints();
381   }
382
383   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
384   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
385   aRadiusAttr->setValue(myRadius);
386   data()->blockSendAttributeUpdated(aWasBlocked, false);
387 }