Salome HOME
59465f1db0e13e22bee437fbae48486bba70b760
[modules/shaper.git] / src / GeomAPI / GeomAPI_Ellipse2d.cpp
1 // Copyright (C) 2017-2021  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 // File:        GeomAPI_Ellipse2d.cpp
21 // Created:     26 April 2017
22 // Author:      Artem ZHIDKOV
23
24 #include <GeomAPI_Ellipse2d.h>
25 #include <GeomAPI_Circ2d.h>
26 #include <GeomAPI_Dir2d.h>
27 #include <GeomAPI_Lin2d.h>
28 #include <GeomAPI_Pnt2d.h>
29
30 #include <Extrema_ExtCC2d.hxx>
31 #include <Extrema_ExtElC2d.hxx>
32 #include <Geom2d_Ellipse.hxx>
33 #include <Geom2dAdaptor_Curve.hxx>
34 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
35 #include <GeomLib_Tool.hxx>
36 #include <gp_Ax22d.hxx>
37 #include <gp_Elips2d.hxx>
38 #include <IntAna2d_AnaIntersection.hxx>
39 #include <IntAna2d_Conic.hxx>
40 #include <Precision.hxx>
41
42 #define MY_ELLIPSE implPtr<gp_Elips2d>()
43
44 static gp_Elips2d* newEllipse(const gp_Pnt2d& theCenter,
45                               const gp_Dir2d& theXAxis,
46                               const double theMajorRadius,
47                               const double theMinorRadius)
48 {
49   if (theMajorRadius < theMinorRadius - Precision::Confusion()) {
50     return newEllipse(theCenter, gp_Dir2d(-theXAxis.Y(), theXAxis.X()),
51                       theMinorRadius, theMajorRadius);
52   }
53
54   gp_Ax22d anAxis(theCenter, theXAxis);
55   return new gp_Elips2d(anAxis, theMajorRadius, theMinorRadius);
56 }
57
58 static gp_Elips2d* newEllipse(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
59                               const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
60                               const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
61 {
62   const gp_Pnt2d& aCenter = theCenter->impl<gp_Pnt2d>();
63   const gp_Pnt2d& anAxisPnt = theAxisPoint->impl<gp_Pnt2d>();
64   const gp_Pnt2d& aPassedPnt = thePassingPoint->impl<gp_Pnt2d>();
65
66   gp_Dir2d aXAxis(anAxisPnt.XY() - aCenter.XY());
67   double aMajorRadius = anAxisPnt.Distance(aCenter);
68
69   gp_XY aPassedDir = aPassedPnt.XY() - aCenter.XY();
70
71   double X = aPassedDir.Dot(aXAxis.XY()) / aMajorRadius;
72   if (Abs(X) > 1.0 - Precision::Confusion())
73     return 0; // ellipse cannot be created for such parameters
74
75   double Y = aPassedDir.CrossMagnitude(aXAxis.XY());
76   double aMinorRadius = Y / Sqrt(1. - X * X);
77
78   return newEllipse(aCenter, aXAxis, aMajorRadius, aMinorRadius);
79 }
80
81
82 GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
83                                      const std::shared_ptr<GeomAPI_Dir2d>& theXAxis,
84                                      const double theMajorRadius,
85                                      const double theMinorRadius)
86   : GeomAPI_Interface(newEllipse(theCenter->impl<gp_Pnt2d>(), theXAxis->impl<gp_Dir2d>(),
87                                  theMajorRadius, theMinorRadius))
88 {
89 }
90
91 GeomAPI_Ellipse2d::GeomAPI_Ellipse2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
92                                      const std::shared_ptr<GeomAPI_Pnt2d>& theAxisPoint,
93                                      const std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
94   : GeomAPI_Interface(newEllipse(theCenter, theAxisPoint, thePassingPoint))
95 {
96 }
97
98 std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::center() const
99 {
100   const gp_Pnt2d& aCenter = MY_ELLIPSE->Location();
101   return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
102 }
103
104 std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::firstFocus() const
105 {
106   const gp_Pnt2d& aFirst = MY_ELLIPSE->Focus1();
107   return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aFirst.X(), aFirst.Y()));
108 }
109
110 std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::secondFocus() const
111 {
112   const gp_Pnt2d& aSecond = MY_ELLIPSE->Focus2();
113   return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aSecond.X(), aSecond.Y()));
114 }
115
116 double GeomAPI_Ellipse2d::minorRadius() const
117 {
118   return MY_ELLIPSE->MinorRadius();
119 }
120
121 double GeomAPI_Ellipse2d::majorRadius() const
122 {
123   return MY_ELLIPSE->MajorRadius();
124 }
125
126 // theArrangePoint is used to select the nearest solution point if intersection is detected
127 template <typename EXTREMAPTR>
128 static double extrema(IntAna2d_AnaIntersection* theIntersectionAlgo,
129                       EXTREMAPTR theExtremaAlgo,
130                       GeomPnt2dPtr theArrangePoint,
131                       GeomPnt2dPtr& thePoint1,
132                       GeomPnt2dPtr& thePoint2)
133 {
134   double aDistance = Precision::Infinite();
135   if (theIntersectionAlgo->IsDone() && theIntersectionAlgo->NbPoints() > 0) {
136     gp_Pnt2d anArrangePoint(theArrangePoint->x(), theArrangePoint->y());
137     gp_Pnt2d anInterPnt = theIntersectionAlgo->Point(1).Value();
138     aDistance = anArrangePoint.SquareDistance(anInterPnt);
139     int aNbMergedPoints = 1;
140     // get solution nearest to theArrangePoint,
141     // if there are several point near each other, calculate average coordinates
142     for (int i = 2; i <= theIntersectionAlgo->NbPoints(); ++i) {
143       const IntAna2d_IntPoint& aPnt = theIntersectionAlgo->Point(i);
144       double aSqDist = aPnt.Value().SquareDistance(anArrangePoint);
145       if (aSqDist - aDistance < -Precision::Confusion() * aDistance) {
146         aDistance = aSqDist;
147         anInterPnt = aPnt.Value();
148         aNbMergedPoints = 1;
149       } else if (aSqDist - aDistance < Precision::Confusion() * aDistance) {
150         anInterPnt.ChangeCoord() =
151             (anInterPnt.XY() * aNbMergedPoints + aPnt.Value().XY()) / (aNbMergedPoints + 1);
152         ++aNbMergedPoints;
153       }
154     }
155
156     aDistance = 0.0; // curves are intersected
157     thePoint1 = GeomPnt2dPtr(new GeomAPI_Pnt2d(anInterPnt.X(), anInterPnt.Y()));
158     thePoint2 = GeomPnt2dPtr(new GeomAPI_Pnt2d(anInterPnt.X(), anInterPnt.Y()));
159   }
160   else if (theExtremaAlgo->IsDone() && theExtremaAlgo->NbExt() > 0) {
161     Extrema_POnCurv2d aP1, aP2;
162     for (int i = 1; i <= theExtremaAlgo->NbExt(); ++i) {
163       double aSqDist = theExtremaAlgo->SquareDistance(i);
164       if (aSqDist < aDistance) {
165         aDistance = aSqDist;
166         theExtremaAlgo->Points(i, aP1, aP2);
167       }
168     }
169     aDistance = Sqrt(aDistance);
170     thePoint1 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP1.Value().X(), aP1.Value().Y()));
171     thePoint2 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP2.Value().X(), aP2.Value().Y()));
172   }
173   return aDistance;
174 }
175
176 double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
177                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
178                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnLine)
179 {
180   IntAna2d_AnaIntersection anInter(theLine->impl<gp_Lin2d>(), IntAna2d_Conic(*MY_ELLIPSE));
181   Extrema_ExtElC2d anExtema(theLine->impl<gp_Lin2d>(), *MY_ELLIPSE);
182   return extrema(&anInter, &anExtema, theLine->location(), thePointOnLine, thePointOnMe);
183 }
184
185 double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Circ2d>& theCircle,
186                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
187                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnCircle)
188 {
189   IntAna2d_AnaIntersection anInter(theCircle->impl<gp_Circ2d>(), IntAna2d_Conic(*MY_ELLIPSE));
190   Extrema_ExtElC2d anExtema(theCircle->impl<gp_Circ2d>(), *MY_ELLIPSE);
191   return extrema(&anInter, &anExtema, firstFocus(), thePointOnCircle, thePointOnMe);
192 }
193
194 double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Ellipse2d>& theEllipse,
195                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
196                                    std::shared_ptr<GeomAPI_Pnt2d>& thePointOnEllipse)
197 {
198   Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(theEllipse->impl<gp_Elips2d>());
199   Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(*MY_ELLIPSE);
200
201   IntAna2d_AnaIntersection anInter(theEllipse->impl<gp_Elips2d>(), IntAna2d_Conic(*MY_ELLIPSE));
202   Extrema_ExtCC2d* anExtema =
203       new Extrema_ExtCC2d(Geom2dAdaptor_Curve(anEllipse1), Geom2dAdaptor_Curve(anEllipse2));
204   double aDistance = extrema(&anInter, anExtema, theEllipse->firstFocus(),
205                              thePointOnEllipse, thePointOnMe);
206   delete anExtema;
207   return aDistance;
208 }
209
210 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Ellipse2d::project(
211     const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
212 {
213   std::shared_ptr<GeomAPI_Pnt2d> aResult;
214   if (!MY_ELLIPSE)
215     return aResult;
216
217   Handle(Geom2d_Ellipse) aEllipse = new Geom2d_Ellipse(*MY_ELLIPSE);
218
219   const gp_Pnt2d& aPoint = thePoint->impl<gp_Pnt2d>();
220
221   Geom2dAPI_ProjectPointOnCurve aProj(aPoint, aEllipse);
222   Standard_Integer aNbPoint = aProj.NbPoints();
223   if (aNbPoint > 0) {
224     gp_Pnt2d aNearest = aProj.NearestPoint();
225     aResult.reset(new GeomAPI_Pnt2d(aNearest.X(), aNearest.Y()));
226   }
227   return aResult;
228 }
229
230 const bool GeomAPI_Ellipse2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
231                                         const double theTolerance,
232                                         double& theParameter) const
233 {
234   Handle(Geom2d_Ellipse) aCurve = new Geom2d_Ellipse(*MY_ELLIPSE);
235   return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt2d>(),
236                                  theTolerance, theParameter) == Standard_True;
237 }