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