1 /***************************************************************************
2                          qgscircle.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 QGSCIRCLE_H
19 #define QGSCIRCLE_H
20 
21 #include <QString>
22 
23 #include "qgis_core.h"
24 #include "qgsellipse.h"
25 #include "qgspolygon.h"
26 #include "qgsrectangle.h"
27 #include "qgscircularstring.h"
28 
29 
30 class QgsPoint;
31 
32 /**
33  * \ingroup core
34  * \class QgsCircle
35  * \brief Circle geometry type.
36  *
37  * A circle is defined by a center point with a radius and an azimuth.
38  * The azimuth is the north angle to the semi-major axis, in degrees. By default, the semi-major axis is oriented to the north (0 degrees).
39  * \since QGIS 3.0
40  */
41 
42 
43 class CORE_EXPORT QgsCircle : public QgsEllipse
44 {
45   public:
46     QgsCircle();
47 
48     /**
49      * Constructs a circle by defining all the members.
50      * \param center The center of the circle.
51      * \param radius The radius of the circle.
52      * \param azimuth Angle in degrees started from the North to the first quadrant.
53      */
54     QgsCircle( const QgsPoint &center, double radius, double azimuth = 0 ) SIP_HOLDGIL;
55 
56     /**
57      * Constructs a circle by 2 points on the circle.
58      * The center point can have m value which is the result from the midpoint
59      * operation between \a pt1 and \a pt2. Z dimension is also supported and
60      * is retrieved from the first 3D point amongst \a pt1 and \a pt2.
61      * The radius is calculated from the 2D distance between \a pt1 and \a pt2.
62      * The azimuth is the angle between \a pt1 and \a pt2.
63      * \param pt1 First point.
64      * \param pt2 Second point.
65      */
66     static QgsCircle from2Points( const QgsPoint &pt1, const QgsPoint &pt2 ) SIP_HOLDGIL;
67 
68     /**
69      * Constructs a circle by 3 points on the circle.
70      * M value is dropped for the center point.
71      * Z dimension is supported and is retrieved from the first 3D point
72      * amongst \a pt1, \a pt2 and \a pt3.
73      * The azimuth always takes the default value.
74      * If the points are colinear an empty circle is returned.
75      * \param pt1 First point.
76      * \param pt2 Second point.
77      * \param pt3 Third point.
78      * \param epsilon Value used to compare point.
79      */
80     static QgsCircle from3Points( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon = 1E-8 ) SIP_HOLDGIL;
81 
82     /**
83      * Constructs a circle by a center point and a diameter.
84      * The center point keeps z and m values from \a center.
85      * \param center Center point.
86      * \param diameter Diameter of the circle.
87      * \param azimuth Azimuth of the circle.
88      */
89     static QgsCircle fromCenterDiameter( const QgsPoint &center, double diameter, double azimuth = 0 ) SIP_HOLDGIL;
90 
91 
92     /**
93      * Constructs a circle by a center point and another point.
94      * The center point keeps z and m values from \a center.
95      * Axes are calculated from the 2D distance between \a center and \a pt1.
96      * The azimuth is the angle between \a center and \a pt1.
97      * \param center Center point.
98      * \param pt1 A point on the circle.
99      */
100     static QgsCircle fromCenterPoint( const QgsPoint &center, const QgsPoint &pt1 ) SIP_HOLDGIL;
101 
102 
103     /**
104      * Constructs a circle by 3 tangents on the circle (aka inscribed circle of a triangle).
105      * Z and m values are dropped for the center point.
106      * The azimuth always takes the default value.
107      * \param pt1_tg1 First point of the first tangent.
108      * \param pt2_tg1 Second point of the first tangent.
109      * \param pt1_tg2 First point of the second tangent.
110      * \param pt2_tg2 Second point of the second tangent.
111      * \param pt1_tg3 First point of the third tangent.
112      * \param pt2_tg3 Second point of the third tangent.
113      * \param epsilon Value used to compare point.
114      */
115     static QgsCircle from3Tangents( const QgsPoint &pt1_tg1, const QgsPoint &pt2_tg1,
116                                     const QgsPoint &pt1_tg2, const QgsPoint &pt2_tg2,
117                                     const QgsPoint &pt1_tg3, const QgsPoint &pt2_tg3, double epsilon = 1E-8 ) SIP_HOLDGIL;
118 
119     /**
120      * Constructs a circle by an extent (aka bounding box / QgsRectangle).
121      * The center point can have m value which is the result from the midpoint
122      * operation between \a pt1 and \a pt2. Z dimension is also supported and
123      * is retrieved from the first 3D point amongst \a pt1 and \a pt2.
124      * Axes are calculated from the 2D distance between \a pt1 and \a pt2.
125      * The azimuth always takes the default value.
126      * \param pt1 First corner.
127      * \param pt2 Second corner.
128      */
129     static QgsCircle fromExtent( const QgsPoint &pt1, const QgsPoint &pt2 ) SIP_HOLDGIL;
130 
131     /**
132      * Constructs the smallest circle from 3 points.
133      * Z and m values are dropped for the center point.
134      * The azimuth always takes the default value.
135      * If the points are colinear an empty circle is returned.
136      * \param pt1 First point.
137      * \param pt2 Second point.
138      * \param pt3 Third point.
139      * \param epsilon Value used to compare point.
140      */
141     static QgsCircle minimalCircleFrom3Points( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon = 1E-8 ) SIP_HOLDGIL;
142 
143     /**
144      * Calculates the intersections points between this circle and an \a other circle.
145      *
146      * If found, the intersection points will be stored in \a intersection1 and \a intersection2.
147      *
148      * By default this method does not consider any z values and instead treats the circles as 2-dimensional.
149      * If \a useZ is set to TRUE, then an intersection will only occur if the z values of both circles are
150      * equal. In this case the points returned for \a intersection1 and \a intersection2 will contain
151      * the z value of the circle intersections.
152      *
153      * \returns number of intersection points found.
154      *
155      * \since QGIS 3.2
156      */
157     int intersections( const QgsCircle &other, QgsPoint &intersection1 SIP_OUT, QgsPoint &intersection2 SIP_OUT, bool useZ = false ) const;
158 
159     /**
160      * Calculates the tangent points between this circle and the point \a p.
161      *
162      * If found, the tangent points will be stored in \a pt1 and \a pt2.
163      *
164      * Note that this method is 2D only and does not consider the z-value of the circle.
165      *
166      * \returns TRUE if tangent was found.
167      *
168      *
169      * \see outerTangents() and innerTangents()
170      * \since QGIS 3.2
171      */
172     bool tangentToPoint( const QgsPointXY &p, QgsPointXY &pt1 SIP_OUT, QgsPointXY &pt2 SIP_OUT ) const;
173 
174     /**
175      * Calculates the outer tangent points between this circle
176      * and an \a other circle.
177      *
178      * The outer tangent points correspond to the points at which the two lines
179      * which are drawn so that they are tangential to both circles touch
180      * the circles.
181      *
182      * The first tangent line is described by the points
183      * stored in \a line1P1 and \a line1P2,
184      * and the second line is described by the points stored in \a line2P1
185      * and \a line2P2.
186      *
187      * Returns the number of tangents (either 0 or 2).
188      *
189      * Note that this method is 2D only and does not consider the z-value of the circle.
190      *
191      *
192      * \see tangentToPoint() and innerTangents()
193      * \since QGIS 3.2
194      */
195     int outerTangents( const QgsCircle &other,
196                        QgsPointXY &line1P1 SIP_OUT, QgsPointXY &line1P2 SIP_OUT,
197                        QgsPointXY &line2P1 SIP_OUT, QgsPointXY &line2P2 SIP_OUT ) const;
198 
199     /**
200      * Calculates the inner tangent points between this circle
201      * and an \a other circle.
202      *
203      * The inner tangent points correspond to the points at which the two lines
204      * which are drawn so that they are tangential to both circles but on
205      * different sides, touching the circles and crossing each other.
206      *
207      * The first tangent line is described by the points
208      * stored in \a line1P1 and \a line1P2,
209      * and the second line is described by the points stored in \a line2P1
210      * and \a line2P2.
211      *
212      * Returns the number of tangents (either 0 or 2).
213      *
214      * Note that this method is 2D only and does not consider the z-value of the circle.
215      *
216      *
217      * \see tangentToPoint() and outerTangents()
218      * \since QGIS 3.6
219      */
220     int innerTangents( const QgsCircle &other,
221                        QgsPointXY &line1P1 SIP_OUT, QgsPointXY &line1P2 SIP_OUT,
222                        QgsPointXY &line2P1 SIP_OUT, QgsPointXY &line2P2 SIP_OUT ) const;
223 
224     double area() const override SIP_HOLDGIL;
225     double perimeter() const override SIP_HOLDGIL;
226 
227     //inherited
228     // void setAzimuth(const double azimuth);
229     // double azimuth() const {return mAzimuth; }
230 
231 
232     /**
233      * Inherited method. Use setRadius instead.
234      * \see radius()
235      * \see setRadius()
236      */
237     void setSemiMajorAxis( double semiMajorAxis ) override SIP_HOLDGIL;
238 
239     /**
240      * Inherited method. Use setRadius instead.
241      * \see radius()
242      * \see setRadius()
243      */
244     void setSemiMinorAxis( double semiMinorAxis ) override SIP_HOLDGIL;
245 
246     //! Returns the radius of the circle
radius()247     double radius() const SIP_HOLDGIL {return mSemiMajorAxis;}
248     //! Sets the radius of the circle
setRadius(double radius)249     void setRadius( double radius ) SIP_HOLDGIL
250     {
251       mSemiMajorAxis = std::fabs( radius );
252       mSemiMinorAxis = mSemiMajorAxis;
253     }
254 
255     /**
256      * The four quadrants of the ellipse.
257      * They are oriented and started from North.
258      * \return quadrants defined by four points.
259      * \see quadrant()
260      */
261     QVector<QgsPoint> northQuadrant() const SIP_FACTORY;
262 
263     /**
264      * Returns a circular string from the circle.
265      * \param oriented If oriented is TRUE the start point is from azimuth instead from north.
266      */
267     QgsCircularString *toCircularString( bool oriented = false ) const;
268 
269     //! Returns TRUE if the circle contains the \a point.
270     bool contains( const QgsPoint &point, double epsilon = 1E-8 ) const;
271 
272     QgsRectangle boundingBox() const override;
273 
274     QString toString( int pointPrecision = 17, int radiusPrecision = 17, int azimuthPrecision = 2 ) const override;
275 
276 #ifdef SIP_RUN
277     SIP_PYOBJECT __repr__();
278     % MethodCode
279     QString str = QStringLiteral( "<QgsCircle: %1>" ).arg( sipCpp->toString() );
280     sipRes = PyUnicode_FromString( str.toUtf8().constData() );
281     % End
282 #endif
283 };
284 
285 #endif // QGSCIRCLE_H
286