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