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