Salome HOME
Update movement of a circle
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Circle.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_Circle.cpp
4 // Created:     26 May 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_Circle.h"
8 #include "SketchPlugin_Sketch.h"
9 #include <ModelAPI_Data.h>
10 #include <ModelAPI_ResultConstruction.h>
11 #include <ModelAPI_AttributeSelection.h>
12 #include <ModelAPI_Validator.h>
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_Session.h>
16
17 #include <GeomAPI_Pnt2d.h>
18 #include <GeomAPI_Circ.h>
19 #include <GeomAPI_Circ2d.h>
20 #include <GeomAPI_XY.h>
21 #include <GeomDataAPI_Point2D.h>
22 #include <GeomDataAPI_Dir.h>
23 #include <GeomAlgoAPI_PointBuilder.h>
24 #include <GeomAlgoAPI_EdgeBuilder.h>
25 #include <GeomAlgoAPI_CompoundBuilder.h>
26
27 namespace {
28   static const std::string& CIRCLE_TYPE()
29   {
30     static const std::string TYPE("CircleType");
31     return TYPE;
32   }
33   static const std::string CIRCLE_TYPE_CENTER_AND_RADIUS()
34   {
35     static const std::string TYPE("CenterRadius");
36     return TYPE;
37   }
38   static const std::string CIRCLE_TYPE_THREE_POINTS()
39   {
40     static const std::string TYPE("ThreePoints");
41     return TYPE;
42   }
43
44   static const std::string& FIRST_POINT_ID()
45   {
46     static const std::string FIRST_PNT("FirstPoint");
47     return FIRST_PNT;
48   }
49   static const std::string& SECOND_POINT_ID()
50   {
51     static const std::string SECOND_PNT("SecondPoint");
52     return SECOND_PNT;
53   }
54   static const std::string& THIRD_POINT_ID()
55   {
56     static const std::string THIRD_PNT("ThirdPoint");
57     return THIRD_PNT;
58   }
59   static const std::string& POINT_ID(int theIndex)
60   {
61     switch (theIndex) {
62     case 1: return FIRST_POINT_ID();
63     case 2: return SECOND_POINT_ID();
64     case 3: return THIRD_POINT_ID();
65     }
66
67     static const std::string DUMMY;
68     return DUMMY;
69   }
70 }
71
72
73 SketchPlugin_Circle::SketchPlugin_Circle()
74     : SketchPlugin_SketchEntity()
75 {
76 }
77
78 void SketchPlugin_Circle::initDerivedClassAttributes()
79 {
80   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
81   data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
82   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
83   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
84
85   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
86   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
87   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
88   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
89   std::dynamic_pointer_cast<ModelAPI_AttributeString>(
90       data()->attribute(CIRCLE_TYPE()))->setValue(CIRCLE_TYPE_CENTER_AND_RADIUS());
91 }
92
93 void SketchPlugin_Circle::execute()
94 {
95   SketchPlugin_Sketch* aSketch = sketch();
96   if (aSketch) {
97     std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
98
99     // compute a circle point in 3D view
100     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
101         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
102     AttributeDoublePtr aRadiusAttr = 
103       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(data()->attribute(RADIUS_ID()));
104     if (aCenterAttr->isInitialized() && aRadiusAttr->isInitialized()) {
105       std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
106       //std::cout<<"Execute circle "<<aCenter->x()<<" "<<aCenter->y()<<" "<<aCenter->z()<<std::endl;
107       // make a visible point
108       SketchPlugin_Sketch::createPoint2DResult(this, sketch(), CENTER_ID(), 0);
109
110       // make a visible circle
111       std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
112         aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
113       std::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
114       // compute the circle radius
115       double aRadius = aRadiusAttr->value();
116
117       std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(
118         aCenter, aNormal, aRadius);
119       aShapes.push_back(aCircleShape);
120       std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
121         data(), 1);
122       aConstr2->setShape(aCircleShape);
123       aConstr2->setIsInHistory(false);
124       setResult(aConstr2, 1);
125     }
126   }
127 }
128
129 AISObjectPtr SketchPlugin_Circle::getAISObject(AISObjectPtr thePrevious)
130 {
131   SketchPlugin_Sketch* aSketch = sketch();
132   if (aSketch && !isFeatureValid()) {
133     // compute a circle point in 3D view
134     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
135         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
136     AttributeDoublePtr aRadiusAttr = 
137         std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
138     if (aCenterAttr->isInitialized() && aRadiusAttr->isInitialized()) {
139         std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
140
141         // make a visible circle
142         std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
143             aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
144         std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
145
146         double aRadius = aRadiusAttr->value();
147         std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(
148             aCenter, aNormal, aRadius);
149         if (aCircleShape && aRadius != 0) {
150           std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
151           // make a visible point
152           std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
153           aShapes.push_back(aCenterPointShape);
154           aShapes.push_back(aCircleShape);
155
156           std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
157           AISObjectPtr anAIS = thePrevious;
158           if (!anAIS)
159             anAIS = AISObjectPtr(new GeomAPI_AISObject);
160           anAIS->createShape(aCompound);
161           anAIS->setWidth(3);
162           return anAIS;
163         }
164     }
165   }
166   return AISObjectPtr();
167 }
168
169 bool SketchPlugin_Circle::isFeatureValid()
170 {
171   std::shared_ptr<GeomDataAPI_Point2D> aCenter = 
172       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
173   std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
174       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
175   std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
176       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
177   std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
178       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
179
180   return aCenter->isInitialized() && aFirstPnt->isInitialized() &&
181          aSecondPnt->isInitialized() && aThirdPnt->isInitialized();
182 }
183
184 void SketchPlugin_Circle::move(double theDeltaX, double theDeltaY)
185 {
186   std::shared_ptr<ModelAPI_Data> aData = data();
187   if (!aData->isValid())
188     return;
189
190   std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
191       aData->attribute(CENTER_ID()));
192   aPoint->move(theDeltaX, theDeltaY);
193
194   aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(FIRST_POINT_ID()));
195   aPoint->move(theDeltaX, theDeltaY);
196   aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(SECOND_POINT_ID()));
197   aPoint->move(theDeltaX, theDeltaY);
198   aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(THIRD_POINT_ID()));
199   aPoint->move(theDeltaX, theDeltaY);
200 }
201
202 bool SketchPlugin_Circle::isFixed() {
203   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
204 }
205
206 void SketchPlugin_Circle::attributeChanged(const std::string& theID) {
207   // the second condition for unability to move external segments anywhere
208   if (theID == EXTERNAL_ID() || isFixed()) {
209     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
210     // update arguments due to the selection value
211     if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
212       std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
213       std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
214       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = 
215         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
216       aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
217       real(RADIUS_ID())->setValue(aCirc->radius());
218     }
219   }
220   else if (theID == CENTER_ID() || theID == RADIUS_ID()) {
221     std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
222       data()->attribute(CIRCLE_TYPE()))->value();
223     if (aType == CIRCLE_TYPE_THREE_POINTS())
224       return;
225
226     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
227         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
228     if (!aCenterAttr->isInitialized())
229       return;
230     AttributeDoublePtr aRadiusAttr = 
231       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
232     if (!aRadiusAttr->isInitialized())
233       return;
234
235     // check the execute() was called and the shape was built
236     if (!lastResult())
237       return;
238
239     data()->blockSendAttributeUpdated(true);
240     std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
241         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
242     std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
243         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
244     std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
245         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
246     double aRadius = aRadiusAttr->value();
247     aFirstPnt->setValue(aCenterAttr->x() + aRadius, aCenterAttr->y());
248     aSecondPnt->setValue(aCenterAttr->x(), aCenterAttr->y() + aRadius);
249     aThirdPnt->setValue(aCenterAttr->x() - aRadius, aCenterAttr->y());
250     data()->blockSendAttributeUpdated(false);
251   }
252   else if (theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
253     std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
254       data()->attribute(CIRCLE_TYPE()))->value();
255     if (aType == CIRCLE_TYPE_CENTER_AND_RADIUS())
256       return;
257
258     data()->blockSendAttributeUpdated(true);
259
260     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
261     int aNbInitialized = 0;
262     for (int i = 1; i <= 3; ++i) {
263       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
264           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
265       if (aCurPnt->isInitialized())
266         aPoints[aNbInitialized++] = aCurPnt->pnt();
267     }
268
269     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
270         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
271     AttributeDoublePtr aRadiusAttr = 
272       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(data()->attribute(RADIUS_ID()));
273
274     if (aNbInitialized == 1)
275       aCenterAttr->setValue(aPoints[0]->x(), aPoints[0]->y());
276     else if (aNbInitialized == 2) {
277       std::shared_ptr<GeomAPI_XY> aCoord =
278           aPoints[0]->xy()->added(aPoints[1]->xy())->multiplied(0.5);
279       double aRadius = aPoints[0]->distance(aPoints[1]) * 0.5;
280       aCenterAttr->setValue(aCoord->x(), aCoord->y());
281       aRadiusAttr->setValue(aRadius);
282     } else {
283       std::shared_ptr<GeomAPI_Circ2d> aCircle(
284           new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
285
286       std::shared_ptr<GeomAPI_Pnt2d> aCenter = aCircle->center();
287       if (aCenter) {
288         double aRadius = aCircle->radius();
289         aCenterAttr->setValue(aCenter->x(), aCenter->y());
290         aRadiusAttr->setValue(aRadius);
291       }
292     }
293
294     data()->blockSendAttributeUpdated(false);
295   }
296 }