Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintRadius.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_ConstraintRadius.cpp
4 // Created: 26 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchPlugin_ConstraintRadius.h"
8
9 #include <SketchPlugin_Arc.h>
10 #include <SketchPlugin_Circle.h>
11 #include <SketchPlugin_Point.h>
12
13 #include <SketcherPrs_Factory.h>
14
15 #include <ModelAPI_AttributeDouble.h>
16 #include <ModelAPI_Data.h>
17
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomAPI_Circ.h>
20 #include <GeomAPI_Circ2d.h>
21 #include <GeomAPI_Dir.h>
22 #include <GeomAPI_XY.h>
23 #include <GeomAPI_XYZ.h>
24 #include <GeomDataAPI_Point2D.h>
25 #include <GeomDataAPI_Dir.h>
26
27 #include <Config_PropManager.h>
28
29 const double tolerance = 1.e-7;
30
31 SketchPlugin_ConstraintRadius::SketchPlugin_ConstraintRadius()
32 {
33   myFlyoutUpdate = false;
34 }
35
36 void SketchPlugin_ConstraintRadius::initAttributes()
37 {
38   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
39   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
40   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
41 }
42
43 void SketchPlugin_ConstraintRadius::execute()
44 {
45   std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = std::dynamic_pointer_cast<
46       ModelAPI_AttributeRefAttr>(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
47   FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object());
48   if (aFeature) {
49     double aRadius = 0;
50     std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
51     if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
52       AttributeDoublePtr anAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
53           aData->attribute(SketchPlugin_Circle::RADIUS_ID()));
54       if (anAttribute)
55         aRadius = anAttribute->value();
56     } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
57       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
58           GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Arc::CENTER_ID()));
59       std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
60           GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Arc::START_ID()));
61       if (aCenterAttr && aStartAttr)
62         aRadius = aCenterAttr->pnt()->distance(aStartAttr->pnt());
63     }
64     //std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
65     //    ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
66     //if(!aValueAttr->isInitialized()) {
67     //  aValueAttr->setValue(aRadius);
68     //}
69
70     // the value should to be computed here, not in the getAISObject in order to change the model value
71     // inside the object transaction. This is important for creating a constraint by preselection.
72     // The display of the presentation in this case happens after the transaction commit
73     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
74         GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
75     if (!aFlyoutAttr->isInitialized())
76       compute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
77   }
78 }
79
80 bool SketchPlugin_ConstraintRadius::compute(const std::string& theAttributeId)
81 {
82   if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
83     return false;
84
85   std::shared_ptr<ModelAPI_Feature> aCyrcFeature;
86   double aRadius = circleRadius(aCyrcFeature);
87   if (aRadius < 0)
88     return false;
89
90   // Flyout point
91   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
92       GeomDataAPI_Point2D>(data()->attribute(theAttributeId));
93   // Prepare a circle
94   if (aCyrcFeature->getKind() == SketchPlugin_Circle::ID()) { // circle
95     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
96         aCyrcFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
97     double aShift = aRadius * 1.1;
98     std::shared_ptr<GeomAPI_Pnt2d> aPnt = aCenterAttr->pnt();
99     std::shared_ptr<GeomAPI_Pnt2d> aFPnt = 
100       std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aPnt->x() + aShift, aPnt->y() + aShift));
101     aFlyoutAttr->setValue(aFPnt);
102   } else { // arc
103     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
104       GeomDataAPI_Point2D>(aCyrcFeature->data()->attribute(SketchPlugin_Arc::START_ID()));      
105     aFlyoutAttr->setValue(aStartAttr->pnt());
106   }
107   return true;
108 }
109
110 double SketchPlugin_ConstraintRadius::circleRadius(std::shared_ptr<ModelAPI_Feature>& theCirc)
111 {
112   static const double kErrorResult = -1.;
113   if (!sketch())
114     return kErrorResult;
115
116   std::shared_ptr<ModelAPI_Data> aData = data();
117   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
118       ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
119   if (!anAttr)
120     return kErrorResult;
121   theCirc = ModelAPI_Feature::feature(anAttr->object());
122   std::string aKind = theCirc ? theCirc->getKind() : "";
123   if (aKind != SketchPlugin_Circle::ID() && aKind != SketchPlugin_Arc::ID())
124     return kErrorResult;
125
126   DataPtr aCircData = theCirc->data();
127   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr;
128   if (aKind == SketchPlugin_Circle::ID()) {
129     AttributeDoublePtr aCircRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
130         aCircData->attribute(SketchPlugin_Circle::RADIUS_ID()));
131     return aCircRadius->value();
132   } else {
133     aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
134         aCircData->attribute(SketchPlugin_Arc::CENTER_ID()));
135     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
136         GeomDataAPI_Point2D>(aCircData->attribute(SketchPlugin_Arc::START_ID()));
137     return aCenterAttr->pnt()->distance(aStartAttr->pnt());
138   }
139   return kErrorResult;
140 }
141
142 AISObjectPtr SketchPlugin_ConstraintRadius::getAISObject(AISObjectPtr thePrevious)
143 {
144   if (!sketch())
145     return thePrevious;
146
147   AISObjectPtr anAIS = thePrevious;
148   if (!anAIS) {
149     anAIS = SketcherPrs_Factory::radiusConstraint(this, sketch()->coordinatePlane());
150   }
151
152   // Set color from preferences
153   std::vector<int> aRGB = Config_PropManager::color("Visualization", "sketch_dimension_color",
154                                                     SKETCH_DIMENSION_COLOR);
155   anAIS->setColor(aRGB[0], aRGB[1], aRGB[2]);
156   return anAIS;
157 }
158
159 void SketchPlugin_ConstraintRadius::move(double theDeltaX, double theDeltaY)
160 {
161   std::shared_ptr<ModelAPI_Data> aData = data();
162   if (!aData->isValid())
163     return;
164
165   myFlyoutUpdate = true;
166   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
167       GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
168   aFlyoutAttr->setValue(aFlyoutAttr->x() + theDeltaX, aFlyoutAttr->y() + theDeltaY);
169   myFlyoutUpdate = false;
170 }
171
172 void SketchPlugin_ConstraintRadius::attributeChanged(const std::string& theID) {
173   if (theID == SketchPlugin_Constraint::ENTITY_A()) {
174     std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
175         ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
176     if (!aValueAttr->isInitialized()) { // only if it is not initialized, try to compute the current value
177       std::shared_ptr<ModelAPI_Feature> aCyrcFeature;
178       double aRadius = circleRadius(aCyrcFeature);
179       if (aRadius > 0) { // set as value the radius of updated reference to another circle
180         aValueAttr->setValue(aRadius);
181       }
182     }
183   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
184     // Recalculate flyout point in local coordinates of the circle (or arc):
185     // coordinates are calculated according to center of the shape
186     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
187         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
188         attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
189
190     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
191         attribute(SketchPlugin_Constraint::ENTITY_A()));
192     if (!aRefAttr || !aRefAttr->isObject())
193       return;
194     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
195     if (!aFeature || (aFeature->getKind() != SketchPlugin_Arc::ID() &&
196         aFeature->getKind() != SketchPlugin_Circle::ID()))
197       return;
198
199     std::string aCenterAttrName;
200     if (aFeature->getKind() == SketchPlugin_Circle::ID())
201       aCenterAttrName = SketchPlugin_Circle::CENTER_ID();
202     else if (aFeature->getKind() == SketchPlugin_Arc::ID())
203       aCenterAttrName = SketchPlugin_Arc::CENTER_ID();
204     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
205         GeomDataAPI_Point2D>(aFeature->data()->attribute(aCenterAttrName));
206     std::shared_ptr<GeomAPI_Pnt2d> aCenter = aCenterAttr->pnt();
207     std::shared_ptr<ModelAPI_AttributeDouble> aRadius = std::dynamic_pointer_cast<
208         ModelAPI_AttributeDouble>(attribute(SketchPlugin_Constraint::VALUE()));
209
210     std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
211     double aDist = aFlyoutPnt->distance(aCenter);
212     if (aDist < tolerance)
213       return;
214
215     myFlyoutUpdate = true;
216     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aCenter->xy());
217     aFlyoutAttr->setValue(aFlyoutDir->x(), aFlyoutDir->y());
218     myFlyoutUpdate = false;
219   }
220 }