Salome HOME
Issue #262: the updated points of arc now projected back to initial circle
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Arc.cpp
1 // File:        SketchPlugin_Arc.cpp
2 // Created:     26 Apr 2014
3 // Author:      Artem ZHIDKOV
4
5 #include "SketchPlugin_Arc.h"
6 #include "SketchPlugin_Sketch.h"
7 #include <ModelAPI_Data.h>
8 #include <ModelAPI_ResultConstruction.h>
9 #include <ModelAPI_AttributeSelection.h>
10 #include <ModelAPI_Validator.h>
11 #include <ModelAPI_Session.h>
12
13 #include <GeomAPI_Circ2d.h>
14 #include <GeomAPI_Pnt2d.h>
15 #include <GeomDataAPI_Point2D.h>
16 #include <GeomDataAPI_Dir.h>
17 #include <GeomAlgoAPI_PointBuilder.h>
18 #include <GeomAlgoAPI_EdgeBuilder.h>
19 #include <GeomAlgoAPI_CompoundBuilder.h>
20
21 const double tolerance = 1e-7;
22
23 SketchPlugin_Arc::SketchPlugin_Arc()
24     : SketchPlugin_Feature()
25 {
26   myStartUpdate = false;
27   myEndUpdate = false;
28 }
29
30 void SketchPlugin_Arc::initAttributes()
31 {
32   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::type());
33   data()->addAttribute(START_ID(), GeomDataAPI_Point2D::type());
34   data()->addAttribute(END_ID(), GeomDataAPI_Point2D::type());
35   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::type());
36   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
37 }
38
39 void SketchPlugin_Arc::execute()
40 {
41   SketchPlugin_Sketch* aSketch = sketch();
42   // result for the arc is set only when all obligatory attributes are initialized,
43   // otherwise AIS object is used to visualize the arc's preview
44   if (aSketch && isFeatureValid()) {
45     // compute a circle point in 3D view
46     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
47         GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
48     // compute the arc start point
49     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
50         GeomDataAPI_Point2D>(data()->attribute(START_ID()));
51
52     std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
53     // make a visible point
54     std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
55     std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
56         data(), 0);
57     aConstr1->setShape(aCenterPointShape);
58     aConstr1->setIsInHistory(false);
59     setResult(aConstr1, 0);
60
61     // make a visible circle
62     std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
63         aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
64     std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
65     std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
66
67     // compute and change the arc end point
68     std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
69         GeomDataAPI_Point2D>(data()->attribute(END_ID()));
70     /* must be automatically done in attributeChanged
71     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
72         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
73     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
74     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
75       anEndAttr->setValue(aProjection);
76     */
77     std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
78
79     std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
80         aCenter, aStartPoint, aEndPoint, aNormal);
81     if (aCircleShape) {
82       std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
83           data(), 1);
84       aConstr2->setShape(aCircleShape);
85       aConstr2->setIsInHistory(false);
86       setResult(aConstr2, 1);
87     }
88   }
89 }
90
91 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
92 {
93   SketchPlugin_Sketch* aSketch = sketch();
94   if (aSketch) {
95     // if the feature is valid, the execute() method should be performed, AIS object is empty
96     if (!isFeatureValid()) {
97       // compute a circle point in 3D view
98       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
99           GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
100       if (aCenterAttr->isInitialized()) {
101         std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
102
103         std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
104             GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
105         if (aStartAttr->isInitialized()) {
106           // make a visible circle
107           std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
108               aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
109           bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
110           if (aHasPlane) {
111             std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
112             std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
113             std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
114                                                             aCenter, aStartPoint, aStartPoint, aNormal);
115             if (aCircleShape) {
116               std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
117               // make a visible point
118               std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
119               aShapes.push_back(aCenterPointShape);
120
121               aShapes.push_back(aCircleShape);
122               if (!aShapes.empty())
123               {
124                 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
125                 AISObjectPtr anAIS = thePrevious;
126                 if (!anAIS)
127                   anAIS = AISObjectPtr(new GeomAPI_AISObject);
128                 anAIS->createShape(aCompound);
129                 return anAIS;
130               }
131             }
132           }
133         }
134       }
135     }
136   }
137   return AISObjectPtr();
138 }
139
140 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
141 {
142   std::shared_ptr<ModelAPI_Data> aData = data();
143   if (!aData->isValid())
144     return;
145
146   std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
147       aData->attribute(SketchPlugin_Arc::CENTER_ID()));
148   aPoint1->move(theDeltaX, theDeltaY);
149
150   myStartUpdate = true;
151   myEndUpdate = true;
152   std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
153       aData->attribute(SketchPlugin_Arc::START_ID()));
154   aPoint2->move(theDeltaX, theDeltaY);
155
156   std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
157       aData->attribute(SketchPlugin_Arc::END_ID()));
158   aPoint3->move(theDeltaX, theDeltaY);
159   myStartUpdate = false;
160   myEndUpdate = false;
161 }
162
163 double SketchPlugin_Arc::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
164 {
165   double aDelta = 0;
166   std::shared_ptr<ModelAPI_Data> aData = data();
167
168   std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
169       aData->attribute(SketchPlugin_Arc::CENTER_ID()));
170   aDelta = aPoint1->pnt()->distance(thePoint);
171
172   std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
173       aData->attribute(SketchPlugin_Arc::START_ID()));
174   double aDistance = aPoint2->pnt()->distance(thePoint);
175   if (aDelta < aDistance)
176     aDelta = aDistance;
177
178   std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
179       aData->attribute(SketchPlugin_Arc::END_ID()));
180   aDistance = aPoint3->pnt()->distance(thePoint);
181   if (aDelta < aDistance)
182     aDelta = aDistance;
183
184   return aDelta;
185 }
186
187 bool SketchPlugin_Arc::isFixed() {
188   return data()->selection(EXTERNAL_ID())->context();
189 }
190
191 bool SketchPlugin_Arc::isFeatureValid()
192 {
193   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
194       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
195   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
196       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
197   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
198       GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
199
200   return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
201 }
202
203 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
204 {
205   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
206       GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
207   if (!aCenterAttr->isInitialized())
208     return;
209   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
210       GeomDataAPI_Point2D>(data()->attribute(START_ID()));
211   if (!aStartAttr->isInitialized())
212     return;
213   std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
214       GeomDataAPI_Point2D>(data()->attribute(END_ID()));
215   if (!anEndAttr->isInitialized())
216     return;
217
218   // update the points in accordance to the changed point changes
219   if (theID == END_ID() && !myEndUpdate) {
220     myEndUpdate = true;
221     // compute and change the arc end point
222     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
223         new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
224     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
225     if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
226       anEndAttr->setValue(aProjection);
227     myEndUpdate = false;
228   } else if (theID == START_ID() && !myStartUpdate) {
229     myStartUpdate = true;
230     // compute and change the arc end point
231     std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
232         new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
233     std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
234     if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
235       aStartAttr->setValue(aProjection);
236     myStartUpdate = false;
237   }
238 }