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