Salome HOME
Copyright update 2020
[modules/shaper.git] / src / SketchAPI / SketchAPI_Ellipse.cpp
1 // Copyright (C) 2014-2020  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 "SketchAPI_Ellipse.h"
21
22 #include <GeomAPI_Pnt2d.h>
23
24 #include <ModelHighAPI_Dumper.h>
25 #include <ModelHighAPI_Selection.h>
26 #include <ModelHighAPI_Tools.h>
27
28 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
29 #include <SketchPlugin_Line.h>
30 #include <SketchPlugin_Point.h>
31
32 static const std::string AUXILIARY_VALUE = "aux";
33 static const std::string MAJOR_AXIS_ID = "majorAxis";
34 static const std::string MINOR_AXIS_ID = "minorAxis";
35
36 SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature> & theFeature)
37   : SketchAPI_SketchEntity(theFeature)
38 {
39   initialize();
40 }
41
42 SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
43                                      double theCenterX, double theCenterY,
44                                      double theFocusX, double theFocusY,
45                                      double theMinorRadius)
46   : SketchAPI_SketchEntity(theFeature)
47 {
48   if(initialize()) {
49     setByCenterFocusAndRadius(theCenterX, theCenterY, theFocusX, theFocusY, theMinorRadius);
50   }
51 }
52
53 SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
54                                      const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
55                                      const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
56                                      double theMinorRadius)
57 : SketchAPI_SketchEntity(theFeature)
58 {
59   if(initialize()) {
60     setByCenterFocusAndRadius(theCenter, theFocus, theMinorRadius);
61   }
62 }
63
64 SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
65                                      const ModelHighAPI_Selection& theExternal)
66   : SketchAPI_SketchEntity(theFeature)
67 {
68   if (initialize()) {
69     setByExternal(theExternal);
70   }
71 }
72
73 SketchAPI_Ellipse::SketchAPI_Ellipse(const std::shared_ptr<ModelAPI_Feature>& theFeature,
74                                      const std::string& theExternalName)
75   : SketchAPI_SketchEntity(theFeature)
76 {
77   if (initialize()) {
78     setByExternalName(theExternalName);
79   }
80 }
81
82 SketchAPI_Ellipse::~SketchAPI_Ellipse()
83 {
84 }
85
86 void SketchAPI_Ellipse::setByCenterFocusAndRadius(double theCenterX, double theCenterY,
87                                                   double theFocusX, double theFocusY,
88                                                   double theMinorRadius)
89 {
90   fillAttribute(center(), theCenterX, theCenterY);
91   fillAttribute(firstFocus(), theFocusX, theFocusY);
92   fillAttribute(theMinorRadius, myminorRadius);
93
94   execute();
95 }
96
97 void SketchAPI_Ellipse::setByCenterFocusAndRadius(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
98                                                   const std::shared_ptr<GeomAPI_Pnt2d>& theFocus,
99                                                   double theMinorRadius)
100 {
101   fillAttribute(theCenter, mycenter);
102   fillAttribute(theFocus, myfirstFocus);
103   fillAttribute(theMinorRadius, myminorRadius);
104
105   execute();
106 }
107
108 void SketchAPI_Ellipse::setByExternal(const ModelHighAPI_Selection & theExternal)
109 {
110   fillAttribute(theExternal, external());
111   execute();
112 }
113
114 void SketchAPI_Ellipse::setByExternalName(const std::string & theExternalName)
115 {
116   fillAttribute(ModelHighAPI_Selection("EDGE", theExternalName), external());
117   execute();
118 }
119
120 void SketchAPI_Ellipse::setCenter(double theX, double theY)
121 {
122   fillAttribute(center(), theX, theY);
123   execute();
124 }
125
126 void SketchAPI_Ellipse::setCenter(const std::shared_ptr<GeomAPI_Pnt2d> & theCenter)
127 {
128   fillAttribute(theCenter, mycenter);
129   execute();
130 }
131
132 void SketchAPI_Ellipse::setFocus(double theX, double theY)
133 {
134   fillAttribute(firstFocus(), theX, theY);
135   execute();
136 }
137
138 void SketchAPI_Ellipse::setFocus(const std::shared_ptr<GeomAPI_Pnt2d> & theFocus)
139 {
140   fillAttribute(theFocus, myfirstFocus);
141   execute();
142 }
143
144 void SketchAPI_Ellipse::setMinorRadius(double theMinorRadius)
145 {
146   fillAttribute(theMinorRadius, myminorRadius);
147   execute();
148 }
149
150 static const std::list<PairOfStrings>& ellipseAttrAndDumpNames()
151 {
152   static std::list<PairOfStrings> anAttributes;
153   if (anAttributes.empty()) {
154     anAttributes.push_back(
155         PairOfStrings(SketchPlugin_Ellipse::CENTER_ID(), "center"));
156     anAttributes.push_back(
157         PairOfStrings(SketchPlugin_Ellipse::FIRST_FOCUS_ID(), "firstFocus"));
158     anAttributes.push_back(
159         PairOfStrings(SketchPlugin_Ellipse::SECOND_FOCUS_ID(), "secondFocus"));
160     anAttributes.push_back(
161         PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(), "majorAxisStart"));
162     anAttributes.push_back(
163         PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID(), "majorAxisEnd"));
164     anAttributes.push_back(
165         PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_START_ID(), "minorAxisStart"));
166     anAttributes.push_back(
167         PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_END_ID(), "minorAxisEnd"));
168   }
169   return anAttributes;
170 }
171
172 static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature)
173 {
174   const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
175   for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
176     if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
177       return std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
178   return CompositeFeaturePtr();
179 }
180
181 static void createInternalConstraint(const CompositeFeaturePtr& theSketch,
182                                      const AttributePoint2DPtr& thePoint1,
183                                      const AttributePoint2DPtr& thePoint2)
184 {
185   FeaturePtr aConstraint = theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID());
186   aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint1);
187   aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(thePoint2);
188   aConstraint->execute();
189 }
190
191 static void createPoint(const CompositeFeaturePtr& theSketch,
192                         const FeaturePtr& theEllipse,
193                         const std::string& theCoincident,
194                         const std::string& theAuxOrName,
195                         std::list<FeaturePtr>& theEntities)
196 {
197   if (theAuxOrName.empty())
198     return;
199
200   AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
201       theEllipse->attribute(theCoincident));
202
203   FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
204   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
205       aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
206   aCoord->setValue(anElPoint->x(), anElPoint->y());
207   aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
208   aPointFeature->execute();
209
210   std::string aName = theEllipse->name() + "_" + theCoincident;
211   aPointFeature->data()->setName(aName);
212   aPointFeature->lastResult()->data()->setName(aName);
213
214   if (theAuxOrName == AUXILIARY_VALUE)
215     aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
216   else if (!theAuxOrName.empty()) {
217     aPointFeature->data()->setName(theAuxOrName);
218     aPointFeature->lastResult()->data()->setName(theAuxOrName);
219   }
220
221   createInternalConstraint(theSketch, anElPoint, aCoord);
222
223   theEntities.push_back(aPointFeature);
224 }
225
226 static void createAxis(const CompositeFeaturePtr& theSketch,
227                        const FeaturePtr& theEllipse,
228                        const std::string& theCoincidentStart,
229                        const std::string& theCoincidentEnd,
230                        const std::string& theAuxOrName,
231                        std::list<FeaturePtr>& theEntities)
232 {
233   if (theAuxOrName.empty())
234     return;
235
236   AttributePoint2DPtr aStartPoint =
237       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentStart));
238   AttributePoint2DPtr aEndPoint =
239       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEllipse->attribute(theCoincidentEnd));
240
241   FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
242   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
243       aLineFeature->attribute(SketchPlugin_Line::START_ID()));
244   aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
245   AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
246       aLineFeature->attribute(SketchPlugin_Line::END_ID()));
247   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
248   aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipse);
249   aLineFeature->execute();
250
251   std::string aName = theEllipse->name() + "_" +
252       (theCoincidentStart == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ?
253        "major_axis" : "minor_axis");
254   aLineFeature->data()->setName(aName);
255   aLineFeature->lastResult()->data()->setName(aName);
256
257   if (theAuxOrName == AUXILIARY_VALUE)
258     aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(true);
259   else if (!theAuxOrName.empty()) {
260     aLineFeature->data()->setName(theAuxOrName);
261     aLineFeature->lastResult()->data()->setName(theAuxOrName);
262   }
263
264   createInternalConstraint(theSketch, aStartPoint, aLineStart);
265   createInternalConstraint(theSketch, aEndPoint, aLineEnd);
266
267   theEntities.push_back(aLineFeature);
268 }
269
270 std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Ellipse::construction(
271     const std::string& center,
272     const std::string& firstFocus,
273     const std::string& secondFocus,
274     const std::string& majorAxisStart,
275     const std::string& majorAxisEnd,
276     const std::string& minorAxisStart,
277     const std::string& minorAxisEnd,
278     const std::string& majorAxis,
279     const std::string& minorAxis) const
280 {
281   FeaturePtr anEllipse = feature();
282
283   std::list<PairOfStrings> anAttributes = ellipseAttrAndDumpNames();
284   // append start and end attributes for axes
285   anAttributes.push_back(PairOfStrings(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
286                                        SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()));
287   anAttributes.push_back(PairOfStrings(SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
288                                        SketchPlugin_Ellipse::MINOR_AXIS_END_ID()));
289
290   return buildConstructionEntities(anEllipse, anAttributes, center, firstFocus, secondFocus,
291             majorAxisStart, majorAxisEnd, minorAxisStart, minorAxisEnd, majorAxis, minorAxis);
292 }
293
294 std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Ellipse::buildConstructionEntities(
295       const FeaturePtr& theEllipse,
296       const std::list<PairOfStrings>& theAttributes,
297       const std::string& theCenter,
298       const std::string& theFirstFocus,
299       const std::string& theSecondFocus,
300       const std::string& theMajorAxisStart,
301       const std::string& theMajorAxisEnd,
302       const std::string& theMinorAxisStart,
303       const std::string& theMinorAxisEnd,
304       const std::string& theMajorAxis,
305       const std::string& theMinorAxis)
306 {
307   CompositeFeaturePtr aSketch = sketchForFeature(theEllipse);
308
309   std::list<FeaturePtr> anEntities;
310   std::list<PairOfStrings>::const_iterator anAttrIt = theAttributes.begin();
311   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theCenter, anEntities);
312   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theFirstFocus, anEntities);
313   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theSecondFocus, anEntities);
314   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMajorAxisStart, anEntities);
315   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMajorAxisEnd, anEntities);
316   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMinorAxisStart, anEntities);
317   createPoint(aSketch, theEllipse, (anAttrIt++)->first, theMinorAxisEnd, anEntities);
318
319   createAxis(aSketch, theEllipse, anAttrIt->first, anAttrIt->second, theMajorAxis, anEntities);
320   ++anAttrIt;
321   createAxis(aSketch, theEllipse, anAttrIt->first, anAttrIt->second, theMinorAxis, anEntities);
322
323   return SketchAPI_SketchEntity::wrap(anEntities);
324 }
325
326 static void ellipseAttributeAndAuxiliaryFeature(
327     const FeaturePtr& theInternalConstraint,
328     const std::pair<std::string, std::string>& theMajorAxisStartEnd,
329     const std::pair<std::string, std::string>& theMinorAxisStartEnd,
330     std::map<std::string, FeaturePtr>& theAttrToFeature)
331 {
332   AttributeRefAttrPtr aRefAttrA =
333       theInternalConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
334   AttributeRefAttrPtr aRefAttrB =
335       theInternalConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
336   // the first point is usually an ellipse attribute
337   // and the second point is an attribute of the auxiliary feature
338   ObjectPtr anAuxObject;
339   if (aRefAttrB->isObject())
340     anAuxObject = aRefAttrB->object();
341   else
342     anAuxObject = aRefAttrB->attr()->owner();
343
344   FeaturePtr anAuxFeature = ModelAPI_Feature::feature(anAuxObject);
345   if (anAuxFeature->getKind() == SketchPlugin_Point::ID())
346     theAttrToFeature[aRefAttrA->attr()->id()] = anAuxFeature;
347   else {
348     const std::string& anAttrID = aRefAttrA->attr()->id();
349     if (anAttrID == theMajorAxisStartEnd.first || anAttrID == theMajorAxisStartEnd.second)
350       theAttrToFeature[MAJOR_AXIS_ID] = anAuxFeature;
351     else if (anAttrID == theMinorAxisStartEnd.first || anAttrID == theMinorAxisStartEnd.second)
352       theAttrToFeature[MINOR_AXIS_ID] = anAuxFeature;
353   }
354 }
355
356 void SketchAPI_Ellipse::collectAuxiliaryFeatures(
357     FeaturePtr theEllipse,
358     const std::pair<std::string, std::string>& theMajorAxis,
359     const std::pair<std::string, std::string>& theMinorAxis,
360     std::map<std::string, FeaturePtr>& theAttrToFeature)
361 {
362   const std::set<AttributePtr>& aRefs = theEllipse->data()->refsToMe();
363   for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
364        aRefIt != aRefs.end(); ++aRefIt) {
365     FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
366     if (anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
367       // process internal constraints only
368       ellipseAttributeAndAuxiliaryFeature(anOwner, theMajorAxis, theMinorAxis, theAttrToFeature);
369     }
370   }
371 }
372
373 void SketchAPI_Ellipse::dump(ModelHighAPI_Dumper& theDumper) const
374 {
375   if (isCopy())
376     return; // no need to dump copied feature
377
378   FeaturePtr aBase = feature();
379   const std::string& aSketchName = theDumper.parentName(aBase);
380
381   AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
382   if (anExternal->context()) {
383     // circle is external
384     theDumper << aBase << " = " << aSketchName << ".addEllipse(" << anExternal << ")" << std::endl;
385   } else {
386     // ellipse given by center, focus and radius
387     theDumper << aBase << " = " << aSketchName << ".addEllipse("
388               << center() << ", " << firstFocus() << ", " << minorRadius() << ")" << std::endl;
389   }
390   // dump "auxiliary" flag if necessary
391   SketchAPI_SketchEntity::dump(theDumper);
392
393   // dump auxiliary features produced by ellipse
394   std::map<std::string, FeaturePtr> anAuxFeatures;
395   static const std::pair<std::string, std::string> aMajorAxis(
396       SketchPlugin_Ellipse::MAJOR_AXIS_START_ID(),
397       SketchPlugin_Ellipse::MAJOR_AXIS_END_ID());
398   static const std::pair<std::string, std::string> aMinorAxis(
399       SketchPlugin_Ellipse::MINOR_AXIS_START_ID(),
400       SketchPlugin_Ellipse::MINOR_AXIS_END_ID());
401   collectAuxiliaryFeatures(aBase, aMajorAxis, aMinorAxis, anAuxFeatures);
402
403   if (!anAuxFeatures.empty()) {
404     // a list of attributes to write features in special order
405     const std::list<PairOfStrings>& anAttributes = ellipseAttrAndDumpNames();
406     dumpConstructionEntities(theDumper, aBase, anAttributes, anAuxFeatures);
407   }
408 }
409
410 void SketchAPI_Ellipse::dumpConstructionEntities(
411     ModelHighAPI_Dumper& theDumper,
412     const FeaturePtr& theEllipse,
413     const std::list<PairOfStrings>& theAttributes,
414     const std::map<std::string, FeaturePtr>& theAuxFeatures)
415 {
416   std::list<PairOfStrings> anAttributes = theAttributes;
417   // append axes
418   anAttributes.push_back(PairOfStrings(MAJOR_AXIS_ID, MAJOR_AXIS_ID));
419   anAttributes.push_back(PairOfStrings(MINOR_AXIS_ID, MINOR_AXIS_ID));
420
421   theDumper << "[";
422   bool isFirst = true;
423   for (std::list<PairOfStrings>::iterator anIt = anAttributes.begin();
424         anIt != anAttributes.end(); ++anIt) {
425     std::map<std::string, FeaturePtr>::const_iterator aFound = theAuxFeatures.find(anIt->first);
426     if (aFound == theAuxFeatures.end())
427       continue;
428     if (!isFirst)
429       theDumper << ", ";
430     theDumper << theDumper.name(aFound->second, false);
431     theDumper.doNotDumpFeature(aFound->second);
432     isFirst = false;
433   }
434   theDumper << "] = " << theDumper.name(theEllipse) << ".construction(";
435   isFirst = true;
436   for (std::list<PairOfStrings>::iterator anIt = anAttributes.begin();
437         anIt != anAttributes.end(); ++anIt) {
438     std::map<std::string, FeaturePtr>::const_iterator aFound = theAuxFeatures.find(anIt->first);
439     if (aFound == theAuxFeatures.end())
440       continue;
441     if (!isFirst)
442       theDumper << ", ";
443     isFirst = false;
444     theDumper << anIt->second << " = \"";
445     if (aFound->second->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value())
446       theDumper << AUXILIARY_VALUE;
447     else
448       theDumper << aFound->second->name();
449     theDumper << "\"";
450   }
451   theDumper << ")" << std::endl;
452 }