Salome HOME
updated copyright message
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintMirror.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SketchPlugin_ConstraintMirror.h"
21
22 #include <ModelAPI_AttributeDouble.h>
23 #include <ModelAPI_Data.h>
24 #include <ModelAPI_ResultConstruction.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_Events.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_Validator.h>
29 #include <ModelAPI_Tools.h>
30
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Sketch.h>
33
34 #include <SketcherPrs_Factory.h>
35
36 #include <Config_PropManager.h>
37
38 SketchPlugin_ConstraintMirror::SketchPlugin_ConstraintMirror()
39 {
40 }
41
42 void SketchPlugin_ConstraintMirror::initAttributes()
43 {
44   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
45   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
46   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
47   data()->addAttribute(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID(),
48                        ModelAPI_AttributeRefList::typeId());
49   ModelAPI_Session::get()->validators()->
50     registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B());
51   ModelAPI_Session::get()->validators()->
52     registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
53 }
54
55 void SketchPlugin_ConstraintMirror::execute()
56 {
57   AttributeRefListPtr aMirrorObjectRefs = reflist(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID());
58
59   // Wait all objects being created, then send update events
60   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
61   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
62   if (isUpdateFlushed)
63     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
64
65   // Save the current feature of the document, because new features may appear while executing.
66   // In this case, they will become current. But if the number of copies is updated from outside
67   // of sketch (e.g. by parameter change), the history line should not hold in sketch.
68   keepCurrentFeature();
69
70   std::shared_ptr<ModelAPI_Data> aData = data();
71   AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
72       aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
73   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
74       aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
75   std::list<ObjectPtr> anInitialList =  aRefListOfShapes->list();
76   std::list<ObjectPtr> aMirroredList =  aRefListOfMirrored->list();
77   std::vector<bool> isUsed(anInitialList.size(), false);
78   // add new items to the list
79   for(int anInd = 0; anInd < aMirrorObjectRefs->size(); anInd++) {
80     ObjectPtr anObject = aMirrorObjectRefs->object(anInd);
81     std::list<ObjectPtr>::const_iterator anIt = anInitialList.begin();
82     std::vector<bool>::iterator aUsedIt = isUsed.begin();
83     for (; anIt != anInitialList.end(); anIt++, aUsedIt++)
84       if (*anIt == anObject) {
85         *aUsedIt = true;
86         break;
87       }
88     if (anIt == anInitialList.end())
89       aRefListOfShapes->append(anObject);
90   }
91   // remove unused items
92   std::list<ObjectPtr>::iterator anInitIter = anInitialList.begin();
93   std::list<ObjectPtr>::iterator aMirrorIter = aMirroredList.begin();
94   std::vector<bool>::iterator aUsedIter = isUsed.begin();
95   std::set<FeaturePtr> aFeaturesToBeRemoved;
96   for (; aUsedIter != isUsed.end(); aUsedIter++) {
97     if (!(*aUsedIter)) {
98       aRefListOfShapes->remove(*anInitIter);
99       if (aMirrorIter != aMirroredList.end()) {
100         aRefListOfMirrored->remove(*aMirrorIter);
101         // remove the corresponding feature from the sketch
102         ResultConstructionPtr aRC =
103             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirrorIter);
104         DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr();
105         FeaturePtr aFeature =  aDoc ? aDoc->feature(aRC) : FeaturePtr();
106         if (aFeature)
107           aFeaturesToBeRemoved.insert(aFeature);
108       }
109     }
110     if (anInitIter != anInitialList.end())
111       anInitIter++;
112     if (aMirrorIter != aMirroredList.end())
113       aMirrorIter++;
114   }
115   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
116
117   static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
118
119   // Check consistency of initial list and mirrored list
120   anInitialList =  aRefListOfShapes->list();
121   anInitIter = anInitialList.begin();
122   aMirrorIter = aMirroredList.begin();
123   int indFirstWrong = 0; // index of element starts difference in the lists
124   std::set<int> anInvalidInd; // list of indices of removed features
125   std::shared_ptr<SketchPlugin_Feature> aFeatureIn, aFeatureOut;
126   for ( ; anInitIter != anInitialList.end(); anInitIter++, indFirstWrong++) {
127     // Add features and store indices of objects to remove
128     aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
129     ResultConstructionPtr aRCIn;
130     if (!aFeatureIn) {
131       aRCIn = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
132       if (aRCIn)
133         aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(
134             aRCIn->document()->feature(aRCIn));
135     }
136     if (aMirrorIter == aMirroredList.end())
137       aFeatureOut = std::shared_ptr<SketchPlugin_Feature>();
138     else {
139       aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter);
140       if (!aFeatureOut) {
141         ResultConstructionPtr aRC =
142             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
143         if (aRC)
144           aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(
145               aRC->document()->feature(aRC));
146       }
147     }
148     if (!aFeatureIn) {
149       if (aFeatureOut)
150         break; // the lists are inconsistent
151       continue;
152     }
153     if (!aFeatureOut) {
154       if (aMirrorIter != aMirroredList.end())
155         break; // the lists are inconsistent
156       // There is no mirrored object yet, create it
157       FeaturePtr aNewFeature =
158         SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aFeatureIn, sketch(), true);
159       aNewFeature->execute();
160       ModelAPI_EventCreator::get()->sendUpdated(aNewFeature, aRedisplayEvent);
161
162       std::shared_ptr<GeomAPI_Shape> aShapeIn = aRCIn->shape();
163       const std::list<ResultPtr>& aResults = aNewFeature->results();
164       std::list<ResultPtr>::const_iterator anIt = aResults.begin();
165       for (; anIt != aResults.end(); anIt++) {
166         ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIt);
167         if (!aRC) continue;
168         std::shared_ptr<GeomAPI_Shape> aShapeOut = aRC->shape();
169         if ((aShapeIn->isVertex() && aShapeOut->isVertex()) ||
170             (aShapeIn->isEdge() && aShapeOut->isEdge()) ||
171             (aShapeIn->isFace() && aShapeOut->isFace()))
172           aRefListOfMirrored->append(aRC);
173       }
174       continue;
175     }
176     if (aFeatureIn->getKind() != aFeatureOut->getKind())
177       break; // the lists are inconsistent
178     if (!aFeatureIn->data()->isValid()) {
179       // initial feature was removed, delete it from lists
180       anInvalidInd.insert(indFirstWrong);
181     }
182     aMirrorIter++;
183   }
184   // Remove from the list objects already deleted before
185   std::set<int>::reverse_iterator anIt = anInvalidInd.rbegin();
186   for ( ; anIt != anInvalidInd.rend(); anIt++) {
187     if (*anIt < indFirstWrong) indFirstWrong--;
188     aRefListOfShapes->remove(aRefListOfShapes->object(*anIt));
189     aRefListOfMirrored->remove(aRefListOfMirrored->object(*anIt));
190   }
191   // If the lists inconsistent, remove all objects from mirrored list starting from indFirstWrong
192   if (anInitIter != anInitialList.end()) {
193     while (aRefListOfMirrored->size() > indFirstWrong)
194       aRefListOfMirrored->remove(aRefListOfMirrored->object(indFirstWrong));
195     // Create mirrored features instead of removed
196     anInitialList =  aRefListOfShapes->list();
197     anInitIter = anInitialList.begin();
198     for (int i = 0; i < indFirstWrong; i++) anInitIter++;
199     for ( ; anInitIter != anInitialList.end(); anInitIter++) {
200       aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
201       FeaturePtr aNewFeature = aFeatureIn->document()->addFeature(aFeatureIn->getKind());
202       aRefListOfMirrored->append(aNewFeature);
203     }
204   }
205
206   restoreCurrentFeature();
207
208   // send events to update the sub-features by the solver
209   if (isUpdateFlushed)
210     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
211 }
212
213 AISObjectPtr SketchPlugin_ConstraintMirror::getAISObject(AISObjectPtr thePrevious)
214 {
215   if (!sketch())
216     return thePrevious;
217
218   AISObjectPtr anAIS = SketcherPrs_Factory::mirrorConstraint(this, sketch(),
219                                                              thePrevious);
220   return anAIS;
221 }
222
223 void SketchPlugin_ConstraintMirror::erase()
224 {
225   // Set copy attribute to false on all copied features.
226   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
227       data()->attribute(SketchPlugin_Constraint::ENTITY_C()));
228
229   if(aRefListOfMirrored.get()) {
230     static Events_Loop* aLoop = Events_Loop::loop();
231     static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
232
233     std::list<ObjectPtr> aTargetList = aRefListOfMirrored->list();
234     for(std::list<ObjectPtr>::const_iterator aTargetIt =
235         aTargetList.cbegin(); aTargetIt != aTargetList.cend(); aTargetIt++) {
236       if((*aTargetIt).get()) {
237         ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(*aTargetIt);
238         if(aRes.get()) {
239           FeaturePtr aFeature = aRes->document()->feature(aRes);
240           if(aFeature.get()) {
241             AttributeBooleanPtr aBooleanAttr =
242               aFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
243             if(aBooleanAttr.get()) {
244               if (ModelAPI_Session::get()->isOperation()) // if this is not undo or redo
245                 aBooleanAttr->setValue(false);
246               // Redisplay object as it is not copy anymore.
247               ModelAPI_EventCreator::get()->sendUpdated(aRes, aRedispEvent);
248             }
249           }
250         }
251       }
252     }
253   }
254
255   SketchPlugin_ConstraintBase::erase();
256 }
257
258 void SketchPlugin_ConstraintMirror::attributeChanged(const std::string& theID)
259 {
260   if (theID == MIRROR_LIST_ID()) {
261     AttributeRefListPtr aMirrorObjectRefs = reflist(MIRROR_LIST_ID());
262     if (aMirrorObjectRefs->size() == 0) {
263       DocumentPtr aDoc = document();
264       // Clear list of objects
265       AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
266           data()->attribute(SketchPlugin_Constraint::ENTITY_C()));
267       std::list<ObjectPtr> aTargetList = aRefListOfMirrored->list();
268       std::list<ObjectPtr>::iterator aTargetIter = aTargetList.begin();
269       for (; aTargetIter != aTargetList.end(); aTargetIter++) {
270         FeaturePtr aFeature = ModelAPI_Feature::feature(*aTargetIter);
271         if (aFeature)
272           aDoc->removeFeature(aFeature);
273       }
274       aRefListOfMirrored->clear();
275       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
276         data()->attribute(SketchPlugin_Constraint::ENTITY_B()))->clear();
277     }
278   }
279 }
280