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