Salome HOME
9ec13a3205a7edc0473ef56d2d3b553743768c5c
[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 SketchPlugin_Arc::SketchPlugin_Arc()
33     : SketchPlugin_SketchEntity()
34 {
35   myStartUpdate = false;
36   myEndUpdate = false;
37   // default values
38   myXEndBefore = 0;
39   myYEndBefore = 0;
40
41   myParamBefore = 0;
42 }
43
44 void SketchPlugin_Arc::initDerivedClassAttributes()
45 {
46   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
47   data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
48   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
49     GeomDataAPI_Point2D>(data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()));
50   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
51   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
52
53   data()->addAttribute(INVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
54   AttributeBooleanPtr isInversed =
55       std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
56   if (!isInversed->isInitialized())
57     isInversed->setValue(false);
58
59   // get the initial values
60   if (anEndAttr->isInitialized()) {
61     myXEndBefore = anEndAttr->x();
62     myYEndBefore = anEndAttr->y();
63   }
64 }
65
66 void SketchPlugin_Arc::execute()
67 {
68   SketchPlugin_Sketch* aSketch = sketch();
69   // result for the arc is set only when all obligatory attributes are initialized,
70   // otherwise AIS object is used to visualize the arc's preview
71   if (aSketch && isFeatureValid()) {
72     // compute a circle point in 3D view
73     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
74         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
75     // compute the arc start point
76     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
77         GeomDataAPI_Point2D>(data()->attribute(START_ID()));
78
79     std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
80     // make a visible point
81     std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
82     std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
83         data(), 0);
84     aConstr1->setShape(aCenterPointShape);
85     aConstr1->setIsInHistory(false);
86     setResult(aConstr1, 0);
87
88     // make a visible circle
89     std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
90         aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
91     std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
92     std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
93
94     // compute and change the arc end point
95     std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
96         GeomDataAPI_Point2D>(data()->attribute(END_ID()));
97     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
98         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
99     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
100     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
101       anEndAttr->setValue(aProjection);
102     std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
103     AttributeBooleanPtr isInversed =
104         std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
105
106     std::shared_ptr<GeomAPI_Dir> anXDir(new GeomAPI_Dir(aStartPoint->xyz()->decreased(aCenter->xyz())));
107     std::shared_ptr<GeomAPI_Ax2> anAx2(new GeomAPI_Ax2(aCenter, aNormal, anXDir));
108     std::shared_ptr<GeomAPI_Circ> aCirc(new GeomAPI_Circ(anAx2, aCenter->distance(aStartPoint)));
109     double aParameterNew = 0.0;
110     if(aCirc->parameter(aEndPoint, paramTolerance, aParameterNew)) {
111       if(0 <= myParamBefore && myParamBefore <= PI / 2.0
112         && PI * 1.5 <= aParameterNew && aParameterNew <= PI * 2.0) {
113           isInversed->setValue(true);
114       } else if(PI * 1.5 <= myParamBefore && myParamBefore <= PI * 2.0
115         && 0 <= aParameterNew && aParameterNew <= PI / 2.0) {
116           isInversed->setValue(false);
117       }
118     }
119     myParamBefore = aParameterNew;
120
121     std::shared_ptr<GeomAPI_Shape> aCircleShape;
122     if(!isInversed->value()) {
123       aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStartPoint, aEndPoint, aNormal);
124     } else {
125       aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aEndPoint, aStartPoint, aNormal);
126     }
127
128     if (aCircleShape) {
129       std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
130           data(), 1);
131       aConstr2->setShape(aCircleShape);
132       aConstr2->setIsInHistory(false);
133       setResult(aConstr2, 1);
134     }
135   }
136 }
137
138 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
139 {
140   SketchPlugin_Sketch* aSketch = sketch();
141   if (aSketch) {
142     // if the feature is valid, the execute() method should be performed, AIS object is empty
143     if (!isFeatureValid()) {
144       // compute a circle point in 3D view
145       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
146           GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
147       if (aCenterAttr->isInitialized()) {
148         std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
149
150         std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
151             GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
152         if (aStartAttr->isInitialized()) {
153           // make a visible circle
154           std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
155               aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
156           bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
157           if (aHasPlane) {
158             std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
159             std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
160             std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
161                                                             aCenter, aStartPoint, aStartPoint, aNormal);
162             if (aCircleShape) {
163               std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
164               // make a visible point
165               std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
166               aShapes.push_back(aCenterPointShape);
167
168               aShapes.push_back(aCircleShape);
169               if (!aShapes.empty())
170               {
171                 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
172                 AISObjectPtr anAIS = thePrevious;
173                 if (!anAIS)
174                   anAIS = AISObjectPtr(new GeomAPI_AISObject);
175                 anAIS->createShape(aCompound);
176                 anAIS->setWidth(3);
177                 return anAIS;
178               }
179             }
180           }
181         }
182       }
183     }
184   }
185   return AISObjectPtr();
186 }
187
188 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
189 {
190   std::shared_ptr<ModelAPI_Data> aData = data();
191   if (!aData->isValid())
192     return;
193
194   myStartUpdate = true;
195   myEndUpdate = true;
196   std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
197       aData->attribute(SketchPlugin_Arc::START_ID()));
198   aPoint2->move(theDeltaX, theDeltaY);
199
200   std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
201       aData->attribute(SketchPlugin_Arc::END_ID()));
202   aPoint3->move(theDeltaX, theDeltaY);
203   myStartUpdate = false;
204   myEndUpdate = false;
205
206   std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
207       aData->attribute(SketchPlugin_Arc::CENTER_ID()));
208   aPoint1->move(theDeltaX, theDeltaY);
209 }
210
211 bool SketchPlugin_Arc::isFixed() {
212   return data()->selection(EXTERNAL_ID())->context().get() != NULL;
213 }
214
215 bool SketchPlugin_Arc::isFeatureValid()
216 {
217   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
218       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
219   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
220       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
221   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
222       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
223
224   return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
225 }
226
227 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
228 {
229   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
230       GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
231   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
232       GeomDataAPI_Point2D>(data()->attribute(START_ID()));
233   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
234       GeomDataAPI_Point2D>(data()->attribute(END_ID()));
235   // the second condition for unability to move external segments anywhere
236   if (theID == EXTERNAL_ID() || isFixed()) {
237     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
238     // update arguments due to the selection value
239     if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
240       std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
241       std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
242       if (aCirc.get()) {
243         aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
244         anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
245         aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
246       }
247     }
248     return;
249   }
250   if (!isFeatureValid())
251     return;
252
253   // update the points in accordance to the changed point changes
254   if (theID == CENTER_ID() && !myEndUpdate) {
255     myEndUpdate = true;
256     // compute and change the arc end point
257     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
258         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
259     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
260     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
261       anEndAttr->setValue(aProjection);
262     myEndUpdate = false;
263   }
264 }
265
266 void SketchPlugin_Arc::setReversed(bool isReversed)
267 {
268   std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()))->setValue(isReversed);
269   myParamBefore = 0.0;
270 }
271
272 bool SketchPlugin_Arc::isReversed()
273 {
274   return std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()))->value();
275 }