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