Salome HOME
Issue #2024: Redesign of circle and arc of circle
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroArc.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_MacroArc.cpp
4 // Created:     26 Apr 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_MacroArc.h"
8
9 #include "SketchPlugin_Sketch.h"
10 #include "SketchPlugin_Tools.h"
11
12 #include <ModelAPI_AttributeDouble.h>
13 #include <ModelAPI_AttributeRefAttr.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_Session.h>
16 #include <ModelAPI_Validator.h>
17
18 #include <GeomAPI_Circ.h>
19 #include <GeomAPI_Circ2d.h>
20 #include <GeomAPI_Dir2d.h>
21 #include <GeomAPI_Edge.h>
22 #include <GeomAPI_Lin.h>
23 #include <GeomAPI_Lin2d.h>
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_Vertex.h>
26 #include <GeomAPI_XY.h>
27
28 #include <GeomDataAPI_Point2D.h>
29 #include <GeomDataAPI_Dir.h>
30 #include <GeomAlgoAPI_PointBuilder.h>
31 #include <GeomAlgoAPI_EdgeBuilder.h>
32 #include <GeomAlgoAPI_CompoundBuilder.h>
33
34 // for sqrt on Linux
35 #include <math.h>
36
37 const double tolerance = 1e-7;
38 const double paramTolerance = 1.e-4;
39 const double PI = 3.141592653589793238463;
40
41
42 SketchPlugin_MacroArc::SketchPlugin_MacroArc()
43 : SketchPlugin_SketchEntity(),
44   myParamBefore(0.0)
45 {
46 }
47
48 void SketchPlugin_MacroArc::initAttributes()
49 {
50   data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId());
51
52   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
53   data()->addAttribute(START_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
54   data()->addAttribute(END_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
55
56   data()->addAttribute(START_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
57   data()->addAttribute(END_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
58   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
59
60   data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
61   data()->addAttribute(END_POINT_3_ID(), GeomDataAPI_Point2D::typeId());
62
63   data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
64
65   data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
66   data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
67
68   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
69
70   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71   data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72   data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
74
75   boolean(REVERSED_ID())->setValue(false);
76
77   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
78   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
79   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
80   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
81 }
82
83 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
84 {
85   std::string anArcType = string(ARC_TYPE())->value();
86
87   // If arc type switched reset according attributes.
88   if(theID == ARC_TYPE()) {
89     std::string aType = string(ARC_TYPE())->value();
90     if(aType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
91       SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
92       SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
93       SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
94       SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
95       SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
96       SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
97     } else if(aType == ARC_TYPE_BY_THREE_POINTS()) {
98       SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
99       SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
100       SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
101       SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
102       SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
103       SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
104     } else if(aType == ARC_TYPE_BY_TANGENT_EDGE()) {
105       SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
106       SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
107       SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
108     }
109
110     myCenter.reset();
111     myStart.reset();
112     myEnd.reset();
113     boolean(REVERSED_ID())->setValue(false);
114     myParamBefore = 0.0;
115   } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
116     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
117         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
118     if(!aCenterPointAttr->isInitialized()) {
119       return;
120     }
121     std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
122         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
123     if(!aStartPointAttr->isInitialized()) {
124       return;
125     }
126
127     myCenter = aCenterPointAttr->pnt();
128     myStart = aStartPointAttr->pnt();
129     myEnd = myStart;
130
131     std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
132         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
133     if(anEndPointAttr->isInitialized()) {
134       // End point should be a projection on circle.
135       GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
136       std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc.project(anEndPointAttr->pnt());
137       if(aProjection.get()) {
138         bool aWasBlocked = data()->blockSendAttributeUpdated(true);
139         anEndPointAttr->setValue(aProjection);
140         data()->blockSendAttributeUpdated(aWasBlocked, false);
141       }
142       myEnd = anEndPointAttr->pnt();
143
144       double aParameterNew = 0.0;
145       if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
146         if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
147           boolean(REVERSED_ID())->setValue(true);
148         } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
149           boolean(REVERSED_ID())->setValue(false);
150         }
151       }
152       myParamBefore = aParameterNew;
153     }
154   } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
155     std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
156         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
157     if(!aStartPointAttr->isInitialized()) {
158       return;
159     }
160     std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
161         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
162     if(!anEndPointAttr->isInitialized()) {
163       return;
164     }
165
166     myStart = aStartPointAttr->pnt();
167     myEnd = anEndPointAttr->pnt();
168
169     std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
170         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
171     if(aPassedPointAttr->isInitialized()) {
172       std::shared_ptr<GeomAPI_Pnt2d> aPassed = aPassedPointAttr->pnt();
173       GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed);
174       myCenter = aCircle.center();
175       aCircle = GeomAPI_Circ2d(myCenter, myStart);
176       double anEndParam, aPassedParam;
177       aCircle.parameter(myEnd, paramTolerance, anEndParam);
178       aCircle.parameter(aPassed, paramTolerance, aPassedParam);
179       if(aPassedParam > anEndParam) {
180         boolean(REVERSED_ID())->setValue(true);
181       } else {
182         boolean(REVERSED_ID())->setValue(false);
183       }
184     } else {
185       std::shared_ptr<GeomAPI_XY> aDir = myEnd->xy()->decreased(myStart->xy())->multiplied(0.5);
186       double x = aDir->x();
187       double y = aDir->y();
188       aDir->setX(x - y);
189       aDir->setY(y + x);
190       myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(aDir)));
191     }
192   } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
193     AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
194     if(!aTangentAttr->isInitialized()) {
195       return;
196     }
197     std::shared_ptr<GeomDataAPI_Point2D> aTangentPointAttr =
198         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
199     if(!aTangentPointAttr->isInitialized()) {
200       return;
201     }
202     std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
203         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
204     if(!anEndPointAttr->isInitialized()) {
205       return;
206     }
207
208     myStart = aTangentPointAttr->pnt();
209     myEnd = anEndPointAttr->pnt();
210
211     if(myStart->isEqual(myEnd)) {
212       return;
213     }
214
215     SketchPlugin_Sketch* aSketch = sketch();
216     if(!aSketch) {
217       return;
218     }
219
220     std::shared_ptr<GeomAPI_Dir2d> anOrthoDir;
221     FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
222     std::shared_ptr<GeomAPI_Edge> aTangEdge =
223       std::dynamic_pointer_cast<GeomAPI_Edge>(aTangFeature->lastResult()->shape());
224     if(aTangEdge->isLine()) {
225       std::shared_ptr<GeomAPI_Dir> aDir = aTangEdge->line()->direction();
226       std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aDir->x(), aDir->y(), aDir->z()));
227       std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aSketch->to2D(aPnt);
228       anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aPnt2d->y(), aPnt2d->x()));
229     }
230     else if (aTangEdge->isArc()) {
231       std::shared_ptr<GeomAPI_Pnt> aCenter = aTangEdge->circle()->center();
232       std::shared_ptr<GeomAPI_Pnt2d> aCenter2d = aSketch->to2D(aCenter);
233       anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(
234           new GeomAPI_Dir2d(myStart->xy()->decreased(aCenter2d->xy())));
235     }
236
237     // compute parameters of the middle perpendicular
238     std::shared_ptr<GeomAPI_XY> aEndPntCoord = myEnd->xy();
239     std::shared_ptr<GeomAPI_XY> aTempDir = aEndPntCoord->decreased(myStart->xy());
240     std::shared_ptr<GeomAPI_Dir2d> aMidDir(new GeomAPI_Dir2d(-aTempDir->y(), aTempDir->x()));
241     std::shared_ptr<GeomAPI_Pnt2d> aMidPnt(
242         new GeomAPI_Pnt2d(aEndPntCoord->added(myStart->xy())->multiplied(0.5)));
243
244     // compute center of arc by calculating intersection of
245     // orthogonal line and middle perpendicular
246     std::shared_ptr<GeomAPI_Lin2d> anOrthoLine(new GeomAPI_Lin2d(myStart, anOrthoDir));
247     std::shared_ptr<GeomAPI_Lin2d> aMiddleLine(new GeomAPI_Lin2d(aMidPnt, aMidDir));
248     std::shared_ptr<GeomAPI_Pnt2d> aCenter = anOrthoLine->intersect(aMiddleLine);
249     if(aCenter) {
250       myCenter = aCenter;
251     }
252
253     GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
254     double aParameterNew = 0.0;
255     if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
256       if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
257         if(!boolean(REVERSED_ID())->value()) {
258           boolean(REVERSED_ID())->setValue(true);
259         }
260       } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
261         if(boolean(REVERSED_ID())->value()) {
262           boolean(REVERSED_ID())->setValue(false);
263         }
264       }
265     }
266     myParamBefore = aParameterNew;
267   }
268
269   double aRadius = 0;
270   double anAngle = 0;
271   if(myCenter.get() && myStart.get()) {
272     aRadius = myCenter->distance(myStart);
273     if(myEnd.get()) {
274       if(myStart->isEqual(myEnd)) {
275         anAngle = 360;
276       } else {
277         GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
278         double aStartParam, anEndParam;
279         aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
280         aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
281         anAngle = (anEndParam - aStartParam) / PI * 180.0;
282         if(boolean(REVERSED_ID())->value()) anAngle = 360.0 - anAngle;
283       }
284     }
285   }
286
287   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
288   real(RADIUS_ID())->setValue(aRadius);
289   real(ANGLE_ID())->setValue(anAngle);
290   data()->blockSendAttributeUpdated(aWasBlocked, false);
291 }
292
293 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
294 {
295   if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
296     return AISObjectPtr();
297   }
298
299   SketchPlugin_Sketch* aSketch = sketch();
300   if(!aSketch) {
301     return AISObjectPtr();
302   }
303
304   std::shared_ptr<GeomAPI_Pnt> aStart = aSketch->to3D(myStart->x(), myStart->y());
305   std::shared_ptr<GeomAPI_Pnt> anEnd = aSketch->to3D(myEnd->x(), myEnd->y());
306   std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
307
308   std::shared_ptr<GeomDataAPI_Dir> aNDir =
309       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
310           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
311   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
312   GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
313       GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
314     : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
315   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
316
317   if(!anArcShape.get() || !aCenterPointShape.get()) {
318     return AISObjectPtr();
319   }
320
321   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
322   aShapes.push_back(anArcShape);
323   aShapes.push_back(aCenterPointShape);
324
325   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
326   AISObjectPtr anAIS = thePrevious;
327   if(!anAIS.get()) {
328     anAIS.reset(new GeomAPI_AISObject());
329   }
330   anAIS->createShape(aCompound);
331   return anAIS;
332 }
333
334 void SketchPlugin_MacroArc::execute()
335 {
336 }