Salome HOME
36c969305b60f69ecbb67385904e4b44cd379514
[modules/shaper.git] / src / PartSet / PartSet_OperationSketchLine.cpp
1 // File:        PartSet_OperationSketchLine.h
2 // Created:     20 Apr 2014
3 // Author:      Natalia ERMOLAEVA
4
5 #include <PartSet_OperationSketchLine.h>
6
7 #include <PartSet_Tools.h>
8 #include <PartSet_OperationSketch.h>
9
10 #include <SketchPlugin_Feature.h>
11 #include <SketchPlugin_Sketch.h>
12
13 #include <GeomDataAPI_Point2D.h>
14
15 #include <ModuleBase_OperationDescription.h>
16
17 #include <ModelAPI_Data.h>
18 #include <ModelAPI_Document.h>
19 #include <ModelAPI_AttributeRefAttr.h>
20 #include <ModelAPI_AttributeRefList.h>
21
22 #include <SketchPlugin_Constraint.h>
23
24 #include <Geom_Line.hxx>
25 #include <gp_Lin.hxx>
26
27 #include <XGUI_ViewerPrs.h>
28
29 #include <SketchPlugin_Line.h>
30
31 #include <V3d_View.hxx>
32 #include <TopoDS_Vertex.hxx>
33 #include <TopoDS.hxx>
34 #include <BRep_Tool.hxx>
35
36 #ifdef _DEBUG
37 #include <QDebug>
38 #endif
39
40 #include <QMouseEvent>
41
42 using namespace std;
43
44 PartSet_OperationSketchLine::PartSet_OperationSketchLine(const QString& theId,
45                                                   QObject* theParent,
46                                               boost::shared_ptr<ModelAPI_Feature> theFeature)
47 : PartSet_OperationSketchBase(theId, theParent), mySketch(theFeature),
48   myPointSelectionMode(SM_FirstPoint)
49 {
50 }
51
52 PartSet_OperationSketchLine::~PartSet_OperationSketchLine()
53 {
54 }
55
56 bool PartSet_OperationSketchLine::isGranted(ModuleBase_IOperation* theOperation) const
57 {
58   return theOperation->getDescription()->operationId().toStdString() == PartSet_OperationSketch::Type();
59 }
60
61 std::list<int> PartSet_OperationSketchLine::getSelectionModes(boost::shared_ptr<ModelAPI_Feature> theFeature) const
62 {
63   std::list<int> aModes;
64   if (theFeature != feature())
65     aModes = PartSet_OperationSketchBase::getSelectionModes(theFeature);
66   return aModes;
67 }
68
69 void PartSet_OperationSketchLine::init(boost::shared_ptr<ModelAPI_Feature> theFeature,
70                                        const std::list<XGUI_ViewerPrs>& /*thePresentations*/)
71 {
72   if (!theFeature || theFeature->getKind() != "SketchLine")
73     return;
74   // use the last point of the previous feature as the first of the new one
75   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
76   myInitPoint = boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_END));
77 }
78
79 boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::sketch() const
80 {
81   return mySketch;
82 }
83
84 void PartSet_OperationSketchLine::mouseReleased(QMouseEvent* theEvent, Handle(V3d_View) theView,
85                                                 const std::list<XGUI_ViewerPrs>& theSelected)
86 {
87   double aX, anY;
88
89   bool isFoundPoint = false;
90   gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
91   if (theSelected.empty()) {
92     PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, aX, anY);
93     isFoundPoint = true;
94   }
95   else {
96     XGUI_ViewerPrs aPrs = theSelected.front();
97     const TopoDS_Shape& aShape = aPrs.shape();
98     if (!aShape.IsNull()) // the point is selected
99     {
100       if (aShape.ShapeType() == TopAbs_VERTEX) {
101         const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
102         if (!aVertex.IsNull()) {
103           aPoint = BRep_Tool::Pnt(aVertex);
104           PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, aX, anY);
105           isFoundPoint = true;
106
107           setConstraints(aX, anY);
108         }
109       }
110       else if (aShape.ShapeType() == TopAbs_EDGE) // the line is selected
111       {
112         boost::shared_ptr<ModelAPI_Feature> aFeature = aPrs.feature();
113         if (aFeature) {
114           double X0, X1, X2, X3;
115           double Y0, Y1, Y2, Y3;
116           getLinePoint(aFeature, LINE_ATTR_START, X2, Y2);
117           getLinePoint(aFeature, LINE_ATTR_END, X3, Y3);
118           PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, X1, Y1);
119
120           switch (myPointSelectionMode) {
121             case SM_FirstPoint:
122               PartSet_Tools::ProjectPointOnLine(X2, Y2, X3, Y3, X1, Y1, aX, anY);
123             break;
124             case SM_SecondPoint: {
125               getLinePoint(feature(), LINE_ATTR_START, X0, Y0);
126               PartSet_Tools::IntersectLines(X0, Y0, X1, Y1, X2, Y2, X3, Y3, aX, anY);
127             }
128             break;
129             default:
130             break;
131           }
132           isFoundPoint = true;
133         }
134       }
135     }
136   }
137   //if (!isFoundPoint)
138   //  return;
139
140   switch (myPointSelectionMode)
141   {
142     case SM_FirstPoint: {
143       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
144       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
145       myPointSelectionMode = SM_SecondPoint;
146     }
147     break;
148     case SM_SecondPoint: {
149       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
150       myPointSelectionMode = SM_DonePoint;
151     }
152     break;
153     default:
154       break;
155   }
156 }
157
158 void PartSet_OperationSketchLine::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View) theView)
159 {
160   switch (myPointSelectionMode)
161   {
162     case SM_FirstPoint: {
163       double aX, anY;
164       gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
165       PartSet_Tools::ConvertTo2D(aPoint, sketch(), theView, aX, anY);
166       setLinePoint(feature(), aX, anY, LINE_ATTR_START);
167       setLinePoint(feature(), aX, anY, LINE_ATTR_END);
168     }
169     break;
170     case SM_SecondPoint:
171     {
172       gp_Pnt aPoint = PartSet_Tools::ConvertClickToPoint(theEvent->pos(), theView);
173       setLinePoint(aPoint, theView, LINE_ATTR_END);
174     }
175     break;
176     case SM_DonePoint:
177     {
178       commit();
179       emit featureConstructed(feature(), FM_Deactivation);
180       emit launchOperation(PartSet_OperationSketchLine::Type(), feature());
181     }
182     default:
183       break;
184   }
185 }
186
187 void PartSet_OperationSketchLine::keyReleased(const int theKey)
188 {
189   switch (theKey) {
190     case Qt::Key_Return: {
191       if (myPointSelectionMode == SM_DonePoint)
192       {
193         commit();
194         emit featureConstructed(feature(), FM_Deactivation);
195       }
196       else
197         abort();
198       emit launchOperation(PartSet_OperationSketchLine::Type(), boost::shared_ptr<ModelAPI_Feature>());
199     }
200     break;
201     default:
202       PartSet_OperationSketchBase::keyReleased(theKey); 
203     break;
204   }
205 }
206
207 void PartSet_OperationSketchLine::startOperation()
208 {
209   PartSet_OperationSketchBase::startOperation();
210   myPointSelectionMode = !myInitPoint ? SM_FirstPoint : SM_SecondPoint;
211   emit multiSelectionEnabled(false);
212 }
213
214 void PartSet_OperationSketchLine::abortOperation()
215 {
216   emit featureConstructed(feature(), FM_Abort);
217   PartSet_OperationSketchBase::abortOperation();
218 }
219
220 void PartSet_OperationSketchLine::stopOperation()
221 {
222   PartSet_OperationSketchBase::stopOperation();
223   emit multiSelectionEnabled(true);
224 }
225
226 boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchLine::createFeature()
227 {
228   boost::shared_ptr<ModelAPI_Feature> aNewFeature = ModuleBase_Operation::createFeature();
229   if (sketch()) {
230     boost::shared_ptr<SketchPlugin_Feature> aFeature = 
231                            boost::dynamic_pointer_cast<SketchPlugin_Feature>(sketch());
232
233     aFeature->addSub(aNewFeature);
234   }
235   if (myInitPoint) {
236     setLinePoint(aNewFeature, myInitPoint->x(), myInitPoint->y(), LINE_ATTR_START);
237     setLinePoint(aNewFeature, myInitPoint->x(), myInitPoint->y(), LINE_ATTR_END);
238
239     boost::shared_ptr<ModelAPI_Data> aData = aNewFeature->data();
240     boost::shared_ptr<GeomDataAPI_Point2D> aPoint = boost::dynamic_pointer_cast<GeomDataAPI_Point2D>
241                                                                 (aData->attribute(LINE_ATTR_START));
242     createConstraint(myInitPoint, aPoint);
243   }
244
245   emit featureConstructed(aNewFeature, FM_Activation);
246   return aNewFeature;
247 }
248
249 void PartSet_OperationSketchLine::createConstraint(boost::shared_ptr<GeomDataAPI_Point2D> thePoint1,
250                                                    boost::shared_ptr<GeomDataAPI_Point2D> thePoint2)
251 {
252   boost::shared_ptr<ModelAPI_Document> aDoc = document();
253   boost::shared_ptr<ModelAPI_Feature> aFeature = aDoc->addFeature("SketchConstraintCoincidence");
254
255   if (sketch()) {
256     boost::shared_ptr<SketchPlugin_Feature> aSketch = 
257                            boost::dynamic_pointer_cast<SketchPlugin_Feature>(sketch());
258     aSketch->addSub(aFeature);
259   }
260
261   boost::shared_ptr<ModelAPI_Data> aData = aFeature->data();
262
263   boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef1 =
264         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(CONSTRAINT_ATTR_ENTITY_A));
265   aRef1->setAttr(thePoint1);
266
267   boost::shared_ptr<ModelAPI_AttributeRefAttr> aRef2 =
268         boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aData->attribute(CONSTRAINT_ATTR_ENTITY_B));
269   aRef2->setAttr(thePoint2);
270
271   if (aFeature) // TODO: generate an error if feature was not created
272     aFeature->execute();
273 }
274
275 void PartSet_OperationSketchLine::setConstraints(double theX, double theY)
276 {
277   std::string aPointArg;
278   switch (myPointSelectionMode)
279   {
280     case SM_FirstPoint:
281       aPointArg = LINE_ATTR_START;
282       break;
283     case SM_SecondPoint:
284       aPointArg = LINE_ATTR_END;
285       break;
286   }
287
288   boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
289   boost::shared_ptr<GeomDataAPI_Point2D> aPoint = boost::dynamic_pointer_cast<GeomDataAPI_Point2D>
290                                                               (aData->attribute(aPointArg));
291   aData = sketch()->data();
292   boost::shared_ptr<ModelAPI_AttributeRefList> aRefList =
293         boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aData->attribute(SKETCH_ATTR_FEATURES));
294
295   std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aRefList->list();
296   std::list<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
297                                                                   aLast = aFeatures.end();
298   for (; anIt != aLast; anIt++) {
299     boost::shared_ptr<ModelAPI_Feature> aFeature = *anIt;
300     boost::shared_ptr<GeomDataAPI_Point2D> aFPoint = findLinePoint(aFeature, theX, theY);
301     if (aFPoint)
302       createConstraint(aFPoint, aPoint);
303   }
304 }
305
306 void PartSet_OperationSketchLine::getLinePoint(boost::shared_ptr<ModelAPI_Feature> theFeature,
307                                                const std::string& theAttribute,
308                                                double& theX, double& theY)
309 {
310   if (!theFeature || theFeature->getKind() != "SketchLine")
311     return;
312   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
313   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
314         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
315   theX = aPoint->x();
316   theY = aPoint->y();
317 }
318
319 boost::shared_ptr<GeomDataAPI_Point2D> PartSet_OperationSketchLine::findLinePoint(
320                                                boost::shared_ptr<ModelAPI_Feature> theFeature,
321                                                double theX, double theY)
322 {
323   boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D;
324   if (!theFeature || theFeature->getKind() != "SketchLine")
325     return aPoint2D;
326   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
327   
328   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
329         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_START));
330   if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
331     aPoint2D = aPoint;
332   else {
333     aPoint = boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(LINE_ATTR_END));
334     if (fabs(aPoint->x() - theX) < Precision::Confusion() && fabs(aPoint->y() - theY) < Precision::Confusion() )
335       aPoint2D = aPoint;
336   }
337   return aPoint2D;
338 }
339
340 void PartSet_OperationSketchLine::setLinePoint(boost::shared_ptr<ModelAPI_Feature> theFeature,
341                                                double theX, double theY,
342                                                const std::string& theAttribute)
343 {
344   if (!theFeature)
345     return;
346   boost::shared_ptr<ModelAPI_Data> aData = theFeature->data();
347   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
348         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
349   aPoint->setValue(theX, theY);
350 }
351
352 void PartSet_OperationSketchLine::setLinePoint(const gp_Pnt& thePoint,
353                                                Handle(V3d_View) theView,
354                                                const std::string& theAttribute)
355 {
356   double aX, anY;
357   PartSet_Tools::ConvertTo2D(thePoint, sketch(), theView, aX, anY);
358   boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
359   boost::shared_ptr<GeomDataAPI_Point2D> aPoint =
360         boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(theAttribute));
361   aPoint->setValue(aX, anY);
362 }