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