1 // Copyright (C) 2014-2023 CEA, EDF
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SketchPlugin_ConstraintMirror.h"
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>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Sketch.h>
34 #include <SketcherPrs_Factory.h>
36 #include <Config_PropManager.h>
38 SketchPlugin_ConstraintMirror::SketchPlugin_ConstraintMirror()
42 void SketchPlugin_ConstraintMirror::initAttributes()
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());
55 void SketchPlugin_ConstraintMirror::execute()
57 AttributeRefListPtr aMirrorObjectRefs = reflist(SketchPlugin_ConstraintMirror::MIRROR_LIST_ID());
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);
63 Events_Loop::loop()->setFlushed(anUpdateEvent, false);
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.
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) {
88 if (anIt == anInitialList.end())
89 aRefListOfShapes->append(anObject);
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++) {
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();
107 aFeaturesToBeRemoved.insert(aFeature);
110 if (anInitIter != anInitialList.end())
112 if (aMirrorIter != aMirroredList.end())
115 ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
117 static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
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;
131 aRCIn = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
133 aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(
134 aRCIn->document()->feature(aRCIn));
136 if (aMirrorIter == aMirroredList.end())
137 aFeatureOut = std::shared_ptr<SketchPlugin_Feature>();
139 aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter);
141 ResultConstructionPtr aRC =
142 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anInitIter);
144 aFeatureOut = std::dynamic_pointer_cast<SketchPlugin_Feature>(
145 aRC->document()->feature(aRC));
150 break; // the lists are inconsistent
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);
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);
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);
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);
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));
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);
206 restoreCurrentFeature();
208 // send events to update the sub-features by the solver
210 Events_Loop::loop()->setFlushed(anUpdateEvent, true);
213 AISObjectPtr SketchPlugin_ConstraintMirror::getAISObject(AISObjectPtr thePrevious)
218 AISObjectPtr anAIS = SketcherPrs_Factory::mirrorConstraint(this, sketch(),
223 void SketchPlugin_ConstraintMirror::erase()
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()));
229 if(aRefListOfMirrored.get()) {
230 static Events_Loop* aLoop = Events_Loop::loop();
231 static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
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);
239 FeaturePtr aFeature = aRes->document()->feature(aRes);
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);
255 SketchPlugin_ConstraintBase::erase();
258 void SketchPlugin_ConstraintMirror::attributeChanged(const std::string& theID)
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);
272 aDoc->removeFeature(aFeature);
274 aRefListOfMirrored->clear();
275 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
276 data()->attribute(SketchPlugin_Constraint::ENTITY_B()))->clear();