Salome HOME
Fix incorrect processing of the copied entities after the "Multi" constraint has...
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMulti.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <SketchSolver_ConstraintMulti.h>
4 #include <SketchSolver_Error.h>
5 #include <SketchSolver_Manager.h>
6
7 #include <GeomDataAPI_Point2D.h>
8 #include <ModelAPI_AttributeInteger.h>
9 #include <ModelAPI_AttributeRefAttr.h>
10 #include <ModelAPI_AttributeRefList.h>
11 #include <SketchPlugin_Arc.h>
12 #include <SketchPlugin_Circle.h>
13 #include <SketchPlugin_Line.h>
14 #include <SketchPlugin_Point.h>
15 #include <SketchPlugin_IntersectionPoint.h>
16
17 static void createCopiedEntity(const FeaturePtr& theFeature, const StoragePtr& theStorage)
18 {
19   EntityWrapperPtr anEntity = theStorage->entity(theFeature);
20   if (anEntity) {
21     std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
22         std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
23     if (!anEntity->isExternal() && aSketchFeature->isCopy())
24       theStorage->makeExternal(anEntity);
25   }
26 }
27
28 void SketchSolver_ConstraintMulti::getEntities(std::list<EntityWrapperPtr>& theEntities)
29 {
30   myAdjusted = false;
31
32   // Lists of objects and number of copies
33   AttributeRefListPtr anInitialRefList =
34       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A());
35   myNumberOfObjects = anInitialRefList->size();
36   myNumberOfCopies = myBaseConstraint->integer(nameNbObjects())->value() - 1;
37   if (myNumberOfCopies <= 0)
38     return;
39
40   AttributeRefListPtr aRefList =
41       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
42   if (!aRefList || aRefList->size() == 0) {
43     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
44     return;
45   }
46
47   FeaturePtr aFeature;
48   std::list<ObjectPtr> anObjectList = aRefList->list();
49   std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
50   // execute for the feature is not called yet
51   if ((myNumberOfCopies + 1) * myNumberOfObjects != aRefList->size())
52     myNumberOfCopies = aRefList->size() / myNumberOfObjects - 1;
53
54   while (anObjIt != anObjectList.end()) {
55     aFeature = ModelAPI_Feature::feature(*anObjIt++);
56     if (!aFeature)
57       continue;
58
59     // the entity is not created, so it is a copy in "multi" constraint, force its creation
60     if (!myStorage->update(aFeature))
61       myStorage->update(aFeature, true);
62     theEntities.push_back(myStorage->entity(aFeature));
63     myFeatures.insert(aFeature);
64     for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) {
65       // just add copied features into the list of objects
66       aFeature = ModelAPI_Feature::feature(*anObjIt);
67       if (aFeature) {
68         createCopiedEntity(aFeature, myStorage);
69         myFeatures.insert(aFeature);
70       }
71     }
72   }
73 }
74
75 bool SketchSolver_ConstraintMulti::remove()
76 {
77   myStorage->unsubscribeUpdates(this);
78
79   // "Multi" constraint has been removed, thus all copy features become non-copied,
80   // add them once again to be a common feature
81   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
82   for (; anIt != myFeatures.end(); ++anIt) {
83     EntityWrapperPtr anEntity = myStorage->entity(*anIt);
84     if (anEntity) {
85       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
86           std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
87       if (anEntity->isExternal() && !aSketchFeature->isExternal())
88         myStorage->makeNonExternal(anEntity);
89     } else
90       myStorage->update(*anIt, true);
91   }
92
93   myFeatures.clear();
94   return SketchSolver_Constraint::remove();
95 }
96
97 void SketchSolver_ConstraintMulti::update()
98 {
99   cleanErrorMsg();
100   AttributeRefListPtr anInitialRefList =
101       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A());
102   AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects());
103   if (!anInitialRefList || !aNbObjects)
104     return; // the "Multi" constraint is in queue to remove
105   bool isUpdated =
106     anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies;
107   if (!isUpdated) {
108     // additional check that the features and their copies are changed
109     AttributeRefListPtr aRefList =
110         myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
111     if (aRefList && aRefList->size() != 0) {
112       FeaturePtr aFeature;
113       std::list<ObjectPtr> anObjectList = aRefList->list();
114       std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
115       for (; anObjIt != anObjectList.end(); ++anObjIt) {
116         aFeature = ModelAPI_Feature::feature(*anObjIt);
117         if (aFeature && myFeatures.find(aFeature) == myFeatures.end()) {
118           isUpdated = true;
119           break;
120         }
121       }
122     } else
123       isUpdated = true;
124   }
125   if (isUpdated) {
126     remove();
127     process();
128   }
129
130   // update derived object
131   updateLocal();
132   adjustConstraint();
133 }
134
135 void SketchSolver_ConstraintMulti::adjustConstraint()
136 {
137   AttributeRefListPtr aRefList =
138       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
139   if (!aRefList || aRefList->size() == 0) {
140     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
141     return;
142   }
143
144   FeaturePtr anOriginal, aFeature;
145   std::list<double>::iterator aXIt, aYIt;
146
147   std::list<ObjectPtr> anObjectList = aRefList->list();
148   std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
149   while (anObjIt != anObjectList.end()) {
150     anOriginal = ModelAPI_Feature::feature(*anObjIt++);
151     if (!anOriginal)
152       continue;
153
154     // Fill lists of coordinates of points composing a feature
155     std::list<double> aX, aY;
156     double aXCoord, aYCoord;
157     std::list<AttributePtr> aPoints =
158         anOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
159     std::list<AttributePtr>::iterator aPtIt = aPoints.begin();
160     for (; aPtIt != aPoints.end(); ++aPtIt) {
161       AttributePoint2DPtr aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*aPtIt);
162       if (aPoint2D->isInitialized()) {
163         aXCoord = aPoint2D->x();
164         aYCoord = aPoint2D->y();
165         getRelative(aXCoord, aYCoord, aXCoord, aYCoord);
166       } else
167         aXCoord = aYCoord = 0;
168
169       aX.push_back(aXCoord);
170       aY.push_back(aYCoord);
171     }
172
173     // Calculate positions of copied features
174     for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) {
175       aFeature = ModelAPI_Feature::feature(*anObjIt);
176       if (!aFeature)
177         continue;
178
179       if (myIsEventsBlocked)
180         aFeature->data()->blockSendAttributeUpdated(true);
181
182       if (aFeature->getKind() == SketchPlugin_Circle::ID()) // update circle's radius
183         aFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
184             anOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
185
186       aPoints = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
187       for (aPtIt = aPoints.begin(), aXIt = aX.begin(), aYIt = aY.begin();
188            aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) {
189         if (!(*aPtIt)->isInitialized())
190           continue;
191         transformRelative(*aXIt, *aYIt);
192         getAbsolute(*aXIt, *aYIt, aXCoord, aYCoord);
193
194         AttributePoint2DPtr aPoint2D =
195             std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*aPtIt);
196         aPoint2D->setValue(aXCoord, aYCoord);
197       }
198
199       // update transformed entity if it exists in the storage
200       if (myStorage->entity(aFeature))
201         myStorage->update(aFeature);
202     }
203   }
204
205   myAdjusted = true;
206 }
207
208 void SketchSolver_ConstraintMulti::notify(const FeaturePtr& theFeature,
209                                           PlaneGCSSolver_Update*)
210 {
211   if (myFeatures.find(theFeature) == myFeatures.end())
212     return; // the feature is not used by constraint => nothing to update
213
214   // update derivative object
215   updateLocal();
216   myAdjusted = false;
217   adjustConstraint();
218 }
219
220 void SketchSolver_ConstraintMulti::blockEvents(bool isBlocked)
221 {
222   myIsEventsBlocked = isBlocked;
223
224   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
225   for (; anIt != myFeatures.end(); ++anIt)
226     (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
227
228   SketchSolver_Constraint::blockEvents(isBlocked);
229 }