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_ConstraintCoincidence.h"
11 #include "SketchPlugin_Point.h"
12 #include "SketchPlugin_Tools.h"
13
14 #include <ModelAPI_Data.h>
15 #include <ModelAPI_Events.h>
16 #include <ModelAPI_ResultConstruction.h>
17 #include <ModelAPI_AttributeSelection.h>
18 #include <ModelAPI_Validator.h>
19 #include <ModelAPI_AttributeDouble.h>
20 #include <ModelAPI_AttributeRefAttr.h>
21 #include <ModelAPI_AttributeString.h>
22 #include <ModelAPI_Session.h>
23
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_Circ.h>
26 #include <GeomAPI_Vertex.h>
27 #include <GeomAPI_XY.h>
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
35 const double tolerance = 1e-7;
36
37 namespace {
38   static const std::string& POINT_ID(int theIndex)
39   {
40     switch (theIndex) {
41     case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
42     case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
43     case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
44     }
45
46     static const std::string DUMMY;
47     return DUMMY;
48   }
49 }
50
51
52 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
53 : SketchPlugin_SketchEntity(),
54 myRadius(0)
55 {
56 }
57
58 void SketchPlugin_MacroCircle::initAttributes()
59 {
60   data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
61
62   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
63   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
64   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
65   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66
67   data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
68   data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
69   data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
70   data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71   data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72   data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73
74   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
75   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
76
77   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
78   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
79   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
80   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
82 }
83
84 void SketchPlugin_MacroCircle::execute()
85 {
86   std::string aType = string(CIRCLE_TYPE())->value();
87   if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
88     createCircleByCenterAndPassed();
89   else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
90     createCircleByThreePoints();
91
92   myCenter.reset();
93   myRadius = 0;
94 }
95
96 static void convertToPointOrTangent(const AttributeRefAttrPtr&      theRefAttr,
97                                     const AttributePtr&             theBaseAttr,
98                                     std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint,
99                                     std::shared_ptr<GeomAPI_Shape>& theTangentCurve)
100 {
101   AttributePtr anAttr = theBaseAttr;
102   if (theRefAttr->isObject()) {
103     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
104     if (aTgFeature) {
105       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
106         theTangentCurve = aTgFeature->lastResult()->shape();
107         return;
108       }
109       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
110     }
111   } else
112     anAttr = theRefAttr->attr();
113
114   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
115 }
116
117 void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
118 {
119   AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
120   AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
121   // Calculate circle parameters
122   std::shared_ptr<GeomAPI_Pnt2d> aCenter =
123       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))->pnt();
124   std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
125   std::shared_ptr<GeomAPI_Shape> aTangentCurve;
126   convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
127
128   // Build a circle
129   std::shared_ptr<GeomAPI_Circ2d> aCircle;
130   if (aTangentCurve) {
131     std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
132     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
133   } else
134     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
135
136   // Create circle feature.
137   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
138
139   // Create constraints.
140   SketchPlugin_Tools::createConstraint(this,
141                                        CENTER_POINT_REF_ID(),
142                                        aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
143                                        NULL,
144                                        false);
145   SketchPlugin_Tools::createConstraint(this,
146                                        PASSED_POINT_REF_ID(),
147                                        NULL,
148                                        aCircleFeature->lastResult(),
149                                        true);
150 }
151
152 void SketchPlugin_MacroCircle::createCircleByThreePoints()
153 {
154   std::string aPointAttr[3] = { FIRST_POINT_ID(),
155                                 SECOND_POINT_ID(),
156                                 THIRD_POINT_ID() };
157   std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
158                                SECOND_POINT_REF_ID(),
159                                THIRD_POINT_REF_ID() };
160   std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
161   for (int i = 0; i < 3; ++i) {
162     AttributePtr aPassedAttr = attribute(aPointAttr[i]);
163     AttributeRefAttrPtr aPassedRef = refattr(aPointRef[i]);
164     // calculate circle parameters
165     std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
166     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
167     convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
168
169     if (aPassedPoint)
170       aPassedEntities[i] = aPassedPoint;
171     else
172       aPassedEntities[i] = aTangentCurve;
173   }
174
175   std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
176   std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
177       new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
178
179   // Create circle feature.
180   FeaturePtr aCircleFeature = createCircleFeature(aCircle);
181   ResultPtr aCircleResult = aCircleFeature->lastResult();
182
183   // Create constraints.
184   for (int i = 0; i < 3; ++i)
185     SketchPlugin_Tools::createConstraint(this, aPointRef[i], NULL, aCircleResult, true);
186 }
187
188 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
189     const std::shared_ptr<GeomAPI_Circ2d>& theCircle)
190 {
191   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
192   std::shared_ptr<GeomAPI_Pnt2d> aCenter = theCircle->center();
193   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
194       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCenter->x(),
195                                                                              aCenter->y());
196   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(theCircle->radius());
197   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
198                 ->setValue(boolean(AUXILIARY_ID())->value());
199   aCircleFeature->execute();
200   return aCircleFeature;
201 }
202
203 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
204 {
205   if(!myCenter.get() || myRadius < tolerance) {
206     return AISObjectPtr();
207   }
208
209   SketchPlugin_Sketch* aSketch = sketch();
210   if(!aSketch) {
211     return AISObjectPtr();
212   }
213
214   // Compute a circle in 3D view.
215   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
216   std::shared_ptr<GeomDataAPI_Dir> aNDir =
217       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
218           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
219   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
220   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
221   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
222   if(!aCircleShape.get() || !aCenterPointShape.get()) {
223     return AISObjectPtr();
224   }
225
226   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
227   aShapes.push_back(aCircleShape);
228   aShapes.push_back(aCenterPointShape);
229
230   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
231   AISObjectPtr anAIS = thePrevious;
232   if(!anAIS.get()) {
233     anAIS.reset(new GeomAPI_AISObject());
234   }
235   anAIS->createShape(aCompound);
236   return anAIS;
237 }
238
239 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
240   // If circle type switched reset according attributes.
241   if(theID == CIRCLE_TYPE()) {
242     std::string aType = string(CIRCLE_TYPE())->value();
243     if(aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
244       resetAttribute(CENTER_POINT_ID());
245       resetAttribute(PASSED_POINT_ID());
246     } else if(aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
247       resetAttribute(FIRST_POINT_ID());
248       resetAttribute(SECOND_POINT_ID());
249       resetAttribute(THIRD_POINT_ID());
250     }
251     myCenter.reset();
252     myRadius = 0;
253   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
254     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
255         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
256     if(!aCenterPointAttr->isInitialized()) {
257       return;
258     }
259     std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
260         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
261     if(!aPassedPointAttr->isInitialized()) {
262       return;
263     }
264
265     myCenter = aCenterPointAttr->pnt();
266     myRadius = myCenter->distance(aPassedPointAttr->pnt());
267   } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
268     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
269     int aNbInitialized = 0;
270     for(int i = 1; i <= 3; ++i) {
271       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
272           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
273       if(aCurPnt->isInitialized())
274         aPoints[aNbInitialized++] = aCurPnt->pnt();
275     }
276
277     if(aNbInitialized == 1) {
278       return;
279     } else if(aNbInitialized == 2) {
280       std::shared_ptr<GeomAPI_XY> aCenterXY =
281           aPoints[0]->xy()->added(aPoints[1]->xy())->multiplied(0.5);
282       myCenter.reset(new GeomAPI_Pnt2d(aCenterXY->x(), aCenterXY->y()));
283       myRadius = aPoints[0]->distance(aPoints[1]) * 0.5;
284     } else {
285       std::shared_ptr<GeomAPI_Circ2d> aCircle(
286           new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
287       myCenter = aCircle->center();
288       if(myCenter.get()) {
289         myRadius = aCircle->radius();
290       }
291     }
292   }
293
294   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
295   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
296   aRadiusAttr->setValue(myRadius);
297   data()->blockSendAttributeUpdated(aWasBlocked, false);
298 }
299
300 void SketchPlugin_MacroCircle::resetAttribute(const std::string& theId)
301 {
302   AttributePtr anAttr = attribute(theId);
303   if(anAttr.get()) {
304     anAttr->reset();
305   }
306 }