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