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