Salome HOME
Simplification and refactoring of unit tests for SketchPlugin
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintMirror.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_ConstraintMirror.cpp
4 // Created: 17 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchPlugin_ConstraintMirror.h"
8
9 #include <ModelAPI_AttributeDouble.h>
10 #include <ModelAPI_Data.h>
11 #include <ModelAPI_ResultConstruction.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <ModelAPI_Events.h>
14 #include <ModelAPI_Session.h>
15 #include <ModelAPI_Validator.h>
16 #include <ModelAPI_Tools.h>
17
18 #include <SketchPlugin_Line.h>
19 #include <SketchPlugin_Sketch.h>
20
21 #include <SketcherPrs_Factory.h>
22
23 #include <Config_PropManager.h>
24
25 SketchPlugin_ConstraintMirror::SketchPlugin_ConstraintMirror()
26 {
27 }
28
29 void SketchPlugin_ConstraintMirror::initAttributes()
30 {
31   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
32   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
33   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
34   data()->addAttribute(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID(),
35                        ModelAPI_AttributeRefList::typeId());
36   ModelAPI_Session::get()->validators()->
37     registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
38   ModelAPI_Session::get()->validators()->
39     registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
40 }
41
42 void SketchPlugin_ConstraintMirror::execute()
43 {
44   AttributeRefListPtr aMirrorObjectRefs = reflist(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID());
45
46   // Wait all objects being created, then send update events
47   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
48   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
49   if (isUpdateFlushed)
50     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
51
52   std::shared_ptr<ModelAPI_Data> aData = data();
53   AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
54       aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
55   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
56       aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
57   std::list<ObjectPtr> anInitialList =  aRefListOfShapes->list();
58   std::list<ObjectPtr> aMirroredList =  aRefListOfMirrored->list();
59   std::vector<bool> isUsed(anInitialList.size(), false);
60   // add new items to the list
61   for(int anInd = 0; anInd < aMirrorObjectRefs->size(); anInd++) {
62     ObjectPtr anObject = aMirrorObjectRefs->object(anInd);
63     std::list<ObjectPtr>::const_iterator anIt = anInitialList.begin();
64     std::vector<bool>::iterator aUsedIt = isUsed.begin();
65     for (; anIt != anInitialList.end(); anIt++, aUsedIt++)
66       if (*anIt == anObject) {
67         *aUsedIt = true;
68         break;
69       }
70     if (anIt == anInitialList.end())
71       aRefListOfShapes->append(anObject);
72   }
73   // remove unused items
74   std::list<ObjectPtr>::iterator anInitIter = anInitialList.begin();
75   std::list<ObjectPtr>::iterator aMirrorIter = aMirroredList.begin();
76   std::vector<bool>::iterator aUsedIter = isUsed.begin();
77   std::set<FeaturePtr> aFeaturesToBeRemoved;
78   for (; aUsedIter != isUsed.end(); aUsedIter++) {
79     if (!(*aUsedIter)) {
80       aRefListOfShapes->remove(*anInitIter);
81       if (aMirrorIter != aMirroredList.end()) {
82         aRefListOfMirrored->remove(*aMirrorIter);
83         // remove the corresponding feature from the sketch
84         ResultConstructionPtr aRC =
85             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirrorIter);
86         DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
87         FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
88         if (aFeature)
89           aFeaturesToBeRemoved.insert(aFeature);
90       }
91     }
92     if (anInitIter != anInitialList.end())
93       anInitIter++;
94     if (aMirrorIter != aMirroredList.end())
95       aMirrorIter++;
96   }
97   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
98
99   static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
100
101   // Check consistency of initial list and mirrored list
102   anInitialList =  aRefListOfShapes->list();
103   anInitIter = anInitialList.begin();
104   aMirrorIter = aMirroredList.begin();
105   int indFirstWrong = 0; // index of element starts difference in the lists
106   std::set<int> anInvalidInd; // list of indices of removed features
107   std::shared_ptr<SketchPlugin_Feature> aFeatureIn, aFeatureOut;
108   for ( ; anInitIter != anInitialList.end(); anInitIter++, indFirstWrong++) {
109     // Add features and store indices of objects to remove
110     aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
111     ResultConstructionPtr aRCIn;
112     if (!aFeatureIn) {
113       aRCIn = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
114       if (aRCIn)
115         aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(
116             aRCIn->document()->feature(aRCIn));
117     }
118     if (aMirrorIter == aMirroredList.end())
119       aFeatureOut = std::shared_ptr<SketchPlugin_Feature>();
120     else {
121       aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter);
122       if (!aFeatureOut) {
123         ResultConstructionPtr aRC =
124             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
125         if (aRC)
126           aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(
127               aRC->document()->feature(aRC));
128       }
129     }
130     if (!aFeatureIn) {
131       if (aFeatureOut)
132         break; // the lists are inconsistent
133       continue;
134     }
135     if (!aFeatureOut) {
136       if (aMirrorIter != aMirroredList.end())
137         break; // the lists are inconsistent
138       // There is no mirrored object yet, create it
139       FeaturePtr aNewFeature =
140         SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aFeatureIn, sketch(), true);
141       aNewFeature->execute();
142       ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
143
144       std::shared_ptr<GeomAPI_Shape> aShapeIn = aRCIn->shape();
145       const std::list<ResultPtr>& aResults = aNewFeature->results();
146       std::list<ResultPtr>::const_iterator anIt = aResults.begin();
147       for (; anIt != aResults.end(); anIt++) {
148         ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIt);
149         if (!aRC) continue;
150         std::shared_ptr<GeomAPI_Shape> aShapeOut = aRC->shape();
151         if ((aShapeIn->isVertex() && aShapeOut->isVertex()) ||
152             (aShapeIn->isEdge() && aShapeOut->isEdge()) ||
153             (aShapeIn->isFace() && aShapeOut->isFace()))
154           aRefListOfMirrored->append(aRC);
155       }
156       continue;
157     }
158     if (aFeatureIn->getKind() != aFeatureOut->getKind())
159       break; // the lists are inconsistent
160     if (!aFeatureIn->data()->isValid()) {
161       // initial feature was removed, delete it from lists
162       anInvalidInd.insert(indFirstWrong);
163     }
164     aMirrorIter++;
165   }
166   // Remove from the list objects already deleted before
167   std::set<int>::reverse_iterator anIt = anInvalidInd.rbegin();
168   for ( ; anIt != anInvalidInd.rend(); anIt++) {
169     if (*anIt < indFirstWrong) indFirstWrong--;
170     aRefListOfShapes->remove(aRefListOfShapes->object(*anIt));
171     aRefListOfMirrored->remove(aRefListOfMirrored->object(*anIt));
172   }
173   // If the lists inconsistent, remove all objects from mirrored list starting from indFirstWrong
174   if (anInitIter != anInitialList.end()) {
175     while (aRefListOfMirrored->size() > indFirstWrong)
176       aRefListOfMirrored->remove(aRefListOfMirrored->object(indFirstWrong));
177     // Create mirrored features instead of removed
178     anInitialList =  aRefListOfShapes->list();
179     anInitIter = anInitialList.begin();
180     for (int i = 0; i < indFirstWrong; i++) anInitIter++;
181     for ( ; anInitIter != anInitialList.end(); anInitIter++) {
182       aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
183       FeaturePtr aNewFeature = aFeatureIn->document()->addFeature(aFeatureIn->getKind());
184       aRefListOfMirrored->append(aNewFeature);
185     }
186   }
187
188   // send events to update the sub-features by the solver
189   if (isUpdateFlushed)
190     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
191 }
192
193 AISObjectPtr SketchPlugin_ConstraintMirror::getAISObject(AISObjectPtr thePrevious)
194 {
195   if (!sketch())
196     return thePrevious;
197
198   AISObjectPtr anAIS = SketcherPrs_Factory::mirrorConstraint(this, sketch()->coordinatePlane(),
199                                                              thePrevious);
200   return anAIS;
201 }
202
203 void SketchPlugin_ConstraintMirror::erase()
204 {
205   // Set copy attribute to false on all copied features.
206   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
207       data()->attribute(SketchPlugin_Constraint::ENTITY_C()));
208
209   if(aRefListOfMirrored.get()) {
210     static Events_Loop* aLoop = Events_Loop::loop();
211     static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
212
213     std::list<ObjectPtr> aTargetList = aRefListOfMirrored->list();
214     for(std::list<ObjectPtr>::const_iterator aTargetIt =
215         aTargetList.cbegin(); aTargetIt != aTargetList.cend(); aTargetIt++) {
216       if((*aTargetIt).get()) {
217         ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(*aTargetIt);
218         if(aRes.get()) {
219           FeaturePtr aFeature = aRes->document()->feature(aRes);
220           if(aFeature.get()) {
221             AttributeBooleanPtr aBooleanAttr =
222               aFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
223             if(aBooleanAttr.get()) {
224               if (ModelAPI_Session::get()->isOperation()) // if this is not undo or redo
225                 aBooleanAttr->setValue(false);
226               // Redisplay object as it is not copy anymore.
227               ModelAPI_EventCreator::get()->sendUpdated(aRes, aRedispEvent);
228             }
229           }
230         }
231       }
232     }
233   }
234
235   SketchPlugin_ConstraintBase::erase();
236 }
237
238 void SketchPlugin_ConstraintMirror::attributeChanged(const std::string& theID)
239 {
240   if (theID == MIRROR_LIST_ID()) {
241     AttributeRefListPtr aMirrorObjectRefs = reflist(MIRROR_LIST_ID());
242     if (aMirrorObjectRefs->size() == 0) {
243       DocumentPtr aDoc = document();
244       // Clear list of objects
245       AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
246           data()->attribute(SketchPlugin_Constraint::ENTITY_C()));
247       std::list<ObjectPtr> aTargetList = aRefListOfMirrored->list();
248       std::list<ObjectPtr>::iterator aTargetIter = aTargetList.begin();
249       for (; aTargetIter != aTargetList.end(); aTargetIter++) {
250         FeaturePtr aFeature = ModelAPI_Feature::feature(*aTargetIter);
251         if (aFeature)
252           aDoc->removeFeature(aFeature);
253       }
254       aRefListOfMirrored->clear();
255       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
256         data()->attribute(SketchPlugin_Constraint::ENTITY_B()))->clear();
257     }
258   }
259 }
260