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