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