Salome HOME
refs #80 - Sketch base GUI: create/draw point, circle and arc
[modules/shaper.git] / src / PartSet / PartSet_Tools.cpp
1 // File:        PartSet_Tools.h
2 // Created:     28 Apr 2014
3 // Author:      Natalia ERMOLAEVA
4
5 #include <PartSet_Tools.h>
6
7 #include <ModelAPI_Data.h>
8 #include <ModelAPI_AttributeDouble.h>
9 #include <ModelAPI_Document.h>
10
11 #include <GeomDataAPI_Point.h>
12 #include <GeomDataAPI_Dir.h>
13 #include <GeomDataAPI_Point2D.h>
14
15 #include <GeomAPI_Dir.h>
16 #include <GeomAPI_XYZ.h>
17
18 #include <SketchPlugin_Feature.h>
19 #include <SketchPlugin_Sketch.h>
20 #include <SketchPlugin_Point.h>
21 #include <SketchPlugin_Line.h>
22 #include <SketchPlugin_Circle.h>
23 #include <SketchPlugin_ConstraintCoincidence.h>
24 #include <SketchPlugin_Constraint.h>
25
26 #include <XGUI_ViewerPrs.h>
27
28 #include <V3d_View.hxx>
29 #include <gp_Pln.hxx>
30 #include <ProjLib.hxx>
31 #include <ElSLib.hxx>
32 #include <Geom_Line.hxx>
33 #include <GeomAPI_ProjectPointOnCurve.hxx>
34
35 #ifdef _DEBUG
36 #include <QDebug>
37 #endif
38
39 const double PRECISION_TOLERANCE = 0.000001;
40
41 gp_Pnt PartSet_Tools::convertClickToPoint(QPoint thePoint, Handle(V3d_View) theView)
42 {
43   if (theView.IsNull())
44     return gp_Pnt();
45
46   V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt;
47   theView->Eye(XEye, YEye, ZEye);
48
49   theView->At(XAt, YAt, ZAt);
50   gp_Pnt EyePoint(XEye, YEye, ZEye);
51   gp_Pnt AtPoint(XAt, YAt, ZAt);
52
53   gp_Vec EyeVector(EyePoint, AtPoint);
54   gp_Dir EyeDir(EyeVector);
55
56   gp_Pln PlaneOfTheView = gp_Pln(AtPoint, EyeDir);
57   Standard_Real X, Y, Z;
58   theView->Convert(thePoint.x(), thePoint.y(), X, Y, Z);
59   gp_Pnt ConvertedPoint(X, Y, Z);
60
61   gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project(PlaneOfTheView, ConvertedPoint);
62   gp_Pnt ResultPoint = ElSLib::Value(ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView);
63   return ResultPoint;
64 }
65
66 void PartSet_Tools::convertTo2D(const gp_Pnt& thePoint, FeaturePtr theSketch,
67                                 Handle(V3d_View) theView, double& theX, double& theY)
68 {
69   if (!theSketch)
70     return;
71
72   boost::shared_ptr<ModelAPI_AttributeDouble> anAttr;
73   boost::shared_ptr<ModelAPI_Data> aData = theSketch->data();
74
75   boost::shared_ptr<GeomDataAPI_Point> anOrigin = 
76     boost::dynamic_pointer_cast<GeomDataAPI_Point>(aData->attribute(SKETCH_ATTR_ORIGIN));
77
78   boost::shared_ptr<GeomDataAPI_Dir> aX = 
79     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRX));
80   boost::shared_ptr<GeomDataAPI_Dir> anY = 
81     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRY));
82
83   gp_Pnt anOriginPnt(anOrigin->x(), anOrigin->y(), anOrigin->z());
84   gp_Vec aVec(anOriginPnt, thePoint);
85
86   if (!theView.IsNull())
87   {
88     V3d_Coordinate XEye, YEye, ZEye, XAt, YAt, ZAt;
89     theView->Eye(XEye, YEye, ZEye);
90
91     theView->At(XAt, YAt, ZAt);
92     gp_Pnt EyePoint(XEye, YEye, ZEye);
93     gp_Pnt AtPoint(XAt, YAt, ZAt);
94
95     gp_Vec anEyeVec(EyePoint, AtPoint);
96     anEyeVec.Normalize();
97
98     boost::shared_ptr<GeomDataAPI_Dir> aNormal = 
99                   boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_NORM));
100     gp_Vec aNormalVec(aNormal->x(), aNormal->y(), aNormal->z());
101
102     double aDen = anEyeVec * aNormalVec;
103     double aLVec = aDen != 0 ? aVec * aNormalVec / aDen : DBL_MAX;
104
105     gp_Vec aDeltaVec = anEyeVec*aLVec;
106     aVec = aVec - aDeltaVec;
107   }
108   theX = aVec.X() * aX->x() + aVec.Y() * aX->y() + aVec.Z() * aX->z();
109   theY = aVec.X() * anY->x() + aVec.Y() * anY->y() + aVec.Z() * anY->z();
110 }
111
112 void PartSet_Tools::convertTo3D(const double theX, const double theY,
113                                 FeaturePtr theSketch,
114                                 gp_Pnt& thePoint)
115 {
116   if (!theSketch)
117     return;
118
119   boost::shared_ptr<ModelAPI_Data> aData = theSketch->data();
120
121   boost::shared_ptr<GeomDataAPI_Point> aC = 
122     boost::dynamic_pointer_cast<GeomDataAPI_Point>(aData->attribute(SKETCH_ATTR_ORIGIN));
123   boost::shared_ptr<GeomDataAPI_Dir> aX = 
124     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRX));
125   boost::shared_ptr<GeomDataAPI_Dir> aY = 
126     boost::dynamic_pointer_cast<GeomDataAPI_Dir>(aData->attribute(SKETCH_ATTR_DIRY));
127
128   boost::shared_ptr<GeomAPI_XYZ> aSum = aC->pnt()->xyz()->added(
129     aX->dir()->xyz()->multiplied(theX))->added(aY->dir()->xyz()->multiplied(theY));
130
131   boost::shared_ptr<GeomAPI_Pnt> aPoint = boost::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aSum));
132   thePoint = gp_Pnt(aPoint->x(), aPoint->y(), aPoint->z());
133 }
134
135 void PartSet_Tools::intersectLines(double theX0, double theY0, double theX1, double theY1,
136                                    double theX2, double theY2, double theX3, double theY3,
137                                    double& theX, double& theY)
138 {
139   double aV1 = theX1 - theX0, aV2 = theY1 - theY0;
140   double aW1 = theX3 - theX2, aW2 = theY3 - theY2;
141
142   double aT2 = 0;
143   if (aV1  != 0 && aV2 != 0)
144     aT2 = (( theY2 - theY0 )/aV2 - ( theX2 - theX0 )/aV1) / ( aW1/aV1 - aW2/aV2 );
145   else
146     aT2 = DBL_MAX;
147
148   theX  = theX2 + aT2*aW1;
149   theY = theY2 + aT2*aW2;
150
151   // the coordinates of two lines are on the common line
152   //It is not possible to use Precision::Confusion(), because it is e-0.8, but V is sometimes e-6
153   Standard_Real aPrec = PRECISION_TOLERANCE;
154   if (fabs(theX - theX0) < aPrec && fabs(theY - theY0) < aPrec) {
155     projectPointOnLine(theX2, theY2, theX3, theY3, theX1, theY1, theX, theY);    
156   }
157 }
158
159 void PartSet_Tools::projectPointOnLine(double theX1, double theY1, double theX2, double theY2,
160                                        double thePointX, double thePointY, double& theX, double& theY)
161 {
162   theX = theY = 0;
163
164   Handle(Geom_Line) aLine = new Geom_Line(gp_Pnt(theX1, theY1, 0),
165                                      gp_Dir(gp_Vec(gp_Pnt(theX1, theY1, 0), gp_Pnt(theX2, theY2, 0))));
166   GeomAPI_ProjectPointOnCurve aProj(gp_Pnt(thePointX, thePointY, 0), aLine);
167
168   Standard_Integer aNbPoint = aProj.NbPoints();
169   if (aNbPoint > 0) {
170     gp_Pnt aPoint = aProj.Point(1);
171     theX = aPoint.X();
172     theY = aPoint.Y();
173   }
174 }
175
176 FeaturePtr PartSet_Tools::nearestFeature(QPoint thePoint,
177                                                    Handle_V3d_View theView,
178                                                    FeaturePtr theSketch,
179                                                    const std::list<XGUI_ViewerPrs>& theFeatures)
180 {
181   double aX, anY;
182   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(thePoint, theView);
183   PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, anY);
184
185   FeaturePtr aFeature;
186   std::list<XGUI_ViewerPrs>::const_iterator anIt = theFeatures.begin(), aLast = theFeatures.end();
187
188   FeaturePtr aDeltaFeature;   
189   double aMinDelta = -1;
190   XGUI_ViewerPrs aPrs;
191   for (; anIt != aLast; anIt++) {
192     aPrs = *anIt;
193     if (!aPrs.feature())
194       continue;
195     double aDelta = distanceToPoint(aPrs.feature(), aX, anY);
196     if (aMinDelta < 0 || aMinDelta > aDelta) {
197       aMinDelta = aDelta;
198       aDeltaFeature = aPrs.feature();
199     }
200   }
201   return aDeltaFeature;
202 }
203
204 double PartSet_Tools::distanceToPoint(FeaturePtr theFeature,
205                                       double theX, double theY)
206 {
207   double aDelta = 0;
208   if (theFeature->getKind() != SKETCH_LINE_KIND)
209     return aDelta;
210
211   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
212
213   boost::shared_ptr<GeomDataAPI_Point2D> aPoint1 =
214         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_START));
215   boost::shared_ptr<GeomDataAPI_Point2D> aPoint2 =
216         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_END));
217
218   double aX, anY;
219   PartSet_Tools::projectPointOnLine(aPoint1->x(), aPoint1->y(), aPoint2->x(), aPoint2->y(), theX, theY, aX, anY);
220
221   aDelta = gp_Pnt(theX, theY, 0).Distance(gp_Pnt(aX, anY, 0));
222
223   return aDelta;
224 }
225
226 boost::shared_ptr<ModelAPI_Document> PartSet_Tools::document()
227 {
228   return ModelAPI_PluginManager::get()->rootDocument();
229 }
230
231 void PartSet_Tools::setFeaturePoint(FeaturePtr theFeature, double theX, double theY,
232                                     const std::string& theAttribute)
233 {
234   if (!theFeature)
235     return;
236   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
237   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
238         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
239   if (aPoint)
240     aPoint->setValue(theX, theY);
241 }
242
243 void PartSet_Tools::setFeatureValue(FeaturePtr theFeature, double theValue,
244                                     const std::string& theAttribute)
245 {
246   if (!theFeature)
247     return;
248   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
249   boost::shared_ptr<ModelAPI_AttributeDouble> anAttribute =
250         boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(aData->attribute(theAttribute));
251   if (anAttribute)
252     anAttribute->setValue(theValue);
253 }
254
255 void PartSet_Tools::createConstraint(FeaturePtr theSketch,
256                                      boost::shared_ptr<GeomDataAPI_Point2D> thePoint1,
257                                      boost::shared_ptr<GeomDataAPI_Point2D> thePoint2)
258 {
259   boost::shared_ptr<ModelAPI_Document> aDoc = document();
260   FeaturePtr aFeature = aDoc->addFeature(SKETCH_CONSTRAINT_COINCIDENCE_KIND);
261
262   if (theSketch) {
263     boost::shared_ptr<SketchPlugin_Feature> aSketch = 
264                            boost::dynamic_pointer_cast<SketchPlugin_Feature>(theSketch);
265     aSketch->addSub(aFeature);
266   }
267
268   boost::shared_ptr<ModelAPI_Data> aData = aFeature->data();
269
270   boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef1 =
271         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(CONSTRAINT_ATTR_ENTITY_A));
272   aRef1->setAttr(thePoint1);
273
274   boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef2 =
275         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(CONSTRAINT_ATTR_ENTITY_B));
276   aRef2->setAttr(thePoint2);
277
278   if (aFeature) // TODO: generate an error if feature was not created
279     aFeature->execute();
280 }
281
282 void PartSet_Tools::getLinePoint(FeaturePtr theFeature, const std::string& theAttribute,
283                                  double& theX, double& theY)
284 {
285   if (!theFeature || theFeature->getKind() != SKETCH_LINE_KIND)
286     return;
287   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
288   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
289         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
290   theX = aPoint->x();
291   theY = aPoint->y();
292 }
293
294 boost::shared_ptr<GeomDataAPI_Point2D> PartSet_Tools::findPoint(FeaturePtr theFeature,
295                                                                 double theX, double theY)
296 {
297   boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D;
298   if (!theFeature)
299     return aPoint2D;
300
301   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
302   if (theFeature->getKind() == SKETCH_LINE_KIND)
303   {
304     boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
305           boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_START));
306     if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
307       aPoint2D = aPoint;
308     else {
309       aPoint = boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_END));
310       if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
311         aPoint2D = aPoint;
312     }
313   }
314   else if (theFeature->getKind() == SKETCH_POINT_KIND)
315   {
316     boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
317           boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(POINT_ATTR_COORD));
318     if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
319       aPoint2D = aPoint;
320   }
321   else if (theFeature->getKind() == SKETCH_CIRCLE_KIND)
322   {
323     boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
324           boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(CIRCLE_ATTR_CENTER));
325     if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
326       aPoint2D = aPoint;
327   }
328
329   return aPoint2D;
330 }