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