]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_ConstraintRadius.cpp
Salome HOME
Precise calculation of the flyout point for the Radius constraint
[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 }
34
35 void SketchPlugin_ConstraintRadius::initAttributes()
36 {
37   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
38   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
39   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
40 }
41
42 void SketchPlugin_ConstraintRadius::execute()
43 {
44   std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = std::dynamic_pointer_cast<
45       ModelAPI_AttributeRefAttr>(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
46   FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object());
47   if (aFeature) {
48     double aRadius = 0;
49     std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
50     if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
51       AttributeDoublePtr anAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
52           aData->attribute(SketchPlugin_Circle::RADIUS_ID()));
53       if (anAttribute)
54         aRadius = anAttribute->value();
55     } else if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
56       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
57           GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Arc::CENTER_ID()));
58       std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
59           GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Arc::START_ID()));
60       if (aCenterAttr && aStartAttr)
61         aRadius = aCenterAttr->pnt()->distance(aStartAttr->pnt());
62     }
63     //std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
64     //    ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
65     //if(!aValueAttr->isInitialized()) {
66     //  aValueAttr->setValue(aRadius);
67     //}
68
69     // the value should to be computed here, not in the getAISObject in order to change the model value
70     // inside the object transaction. This is important for creating a constraint by preselection.
71     // The display of the presentation in this case happens after the transaction commit
72     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
73         GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
74     if (!aFlyoutAttr->isInitialized())
75       compute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
76   }
77 }
78
79 bool SketchPlugin_ConstraintRadius::compute(const std::string& theAttributeId)
80 {
81   if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
82     return false;
83
84   std::shared_ptr<ModelAPI_Feature> aCyrcFeature;
85   double aRadius = circleRadius(aCyrcFeature);
86   if (aRadius < 0)
87     return false;
88
89   // Flyout point
90   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
91       GeomDataAPI_Point2D>(data()->attribute(theAttributeId));
92   // Prepare a circle
93   if (aCyrcFeature->getKind() == SketchPlugin_Circle::ID()) { // circle
94     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
95         aCyrcFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
96     double aShift = aRadius * 1.1;
97     std::shared_ptr<GeomAPI_Pnt2d> aPnt = aCenterAttr->pnt();
98     std::shared_ptr<GeomAPI_Pnt2d> aFPnt = 
99       std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aPnt->x() + aShift, aPnt->y() + aShift));
100     aFlyoutAttr->setValue(aFPnt);
101   } else { // arc
102     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
103       GeomDataAPI_Point2D>(aCyrcFeature->data()->attribute(SketchPlugin_Arc::START_ID()));      
104     aFlyoutAttr->setValue(aStartAttr->pnt());
105   }
106   return true;
107 }
108
109 double SketchPlugin_ConstraintRadius::circleRadius(std::shared_ptr<ModelAPI_Feature>& theCirc)
110 {
111   static const double kErrorResult = -1.;
112   if (!sketch())
113     return kErrorResult;
114
115   std::shared_ptr<ModelAPI_Data> aData = data();
116   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
117       ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
118   if (!anAttr)
119     return kErrorResult;
120   theCirc = ModelAPI_Feature::feature(anAttr->object());
121   std::string aKind = theCirc ? theCirc->getKind() : "";
122   if (aKind != SketchPlugin_Circle::ID() && aKind != SketchPlugin_Arc::ID())
123     return kErrorResult;
124
125   DataPtr aCircData = theCirc->data();
126   std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr;
127   if (aKind == SketchPlugin_Circle::ID()) {
128     AttributeDoublePtr aCircRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
129         aCircData->attribute(SketchPlugin_Circle::RADIUS_ID()));
130     return aCircRadius->value();
131   } else {
132     aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
133         aCircData->attribute(SketchPlugin_Arc::CENTER_ID()));
134     std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
135         GeomDataAPI_Point2D>(aCircData->attribute(SketchPlugin_Arc::START_ID()));
136     return aCenterAttr->pnt()->distance(aStartAttr->pnt());
137   }
138   return kErrorResult;
139 }
140
141 AISObjectPtr SketchPlugin_ConstraintRadius::getAISObject(AISObjectPtr thePrevious)
142 {
143   if (!sketch())
144     return thePrevious;
145
146   AISObjectPtr anAIS = thePrevious;
147   if (!anAIS) {
148     anAIS = SketcherPrs_Factory::radiusConstraint(this, sketch()->coordinatePlane());
149   }
150
151   // Set color from preferences
152   std::vector<int> aRGB = Config_PropManager::color("Visualization", "sketch_dimension_color",
153                                                     SKETCH_DIMENSION_COLOR);
154   anAIS->setColor(aRGB[0], aRGB[1], aRGB[2]);
155   return anAIS;
156 }
157
158 void SketchPlugin_ConstraintRadius::move(double theDeltaX, double theDeltaY)
159 {
160   std::shared_ptr<ModelAPI_Data> aData = data();
161   if (!aData->isValid())
162     return;
163
164   // The flyout point is calculated in local coordinates of the shape,
165   // so the center should be coincident with origin
166   std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(0.0, 0.0));
167
168   // The specified delta applied on the circle curve, 
169   // so it will be scaled due to distance between flyout and center points
170   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
171       GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
172   std::shared_ptr<GeomAPI_Pnt2d> aFlyout = aFlyoutAttr->pnt();
173
174   std::shared_ptr<ModelAPI_AttributeDouble> aRadius = std::dynamic_pointer_cast<
175       ModelAPI_AttributeDouble>(aData->attribute(SketchPlugin_Constraint::VALUE()));
176   double aScale = aFlyout->distance(aCenter) / aRadius->value();
177
178   std::shared_ptr<GeomAPI_Circ2d> aCircle(new GeomAPI_Circ2d(aCenter, aFlyout));
179   aFlyout->setX(aFlyout->x() + aScale * theDeltaX);
180   aFlyout->setY(aFlyout->y() + aScale * theDeltaY);
181   aFlyout = aCircle->project(aFlyout);
182
183   myFlyoutUpdate = true;
184   aFlyoutAttr->setValue(aFlyout->x(), aFlyout->y());
185   myFlyoutUpdate = false;
186 }
187
188 void SketchPlugin_ConstraintRadius::attributeChanged(const std::string& theID) {
189   if (theID == SketchPlugin_Constraint::ENTITY_A()) {
190     std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
191         ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
192     if (!aValueAttr->isInitialized()) { // only if it is not initialized, try to compute the current value
193       std::shared_ptr<ModelAPI_Feature> aCyrcFeature;
194       double aRadius = circleRadius(aCyrcFeature);
195       if (aRadius > 0) { // set as value the radius of updated reference to another circle
196         aValueAttr->setValue(aRadius);
197       }
198     }
199   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
200     // Recalculate flyout point in local coordinates of the circle (or arc):
201     // coordinates are calculated according to center of the shape
202     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
203         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
204         attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
205
206     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
207         attribute(SketchPlugin_Constraint::ENTITY_A()));
208     if (!aRefAttr || !aRefAttr->isObject())
209       return;
210     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
211     if (!aFeature || (aFeature->getKind() != SketchPlugin_Arc::ID() &&
212         aFeature->getKind() != SketchPlugin_Circle::ID()))
213       return;
214
215     std::string aCenterAttrName;
216     if (aFeature->getKind() == SketchPlugin_Circle::ID())
217       aCenterAttrName = SketchPlugin_Circle::CENTER_ID();
218     else if (aFeature->getKind() == SketchPlugin_Arc::ID())
219       aCenterAttrName = SketchPlugin_Arc::CENTER_ID();
220     std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
221         GeomDataAPI_Point2D>(aFeature->data()->attribute(aCenterAttrName));
222     std::shared_ptr<GeomAPI_Pnt2d> aCenter = aCenterAttr->pnt();
223     std::shared_ptr<ModelAPI_AttributeDouble> aRadius = std::dynamic_pointer_cast<
224         ModelAPI_AttributeDouble>(attribute(SketchPlugin_Constraint::VALUE()));
225
226     std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
227     double aDist = aFlyoutPnt->distance(aCenter);
228     if (aDist < tolerance)
229       return;
230
231     myFlyoutUpdate = true;
232     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aCenter->xy());
233     aFlyoutAttr->setValue(aFlyoutDir->x(), aFlyoutDir->y());
234     myFlyoutUpdate = false;
235   }
236 }