Salome HOME
Improve PythonAPI documentation
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Arc.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_Arc.cpp
4 // Created:     26 Apr 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_Arc.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_Session.h>
14
15 #include <GeomAPI_Ax2.h>
16 #include <GeomAPI_Circ2d.h>
17 #include <GeomAPI_Circ.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomDataAPI_Point2D.h>
20 #include <GeomDataAPI_Dir.h>
21 #include <GeomAlgoAPI_PointBuilder.h>
22 #include <GeomAlgoAPI_EdgeBuilder.h>
23 #include <GeomAlgoAPI_CompoundBuilder.h>
24 // for sqrt on Linux
25 #include <math.h>
26
27 const double tolerance = 1e-7;
28 const double paramTolerance = 1.e-4;
29 const double PI =3.141592653589793238463;
30
31
32 static const std::string& INVERSED_ID()
33 {
34   static const std::string MY_INVERSED_ID("InversedArc");
35   return MY_INVERSED_ID;
36 }
37
38 SketchPlugin_Arc::SketchPlugin_Arc()
39     : SketchPlugin_SketchEntity()
40 {
41   myStartUpdate = false;
42   myEndUpdate = false;
43   // default values
44   myXEndBefore = 0;
45   myYEndBefore = 0;
46
47   myParamBefore = 0;
48 }
49
50 void SketchPlugin_Arc::initAttributes()
51 {
52   SketchPlugin_SketchEntity::initAttributes();
53
54   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
55   data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
56   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
57     GeomDataAPI_Point2D>(data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()));
58   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
59   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
60
61   data()->addAttribute(INVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
62   AttributeBooleanPtr isInversed =
63       std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
64   if (!isInversed->isInitialized())
65     isInversed->setValue(false);
66
67   // get the initial values
68   if (anEndAttr->isInitialized()) {
69     myXEndBefore = anEndAttr->x();
70     myYEndBefore = anEndAttr->y();
71   }
72 }
73
74 void SketchPlugin_Arc::execute()
75 {
76   SketchPlugin_Sketch* aSketch = sketch();
77   // result for the arc is set only when all obligatory attributes are initialized,
78   // otherwise AIS object is used to visualize the arc's preview
79   if (aSketch && isFeatureValid()) {
80     // compute a circle point in 3D view
81     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
82         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
83     // compute the arc start point
84     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
85         GeomDataAPI_Point2D>(data()->attribute(START_ID()));
86
87     std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
88     // make a visible point
89     std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
90     std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
91         data(), 0);
92     aConstr1->setShape(aCenterPointShape);
93     aConstr1->setIsInHistory(false);
94     setResult(aConstr1, 0);
95
96     // make a visible circle
97     std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
98         aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
99     std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
100     std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
101
102     // compute and change the arc end point
103     std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
104         GeomDataAPI_Point2D>(data()->attribute(END_ID()));
105     /* must be automatically done in attributeChanged
106     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
107         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
108     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
109     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
110       anEndAttr->setValue(aProjection);
111     */
112     std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
113     AttributeBooleanPtr isInversed =
114         std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
115
116     std::shared_ptr<GeomAPI_Dir> anXDir(new GeomAPI_Dir(aStartPoint->xyz()->decreased(aCenter->xyz())));
117     std::shared_ptr<GeomAPI_Ax2> anAx2(new GeomAPI_Ax2(aCenter, aNormal, anXDir));
118     std::shared_ptr<GeomAPI_Circ> aCirc(new GeomAPI_Circ(anAx2, aCenter->distance(aStartPoint)));
119     double aParameterNew = 0.0;
120     if(aCirc->parameter(aEndPoint, paramTolerance, aParameterNew)) {
121       if(0 <= myParamBefore && myParamBefore <= PI / 2.0
122         && PI * 1.5 <= aParameterNew && aParameterNew <= PI * 2.0) {
123           isInversed->setValue(true);
124       } else if(PI * 1.5 <= myParamBefore && myParamBefore <= PI * 2.0
125         && 0 <= aParameterNew && aParameterNew <= PI / 2.0) {
126           isInversed->setValue(false);
127       }
128     }
129     myParamBefore = aParameterNew;
130
131     std::shared_ptr<GeomAPI_Shape> aCircleShape;
132     if(!isInversed->value()) {
133       aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStartPoint, aEndPoint, aNormal);
134     } else {
135       aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aEndPoint, aStartPoint, aNormal);
136     }
137
138     if (aCircleShape) {
139       std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
140           data(), 1);
141       aConstr2->setShape(aCircleShape);
142       aConstr2->setIsInHistory(false);
143       setResult(aConstr2, 1);
144     }
145   }
146 }
147
148 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
149 {
150   SketchPlugin_Sketch* aSketch = sketch();
151   if (aSketch) {
152     // if the feature is valid, the execute() method should be performed, AIS object is empty
153     if (!isFeatureValid()) {
154       // compute a circle point in 3D view
155       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
156           GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
157       if (aCenterAttr->isInitialized()) {
158         std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
159
160         std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
161             GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
162         if (aStartAttr->isInitialized()) {
163           // make a visible circle
164           std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
165               aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
166           bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
167           if (aHasPlane) {
168             std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
169             std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
170             std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
171                                                             aCenter, aStartPoint, aStartPoint, aNormal);
172             if (aCircleShape) {
173               std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
174               // make a visible point
175               std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
176               aShapes.push_back(aCenterPointShape);
177
178               aShapes.push_back(aCircleShape);
179               if (!aShapes.empty())
180               {
181                 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
182                 AISObjectPtr anAIS = thePrevious;
183                 if (!anAIS)
184                   anAIS = AISObjectPtr(new GeomAPI_AISObject);
185                 anAIS->createShape(aCompound);
186                 anAIS->setWidth(3);
187                 return anAIS;
188               }
189             }
190           }
191         }
192       }
193     }
194   }
195   return AISObjectPtr();
196 }
197
198 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
199 {
200   std::shared_ptr<ModelAPI_Data> aData = data();
201   if (!aData->isValid())
202     return;
203
204   myStartUpdate = true;
205   myEndUpdate = true;
206   std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
207       aData->attribute(SketchPlugin_Arc::START_ID()));
208   aPoint2->move(theDeltaX, theDeltaY);
209
210   std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
211       aData->attribute(SketchPlugin_Arc::END_ID()));
212   aPoint3->move(theDeltaX, theDeltaY);
213   myStartUpdate = false;
214   myEndUpdate = false;
215
216   std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
217       aData->attribute(SketchPlugin_Arc::CENTER_ID()));
218   aPoint1->move(theDeltaX, theDeltaY);
219 }
220
221 bool SketchPlugin_Arc::isFixed() {
222   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
223 }
224
225 bool SketchPlugin_Arc::isFeatureValid()
226 {
227   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
228       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
229   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
230       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
231   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
232       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
233
234   return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
235 }
236
237 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
238 {
239   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
240       GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
241   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
242       GeomDataAPI_Point2D>(data()->attribute(START_ID()));
243   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
244       GeomDataAPI_Point2D>(data()->attribute(END_ID()));
245   // the second condition for unability to move external segments anywhere
246   if (theID == EXTERNAL_ID() || isFixed()) {
247     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
248     // update arguments due to the selection value
249     if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
250       std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
251       std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
252       if (aCirc.get()) {
253         aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
254         anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
255         aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
256       }
257     }
258     return;
259   }
260   if (!aCenterAttr->isInitialized())
261     return;
262   if (!aStartAttr->isInitialized())
263     return;
264   if (!anEndAttr->isInitialized())
265     return;
266
267   // update the points in accordance to the changed point changes
268   if (theID == END_ID() && !myEndUpdate) {
269     myEndUpdate = true;
270     // compute and change the arc end point
271     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
272         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
273     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
274     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) {
275       // issue #855: trying to update only not-updated coordinate if it is possible
276       /*
277       if (abs(myXEndBefore - anEndAttr->x()) < 1.e-10) { // keep Y unchanged
278         double aVy = aCenterAttr->y() - anEndAttr->y();
279         double aVy2 = aVy * aVy;
280         double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
281         if (aVy2 <= aR2) {
282           double aDX = sqrt(aR2 - aVy * aVy);
283           if (anEndAttr->x() > aCenterAttr->x())
284             aProjection->setX(aCenterAttr->x() + aDX);
285           else 
286             aProjection->setX(aCenterAttr->x() - aDX);
287           aProjection->setY(anEndAttr->y());
288         }
289       } else if (abs(myYEndBefore - anEndAttr->y()) < 1.e-10) { // keep X unchanged
290         double aVx = aCenterAttr->x() - anEndAttr->x();
291         double aVx2 = aVx * aVx;
292         double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
293         if (aVx2 <= aR2) {
294           double aDY = sqrt(aR2 - aVx * aVx);
295           if (anEndAttr->y() > aCenterAttr->y())
296             aProjection->setY(aCenterAttr->y() + aDY);
297           else 
298             aProjection->setY(aCenterAttr->y() - aDY);
299           aProjection->setX(anEndAttr->x());
300         }
301       }*/
302
303       anEndAttr->setValue(aProjection);
304     }
305     myXEndBefore = anEndAttr->x();
306     myYEndBefore = anEndAttr->y();
307     myEndUpdate = false;
308   } else if (theID == START_ID() && !myStartUpdate) {
309     myStartUpdate = true;
310     // compute and change the arc start point
311     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
312         new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
313     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
314     if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
315       aStartAttr->setValue(aProjection);
316     myStartUpdate = false;
317   } else if (theID == CENTER_ID() && !myEndUpdate) {
318     myEndUpdate = true;
319     // compute and change the arc end point
320     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
321         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
322     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
323     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
324       anEndAttr->setValue(aProjection);
325     myEndUpdate = false;
326   }
327 }