1 /***************************************************************************
2                          qgsellipse.h
3                          --------------
4     begin                : March 2017
5     copyright            : (C) 2017 by Loîc Bartoletti
6     email                : lbartoletti at tuxfamily dot org
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifndef QGSELLIPSE_H
19 #define QGSELLIPSE_H
20 
21 #include <QString>
22 
23 #include "qgis_core.h"
24 #include "qgspoint.h"
25 #include "qgspolygon.h"
26 #include "qgslinestring.h"
27 #include "qgsrectangle.h"
28 
29 /**
30  * \ingroup core
31  * \class QgsEllipse
32  * \brief Ellipse geometry type.
33  *
34  * An ellipse is defined by a center point with a semi-major axis, a semi-minor axis and an azimuth.
35  * The azimuth is the north angle to the first quadrant (always oriented on the semi-major axis), in degrees. By default, the semi-major axis is oriented to the east (90 degrees).
36  * The semi-minor axis is always smaller than the semi-major axis. If it is set larger, it will be swapped and the azimuth will increase by 90 degrees.
37  * \since QGIS 3.0
38  */
39 class CORE_EXPORT QgsEllipse
40 {
41 
42   public:
43 
44     /**
45      * Constructor for QgsEllipse.
46      */
47     QgsEllipse() SIP_HOLDGIL = default;
48 
49     virtual ~QgsEllipse() = default;
50 
51     /**
52      * Constructs an ellipse by defining all the members.
53      * \param center The center of the ellipse.
54      * \param semiMajorAxis Semi-major axis of the ellipse.
55      * \param semiMinorAxis Semi-minor axis of the ellipse.
56      * \param azimuth Angle in degrees started from the North to the first quadrant.
57      */
58     QgsEllipse( const QgsPoint &center, double semiMajorAxis, double semiMinorAxis, double azimuth = 90 ) SIP_HOLDGIL;
59 
60     /**
61      * Constructs an ellipse by foci (\a pt1 and \a pt2) and a point \a pt3.
62      * The center point can have m value which is the result from the midpoint
63      * operation between \a pt1 and \a pt2. Z dimension is also supported and
64      * is retrieved from the first 3D point amongst \a pt1 and \a pt2.
65      * Axes are calculated from the 2D distance with the third point \a pt3.
66      * The azimuth is the angle between \a pt1 and \a pt2.
67      * \param pt1 First focus.
68      * \param pt2 Second focus.
69      * \param pt3 A point to calculate the axes.
70      */
71     static QgsEllipse fromFoci( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3 ) SIP_HOLDGIL;
72 
73     /**
74      * Constructs an ellipse by an extent (aka bounding box / QgsRectangle).
75      * The center point can have m value which is the result from the midpoint
76      * operation between \a pt1 and \a pt2. Z dimension is also supported and
77      * is retrieved from the first 3D point amongst \a pt1 and \a pt2.
78      * Axes are calculated from the 2D distance between \a pt1 and \a pt2.
79      * The azimuth always takes the default value.
80      * \param pt1 First corner.
81      * \param pt2 Second corner.
82      */
83     static QgsEllipse fromExtent( const QgsPoint &pt1, const QgsPoint &pt2 ) SIP_HOLDGIL;
84 
85     /**
86      * Constructs an ellipse by a center point and a another point.
87      * The center point keeps m value from \a ptc. Z dimension is also
88      * supported and is retrieved from the first 3D point amongst \a ptc and
89      * \a pt1.
90      * Axes are calculated from the 2D distance between \a ptc and \a pt1.
91      * The azimuth always takes the default value.
92      * \param ptc Center point.
93      * \param pt1 First point.
94      */
95     static QgsEllipse fromCenterPoint( const QgsPoint &ptc, const QgsPoint &pt1 ) SIP_HOLDGIL;
96 
97     /**
98      * Constructs an ellipse by a central point and two other points.
99      * The center point keeps m value from \a ptc. Z dimension is also
100      * supported and is retrieved from the first 3D point amongst \a ptc,
101      * \a pt1 and \a pt2.
102      * Axes are calculated from the 2D distance between \a ptc and \a pt1 and \a pt2.
103      * The azimuth is the angle between \a ptc and \a pt1.
104      * \param ptc Center point.
105      * \param pt1 First point.
106      * \param pt2 Second point.
107      */
108     static QgsEllipse fromCenter2Points( const QgsPoint &ptc, const QgsPoint &pt1, const QgsPoint &pt2 ) SIP_HOLDGIL;
109 
110     virtual bool operator ==( const QgsEllipse &elp ) const;
111     virtual bool operator !=( const QgsEllipse &elp ) const;
112 
113     //! An ellipse is empty if axes are equal to 0
114     virtual bool isEmpty() const SIP_HOLDGIL;
115 
116     /**
117      * Returns the center point.
118      * \see setCenter()
119      * \see rcenter()
120      */
center()121     QgsPoint center() const SIP_HOLDGIL {return mCenter; }
122 
123     /**
124      * Returns the semi-major axis.
125      * \see setSemiMajorAxis()
126      */
semiMajorAxis()127     double semiMajorAxis() const SIP_HOLDGIL {return mSemiMajorAxis; }
128 
129     /**
130      * Returns the semi-minor axis.
131      * \see setSemiMinorAxis()
132      */
semiMinorAxis()133     double semiMinorAxis() const SIP_HOLDGIL {return mSemiMinorAxis; }
134 
135     /**
136      * Returns the azimuth.
137      * \see setAzimuth()
138      */
azimuth()139     double azimuth() const SIP_HOLDGIL {return mAzimuth; }
140 
141     /**
142      * Returns a reference to the center point of this ellipse.
143      * Using a reference makes it possible to directly manipulate center in place.
144      * \see center()
145      * \see setCenter()
146      * \note not available in Python bindings
147      */
rcenter()148     QgsPoint &rcenter() SIP_SKIP { return mCenter; }
149 
150     /**
151      * Sets the center point.
152      * \see center()
153      * \see rcenter()
154      */
setCenter(const QgsPoint & center)155     void setCenter( const QgsPoint &center ) SIP_HOLDGIL {mCenter = center; }
156 
157     /**
158      * Sets the semi-major axis.
159      * \see semiMajorAxis()
160      */
161     virtual void setSemiMajorAxis( double semiMajorAxis ) SIP_HOLDGIL;
162 
163     /**
164      * Sets the semi-minor axis.
165      * \see semiMinorAxis()
166      */
167     virtual void setSemiMinorAxis( double semiMinorAxis ) SIP_HOLDGIL;
168 
169     /**
170      * Sets the azimuth (orientation).
171      * \see azimuth()
172      */
173     void setAzimuth( double azimuth ) SIP_HOLDGIL;
174 
175     /**
176      * The distance between the center and each foci.
177      * \see fromFoci()
178      * \see foci()
179      * \return The distance between the center and each foci.
180      */
181     virtual double focusDistance() const SIP_HOLDGIL;
182 
183     /**
184      * Two foci of the ellipse. The axes are oriented by the azimuth and are on the semi-major axis.
185      * \see fromFoci()
186      * \see focusDistance()
187      * \return the two foci.
188      */
189     virtual QVector<QgsPoint> foci() const;
190 
191     /**
192      * The eccentricity of the ellipse.
193      * nan is returned if the ellipse is empty.
194      */
195     virtual double eccentricity() const SIP_HOLDGIL;
196     //! The area of the ellipse.
197     virtual double area() const SIP_HOLDGIL;
198     //! The circumference of the ellipse using first approximation of Ramanujan.
199     virtual double perimeter() const SIP_HOLDGIL;
200 
201     /**
202      * The four quadrants of the ellipse.
203      * They are oriented and started always from semi-major axis.
204      * \return quadrants defined by four points.
205      */
206     virtual QVector<QgsPoint> quadrant() const;
207 
208     /**
209      * Returns a list of points with segmentation from \a segments.
210      * \param segments Number of segments used to segment geometry.
211      */
212     virtual QgsPointSequence points( unsigned int segments = 36 ) const;
213 
214     /**
215      * Returns a segmented polygon.
216      * \param segments Number of segments used to segment geometry.
217      */
218     virtual QgsPolygon *toPolygon( unsigned int segments = 36 ) const SIP_FACTORY;
219 
220     /**
221      * Returns a segmented linestring.
222      * \param segments Number of segments used to segment geometry.
223      */
224     virtual QgsLineString *toLineString( unsigned int segments = 36 ) const SIP_FACTORY;
225     //virtual QgsCurvePolygon toCurvePolygon() const;
226 
227     /**
228      * Returns the oriented minimal bounding box for the ellipse.
229      */
230     virtual QgsPolygon *orientedBoundingBox() const SIP_FACTORY;
231 
232     /**
233      * Returns the minimal bounding box for the ellipse.
234      */
235     virtual QgsRectangle boundingBox() const;
236 
237     /**
238      * returns a string representation of the ellipse.
239      * Members will be truncated to the specified precision.
240      */
241     virtual QString toString( int pointPrecision = 17, int axisPrecision = 17, int azimuthPrecision = 2 ) const;
242 
243 #ifdef SIP_RUN
244     SIP_PYOBJECT __repr__();
245     % MethodCode
246     QString str = QStringLiteral( "<QgsEllipse: %1>" ).arg( sipCpp->toString() );
247     sipRes = PyUnicode_FromString( str.toUtf8().constData() );
248     % End
249 #endif
250 
251   protected:
252     QgsPoint mCenter;
253     double mSemiMajorAxis = 0.0;
254     double mSemiMinorAxis = 0.0;
255     double mAzimuth = 90.0;
256 
257   private:
258     //! The semi-minor axis is always smaller than the semi-major axis. If it is set larger, it will be swapped and the azimuth will increase by 90 degrees.
259     void normalizeAxis();
260 };
261 
262 #endif // QGSELLIPSE_H
263