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