Salome HOME
51329df2869fc37ac097dc96c87d12b1335cc4c3
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_AttributeBuilder.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 <PlaneGCSSolver_AngleWrapper.h>
21 #include <PlaneGCSSolver_AttributeBuilder.h>
22 #include <PlaneGCSSolver_PointArrayWrapper.h>
23 #include <PlaneGCSSolver_PointWrapper.h>
24 #include <PlaneGCSSolver_ScalarWrapper.h>
25 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
26 #include <PlaneGCSSolver_BooleanWrapper.h>
27 #include <PlaneGCSSolver_Tools.h>
28
29 #include <GeomAPI_Pnt2d.h>
30 #include <GeomDataAPI_Point2D.h>
31 #include <GeomDataAPI_Point2DArray.h>
32 #include <ModelAPI_AttributeDouble.h>
33 #include <ModelAPI_AttributeDoubleArray.h>
34 #include <ModelAPI_AttributeInteger.h>
35 #include <SketchPlugin_BSpline.h>
36 #include <SketchPlugin_BSplinePeriodic.h>
37 #include <SketchPlugin_ConstraintAngle.h>
38 #include <SketchPlugin_MultiRotation.h>
39
40 PlaneGCSSolver_AttributeBuilder::PlaneGCSSolver_AttributeBuilder(
41     PlaneGCSSolver_Storage* theStorage)
42   : PlaneGCSSolver_EntityBuilder(theStorage)
43 {
44 }
45
46 PlaneGCSSolver_AttributeBuilder::PlaneGCSSolver_AttributeBuilder(const StoragePtr& theStorage)
47   : PlaneGCSSolver_EntityBuilder(
48         std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(theStorage).get())
49 {
50 }
51
52 static double* createParameter(PlaneGCSSolver_Storage* theStorage)
53 {
54   return theStorage ? theStorage->createParameter() : (new double(0));
55 }
56
57 static EntityWrapperPtr createBoolean(const AttributePtr& theAttribute)
58 {
59   BooleanWrapperPtr aWrapper;
60   AttributeBooleanPtr aBoolean =
61       std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
62   if (aBoolean)
63     aWrapper = BooleanWrapperPtr(new PlaneGCSSolver_BooleanWrapper(aBoolean->value()));
64   return aWrapper;
65 }
66
67 static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
68                                      PlaneGCSSolver_Storage* theStorage)
69 {
70   double aValue = 0.0;
71   AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
72   if (aDouble)
73     aValue = aDouble->isInitialized() ? aDouble->value() : 0.0;
74   else {
75     AttributeIntegerPtr anInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
76     if (anInt)
77       aValue = anInt->isInitialized() ? anInt->value() : 0.0;
78     else
79       return EntityWrapperPtr();
80   }
81
82   ScalarWrapperPtr aWrapper;
83   // following attributes should be converted from degrees to radians
84   //  - value of the Angle constraint
85   //  - angle of the Multi-Rotation constraint
86   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
87   if ((theAttribute->id() == SketchPlugin_Constraint::VALUE() &&
88       anOwner->getKind() == SketchPlugin_ConstraintAngle::ID()) ||
89      (theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() &&
90       anOwner->getKind() == SketchPlugin_MultiRotation::ID()))
91     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage)));
92   else if ((anOwner->getKind() == SketchPlugin_BSpline::ID() ||
93             anOwner->getKind() == SketchPlugin_BSplinePeriodic::ID()) &&
94            theAttribute->id() == SketchPlugin_BSplineBase::DEGREE_ID())
95     // Degree of B-spline is not processed by the solver
96     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr)));
97   else
98     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage)));
99
100   aWrapper->setValue(aValue);
101   return aWrapper;
102 }
103
104 template <typename TYPE>
105 static bool nonSolverAttribute(const FeaturePtr theOwner, const std::string& theAttrId)
106 {
107   return theOwner->getKind() == TYPE::ID() && (theAttrId == TYPE::WEIGHTS_ID()
108       || theAttrId == TYPE::KNOTS_ID() || theAttrId == TYPE::MULTS_ID());
109 }
110
111 static EntityWrapperPtr createScalarArray(const AttributePtr&     theAttribute,
112                                           PlaneGCSSolver_Storage* theStorage)
113 {
114   PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
115
116   if (!anArray.isInitialized())
117     return EntityWrapperPtr();
118
119   PlaneGCSSolver_Storage* aStorage = theStorage;
120   // Weights, knots and multiplicities of B-spline curve are not processed by the solver
121   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
122   if (nonSolverAttribute<SketchPlugin_BSpline>(anOwner, theAttribute->id()) ||
123       nonSolverAttribute<SketchPlugin_BSplinePeriodic>(anOwner, theAttribute->id()))
124     aStorage = 0;
125
126   int aSize = anArray.size();
127   GCS::VEC_pD aParameters;
128   aParameters.reserve(aSize);
129   for (int index = 0; index < aSize; ++index) {
130     double* aParam = createParameter(aStorage);
131     *aParam = anArray.value(index);
132     aParameters.push_back(aParam);
133   }
134
135   return EntityWrapperPtr(new PlaneGCSSolver_ScalarArrayWrapper(aParameters));
136 }
137
138 static PointWrapperPtr createPoint(const GeomPnt2dPtr& thePoint, PlaneGCSSolver_Storage* theStorage)
139 {
140   GCSPointPtr aNewPoint(new GCS::Point);
141
142   aNewPoint->x = createParameter(theStorage);
143   aNewPoint->y = createParameter(theStorage);
144   if (thePoint) {
145     *(aNewPoint->x) = thePoint->x();
146     *(aNewPoint->y) = thePoint->y();
147   }
148
149   return PointWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
150 }
151
152 static EntityWrapperPtr createPoint(const AttributePtr&     theAttribute,
153                                     PlaneGCSSolver_Storage* theStorage)
154 {
155   std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
156       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
157   if (!aPoint2D)
158     return EntityWrapperPtr();
159
160   GeomPnt2dPtr aPnt;
161   if (aPoint2D->isInitialized())
162     aPnt = aPoint2D->pnt();
163
164   return createPoint(aPnt, theStorage);
165 }
166
167 static EntityWrapperPtr createPointArray(const AttributePtr& theAttribute,
168                                          PlaneGCSSolver_Storage* theStorage)
169 {
170   std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
171       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
172   if (!aPointArray)
173     return EntityWrapperPtr();
174
175   int aSize = aPointArray->size();
176
177   std::vector<PointWrapperPtr> aPointWrappers;
178   aPointWrappers.reserve(aSize);
179   for (int index = 0; index < aSize; ++index)
180     aPointWrappers.push_back(createPoint(aPointArray->pnt(index), theStorage));
181
182   return EntityWrapperPtr(new PlaneGCSSolver_PointArrayWrapper(aPointWrappers));
183 }
184
185 EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
186     AttributePtr theAttribute)
187 {
188   EntityWrapperPtr aResult;
189   if (myStorage)
190     aResult = myStorage->entity(theAttribute);
191   if (!aResult)
192     aResult = createPoint(theAttribute, myStorage);
193   if (!aResult)
194     aResult = createScalar(theAttribute, myStorage);
195   if (!aResult)
196     aResult = createBoolean(theAttribute);
197   if (!aResult)
198     aResult = createPointArray(theAttribute, myStorage);
199   if (!aResult)
200     aResult = createScalarArray(theAttribute, myStorage);
201   if (aResult && !myStorage)
202     aResult->setExternal(true);
203   return aResult;
204 }
205
206 bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
207     AttributePtr theAttribute,
208     EntityWrapperPtr theEntity)
209 {
210   bool isUpdated = false;
211   GCS::SET_pD aParamsToRemove;
212   // rebuild array if its size is changed
213   if (theEntity->type() == ENTITY_POINT_ARRAY) {
214     std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> aWrapper =
215         std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theEntity);
216     std::shared_ptr<GeomDataAPI_Point2DArray> anAttribute =
217         std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
218
219     std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
220     std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
221     if (aWrapper->size() != anAttribute->size()) {
222       while (anAttribute->size() > (int)aPointsArray.size()) {
223         // add points to the middle of array
224         GeomPnt2dPtr aValue;
225         for (; aPos != aPointsArray.end(); ++aPos) {
226           aValue = anAttribute->pnt(aPos - aPointsArray.begin());
227           if (aValue->distance(PlaneGCSSolver_Tools::point(*aPos)) > tolerance)
228             break;
229         }
230         int aShift = aPos - aPointsArray.begin();
231         aPointsArray.insert(aPos, createPoint(aValue, myStorage));
232         aPos = aPointsArray.begin() + aShift;
233       }
234
235       while (anAttribute->size() < (int)aPointsArray.size()) {
236         // remove middle points
237         std::vector<PointWrapperPtr>::iterator anIt = --aPointsArray.end();
238         GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(*anIt);
239         aParamsToRemove.insert(aParams.begin(), aParams.end());
240         aPointsArray.erase(anIt);
241       }
242
243       aWrapper->setArray(aPointsArray);
244     }
245     else {
246       // update coordinates of points
247       for (int anIndex = 0; aPos != aPointsArray.end(); ++aPos, ++anIndex) {
248         const GCSPointPtr& aGCSPoint = (*aPos)->point();
249         GeomPnt2dPtr aCoord = anAttribute->pnt(anIndex);
250         *aGCSPoint->x = aCoord->x();
251         *aGCSPoint->y = aCoord->y();
252       }
253     }
254   }
255   else if (theEntity->type() == ENTITY_SCALAR_ARRAY) {
256     std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aWrapper =
257         std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theEntity);
258     if (aWrapper->size() != PlaneGCSSolver_Tools::AttributeArray(theAttribute).size()) {
259       aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
260       std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
261           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
262           createScalarArray(theAttribute, myStorage));
263       aWrapper->setArray(aNewArray->array());
264       isUpdated = true;
265     }
266   }
267
268   if (!aParamsToRemove.empty()) {
269     if (myStorage)
270       myStorage->removeParameters(aParamsToRemove);
271     else {
272       std::for_each(aParamsToRemove.begin(), aParamsToRemove.end(),
273                     [](double* theParam) { delete theParam; });
274     }
275   }
276
277   return isUpdated || theEntity->update(theAttribute);
278 }