Salome HOME
77a04c978a2db57df1a1f2d50f32b78da2b5152b
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroEllipse.cpp
1 // Copyright (C) 2017-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_MacroEllipse.cpp
4 // Created:     26 April 2017
5 // Author:      Artem ZHIDKOV
6
7 #include <SketchPlugin_MacroEllipse.h>
8
9 #include <SketchPlugin_Ellipse.h>
10 #include <SketchPlugin_Tools.h>
11 #include <SketchPlugin_Sketch.h>
12
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeRefAttr.h>
15 #include <ModelAPI_EventReentrantMessage.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
18 #include <ModelAPI_Events.h>
19
20 #include <GeomDataAPI_Point2D.h>
21
22 #include <GeomAPI_Dir2d.h>
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Ellipse2d.h>
25 #include <GeomAPI_Vertex.h>
26
27 #include <GeomAlgoAPI_CompoundBuilder.h>
28 #include <GeomAlgoAPI_EdgeBuilder.h>
29 #include <GeomAlgoAPI_PointBuilder.h>
30
31
32 SketchPlugin_MacroEllipse::SketchPlugin_MacroEllipse()
33 : SketchPlugin_SketchEntity(),
34   myMajorRadius(0.0),
35   myMinorRadius(0.0)
36 {
37 }
38
39 void SketchPlugin_MacroEllipse::initAttributes()
40 {
41   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
42   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
43   data()->addAttribute(MAJOR_AXIS_POINT_ID(), GeomDataAPI_Point2D::typeId());
44   data()->addAttribute(MAJOR_AXIS_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
45   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
46   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
47
48   data()->addAttribute(MAJOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
49   data()->addAttribute(MINOR_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
50   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
51
52   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
53   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAJOR_AXIS_POINT_REF_ID());
54   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
55 }
56
57 void SketchPlugin_MacroEllipse::execute()
58 {
59   FeaturePtr anEllipse = createEllipseFeature();
60   constraintsForEllipse(anEllipse);
61
62   // message to init reentrant operation
63   static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
64   ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
65   aMessage->setCreatedFeature(anEllipse);
66   Events_Loop::loop()->send(aMessage);
67 }
68
69 void SketchPlugin_MacroEllipse::attributeChanged(const std::string& theID)
70 {
71   static const int NB_POINTS = 3;
72   std::string aPointAttrName[NB_POINTS] = { CENTER_POINT_ID(),
73                                             MAJOR_AXIS_POINT_ID(),
74                                             PASSED_POINT_ID() };
75   std::string aPointRefName[NB_POINTS] = { CENTER_POINT_REF_ID(),
76                                            MAJOR_AXIS_POINT_REF_ID(),
77                                            PASSED_POINT_REF_ID() };
78
79   int aNbInitialized = 0;
80   std::shared_ptr<GeomAPI_Pnt2d> anEllipsePoints[NB_POINTS];
81
82   for (int aPntIndex = 0; aPntIndex < NB_POINTS; ++aPntIndex) {
83     AttributePtr aPointAttr = attribute(aPointAttrName[aPntIndex]);
84     if (!aPointAttr->isInitialized())
85       continue;
86
87     AttributeRefAttrPtr aPointRef = refattr(aPointRefName[aPntIndex]);
88     // calculate ellipse parameters
89     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
90     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
91     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
92         aPointRef, aPointAttr, aTangentCurve, aPassedPoint);
93
94     anEllipsePoints[aNbInitialized++] = aPassedPoint;
95   }
96
97   std::shared_ptr<GeomAPI_Ellipse2d> anEllipse;
98   if (aNbInitialized == 2) {
99     std::shared_ptr<GeomAPI_Dir2d> aXDir(new GeomAPI_Dir2d(
100         anEllipsePoints[1]->x() - anEllipsePoints[0]->x(),
101         anEllipsePoints[1]->y() - anEllipsePoints[0]->y()));
102     double aMajorRad = anEllipsePoints[1]->distance(anEllipsePoints[0]);
103     anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
104         new GeomAPI_Ellipse2d(anEllipsePoints[0], aXDir, aMajorRad, 0.5 * aMajorRad));
105   } else if (aNbInitialized == 3) {
106     anEllipse = std::shared_ptr<GeomAPI_Ellipse2d>(
107         new GeomAPI_Ellipse2d(anEllipsePoints[0], anEllipsePoints[1], anEllipsePoints[2]));
108   }
109
110   if (!anEllipse || anEllipse->implPtr<void>() == 0)
111     return;
112
113   myCenter = anEllipse->center();
114   myFocus = anEllipse->firstFocus();
115   myMajorRadius = anEllipse->majorRadius();
116   myMinorRadius = anEllipse->minorRadius();
117
118   AttributeDoublePtr aMajorRadiusAttr = real(MAJOR_RADIUS_ID());
119   AttributeDoublePtr aMinorRadiusAttr = real(MINOR_RADIUS_ID());
120
121   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
122   // center attribute is used in processEvent() to set reference to reentrant arc
123   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->setValue(myCenter);
124   aMajorRadiusAttr->setValue(myMajorRadius);
125   aMinorRadiusAttr->setValue(myMinorRadius);
126   data()->blockSendAttributeUpdated(aWasBlocked, false);
127 }
128
129 std::string SketchPlugin_MacroEllipse::processEvent(
130                                               const std::shared_ptr<Events_Message>& theMessage)
131 {
132   std::string aFilledAttributeName;
133
134   ReentrantMessagePtr aReentrantMessage =
135         std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
136   if (aReentrantMessage) {
137     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
138     ObjectPtr anObject = aReentrantMessage->selectedObject();
139     AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
140     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
141
142     if (aClickedPoint && (anObject || anAttribute)) {
143       aFilledAttributeName = CENTER_POINT_ID();
144       std::string aReferenceAttributeName = CENTER_POINT_REF_ID();
145
146       // fill 2d point attribute
147       AttributePoint2DPtr aPointAttr =
148           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(aFilledAttributeName));
149       aPointAttr->setValue(aClickedPoint);
150
151       // fill reference attribute
152       AttributeRefAttrPtr aRefAttr =
153           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(attribute(aReferenceAttributeName));
154       if (anAttribute) {
155         if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
156           if (aCreatedFeature && anAttribute->id() == CENTER_POINT_ID())
157             anAttribute = aCreatedFeature->attribute(SketchPlugin_Ellipse::CENTER_ID());
158         }
159         aRefAttr->setAttr(anAttribute);
160       }
161       else if (anObject.get()) {
162         // if presentation of previous reentrant macro arc is used, the object is invalid,
163         // we should use result of previous feature of the message(Arc)
164         if (!anObject->data()->isValid())
165           anObject = aCreatedFeature->lastResult();
166         aRefAttr->setObject(anObject);
167       }
168     }
169     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
170   }
171   return aFilledAttributeName;
172 }
173
174 void SketchPlugin_MacroEllipse::constraintsForEllipse(FeaturePtr theEllipseFeature)
175 {
176   // Create constraints.
177   SketchPlugin_Tools::createConstraint(
178       this, CENTER_POINT_REF_ID(),
179       theEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
180       ObjectPtr(), false);
181   SketchPlugin_Tools::createConstraint(
182       this, MAJOR_AXIS_POINT_REF_ID(), AttributePtr(),
183       theEllipseFeature->lastResult(), true);
184   SketchPlugin_Tools::createConstraint(
185       this, PASSED_POINT_REF_ID(), AttributePtr(),
186       theEllipseFeature->lastResult(), true);
187 }
188
189 FeaturePtr SketchPlugin_MacroEllipse::createEllipseFeature()
190 {
191   FeaturePtr aEllipseFeature = sketch()->addFeature(SketchPlugin_Ellipse::ID());
192
193   AttributePoint2DPtr aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
194       aEllipseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()));
195   aCenterAttr->setValue(myCenter->x(), myCenter->y());
196
197   AttributePoint2DPtr aFocusAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
198       aEllipseFeature->attribute(SketchPlugin_Ellipse::FOCUS_ID()));
199   aFocusAttr->setValue(myFocus->x(), myFocus->y());
200
201   aEllipseFeature->real(SketchPlugin_Ellipse::MAJOR_RADIUS_ID())->setValue(myMajorRadius);
202   aEllipseFeature->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(myMinorRadius);
203
204   aEllipseFeature->boolean(SketchPlugin_Ellipse::AUXILIARY_ID())->setValue(
205       boolean(AUXILIARY_ID())->value());
206
207   aEllipseFeature->execute();
208   return aEllipseFeature;
209 }
210
211 AISObjectPtr SketchPlugin_MacroEllipse::getAISObject(AISObjectPtr thePrevious)
212 {
213   SketchPlugin_Sketch* aSketch = sketch();
214   if (!aSketch || !myCenter || myMajorRadius == 0)
215     return AISObjectPtr();
216
217   std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
218       aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
219
220   // Compute a ellipse in 3D view.
221   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
222   std::shared_ptr<GeomAPI_Pnt> aFocus(aSketch->to3D(myFocus->x(), myFocus->y()));
223   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
224   std::shared_ptr<GeomAPI_Dir> aMajorAxis(new GeomAPI_Dir(aFocus->x() - aCenter->x(),
225       aFocus->y() - aCenter->y(), aFocus->z() - aCenter->z()));
226
227   std::shared_ptr<GeomAPI_Shape> anEllipseShape =
228       GeomAlgoAPI_EdgeBuilder::ellipse(aCenter, aNormal, aMajorAxis, myMajorRadius, myMinorRadius);
229   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
230   if (!anEllipseShape.get() || !aCenterPointShape.get())
231     return AISObjectPtr();
232
233   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
234   aShapes.push_back(anEllipseShape);
235   aShapes.push_back(aCenterPointShape);
236
237   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
238   AISObjectPtr anAIS = thePrevious;
239   if (!anAIS)
240     anAIS.reset(new GeomAPI_AISObject());
241   anAIS->createShape(aCompound);
242   return anAIS;
243 }