Salome HOME
2.5. Select the point of a sketch entity must display the editing point panel
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintAngle.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_ConstraintAngle.cpp
4 // Created: 19 August 2015
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchPlugin_ConstraintAngle.h"
8 #include <SketchPlugin_Line.h>
9
10 #include <ModelAPI_AttributeDouble.h>
11 #include <GeomDataAPI_Point2D.h>
12
13 #include <GeomAPI_Dir2d.h>
14 #include <GeomAPI_Lin2d.h>
15 #include <GeomAPI_Pnt2d.h>
16 #include <GeomAPI_XY.h>
17
18 #include <SketcherPrs_Factory.h>
19 #include <SketcherPrs_Tools.h>
20
21 #include <math.h>
22
23 const double tolerance = 1.e-7;
24 #define PI 3.1415926535897932
25
26 /// \brief Calculate intersection point of two lines
27 static std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2);
28
29
30 SketchPlugin_ConstraintAngle::SketchPlugin_ConstraintAngle()
31 {
32   myFlyoutUpdate = false;
33 }
34
35 void SketchPlugin_ConstraintAngle::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::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
40   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
41 }
42
43 void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName,
44                                                    std::string& theDefault)
45 {
46   theSection = "Visualization";
47   theName = "sketch_dimension_color";
48   theDefault = SKETCH_DIMENSION_COLOR;
49 }
50
51 void SketchPlugin_ConstraintAngle::execute()
52 {
53   std::shared_ptr<ModelAPI_Data> aData = data();
54
55   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrA = aData->refattr(SketchPlugin_Constraint::ENTITY_A());
56   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrB = aData->refattr(SketchPlugin_Constraint::ENTITY_B());
57   if (!anAttrA->isInitialized() || !anAttrB->isInitialized())
58     return;
59
60   AttributeDoublePtr anAttrValue = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
61       aData->attribute(SketchPlugin_Constraint::VALUE()));
62
63   if (!anAttrValue->isInitialized()) {
64     double anAngle = calculateAngle();
65     anAttrValue->setValue(anAngle);
66   }
67   // the value should to be computed here, not in the getAISObject in order to change the model value
68   // inside the object transaction. This is important for creating a constraint by preselection.
69   // The display of the presentation in this case happens after the transaction commit
70   std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
71       GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
72   if(!aFlyOutAttr->isInitialized())
73     compute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
74 }
75
76 AISObjectPtr SketchPlugin_ConstraintAngle::getAISObject(AISObjectPtr thePrevious)
77 {
78   if (!sketch())
79     return thePrevious;
80
81   AISObjectPtr anAIS = thePrevious;
82   if (!anAIS) {
83     anAIS = SketcherPrs_Factory::angleConstraint(this, sketch()->coordinatePlane());
84   }
85   return anAIS;
86 }
87
88 void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
89 {
90   std::shared_ptr<ModelAPI_Data> aData = data();
91   if (!aData)
92     return;
93   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
94   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
95   if (!aLineA || !aLineB)
96     return;
97
98   if (theID == SketchPlugin_Constraint::ENTITY_A() || 
99       theID == SketchPlugin_Constraint::ENTITY_B()) {
100     std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
101         ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
102     if (!aValueAttr->isInitialized()) { // only if it is not initialized, try to compute the current value
103       double anAngle = calculateAngle();
104       aValueAttr->setValue(anAngle);
105     }
106   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
107     // Recalculate flyout point in local coordinates
108     // coordinates are calculated according to the center of shapes intersection
109     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
110         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
111
112     std::shared_ptr<ModelAPI_Data> aData = data();
113     std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
114     FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
115     FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
116
117     // Intersection of lines
118     std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
119     if (!anInter)
120       return;
121
122     myFlyoutUpdate = true;
123     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutAttr->pnt()->xy()->decreased(anInter->xy());
124     if (aFlyoutDir->dot(aFlyoutDir) < tolerance * tolerance)
125       aFlyoutAttr->setValue(aFlyoutAttr->x() + tolerance, aFlyoutAttr->y());
126     myFlyoutUpdate = false;
127   }
128 }
129
130 double SketchPlugin_ConstraintAngle::calculateAngle()
131 {
132   double anAngle = 0.0;
133
134   std::shared_ptr<ModelAPI_Data> aData = data();
135   std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
136   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
137   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
138
139   // Intersection of lines
140   std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
141   if (!anInter)
142     return anAngle;
143
144   // Start and end points of lines
145   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
146       aLineA->attribute(SketchPlugin_Line::START_ID()));
147   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
148       aLineA->attribute(SketchPlugin_Line::END_ID()));
149
150   std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
151       aLineB->attribute(SketchPlugin_Line::START_ID()));
152   std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
153       aLineB->attribute(SketchPlugin_Line::END_ID()));
154
155   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
156   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
157   std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
158   std::shared_ptr<GeomAPI_Pnt2d> aEndB   = aPointB2->pnt();
159
160   double aDist[2][2] = {
161       { anInter->distance(aStartA), anInter->distance(aEndA) },
162       { anInter->distance(aStartB), anInter->distance(aEndB) }
163   };
164
165   // Directions of lines
166   if (aDist[0][0] > aDist[0][1])
167     aEndA = aStartA;
168   if (aDist[1][0] > aDist[1][1])
169     aEndB = aStartB;
170   std::shared_ptr<GeomAPI_Dir2d> aDirA(new GeomAPI_Dir2d(aEndA->xy()->decreased(anInter->xy())));
171   std::shared_ptr<GeomAPI_Dir2d> aDirB(new GeomAPI_Dir2d(aEndB->xy()->decreased(anInter->xy())));
172
173   anAngle = fabs(aDirA->angle(aDirB)) * 180.0 / PI;
174   return anAngle;
175 }
176
177 void SketchPlugin_ConstraintAngle::move(double theDeltaX, double theDeltaY)
178 {
179   std::shared_ptr<ModelAPI_Data> aData = data();
180   if (!aData->isValid())
181     return;
182
183   myFlyoutUpdate = true;
184   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
185       GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
186   aFlyoutAttr->setValue(aFlyoutAttr->x() + theDeltaX, aFlyoutAttr->y() + theDeltaY);
187   myFlyoutUpdate = false;
188 }
189
190
191 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
192 {
193   if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
194     return false;
195   if (!sketch())
196     return false;
197
198   std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
199                            GeomDataAPI_Point2D>(attribute(theAttributeId));
200   if (fabs(aFlyOutAttr->x()) >= tolerance || fabs(aFlyOutAttr->y()) >= tolerance)
201     return false;
202
203   DataPtr aData = data();
204   std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
205   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
206   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
207
208   if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
209     return false;
210
211   // Start and end points of lines
212   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
213       aLineA->attribute(SketchPlugin_Line::START_ID()));
214   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
215       aLineA->attribute(SketchPlugin_Line::END_ID()));
216
217   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
218   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
219   if (aStartA->distance(aEndA) < tolerance)
220     return false;
221
222   myFlyoutUpdate = true;
223   double aX = (aStartA->x() + aEndA->x()) / 2.;
224   double aY = (aStartA->y() + aEndA->y()) / 2.;
225
226   aFlyOutAttr->setValue(aX, aY);
227   myFlyoutUpdate = false;
228
229   return true;
230 }
231
232
233 // ===============   Auxiliary functions   ==================================
234 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
235 {
236   // Start and end points of lines
237   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
238       theLine1->attribute(SketchPlugin_Line::START_ID()));
239   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
240       theLine1->attribute(SketchPlugin_Line::END_ID()));
241
242   std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
243       theLine2->attribute(SketchPlugin_Line::START_ID()));
244   std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
245       theLine2->attribute(SketchPlugin_Line::END_ID()));
246
247   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
248   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
249   std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
250   std::shared_ptr<GeomAPI_Pnt2d> aEndB   = aPointB2->pnt();
251   if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
252     std::shared_ptr<GeomAPI_Pnt2d>();
253
254   // Lines and their intersection point
255   std::shared_ptr<GeomAPI_Lin2d> aLA(new GeomAPI_Lin2d(aStartA, aEndA));
256   std::shared_ptr<GeomAPI_Lin2d> aLB(new GeomAPI_Lin2d(aStartB, aEndB));
257   return aLA->intersect(aLB);
258 }