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_Tools.h"
12
13 #include <ModelAPI_Data.h>
14 #include <ModelAPI_Events.h>
15 #include <ModelAPI_ResultConstruction.h>
16 #include <ModelAPI_AttributeSelection.h>
17 #include <ModelAPI_Validator.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeRefAttr.h>
20 #include <ModelAPI_AttributeString.h>
21 #include <ModelAPI_Session.h>
22
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Circ.h>
25 #include <GeomAPI_Circ2d.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
71   data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
72   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
73
74   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
75   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
76 }
77
78 void SketchPlugin_MacroCircle::execute()
79 {
80   // Create circle feature.
81   FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
82   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
83       aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
84                                                                              myCenter->y());
85   aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
86   aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
87                 ->setValue(boolean(AUXILIARY_ID())->value());
88   aCircleFeature->execute();
89
90   myCenter.reset();
91   myRadius = 0;
92
93   // Create constraints.
94   SketchPlugin_Tools::createConstraint(this,
95                                        CENTER_POINT_REF_ID(),
96                                        aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
97                                        NULL,
98                                        false);
99   SketchPlugin_Tools::createConstraint(this,
100                                        PASSED_POINT_REF_ID(),
101                                        NULL,
102                                        aCircleFeature->lastResult(),
103                                        true);
104 }
105
106 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
107 {
108   if(!myCenter.get() || myRadius < tolerance) {
109     return AISObjectPtr();
110   }
111
112   SketchPlugin_Sketch* aSketch = sketch();
113   if(!aSketch) {
114     return AISObjectPtr();
115   }
116
117   // Compute a circle in 3D view.
118   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
119   std::shared_ptr<GeomDataAPI_Dir> aNDir =
120       std::dynamic_pointer_cast<GeomDataAPI_Dir>(
121           aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
122   std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
123   GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
124   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
125   if(!aCircleShape.get() || !aCenterPointShape.get()) {
126     return AISObjectPtr();
127   }
128
129   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
130   aShapes.push_back(aCircleShape);
131   aShapes.push_back(aCenterPointShape);
132
133   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
134   AISObjectPtr anAIS = thePrevious;
135   if(!anAIS.get()) {
136     anAIS.reset(new GeomAPI_AISObject());
137   }
138   anAIS->createShape(aCompound);
139   return anAIS;
140 }
141
142 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
143   // If circle type switched reset according attributes.
144   if(theID == CIRCLE_TYPE()) {
145     std::string aType = string(CIRCLE_TYPE())->value();
146     if(aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
147       resetAttribute(CENTER_POINT_ID());
148       resetAttribute(PASSED_POINT_ID());
149     } else if(aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
150       resetAttribute(FIRST_POINT_ID());
151       resetAttribute(SECOND_POINT_ID());
152       resetAttribute(THIRD_POINT_ID());
153     }
154     myCenter.reset();
155     myRadius = 0;
156   } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
157     std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
158         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
159     if(!aCenterPointAttr->isInitialized()) {
160       return;
161     }
162     std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
163         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
164     if(!aPassedPointAttr->isInitialized()) {
165       return;
166     }
167
168     myCenter = aCenterPointAttr->pnt();
169     myRadius = myCenter->distance(aPassedPointAttr->pnt());
170   } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
171     std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
172     int aNbInitialized = 0;
173     for(int i = 1; i <= 3; ++i) {
174       std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
175           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
176       if(aCurPnt->isInitialized())
177         aPoints[aNbInitialized++] = aCurPnt->pnt();
178     }
179
180     if(aNbInitialized == 1) {
181       return;
182     } else if(aNbInitialized == 2) {
183       std::shared_ptr<GeomAPI_XY> aCenterXY =
184           aPoints[0]->xy()->added(aPoints[1]->xy())->multiplied(0.5);
185       myCenter.reset(new GeomAPI_Pnt2d(aCenterXY->x(), aCenterXY->y()));
186       myRadius = aPoints[0]->distance(aPoints[1]) * 0.5;
187     } else {
188       std::shared_ptr<GeomAPI_Circ2d> aCircle(
189           new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
190       myCenter = aCircle->center();
191       if(myCenter.get()) {
192         myRadius = aCircle->radius();
193       }
194     }
195   }
196
197   AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
198   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
199   aRadiusAttr->setValue(myRadius);
200   data()->blockSendAttributeUpdated(aWasBlocked, false);
201 }
202
203 void SketchPlugin_MacroCircle::resetAttribute(const std::string& theId)
204 {
205   AttributePtr anAttr = attribute(theId);
206   if(anAttr.get()) {
207     anAttr->reset();
208   }
209 }