Salome HOME
Erroneous cases in SALOME mode: Sketch, start sub-feature operation[some control...
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MultiRotation.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_MultiRotation.cpp
4 // Created: 21 Apr 2015
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchPlugin_MultiRotation.h"
8
9 #include <GeomDataAPI_Point2D.h>
10 #include <ModelAPI_AttributeDouble.h>
11 #include <ModelAPI_AttributeInteger.h>
12 #include <ModelAPI_Data.h>
13 #include <ModelAPI_ResultConstruction.h>
14 #include <ModelAPI_AttributeRefList.h>
15 #include <ModelAPI_Events.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
18
19 #include <GeomAPI_Pnt2d.h>
20 #include <GeomAPI_XY.h>
21
22 #include <SketcherPrs_Factory.h>
23
24 #include <cmath>
25
26 #define PI 3.1415926535897932
27
28 SketchPlugin_MultiRotation::SketchPlugin_MultiRotation()
29 {
30 }
31
32 void SketchPlugin_MultiRotation::initAttributes()
33 {
34   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
35   data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
36   data()->addAttribute(NUMBER_OF_COPIES_ID(), ModelAPI_AttributeInteger::typeId());
37   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefList::typeId());
38   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
39   data()->addAttribute(ROTATION_LIST_ID(), ModelAPI_AttributeRefList::typeId());
40   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_A());
41   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
42 }
43
44 void SketchPlugin_MultiRotation::execute()
45 {
46   if (!sketch()) {
47     // it is possible, that this method is called before this feature has back reference to sketch
48     // in this case, the execute is performed after this is done
49     return;
50   }
51
52   AttributeRefListPtr aRotationObjectRefs = reflist(ROTATION_LIST_ID());
53   int aNbCopies = integer(NUMBER_OF_COPIES_ID())->value();
54
55   // Obtain center and angle of rotation
56   std::shared_ptr<GeomDataAPI_Point2D> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
57       attribute(CENTER_ID()));
58   if (!aCenter || !aCenter->isInitialized())
59     return;
60   // make a visible points
61   SketchPlugin_Sketch::createPoint2DResult(this, sketch(), CENTER_ID(), 0);
62
63   double anAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
64       attribute(ANGLE_ID()))->value();
65   // Convert angle to radians
66   anAngle *= PI / 180.0;
67
68   // Wait all objects being created, then send update events
69   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
70   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
71   if (isUpdateFlushed)
72     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
73
74   std::shared_ptr<ModelAPI_Data> aData = data();
75   AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
76       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
77   AttributeRefListPtr aRefListOfRotated = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
78       aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
79   int aCurrentNbCopies = aRefListOfShapes->size() ?
80       aRefListOfRotated->size() / aRefListOfShapes->size() - 1 : 0;
81   std::list<ObjectPtr> anInitialList = aRefListOfShapes->list();
82   std::list<ObjectPtr> aTargetList = aRefListOfRotated->list();
83   std::list<ObjectPtr> anAddition;
84   std::vector<bool> isUsed(anInitialList.size(), false);
85   // collect new items and check the items to remove
86   for(int anInd = 0; anInd < aRotationObjectRefs->size(); anInd++) {
87     ObjectPtr anObject = aRotationObjectRefs->object(anInd);
88     std::list<ObjectPtr>::const_iterator anIt = anInitialList.begin();
89     std::vector<bool>::iterator aUsedIt = isUsed.begin();
90     for (; anIt != anInitialList.end(); anIt++, aUsedIt++)
91       if (*anIt == anObject) {
92         *aUsedIt = true;
93         break;
94       }
95     if (anIt == anInitialList.end())
96       anAddition.push_back(anObject);
97   }
98   // remove unused items
99   std::list<ObjectPtr>::iterator anInitIter = anInitialList.begin();
100   std::list<ObjectPtr>::iterator aTargetIter = aTargetList.begin();
101   std::vector<bool>::iterator aUsedIter = isUsed.begin();
102   for (; aUsedIter != isUsed.end(); aUsedIter++) {
103     if (!(*aUsedIter)) {
104       aRefListOfShapes->remove(*anInitIter);
105       aRefListOfRotated->remove(*aTargetIter++);
106       for (int i = 0; i < aCurrentNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) {
107         aRefListOfRotated->remove(*aTargetIter);
108         // remove the corresponding feature from the sketch
109         ResultConstructionPtr aRC =
110             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aTargetIter);
111         DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
112         FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
113         if (aFeature)
114           aDoc->removeFeature(aFeature);
115       }
116     } else {
117       for (int i = 0; i <= aNbCopies && aTargetIter != aTargetList.end(); i++)
118         aTargetIter++;
119     }
120     if (anInitIter != anInitialList.end())
121       anInitIter++;
122   }
123   // change number of copies
124   if (aCurrentNbCopies != 0 && aNbCopies != aCurrentNbCopies) {
125     bool isAdd = aNbCopies > aCurrentNbCopies;
126     int aMinCopies = isAdd ? aCurrentNbCopies : aNbCopies;
127     int aMaxCopies = isAdd ? aNbCopies : aCurrentNbCopies;
128     int ind = 0;
129
130     aTargetList = aRefListOfRotated->list();
131     aTargetIter = aTargetList.begin();
132     ObjectPtr anObjToCopy = *aTargetIter;
133     while (aTargetIter != aTargetList.end()) {
134       aRefListOfRotated->remove(*aTargetIter);
135       aTargetIter++;
136       ind++;
137       if (ind > aMinCopies && ind <=aMaxCopies) {
138         while (ind <= aMaxCopies) {
139           if (isAdd) {
140             // Add new shifted item
141             ObjectPtr anObject = copyFeature(anObjToCopy);
142             aTargetList.insert(aTargetIter, anObject);
143           } else {
144             // remove object
145             std::list<ObjectPtr>::iterator aRemoveIt = aTargetIter++;
146             ObjectPtr anObject = *aRemoveIt;
147             aTargetList.erase(aRemoveIt);
148             aRefListOfRotated->remove(anObject);
149             // remove the corresponding feature from the sketch
150             ResultConstructionPtr aRC =
151                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(anObject);
152             DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
153             FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
154             if (aFeature)
155               aDoc->removeFeature(aFeature);
156           }
157           ind++;
158         }
159         ind = 0;
160         if (aTargetIter != aTargetList.end())
161           anObjToCopy = *aTargetIter;
162       }
163     }
164
165     for (aTargetIter = aTargetList.begin(); aTargetIter != aTargetList.end(); aTargetIter++)
166       aRefListOfRotated->append(*aTargetIter);
167   }
168   // add new items
169   std::list<ObjectPtr>::iterator anAddIter = anAddition.begin();
170   for (; anAddIter != anAddition.end(); anAddIter++) {
171     aRefListOfShapes->append(*anAddIter);
172     aRefListOfRotated->append(*anAddIter);
173     for (int i = 0; i < aNbCopies; i++) {
174       ObjectPtr anObject = copyFeature(*anAddIter);
175       aRefListOfRotated->append(anObject);
176     }
177   }
178
179 ////  if (fabs(anAngle) > 1.e-12) {
180 ////    // Recalculate positions of features
181 ////    aTargetList = aRefListOfRotated->list();
182 ////    aTargetIter = aTargetList.begin();
183 ////    while (aTargetIter != aTargetList.end()) {
184 ////      ObjectPtr anInitialObject = *aTargetIter++;
185 ////      for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++)
186 ////        rotateFeature(anInitialObject, *aTargetIter, aCenter->x(), aCenter->y(), anAngle * (i + 1));
187 ////    }
188 ////  }
189
190   // send events to update the sub-features by the solver
191   if (isUpdateFlushed)
192     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
193 }
194
195 AISObjectPtr SketchPlugin_MultiRotation::getAISObject(AISObjectPtr thePrevious)
196 {
197   if (!sketch())
198     return thePrevious;
199
200   AISObjectPtr anAIS = thePrevious;
201   if (!anAIS) {
202     anAIS = SketcherPrs_Factory::rotateConstraint(this, sketch()->coordinatePlane());
203   }
204   return anAIS;
205 }
206
207
208 ObjectPtr SketchPlugin_MultiRotation::copyFeature(ObjectPtr theObject)
209 {
210   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theObject);
211   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
212   if (!aFeature || !aResult)
213     return ObjectPtr();
214
215   FeaturePtr aNewFeature = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aFeature, sketch());
216   aNewFeature->execute();
217
218   static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
219   ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
220
221   std::shared_ptr<GeomAPI_Shape> aShapeIn = aResult->shape();
222   const std::list<ResultPtr>& aResults = aNewFeature->results();
223   std::list<ResultPtr>::const_iterator anIt = aResults.begin();
224   for (; anIt != aResults.end(); anIt++) {
225     ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIt);
226     if (!aRC) continue;
227     std::shared_ptr<GeomAPI_Shape> aShapeOut = aRC->shape();
228     if ((aShapeIn->isVertex() && aShapeOut->isVertex()) ||
229         (aShapeIn->isEdge() && aShapeOut->isEdge()) ||
230         (aShapeIn->isFace() && aShapeOut->isFace()))
231       return aRC;
232   }
233   return ObjectPtr();
234 }
235
236 void SketchPlugin_MultiRotation::rotateFeature(
237     ObjectPtr theInitial, ObjectPtr theTarget,
238     double theCenterX, double theCenterY, double theAngle)
239 {
240   std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(theCenterX, theCenterY));
241   double cosA = std::cos(theAngle);
242   double sinA = std::sin(theAngle);
243
244   FeaturePtr anInitialFeature = ModelAPI_Feature::feature(theInitial);
245   FeaturePtr aTargetFeature = ModelAPI_Feature::feature(theTarget);
246
247   // block feature update
248   aTargetFeature->data()->blockSendAttributeUpdated(true);
249
250   std::list<AttributePtr> anInitAttrList =
251       anInitialFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
252   std::list<AttributePtr> aTargetAttrList =
253       aTargetFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
254   std::list<AttributePtr>::iterator anInitIt = anInitAttrList.begin();
255   std::list<AttributePtr>::iterator aTargetIt = aTargetAttrList.begin();
256   for (; anInitIt != anInitAttrList.end(); anInitIt++, aTargetIt++) {
257     std::shared_ptr<GeomDataAPI_Point2D> aPointFrom =
258         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anInitIt);
259     std::shared_ptr<GeomDataAPI_Point2D> aPointTo =
260         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*aTargetIt);
261     std::shared_ptr<GeomAPI_XY> aPnt = aPointFrom->pnt()->xy();
262     if (aPnt->distance(aCenter->xy()) > 1.e-7) {
263       std::shared_ptr<GeomAPI_XY> aDir = aPnt->decreased(aCenter->xy());
264       double dx = cosA * aDir->x() - sinA * aDir->y();
265       double dy = sinA * aDir->x() + cosA * aDir->y();
266       aPnt->setX(aCenter->x() + dx);
267       aPnt->setY(aCenter->y() + dy);
268     }
269     aPointTo->setValue(aPnt->x(), aPnt->y());
270   }
271
272   // unblock feature update
273   aTargetFeature->data()->blockSendAttributeUpdated(false);
274 }
275
276
277 void SketchPlugin_MultiRotation::attributeChanged(const std::string& theID)
278 {
279   if (theID == ROTATION_LIST_ID()) {
280     AttributeRefListPtr aRotationObjectRefs = reflist(ROTATION_LIST_ID());
281     if (aRotationObjectRefs->size() == 0) {
282       int aNbCopies = integer(NUMBER_OF_COPIES_ID())->value();
283       // Clear list of objects
284       AttributeRefListPtr aRefListOfRotated = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
285           data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
286       std::list<ObjectPtr> aTargetList = aRefListOfRotated->list();
287       std::list<ObjectPtr>::iterator aTargetIter = aTargetList.begin();
288       while (aTargetIter != aTargetList.end()) {
289         aTargetIter++;
290         for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) {
291           aRefListOfRotated->remove(*aTargetIter);
292           // remove the corresponding feature from the sketch
293           ResultConstructionPtr aRC =
294             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aTargetIter);
295           DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
296           FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
297           if (aFeature)
298             aDoc->removeFeature(aFeature);
299         }
300       }
301       aRefListOfRotated->clear();
302       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
303         data()->attribute(SketchPlugin_Constraint::ENTITY_A()))->clear();
304       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
305         data()->attribute(SketchPlugin_Constraint::ENTITY_B()))->clear();
306     }
307   }
308 }