Salome HOME
Issue #17347: B-Splines in Sketcher
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_FeatureBuilder.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_FeatureBuilder.h>
21 #include <PlaneGCSSolver_EdgeWrapper.h>
22 #include <PlaneGCSSolver_PointWrapper.h>
23 #include <PlaneGCSSolver_PointArrayWrapper.h>
24 #include <PlaneGCSSolver_ScalarWrapper.h>
25 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
26 #include <PlaneGCSSolver_BooleanWrapper.h>
27 #include <PlaneGCSSolver_Tools.h>
28
29 #include <SketchPlugin_Arc.h>
30 #include <SketchPlugin_BSpline.h>
31 #include <SketchPlugin_Circle.h>
32 #include <SketchPlugin_Ellipse.h>
33 #include <SketchPlugin_EllipticArc.h>
34 #include <SketchPlugin_IntersectionPoint.h>
35 #include <SketchPlugin_Line.h>
36 #include <SketchPlugin_Point.h>
37
38 #include <GeomAPI_Dir2d.h>
39 #include <GeomAPI_Pnt2d.h>
40 #include <GeomAPI_XY.h>
41
42 static bool isAttributeApplicable(const std::string& theAttrName,
43                                   const std::string& theOwnerName);
44
45 static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes);
46 static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes);
47 static EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
48                                   PlaneGCSSolver_Storage*      theStorage);
49 static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
50 static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
51                                           PlaneGCSSolver_Storage*   theStorage);
52 static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
53
54
55 PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
56     PlaneGCSSolver_Storage* theStorage)
57   : PlaneGCSSolver_AttributeBuilder(theStorage)
58 {
59 }
60
61 PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(const StoragePtr& theStorage)
62   : PlaneGCSSolver_AttributeBuilder(theStorage)
63 {
64 }
65
66 EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createAttribute(
67     AttributePtr theAttribute)
68 {
69   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
70   EntityWrapperPtr anAttr;
71   if (isAttributeApplicable(theAttribute->id(), anOwner->getKind()))
72     anAttr = PlaneGCSSolver_AttributeBuilder::createAttribute(theAttribute);
73   if (anAttr)
74     myAttributes[theAttribute] = anAttr;
75   return anAttr;
76 }
77
78 EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeature)
79 {
80   EntityWrapperPtr aResult;
81   if (myStorage)
82     aResult = myStorage->entity(theFeature);
83   if (aResult)
84     return aResult;
85
86   // Process SketchPlugin features only
87   std::shared_ptr<SketchPlugin_Feature> aFeature =
88       std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
89   if (!aFeature)
90     return aResult;
91
92   // Verify the feature by its kind
93   const std::string& aFeatureKind = aFeature->getKind();
94   // Line
95   if (aFeatureKind == SketchPlugin_Line::ID())
96     aResult = createLine(myAttributes);
97   // Circle
98   else if (aFeatureKind == SketchPlugin_Circle::ID())
99     aResult = createCircle(myAttributes);
100   // Arc
101   else if (aFeatureKind == SketchPlugin_Arc::ID())
102     aResult = createArc(myAttributes, myStorage);
103   // Ellipse
104   else if (aFeatureKind == SketchPlugin_Ellipse::ID())
105     aResult = createEllipse(myAttributes);
106   // Arc of ellipse
107   else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
108     aResult = createEllipticArc(myAttributes, myStorage);
109   // B-spline curve
110   else if (aFeatureKind == SketchPlugin_BSpline::ID())
111     aResult = createBSpline(myAttributes);
112   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
113   else if (aFeatureKind == SketchPlugin_Point::ID() ||
114            aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
115     AttributeEntityMap::const_iterator anIt = myAttributes.begin();
116     for (; anIt != myAttributes.end(); ++anIt)
117       if (anIt->first->id() == SketchPlugin_Point::COORD_ID()) {
118         aResult = anIt->second;
119         break;
120       }
121   }
122
123   if (aResult && !myStorage)
124     aResult->setExternal(true);
125
126   myAttributes.clear();
127   return aResult;
128 }
129
130
131
132
133
134 // ==============   Auxiliary functions   =====================================
135 EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes)
136 {
137   std::shared_ptr<GCS::Line> aNewLine(new GCS::Line);
138
139   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
140   for (; anIt != theAttributes.end(); ++anIt) {
141     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
142         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
143     if (!aPoint)
144       continue;
145
146     if (anIt->first->id() == SketchPlugin_Line::START_ID())
147       aNewLine->p1 = *(aPoint->point());
148     else if (anIt->first->id() == SketchPlugin_Line::END_ID())
149       aNewLine->p2 = *(aPoint->point());
150   }
151
152   return EntityWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewLine));
153 }
154
155 EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes)
156 {
157   std::shared_ptr<GCS::Circle> aNewCircle(new GCS::Circle);
158
159   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
160   for (; anIt != theAttributes.end(); ++anIt) {
161     if (anIt->first->id() == SketchPlugin_Circle::CENTER_ID()) {
162       std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
163           std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
164       aNewCircle->center = *(aPoint->point());
165     }
166     else if(anIt->first->id() == SketchPlugin_Circle::RADIUS_ID()) {
167       ScalarWrapperPtr aScalar =
168           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
169       aNewCircle->rad = aScalar->scalar();
170     }
171   }
172
173   return EntityWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewCircle));
174 }
175
176 static double* createParameter(PlaneGCSSolver_Storage* theStorage)
177 {
178   return theStorage ? theStorage->createParameter() : (new double(0));
179 }
180
181 EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
182                            PlaneGCSSolver_Storage*      theStorage)
183 {
184   std::shared_ptr<GCS::Arc> aNewArc(new GCS::Arc);
185   BooleanWrapperPtr isReversed;
186
187   // Base attributes of arc (center, start and end points)
188   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
189   for (; anIt != theAttributes.end(); ++anIt) {
190     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
191         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
192     if (aPoint) {
193       if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID())
194         aNewArc->center = *(aPoint->point());
195       else if (anIt->first->id() == SketchPlugin_Arc::START_ID())
196         aNewArc->start = *(aPoint->point());
197       else if (anIt->first->id() == SketchPlugin_Arc::END_ID())
198         aNewArc->end = *(aPoint->point());
199     }
200     else {
201       // reversed flag
202       isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
203     }
204   }
205
206   // Additional attributes of arc necessary for PlaneGCS solver
207   // (start and end angles, radius)
208   aNewArc->startAngle = createParameter(theStorage);
209   aNewArc->endAngle   = createParameter(theStorage);
210   aNewArc->rad        = createParameter(theStorage);
211
212   EdgeWrapperPtr anArcWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
213   anArcWrapper->setReversed(isReversed);
214   PlaneGCSSolver_Tools::recalculateArcParameters(anArcWrapper);
215
216   return anArcWrapper;
217 }
218
219 EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes)
220 {
221   std::shared_ptr<GCS::Ellipse> aNewEllipse(new GCS::Ellipse);
222
223   std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
224
225   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
226   for (; anIt != theAttributes.end(); ++anIt) {
227     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
228         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
229     if (aPoint) {
230       if (anIt->first->id() == SketchPlugin_Ellipse::CENTER_ID())
231         aNewEllipse->center = *(aPoint->point());
232       else if (anIt->first->id() == SketchPlugin_Ellipse::FIRST_FOCUS_ID())
233         aNewEllipse->focus1 = *(aPoint->point());
234       else
235         anAdditionalAttributes[anIt->first->id()] = anIt->second;
236     }
237     else if (anIt->first->id() == SketchPlugin_Ellipse::MINOR_RADIUS_ID()) {
238       ScalarWrapperPtr aScalar =
239           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
240       aNewEllipse->radmin = aScalar->scalar();
241     }
242     else
243       anAdditionalAttributes[anIt->first->id()] = anIt->second;
244   }
245
246   EntityWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewEllipse));
247   anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes);
248   return anEllipseWrapper;
249 }
250
251 EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
252                                    PlaneGCSSolver_Storage*   theStorage)
253 {
254   std::shared_ptr<GCS::ArcOfEllipse> aNewArc(new GCS::ArcOfEllipse);
255
256   BooleanWrapperPtr isReversed;
257   std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
258
259   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
260   for (; anIt != theAttributes.end(); ++anIt) {
261     std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
262         std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
263     if (aPoint) {
264       if (anIt->first->id() == SketchPlugin_EllipticArc::CENTER_ID())
265         aNewArc->center = *(aPoint->point());
266       else if (anIt->first->id() == SketchPlugin_EllipticArc::FIRST_FOCUS_ID())
267         aNewArc->focus1 = *(aPoint->point());
268       else if (anIt->first->id() == SketchPlugin_EllipticArc::START_POINT_ID())
269         aNewArc->start = *(aPoint->point());
270       else if (anIt->first->id() == SketchPlugin_EllipticArc::END_POINT_ID())
271         aNewArc->end = *(aPoint->point());
272       else
273         anAdditionalAttributes[anIt->first->id()] = anIt->second;
274     }
275     else if (anIt->first->id() == SketchPlugin_EllipticArc::MINOR_RADIUS_ID()) {
276       ScalarWrapperPtr aScalar =
277           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
278       aNewArc->radmin = aScalar->scalar();
279     }
280     else if (anIt->first->id() == SketchPlugin_EllipticArc::REVERSED_ID())
281       isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
282     else
283       anAdditionalAttributes[anIt->first->id()] = anIt->second;
284   }
285
286   // Additional attributes of elliptic arc necessary for PlaneGCS solver (start and end angles)
287   aNewArc->startAngle = createParameter(theStorage);
288   aNewArc->endAngle = createParameter(theStorage);
289
290   EdgeWrapperPtr anEllipseWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
291   anEllipseWrapper->setReversed(isReversed);
292   anEllipseWrapper->setAdditionalAttributes(anAdditionalAttributes);
293   PlaneGCSSolver_Tools::recalculateArcParameters(anEllipseWrapper);
294
295   return anEllipseWrapper;
296 }
297
298 EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
299 {
300   std::shared_ptr<GCS::BSpline> aNewSpline(new GCS::BSpline);
301
302   aNewSpline->degree = 3;
303   aNewSpline->periodic = false;
304
305   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
306   for (; anIt != theAttributes.end(); ++anIt) {
307     const std::string& anAttrID = anIt->first->id();
308     if (anAttrID == SketchPlugin_BSpline::POLES_ID()) {
309       PointArrayWrapperPtr anArray =
310           std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
311
312       int aSize = anArray->size();
313       aNewSpline->poles.reserve(aSize);
314       for (int anIndex = 0; anIndex < aSize; ++anIndex)
315         aNewSpline->poles.push_back(*anArray->value(anIndex)->point());
316
317       aNewSpline->start = aNewSpline->poles.front();
318       aNewSpline->end = aNewSpline->poles.back();
319     }
320     else if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID()) {
321       ScalarArrayWrapperPtr anArray =
322           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
323       aNewSpline->weights = anArray->array();
324     }
325   }
326
327   return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
328 }
329
330 bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
331 {
332   if (theOwnerName == SketchPlugin_Arc::ID()) {
333     return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
334            theAttrName == SketchPlugin_Arc::START_ID() ||
335            theAttrName == SketchPlugin_Arc::END_ID() ||
336            theAttrName == SketchPlugin_Arc::REVERSED_ID();
337   }
338   else if (theOwnerName == SketchPlugin_Circle::ID()) {
339     return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
340            theAttrName == SketchPlugin_Circle::RADIUS_ID();
341   }
342   else if (theOwnerName == SketchPlugin_Line::ID()) {
343     return theAttrName == SketchPlugin_Line::START_ID() ||
344            theAttrName == SketchPlugin_Line::END_ID();
345   }
346   else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
347     return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
348            theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
349            theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
350            theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
351            theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
352            theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
353            theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
354            theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
355            theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
356   }
357   else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
358     return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
359            theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
360            theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
361            theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
362            theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
363            theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
364            theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
365            theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
366            theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
367            theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
368            theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
369            theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
370   }
371   else if (theOwnerName == SketchPlugin_BSpline::ID()) {
372     return theAttrName == SketchPlugin_BSpline::POLES_ID() ||
373            theAttrName == SketchPlugin_BSpline::WEIGHTS_ID();
374   }
375
376   // suppose that all remaining features are points
377   return theAttrName == SketchPlugin_Point::COORD_ID();
378 }