Salome HOME
6fc020ddb0143117f5ab56531494b7d12bb6a679
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Tools.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "SketchPlugin_Tools.h"
22
23 #include "SketchPlugin_ConstraintCoincidence.h"
24 #include "SketchPlugin_ConstraintLength.h"
25 #include "SketchPlugin_ConstraintTangent.h"
26 #include "SketchPlugin_Line.h"
27 #include "SketchPlugin_Point.h"
28 #include "SketchPlugin_SketchEntity.h"
29
30 #include <SketcherPrs_Tools.h>
31
32 #include <ModelAPI_AttributeDouble.h>
33
34 #include <GeomAPI_Dir2d.h>
35 #include <GeomAPI_Pnt2d.h>
36 #include <GeomAPI_XY.h>
37
38 #include <GeomDataAPI_Point.h>
39 #include <GeomDataAPI_Point2D.h>
40
41 #ifdef DEBUG_TRIM
42 #include <iostream>
43 #endif
44
45 namespace SketchPlugin_Tools {
46
47 void clearExpressions(AttributeDoublePtr theAttribute)
48 {
49   theAttribute->setText(std::string());
50 }
51
52 void clearExpressions(AttributePointPtr theAttribute)
53 {
54   theAttribute->setText(std::string(), std::string(), std::string());
55 }
56
57 void clearExpressions(AttributePoint2DPtr theAttribute)
58 {
59   theAttribute->setText(std::string(), std::string());
60 }
61
62 void clearExpressions(AttributePtr theAttribute)
63 {
64   // Double
65   AttributeDoublePtr anAttributeDouble =
66       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
67   if (anAttributeDouble.get())
68     clearExpressions(anAttributeDouble);
69   // Point
70   AttributePointPtr anAttributePoint =
71       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
72   if (anAttributePoint.get())
73     clearExpressions(anAttributePoint);
74   // Point2D
75   AttributePoint2DPtr anAttributePoint2D =
76       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
77   if (anAttributePoint2D.get())
78     clearExpressions(anAttributePoint2D);
79 }
80
81 void clearExpressions(FeaturePtr theFeature)
82 {
83   if (!theFeature.get())
84     return;
85
86   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
87   std::list<AttributePtr>::iterator anAttributeIt = anAttributes.begin();
88   for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
89     clearExpressions(*anAttributeIt);
90   }
91 }
92
93 std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin)
94 {
95   std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
96                                                           SketchPlugin_Constraint::ENTITY_A());
97   if (aPnt.get() == NULL)
98     aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
99   return aPnt;
100 }
101
102 std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature)
103 {
104   std::set<FeaturePtr> aCoincident;
105   const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
106   std::set<AttributePtr>::const_iterator aIt;
107   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
108     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
109     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
110       aCoincident.insert(aConstrFeature);
111   }
112   return aCoincident;
113 }
114
115 void findCoincidences(const FeaturePtr theStartCoin,
116                       const std::string& theAttr,
117                       std::set<FeaturePtr>& theList,
118                       const bool theIsAttrOnly)
119 {
120   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
121   if(!aPnt) {
122     return;
123   }
124   FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
125   if(theList.find(aObj) == theList.end()) {
126     std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincidencePoint(theStartCoin);
127     if(aOrig.get() == NULL) {
128       return;
129     }
130     if(!theIsAttrOnly || !aPnt->isObject()) {
131       theList.insert(aObj);
132     }
133     std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(aObj);
134     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
135     for (; aCIt != aCoincidences.end(); ++aCIt) {
136       FeaturePtr aConstrFeature = *aCIt;
137       std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincidencePoint(aConstrFeature);
138       if(aPnt.get() && aOrig->isEqual(aPnt)) {
139         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A(),
140                          theList, theIsAttrOnly);
141         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B(),
142                          theList, theIsAttrOnly);
143       }
144     }
145   }
146 }
147
148 std::set<FeaturePtr> findFeaturesCoincidentToPoint(const AttributePoint2DPtr& thePoint)
149 {
150   std::set<FeaturePtr> aCoincidentFeatures;
151
152   FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
153   aCoincidentFeatures.insert(anOwner);
154
155   std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(anOwner);
156   std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
157   for (; aCIt != aCoincidences.end(); ++aCIt) {
158     bool isPointUsedInCoincidence = false;
159     AttributeRefAttrPtr anOtherCoincidentAttr;
160     for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
161       AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
162       if (!aRefAttr)
163         continue;
164       if (!aRefAttr->isObject() && aRefAttr->attr() == thePoint)
165         isPointUsedInCoincidence = true;
166       else
167         anOtherCoincidentAttr = aRefAttr;
168     }
169
170     if (isPointUsedInCoincidence) {
171       ObjectPtr anObj;
172       if (anOtherCoincidentAttr->isObject())
173         anObj = anOtherCoincidentAttr->object();
174       else
175         anObj = anOtherCoincidentAttr->attr()->owner();
176       aCoincidentFeatures.insert(ModelAPI_Feature::feature(anObj));
177     }
178   }
179
180   return aCoincidentFeatures;
181 }
182
183 // Container for point-point coincidences.
184 // Useful to find points coincident to a given point.
185 class CoincidentPoints
186 {
187 public:
188   void addCoincidence(const AttributePoint2DPtr& thePoint1,
189                       const AttributePoint2DPtr& thePoint2 = AttributePoint2DPtr())
190   {
191     std::list< std::set<AttributePoint2DPtr> >::iterator aFound1 = find(thePoint1);
192     std::list< std::set<AttributePoint2DPtr> >::iterator aFound2 = find(thePoint2);
193     if (aFound1 == myCoincidentPoints.end()) {
194       if (aFound2 == myCoincidentPoints.end()) {
195         std::set<AttributePoint2DPtr> aNewSet;
196         aNewSet.insert(thePoint1);
197         if (thePoint2)
198           aNewSet.insert(thePoint2);
199         myCoincidentPoints.push_back(aNewSet);
200       } else
201         aFound2->insert(thePoint1);
202     } else if (aFound2 == myCoincidentPoints.end()) {
203       if (thePoint2)
204         aFound1->insert(thePoint2);
205     } else {
206       aFound1->insert(aFound2->begin(), aFound2->end());
207       myCoincidentPoints.erase(aFound2);
208     }
209   }
210
211   std::set<AttributePoint2DPtr> coincidentPoints(const AttributePoint2DPtr& thePoint)
212   {
213     collectCoincidentPoints(thePoint);
214
215     std::list< std::set<AttributePoint2DPtr> >::iterator aFound = find(thePoint);
216     if (aFound == myCoincidentPoints.end())
217       return std::set<AttributePoint2DPtr>();
218     return *aFound;
219   }
220
221 private:
222   void coincidences(const FeaturePtr& theFeature,
223                     std::set<FeaturePtr>& theCoincidences) const
224   {
225     // iterate through coincideces for the given feature
226     std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
227     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
228     for (; aCIt != aCoincidences.end(); ++aCIt)
229     {
230       if (theCoincidences.find(*aCIt) != theCoincidences.end())
231         continue; // already processed
232       theCoincidences.insert(*aCIt);
233       // iterate on coincident attributes
234       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
235         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
236         if (aRefAttr && !aRefAttr->isObject())
237         {
238           FeaturePtr anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
239           if (anOwner != theFeature)
240             coincidences(anOwner, theCoincidences);
241         }
242       }
243     }
244   }
245
246   // Iteratively search points coincident to the given point
247   // (two points may be coincident through the third point)
248   void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
249   {
250     AttributePoint2DPtr aPoints[2];
251
252     FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
253     std::set<FeaturePtr> aCoincidences;
254     coincidences(anOwner, aCoincidences);
255
256     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
257     for (; aCIt != aCoincidences.end(); ++aCIt) {
258       aPoints[0] = AttributePoint2DPtr();
259       aPoints[1] = AttributePoint2DPtr();
260       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
261         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
262         if (aRefAttr && !aRefAttr->isObject())
263           aPoints[aPtInd++] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
264       }
265
266       if (aPoints[0] && aPoints[1])
267         addCoincidence(aPoints[0], aPoints[1]);
268     }
269   }
270
271   std::list< std::set<AttributePoint2DPtr> >::iterator find(const AttributePoint2DPtr& thePoint)
272   {
273     std::list< std::set<AttributePoint2DPtr> >::iterator aSeek = myCoincidentPoints.begin();
274     for (; aSeek != myCoincidentPoints.end(); ++aSeek)
275       if (aSeek->find(thePoint) != aSeek->end())
276         return aSeek;
277     return myCoincidentPoints.end();
278   }
279
280 private:
281   std::list< std::set<AttributePoint2DPtr> > myCoincidentPoints;
282 };
283
284 std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
285 {
286   CoincidentPoints aCoincidentPoints;
287   return aCoincidentPoints.coincidentPoints(thePoint);
288 }
289
290 void resetAttribute(SketchPlugin_Feature* theFeature,
291                     const std::string& theId)
292 {
293   AttributePtr anAttr = theFeature->attribute(theId);
294   if(anAttr.get()) {
295     anAttr->reset();
296   }
297 }
298
299 void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
300                                  const std::string& theId,
301                                  const AttributePtr theAttr,
302                                  const ObjectPtr theObject,
303                                  const bool theIsCanBeTangent)
304 {
305   AttributeRefAttrPtr aRefAttr = theFeature->refattr(theId);
306   if(aRefAttr.get() && aRefAttr->isInitialized()) {
307     FeaturePtr aConstraint;
308     if(!theIsCanBeTangent) {
309       aConstraint = theFeature->sketch()
310                               ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
311     } else {
312       if(aRefAttr->isObject()) {
313         ObjectPtr anObject = aRefAttr->object();
314         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
315         if(aFeature->getKind() == SketchPlugin_Point::ID()) {
316           aConstraint = theFeature->sketch()
317                                   ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
318         } else {
319           aConstraint = theFeature->sketch()
320                                   ->addFeature(SketchPlugin_ConstraintTangent::ID());
321         }
322       } else {
323         aConstraint = theFeature->sketch()
324                                 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
325       }
326     }
327     AttributeRefAttrPtr aRefAttrA = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
328     aRefAttr->isObject() ? aRefAttrA->setObject(aRefAttr->object())
329                          : aRefAttrA->setAttr(aRefAttr->attr());
330     AttributeRefAttrPtr aRefAttrB = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
331     if(theObject.get()) {
332       aRefAttrB->setObject(theObject);
333     } else if(theAttr.get()) {
334       aRefAttrB->setAttr(theAttr);
335     }
336   }
337 }
338
339 void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefAttr,
340                                          const AttributePtr&             theDefaultAttr,
341                                          std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
342                                          std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
343 {
344   AttributePtr anAttr = theDefaultAttr;
345   if (theRefAttr->isObject()) {
346     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
347     if (aTgFeature) {
348       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
349         theTangentCurve = aTgFeature->lastResult()->shape();
350         return;
351       }
352       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
353     }
354   } else
355     anAttr = theRefAttr->attr();
356
357   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
358 }
359
360
361 FeaturePtr createConstraintAttrAttr(SketchPlugin_Sketch* theSketch,
362                                     const std::string& theConstraintId,
363                                     const AttributePtr& theFirstAttribute,
364                                     const AttributePtr& theSecondAttribute)
365 {
366   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
367   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
368                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
369   aRefAttr->setAttr(theFirstAttribute);
370
371   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
372                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
373   aRefAttr->setAttr(theSecondAttribute);
374
375 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
376   std::cout << "<createConstraint to attribute> :"
377             << " first attribute - " << theFirstAttribute->id()
378             << " second attribute - " << theSecondAttribute->id()
379             << std::endl;
380 #endif
381
382   return aConstraint;
383 }
384
385 FeaturePtr createConstraintAttrObject(SketchPlugin_Sketch* theSketch,
386                                       const std::string& theConstraintId,
387                                       const AttributePtr& theFirstAttribute,
388                                       const ObjectPtr& theSecondObject)
389 {
390   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
391   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
392                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
393   aRefAttr->setAttr(theFirstAttribute);
394
395   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
396                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
397   aRefAttr->setObject(theSecondObject);
398
399 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
400   std::cout << "<createConstraint to attribute> :"
401             << " first attribute - " << theFirstAttribute->id()
402             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
403             << std::endl;
404 #endif
405
406   return aConstraint;
407 }
408
409 FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
410                                         const std::string& theConstraintId,
411                                         const ObjectPtr& theFirstObject,
412                                         const ObjectPtr& theSecondObject)
413 {
414   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
415   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
416                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
417   aRefAttr->setObject(theFirstObject);
418
419   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
420                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
421   aRefAttr->setObject(theSecondObject);
422
423 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
424   std::cout << "<createConstraint to attribute> :"
425             << " first object - " << ModelAPI_Feature::feature(theFirstObject)->getKind()
426             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
427             << std::endl;
428 #endif
429
430   return aConstraint;
431 }
432
433 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
434 {
435   // currently process Length constraints only
436   if (theConstraint->getKind() != SketchPlugin_ConstraintLength::ID())
437     return GeomPnt2dPtr();
438
439   AttributeRefAttrPtr aLineAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
440   if (!aLineAttr || !aLineAttr->isObject())
441     return GeomPnt2dPtr();
442   FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
443   if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
444     return GeomPnt2dPtr();
445
446   std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
447       aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
448   std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
449       aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
450
451   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
452       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
453       theConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
454   std::shared_ptr<GeomAPI_Pnt2d> aFltPnt = aFlyoutAttr->pnt();
455
456   std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
457
458   double X = aStartPnt->x() + aFltPnt->x() * aLineDir->x() - aFltPnt->y() * aLineDir->y();
459   double Y = aStartPnt->y() + aFltPnt->x() * aLineDir->y() + aFltPnt->y() * aLineDir->x();
460
461   return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
462 }
463
464 } // namespace SketchPlugin_Tools