]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_MacroCircle.cpp
Salome HOME
Issue #2024: Redesign of circle and arc of circle
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroCircle.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_MacroCircle.cpp
4 // Created:     26 May 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_MacroCircle.h"
8
9 #include "SketchPlugin_Circle.h"
10 #include "SketchPlugin_Point.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 <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point2D.h>
21
22 #include <GeomAPI_Circ2d.h>
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Vertex.h>
25
26 #include <GeomAlgoAPI_CompoundBuilder.h>
27 #include <GeomAlgoAPI_EdgeBuilder.h>
28 #include <GeomAlgoAPI_PointBuilder.h>
29
30
31 const double tolerance = 1e-7;
32
33 namespace {
34   static const std::string& POINT_ID(int theIndex)
35   {
36     switch (theIndex) {
37       case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
38       case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
39       case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
40     }
41
42     static const std::string DUMMY;
43     return DUMMY;
44   }
45 }
46
47
48 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
49 : SketchPlugin_SketchEntity()
50 {
51 }
52
53 void SketchPlugin_MacroCircle::initAttributes()
54 {
55   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
56
57   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
58   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
59   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
60   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
61
62   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
63   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
64   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
65   data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66   data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
67   data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
68
69   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
70   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
71
72   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
73   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
74   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
75   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
76   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
77 }
78
79 void SketchPlugin_MacroCircle::execute()
80 {
81   std::string aType = string(CIRCLE_TYPE())->value();
82   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
83     createCircleByCenterAndPassed();
84   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
85     createCircleByThreePoints();
86 }
87
88 static void convertToPointOrTangent(const AttributeRefAttrPtr&      theRefAttr,
89                                     const AttributePtr&             theBaseAttr,
90                                     std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint,
91                                     std::shared_ptr<GeomAPI_Shape>& theTangentCurve)
92 {
93   AttributePtr anAttr = theBaseAttr;
94   if (theRefAttr->isObject()) {
95     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
96     if (aTgFeature) {
97       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
98         theTangentCurve = aTgFeature->lastResult()->shape();
99         return;
100       }
101       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
102     }
103   } else
104     anAttr = theRefAttr->attr();
105
106   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
107 }
108
109 void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
110 {
111   // Create circle feature.
112   std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByCenterAndPassed();
113   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
114
115   // Create constraints.
116   SketchPlugin_Tools::createConstraint(this,
117                                        CENTER_POINT_REF_ID(),
118                                        aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
119                                        ObjectPtr(),
120                                        false);
121   SketchPlugin_Tools::createConstraint(this,
122                                        PASSED_POINT_REF_ID(),
123                                        AttributePtr(),
124                                        aCircleFeature->lastResult(),
125                                        true);
126 }
127
128 void SketchPlugin_MacroCircle::createCircleByThreePoints()
129 {
130   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
131                                SECOND_POINT_REF_ID(),
132                                THIRD_POINT_REF_ID() };
133
134   // Create circle feature.
135   std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByThreePoints();
136   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
137   ResultPtr aCircleResult = aCircleFeature->lastResult();
138
139   // Create constraints.
140   for (int i = 0; i < 3; ++i)
141     SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
142 }
143
144 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
145     const std::shared_ptr<GeomAPI_Circ2d>& theCircle)
146 {
147   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
148   std::shared_ptr<GeomAPI_Pnt2d> aCenter = theCircle->center();
149   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
150       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCenter->x(),
151                                                                              aCenter->y());
152   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(theCircle->radius());
153   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
154                 ->setValue(boolean(AUXILIARY_ID())->value());
155   aCircleFeature->execute();
156   return aCircleFeature;
157 }
158
159 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByCenterAndPassed()
160 {
161   AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
162   AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
163   if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
164     return std::shared_ptr<GeomAPI_Circ2d>();
165
166   AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
167   // Calculate circle parameters
168   std::shared_ptr<GeomAPI_Pnt2d> aCenter =
169       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
170   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
171   std::shared_ptr<GeomAPI_Shape> aTangentCurve;
172   convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
173
174   // Build a circle
175   std::shared_ptr<GeomAPI_Circ2d> aCircle;
176   if (aTangentCurve) {
177     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
178     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
179   } else
180     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
181   return aCircle;
182 }
183
184 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByThreePoints()
185 {
186   std::string aPointAttr[3] = { FIRST_POINT_ID(),
187                                 SECOND_POINT_ID(),
188                                 THIRD_POINT_ID() };
189   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
190                                SECOND_POINT_REF_ID(),
191                                THIRD_POINT_REF_ID() };
192   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
193   for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
194     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
195     if (!aPassedAttr->isInitialized())
196       break;
197
198     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
199     // calculate circle parameters
200     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
201     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
202     convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
203
204     if (aPassedPoint)
205       aPassedEntities[aPntIndex] = aPassedPoint;
206     else
207       aPassedEntities[aPntIndex] = aTangentCurve;
208   }
209
210   std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
211   std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
212       new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
213   if (!aCircle->implPtr<char>())
214     return std::shared_ptr<GeomAPI_Circ2d>();
215   return aCircle;
216 }
217
218 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByTwoPassedPoints()
219 {
220   std::string aPointAttr[2] = { FIRST_POINT_ID(),
221                                 SECOND_POINT_ID() };
222   std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
223                                SECOND_POINT_REF_ID() };
224   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
225   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
226   int aPntIndex = 0;
227   for (; aPntIndex < 2; ++aPntIndex) {
228     AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
229     if (!aPassedAttr->isInitialized())
230       break;
231
232     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
233     // calculate circle parameters
234     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
235     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
236     convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
237
238     if (aPassedPoint) {
239       aPassedEntities[aPntIndex] = aPassedPoint;
240       aPassedPoints[aPntIndex] = aPassedPoint;
241     } else {
242       aPassedEntities[aPntIndex] = aTangentCurve;
243       // if the circle is tangent to any curve,
244       // the third point will be initialized by the tangent point
245       aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
246     }
247   }
248   if (aPntIndex <= 1)
249     return std::shared_ptr<GeomAPI_Circ2d>();
250
251   std::shared_ptr<GeomAPI_Circ2d> aCircle;
252   if (aPassedEntities[2]) {
253     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
254     aCircle = std::shared_ptr<GeomAPI_Circ2d>(
255         new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
256   } else {
257     // the circle is defined by two points, calculate its parameters manually
258     std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
259         (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
260         (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
261     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
262   }
263   if (!aCircle->implPtr<char>())
264     return std::shared_ptr<GeomAPI_Circ2d>();
265   return aCircle;
266 }
267
268 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
269 {
270   SketchPlugin_Sketch* aSketch = sketch();
271   if(!aSketch) {
272     return AISObjectPtr();
273   }
274
275   // Create circle on the sketch plane
276   std::shared_ptr<GeomAPI_Circ2d> aCircleOnSketch;
277   std::string aType = string(CIRCLE_TYPE())->value();
278   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
279     aCircleOnSketch = shapeByCenterAndPassed();
280   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
281     if (attribute(THIRD_POINT_ID())->isInitialized())
282       aCircleOnSketch = shapeByThreePoints();
283     else
284       aCircleOnSketch = shapeByTwoPassedPoints();
285   }
286
287   if (!aCircleOnSketch)
288     return AISObjectPtr();
289
290   std::shared_ptr<GeomAPI_Pnt2d> aCenter2D = aCircleOnSketch->center();
291   double aRadius = aCircleOnSketch->radius();
292
293   // Compute a circle in 3D view.
294   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenter2D->x(), aCenter2D->y()));
295   std::shared_ptr<GeomDataAPI_Dir> aNDir =
296       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
297           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
298   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
299   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius);
300   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
301   if(!aCircleShape.get() || !aCenterPointShape.get()) {
302     return AISObjectPtr();
303   }
304
305   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
306   aShapes.push_back(aCircleShape);
307   aShapes.push_back(aCenterPointShape);
308
309   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
310   AISObjectPtr anAIS = thePrevious;
311   if(!anAIS.get()) {
312     anAIS.reset(new GeomAPI_AISObject());
313   }
314   anAIS->createShape(aCompound);
315   return anAIS;
316 }
317
318 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
319   double aRadius = 0.0;
320   // If circle type switched reset all attributes.
321   if(theID == CIRCLE_TYPE()) {
322     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
323     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
324     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
325     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
326     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
327     SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
328     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
329     SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
330     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
331     SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
332   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
333     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
334         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
335     if(!aCenterPointAttr->isInitialized()) {
336       return;
337     }
338     std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
339         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
340     if(!aPassedPointAttr->isInitialized()) {
341       return;
342     }
343
344     aRadius = aCenterPointAttr->pnt()->distance(aPassedPointAttr->pnt());
345   } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
346     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
347     int aNbInitialized = 0;
348     for(int i = 1; i <= 3; ++i) {
349       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
350           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
351       if(aCurPnt->isInitialized())
352         aPoints[aNbInitialized++] = aCurPnt->pnt();
353     }
354
355     std::shared_ptr<GeomAPI_Circ2d> aCircle;
356     if(aNbInitialized == 1)
357       return;
358     else if(aNbInitialized == 2)
359       aCircle = shapeByTwoPassedPoints();
360     else
361       aCircle = shapeByThreePoints();
362     if (aCircle)
363       aRadius = aCircle->radius();
364   }
365
366   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
367   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
368   aRadiusAttr->setValue(aRadius);
369   data()->blockSendAttributeUpdated(aWasBlocked, false);
370 }