Salome HOME
registerNotObligatory is not necessary if this property is set in XML.
[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 = SketcherPrs_Factory::rotateConstraint(this, sketch()->coordinatePlane(),
208                                                              thePrevious);
209   return anAIS;
210 }
211
212 void SketchPlugin_MultiRotation::erase()
213 {
214   static Events_Loop* aLoop = Events_Loop::loop();
215   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
216
217   // Set copy attribute to false on all copied features.
218   AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
219       data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
220   AttributeRefListPtr aRefListOfRotated = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
221       data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
222
223   if(aRefListOfShapes.get() && aRefListOfRotated.get()) {
224     for(int anIndex = 0; anIndex < aRefListOfRotated->size(); anIndex++) {
225       ObjectPtr anObject = aRefListOfRotated->object(anIndex);
226       if(aRefListOfShapes->isInList(anObject)) {
227         // Don't modify attribute of original features, just skip.
228         continue;
229       }
230       if(anObject.get()) {
231         ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
232         if(aRes.get()) {
233           FeaturePtr aFeature = aRes->document()->feature(aRes);
234           if(aFeature.get()) {
235             AttributeBooleanPtr aBooleanAttr = aFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
236             if(aBooleanAttr.get()) {
237               if (ModelAPI_Session::get()->isOperation()) // if this is not undo or redo
238                 aBooleanAttr->setValue(false);
239               // Redisplay object as it is not copy anymore.
240               ModelAPI_EventCreator::get()->sendUpdated(aRes, aRedispEvent);
241             }
242           }
243         }
244       }
245     }
246   }
247
248   SketchPlugin_ConstraintBase::erase();
249 }
250
251 ObjectPtr SketchPlugin_MultiRotation::copyFeature(ObjectPtr theObject)
252 {
253   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theObject);
254   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
255   if (!aFeature || !aResult)
256     return ObjectPtr();
257
258   FeaturePtr aNewFeature = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aFeature, sketch(), true);
259   aNewFeature->execute();
260
261   static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
262   ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
263
264   std::shared_ptr<GeomAPI_Shape> aShapeIn = aResult->shape();
265   const std::list<ResultPtr>& aResults = aNewFeature->results();
266   std::list<ResultPtr>::const_iterator anIt = aResults.begin();
267   for (; anIt != aResults.end(); anIt++) {
268     ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIt);
269     if (!aRC) continue;
270     std::shared_ptr<GeomAPI_Shape> aShapeOut = aRC->shape();
271     if ((aShapeIn->isVertex() && aShapeOut->isVertex()) ||
272         (aShapeIn->isEdge() && aShapeOut->isEdge()) ||
273         (aShapeIn->isFace() && aShapeOut->isFace()))
274       return aRC;
275   }
276   return ObjectPtr();
277 }
278
279 /*void SketchPlugin_MultiRotation::rotateFeature(
280     ObjectPtr theInitial, ObjectPtr theTarget,
281     double theCenterX, double theCenterY, double theAngle)
282 {
283   std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(theCenterX, theCenterY));
284   double cosA = std::cos(theAngle);
285   double sinA = std::sin(theAngle);
286
287   FeaturePtr anInitialFeature = ModelAPI_Feature::feature(theInitial);
288   FeaturePtr aTargetFeature = ModelAPI_Feature::feature(theTarget);
289
290   // block feature update
291   aTargetFeature->data()->blockSendAttributeUpdated(true);
292
293   std::list<AttributePtr> anInitAttrList =
294       anInitialFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
295   std::list<AttributePtr> aTargetAttrList =
296       aTargetFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
297   std::list<AttributePtr>::iterator anInitIt = anInitAttrList.begin();
298   std::list<AttributePtr>::iterator aTargetIt = aTargetAttrList.begin();
299   for (; anInitIt != anInitAttrList.end(); anInitIt++, aTargetIt++) {
300     std::shared_ptr<GeomDataAPI_Point2D> aPointFrom =
301         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anInitIt);
302     std::shared_ptr<GeomDataAPI_Point2D> aPointTo =
303         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*aTargetIt);
304     std::shared_ptr<GeomAPI_XY> aPnt = aPointFrom->pnt()->xy();
305     if (aPnt->distance(aCenter->xy()) > 1.e-7) {
306       std::shared_ptr<GeomAPI_XY> aDir = aPnt->decreased(aCenter->xy());
307       double dx = cosA * aDir->x() - sinA * aDir->y();
308       double dy = sinA * aDir->x() + cosA * aDir->y();
309       aPnt->setX(aCenter->x() + dx);
310       aPnt->setY(aCenter->y() + dy);
311     }
312     aPointTo->setValue(aPnt->x(), aPnt->y());
313   }
314
315   // unblock feature update
316   aTargetFeature->data()->blockSendAttributeUpdated(false);
317 }*/
318
319
320 void SketchPlugin_MultiRotation::attributeChanged(const std::string& theID)
321 {
322   if (theID == ROTATION_LIST_ID()) {
323     AttributeRefListPtr aRotationObjectRefs = reflist(ROTATION_LIST_ID());
324     if (aRotationObjectRefs->size() == 0) {
325       int aNbCopies = integer(NUMBER_OF_OBJECTS_ID())->value()-1;
326       if (aNbCopies <= 0)
327         return;
328
329       // Clear list of objects
330       AttributeRefListPtr aRefListOfRotated = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
331           data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
332       std::list<ObjectPtr> aTargetList = aRefListOfRotated->list();
333       std::list<ObjectPtr>::iterator aTargetIter = aTargetList.begin();
334       while (aTargetIter != aTargetList.end()) {
335         aTargetIter++;
336         for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) {
337           aRefListOfRotated->remove(*aTargetIter);
338           // remove the corresponding feature from the sketch
339           ResultConstructionPtr aRC =
340             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aTargetIter);
341           DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
342           FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
343           if (aFeature)
344             aDoc->removeFeature(aFeature);
345         }
346       }
347       aRefListOfRotated->clear();
348       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
349         data()->attribute(SketchPlugin_Constraint::ENTITY_A()))->clear();
350       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
351         data()->attribute(SketchPlugin_Constraint::ENTITY_B()))->clear();
352     }
353   }
354 }