]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_MacroEllipse.cpp
Salome HOME
Fix problem with sequential drawing of ellipses.
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroEllipse.cpp
1 // Copyright (C) 2017-2019  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_MacroEllipse.h>
21
22 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
23 #include <SketchPlugin_Ellipse.h>
24 #include <SketchPlugin_Line.h>
25 #include <SketchPlugin_MacroArcReentrantMessage.h>
26 #include <SketchPlugin_Point.h>
27 #include <SketchPlugin_Tools.h>
28 #include <SketchPlugin_Sketch.h>
29
30 #include <ModelAPI_AttributeDouble.h>
31 #include <ModelAPI_AttributeRefAttr.h>
32 #include <ModelAPI_AttributeString.h>
33 #include <ModelAPI_Session.h>
34 #include <ModelAPI_Validator.h>
35 #include <ModelAPI_Events.h>
36
37 #include <GeomDataAPI_Point2D.h>
38
39 #include <GeomAPI_Dir2d.h>
40 #include <GeomAPI_Ellipse2d.h>
41 #include <GeomAPI_Vertex.h>
42
43 #include <GeomAlgoAPI_CompoundBuilder.h>
44 #include <GeomAlgoAPI_EdgeBuilder.h>
45 #include <GeomAlgoAPI_PointBuilder.h>
46
47
48 SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
49 : SketchPlugin_SketchEntity(),
50   myMajorRadius(0.0),
51   myMinorRadius(0.0)
52 {
53 }
54
55 void SketchPlugin_MacroEllipse::initAttributes()
56 {
57   data()->addAttribute(ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId());
58   data()->addAttribute(EDIT_ELLIPSE_TYPE(), ModelAPI_AttributeString::typeId());
59
60   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
61   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
62   data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
63   data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
64   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
65   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66
67   data()->addAttribute(MAJOR_AXIS_START_ID(), GeomDataAPI_Point2D::typeId());
68   data()->addAttribute(MAJOR_AXIS_START_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
69   data()->addAttribute(MAJOR_AXIS_END_ID(), GeomDataAPI_Point2D::typeId());
70   data()->addAttribute(MAJOR_AXIS_END_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71   data()->addAttribute(PASSED_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
72   data()->addAttribute(PASSED_POINT_1_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73
74   data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
75   data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
76   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
77
78   string(EDIT_ELLIPSE_TYPE())->setValue("");
79
80   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID());
82   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
83   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_START_REF_ID());
84   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_END_REF_ID());
85   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_1_REF_ID());
86   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_ELLIPSE_TYPE());
87 }
88
89 void SketchPlugin_MacroEllipse::execute()
90 {
91   FeaturePtr anEllipse = createEllipseFeature();
92
93   std::string aType = string(ELLIPSE_TYPE())->value();
94   if (aType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT())
95     constraintsForEllipseByCenterAxisAndPassed(anEllipse);
96   else if (aType == ELLIPSE_TYPE_BY_AXIS_AND_POINT())
97     constraintsForEllipseByMajoxAxisAndPassed(anEllipse);
98
99   // message to init reentrant operation
100   static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
101   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
102     <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
103
104   std::string anEditType = string(EDIT_ELLIPSE_TYPE())->value();
105   aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
106   aMessage->setCreatedFeature(anEllipse);
107   Events_Loop::loop()->send(aMessage);
108 }
109
110 void SketchPlugin_MacroEllipse::attributeChanged(const std::string& theID)
111 {
112   static const int NB_POINTS = 3;
113   std::string aPointAttrName[NB_POINTS];
114   std::string aPointRefName[NB_POINTS];
115   if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT()) {
116     aPointAttrName[0] = CENTER_POINT_ID();
117     aPointAttrName[1] = MAJOR_AXIS_POINT_ID();
118     aPointAttrName[2] = PASSED_POINT_ID();
119     aPointRefName[0] = CENTER_POINT_REF_ID();
120     aPointRefName[1] = MAJOR_AXIS_POINT_REF_ID();
121     aPointRefName[2] = PASSED_POINT_REF_ID();
122   } else if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
123     aPointAttrName[0] = MAJOR_AXIS_START_ID();
124     aPointAttrName[1] = MAJOR_AXIS_END_ID();
125     aPointAttrName[2] = PASSED_POINT_1_ID();
126     aPointRefName[0] = MAJOR_AXIS_START_REF_ID();
127     aPointRefName[1] = MAJOR_AXIS_END_REF_ID();
128     aPointRefName[2] = PASSED_POINT_1_REF_ID();
129   }
130   else
131     return;
132
133   // type of ellipse switched, thus reset all attributes
134   if (theID == ELLIPSE_TYPE()) {
135     for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
136       SketchPlugin_Tools::resetAttribute(this, aPointAttrName[aPntIndex]);
137       SketchPlugin_Tools::resetAttribute(this, aPointRefName[aPntIndex]);
138     }
139   }
140   else {
141     int aNbInitialized = 0;
142     GeomPnt2dPtr anEllipsePoints[NB_POINTS];
143
144     for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
145       AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
146       if (!aPointAttr->isInitialized())
147         continue;
148
149       AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
150       // calculate ellipse parameters
151       GeomPnt2dPtr aPassedPoint =
152           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr)->pnt();
153       GeomShapePtr aTangentCurve;
154       SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
155         aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
156
157       anEllipsePoints[aNbInitialized++] = aPassedPoint;
158     }
159
160     if (aNbInitialized <= 1)
161       return; // too few points for the ellipse
162
163     if (string(ELLIPSE_TYPE())->value() == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
164       // ellipse is given by major axis and passing point,
165       // recalculate the first point to be a center
166       anEllipsePoints[0]->setX(0.5 * (anEllipsePoints[0]->x() + anEllipsePoints[1]->x()));
167       anEllipsePoints[0]->setY(0.5 * (anEllipsePoints[0]->y() + anEllipsePoints[1]->y()));
168     }
169
170     std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
171     if (aNbInitialized == 2) {
172       GeomDir2dPtr aXDir(new GeomAPI_Dir2d(anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
173                                            anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
174       double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
175       anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
176           new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
177     }
178     else if (aNbInitialized == 3) {
179       anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
180         new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
181     }
182
183     if (!anEllipse || anEllipse->implPtr<void>() == 0)
184       return;
185
186     myCenter = anEllipse->center();
187     myFocus = anEllipse->firstFocus();
188     myMajorRadius = anEllipse->majorRadius();
189     myMinorRadius = anEllipse->minorRadius();
190
191     AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
192     AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
193
194     bool aWasBlocked = data()->blockSendAttributeUpdated(true);
195     aMajorRadiusAttr->setValue(myMajorRadius);
196     aMinorRadiusAttr->setValue(myMinorRadius);
197     data()->blockSendAttributeUpdated(aWasBlocked, false);
198   }
199 }
200
201 // LCOV_EXCL_START
202 std::string SketchPlugin_MacroEllipse::processEvent(
203                                               const std::shared_ptr<Events_Message>& theMessage)
204 {
205   std::string aFilledAttributeName;
206
207   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
208       std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
209   if (aReentrantMessage) {
210     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
211     std::string anEllipseType = aReentrantMessage->typeOfCreation();
212
213     string(ELLIPSE_TYPE())->setValue(anEllipseType);
214
215     aFilledAttributeName = ELLIPSE_TYPE();
216     ObjectPtr anObject = aReentrantMessage->selectedObject();
217     AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
218     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
219
220     if (aClickedPoint && (anObject || anAttribute)) {
221       aFilledAttributeName = CENTER_POINT_ID();
222       std::string aReferenceAttributeName = CENTER_POINT_REF_ID();
223       if (anEllipseType == ELLIPSE_TYPE_BY_AXIS_AND_POINT()) {
224         aFilledAttributeName = MAJOR_AXIS_START_ID();
225         aReferenceAttributeName = MAJOR_AXIS_START_REF_ID();
226       }
227
228       // fill 2d point attribute
229       AttributePoint2DPtr aPointAttr =
230           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(aFilledAttributeName));
231       aPointAttr->setValue(aClickedPoint);
232
233       // fill reference attribute
234       AttributeRefAttrPtr aRefAttr =
235           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(attribute(aReferenceAttributeName));
236       if (anAttribute) {
237         if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
238           if (aCreatedFeature && anAttribute->id() == CENTER_POINT_ID())
239             anAttribute = aCreatedFeature->attribute(
240                 anEllipseType == ELLIPSE_TYPE_BY_CENTER_AXIS_POINT() ?
241                 SketchPlugin_Ellipse::CENTER_ID() :
242                 SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
243         }
244         aRefAttr->setAttr(anAttribute);
245       }
246       else if (anObject.get()) {
247         // if attribute is NULL, only object is defined, it should be processed outside
248         // the feature because it might be an external feature, that will be
249         // removed/created again after restart operation
250         // #2468 - Crash when sketching circles successively on a repetition
251         aFilledAttributeName = ELLIPSE_TYPE();
252       }
253     }
254     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
255   }
256   return aFilledAttributeName;
257 }
258 // LCOV_EXCL_STOP
259
260 void SketchPlugin_MacroEllipse::constraintsForEllipseByCenterAxisAndPassed(
261     FeaturePtr theEllipseFeature)
262 {
263   // tangency on-the-fly is not applicable for ellipses
264   static const bool isTangencyApplicable = false;
265   // Create constraints.
266   SketchPlugin_Tools::createCoincidenceOrTangency(
267       this, CENTER_POINT_REF_ID(),
268       theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
269       ObjectPtr(), isTangencyApplicable);
270   SketchPlugin_Tools::createCoincidenceOrTangency(
271       this, MAJOR_AXIS_POINT_REF_ID(),
272       theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
273       ObjectPtr(), isTangencyApplicable);
274   // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
275   if (!refattr(PASSED_POINT_REF_ID())->isObject()) {
276     SketchPlugin_Tools::createCoincidenceOrTangency(
277         this, PASSED_POINT_REF_ID(), AttributePtr(),
278         theEllipseFeature->lastResult(), isTangencyApplicable);
279   }
280 }
281
282 void SketchPlugin_MacroEllipse::constraintsForEllipseByMajoxAxisAndPassed(
283     FeaturePtr theEllipseFeature)
284 {
285   // tangency on-the-fly is not applicable for ellipses
286   static const bool isTangencyApplicable = false;
287   // Create constraints.
288   SketchPlugin_Tools::createCoincidenceOrTangency(
289       this, MAJOR_AXIS_START_REF_ID(),
290       theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
291       ObjectPtr(), isTangencyApplicable);
292   SketchPlugin_Tools::createCoincidenceOrTangency(
293       this, MAJOR_AXIS_END_REF_ID(),
294       theEllipseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
295       ObjectPtr(), isTangencyApplicable);
296   // make coincidence only if PASSED_POINT_REF_ID() refers a point but not an object
297   if (!refattr(PASSED_POINT_1_REF_ID())->isObject()) {
298     SketchPlugin_Tools::createCoincidenceOrTangency(
299         this, PASSED_POINT_1_REF_ID(), AttributePtr(),
300         theEllipseFeature->lastResult(), isTangencyApplicable);
301   }
302 }
303
304 FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
305 {
306   FeaturePtr aEllipseFeature = sketch()->addFeature(SketchPlugin_Ellipse::ID());
307
308   AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
309       aEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()));
310   aCenterAttr->setValue(myCenter->x(), myCenter->y());
311
312   AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
313       aEllipseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
314   aFocusAttr->setValue(myFocus->x(), myFocus->y());
315
316   aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
317   aEllipseFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(myMinorRadius);
318
319   aEllipseFeature->boolean(SketchPlugin_Ellipse::AUXILIARY_ID())->setValue(
320       boolean(AUXILIARY_ID())->value());
321
322   aEllipseFeature->execute();
323
324   // create auxiliary points
325   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
326       aEllipseFeature, SketchPlugin_Ellipse::CENTER_ID());
327   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
328       aEllipseFeature, SketchPlugin_Ellipse::FIRST_FOCUS_ID());
329   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
330       aEllipseFeature, SketchPlugin_Ellipse::SECOND_FOCUS_ID());
331   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
332       aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_START_ID());
333   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
334       aEllipseFeature, SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
335   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
336       aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_START_ID());
337   SketchPlugin_Tools::createAuxiliaryPointOnEllipse(
338       aEllipseFeature, SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
339   // create auxiliary axes
340   SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
341                       SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
342                       SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
343   SketchPlugin_Tools::createAuxiliaryAxisOfEllipse(aEllipseFeature,
344                       SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
345                       SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
346
347   return aEllipseFeature;
348 }
349
350 AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
351 {
352   SketchPlugin_Sketch* aSketch = sketch();
353   if (!aSketch || !myCenter || myMajorRadius == 0)
354     return AISObjectPtr();
355
356   std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
357       aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
358
359   // Compute a ellipse in 3D view.
360   GeomPointPtr aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
361   GeomPointPtr aFocus(aSketch->to3D(myFocus->x(), myFocus->y()));
362   GeomDirPtr aNormal = aNDir->dir();
363   GeomDirPtr aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
364       aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
365
366   std::shared_ptr<GeomAPI_Shape> anEllipseShape =
367       GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, myMajorRadius, myMinorRadius);
368   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
369   if (!anEllipseShape.get() || !aCenterPointShape.get())
370     return AISObjectPtr();
371
372   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
373   aShapes.push_back(anEllipseShape);
374   aShapes.push_back(aCenterPointShape);
375
376   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
377   AISObjectPtr anAIS = thePrevious;
378   if (!anAIS)
379     anAIS.reset(new GeomAPI_AISObject());
380   anAIS->createShape(aCompound);
381   return anAIS;
382 }