Salome HOME
Auxiliary state for Intersection point
[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 = SketcherPrs_Factory::angleConstraint(this, sketch()->coordinatePlane(),
82                                                             thePrevious);
83   return anAIS;
84 }
85
86 void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID)
87 {
88   std::shared_ptr<ModelAPI_Data> aData = data();
89   if (!aData)
90     return;
91   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
92   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
93   if (!aLineA || !aLineB)
94     return;
95
96   if (theID == SketchPlugin_Constraint::ENTITY_A() || 
97       theID == SketchPlugin_Constraint::ENTITY_B()) {
98     std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
99         ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE()));
100     if (!aValueAttr->isInitialized()) { // only if it is not initialized, try to compute the current value
101       double anAngle = calculateAngle();
102       aValueAttr->setValue(anAngle);
103     }
104   } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
105     // Recalculate flyout point in local coordinates
106     // coordinates are calculated according to the center of shapes intersection
107     std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
108         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
109
110     std::shared_ptr<ModelAPI_Data> aData = data();
111     std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
112     FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
113     FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
114
115     // Intersection of lines
116     std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
117     if (!anInter)
118       return;
119
120     myFlyoutUpdate = true;
121     std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutAttr->pnt()->xy()->decreased(anInter->xy());
122     if (aFlyoutDir->dot(aFlyoutDir) < tolerance * tolerance)
123       aFlyoutAttr->setValue(aFlyoutAttr->x() + tolerance, aFlyoutAttr->y());
124     myFlyoutUpdate = false;
125   }
126 }
127
128 double SketchPlugin_ConstraintAngle::calculateAngle()
129 {
130   double anAngle = 0.0;
131
132   std::shared_ptr<ModelAPI_Data> aData = data();
133   std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
134   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
135   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
136
137   // Intersection of lines
138   std::shared_ptr<GeomAPI_Pnt2d> anInter = intersect(aLineA, aLineB);
139   if (!anInter)
140     return anAngle;
141
142   // Start and end points of lines
143   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
144       aLineA->attribute(SketchPlugin_Line::START_ID()));
145   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
146       aLineA->attribute(SketchPlugin_Line::END_ID()));
147
148   std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
149       aLineB->attribute(SketchPlugin_Line::START_ID()));
150   std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
151       aLineB->attribute(SketchPlugin_Line::END_ID()));
152
153   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
154   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
155   std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
156   std::shared_ptr<GeomAPI_Pnt2d> aEndB   = aPointB2->pnt();
157
158   double aDist[2][2] = {
159       { anInter->distance(aStartA), anInter->distance(aEndA) },
160       { anInter->distance(aStartB), anInter->distance(aEndB) }
161   };
162
163   // Directions of lines
164   if (aDist[0][0] > aDist[0][1])
165     aEndA = aStartA;
166   if (aDist[1][0] > aDist[1][1])
167     aEndB = aStartB;
168   std::shared_ptr<GeomAPI_Dir2d> aDirA(new GeomAPI_Dir2d(aEndA->xy()->decreased(anInter->xy())));
169   std::shared_ptr<GeomAPI_Dir2d> aDirB(new GeomAPI_Dir2d(aEndB->xy()->decreased(anInter->xy())));
170
171   anAngle = fabs(aDirA->angle(aDirB)) * 180.0 / PI;
172   return anAngle;
173 }
174
175 void SketchPlugin_ConstraintAngle::move(double theDeltaX, double theDeltaY)
176 {
177   std::shared_ptr<ModelAPI_Data> aData = data();
178   if (!aData->isValid())
179     return;
180
181   myFlyoutUpdate = true;
182   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr = std::dynamic_pointer_cast<
183       GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
184   aFlyoutAttr->setValue(aFlyoutAttr->x() + theDeltaX, aFlyoutAttr->y() + theDeltaY);
185   myFlyoutUpdate = false;
186 }
187
188
189 bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId)
190 {
191   if (theAttributeId != SketchPlugin_Constraint::FLYOUT_VALUE_PNT())
192     return false;
193   if (!sketch())
194     return false;
195
196   std::shared_ptr<GeomDataAPI_Point2D> aFlyOutAttr = std::dynamic_pointer_cast<
197                            GeomDataAPI_Point2D>(attribute(theAttributeId));
198   if (fabs(aFlyOutAttr->x()) >= tolerance || fabs(aFlyOutAttr->y()) >= tolerance)
199     return false;
200
201   DataPtr aData = data();
202   std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
203   FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
204   FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
205
206   if ((aLineA.get() == NULL) || (aLineB.get() == NULL))
207     return false;
208
209   // Start and end points of lines
210   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
211       aLineA->attribute(SketchPlugin_Line::START_ID()));
212   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
213       aLineA->attribute(SketchPlugin_Line::END_ID()));
214
215   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
216   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
217   if (aStartA->distance(aEndA) < tolerance)
218     return false;
219
220   myFlyoutUpdate = true;
221   double aX = (aStartA->x() + aEndA->x()) / 2.;
222   double aY = (aStartA->y() + aEndA->y()) / 2.;
223
224   aFlyOutAttr->setValue(aX, aY);
225   myFlyoutUpdate = false;
226
227   return true;
228 }
229
230
231 // ===============   Auxiliary functions   ==================================
232 std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2)
233 {
234   // Start and end points of lines
235   std::shared_ptr<GeomDataAPI_Point2D> aPointA1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
236       theLine1->attribute(SketchPlugin_Line::START_ID()));
237   std::shared_ptr<GeomDataAPI_Point2D> aPointA2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
238       theLine1->attribute(SketchPlugin_Line::END_ID()));
239
240   std::shared_ptr<GeomDataAPI_Point2D> aPointB1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
241       theLine2->attribute(SketchPlugin_Line::START_ID()));
242   std::shared_ptr<GeomDataAPI_Point2D> aPointB2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
243       theLine2->attribute(SketchPlugin_Line::END_ID()));
244
245   std::shared_ptr<GeomAPI_Pnt2d> aStartA = aPointA1->pnt();
246   std::shared_ptr<GeomAPI_Pnt2d> aEndA   = aPointA2->pnt();
247   std::shared_ptr<GeomAPI_Pnt2d> aStartB = aPointB1->pnt();
248   std::shared_ptr<GeomAPI_Pnt2d> aEndB   = aPointB2->pnt();
249   if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance)
250     std::shared_ptr<GeomAPI_Pnt2d>();
251
252   // Lines and their intersection point
253   std::shared_ptr<GeomAPI_Lin2d> aLA(new GeomAPI_Lin2d(aStartA, aEndA));
254   std::shared_ptr<GeomAPI_Lin2d> aLB(new GeomAPI_Lin2d(aStartB, aEndB));
255   return aLA->intersect(aLB);
256 }