Branch data Line data Source code
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 : 465 : 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 ¢er, 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 ¢er, 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 ¢er, 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 : : * \param pos Point to determine which circle use in case of multi return.
115 : : * If the solution is not unique and pos is an empty point, an empty circle is returned. -- This case happens only when two tangets are parallels. (since QGIS 3.18)
116 : : *
117 : : * \see from3TangentsMulti()
118 : : *
119 : : * ### Example
120 : : *
121 : : * \code{.py}
122 : : * # [(0 0), (5 0)] and [(5 5), (10 5)] are parallels
123 : : * QgsCircle.from3Tangents(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5))
124 : : * # <QgsCircle: Empty>
125 : : * QgsCircle.from3Tangents(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5), pos=QgsPoint(2, 0))
126 : : * # <QgsCircle: Circle (Center: Point (1.46446609406726203 2.49999999999999911), Radius: 2.5, Azimuth: 0)>
127 : : * QgsCircle.from3Tangents(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5), pos=QgsPoint(3, 0))
128 : : * # <QgsCircle: Circle (Center: Point (8.53553390593273775 2.5), Radius: 2.5, Azimuth: 0)>
129 : : * \endcode
130 : : */
131 : : static QgsCircle from3Tangents( const QgsPoint &pt1_tg1, const QgsPoint &pt2_tg1,
132 : : const QgsPoint &pt1_tg2, const QgsPoint &pt2_tg2,
133 : : const QgsPoint &pt1_tg3, const QgsPoint &pt2_tg3,
134 : : double epsilon = 1E-8,
135 : : QgsPoint pos = QgsPoint() ) SIP_HOLDGIL;
136 : :
137 : : /**
138 : : * Returns an array of circle constructed by 3 tangents on the circle (aka inscribed circle of a triangle).
139 : : *
140 : : * The vector can contain 0, 1 or 2 circles:
141 : : *
142 : : * - 0: Impossible to construct a circle from 3 tangents (three parallel tangents)
143 : : * - 1: The three tangents make a triangle or when two tangents are parallel there are two possible circles (see examples).
144 : : * If pos is not an empty point, we use its coordinates to determine which circle will be returned.
145 : : * More precisely the circle that will be returned will be the one whose center is on the same side as pos relative to the third tangent.
146 : : * - 2: Returns both solutions when two tangents are parallel (this implies that pos is an empty point).
147 : : *
148 : : * Z and m values are dropped for the center point.
149 : : * The azimuth always takes the default value.
150 : : * \param pt1_tg1 First point of the first tangent.
151 : : * \param pt2_tg1 Second point of the first tangent.
152 : : * \param pt1_tg2 First point of the second tangent.
153 : : * \param pt2_tg2 Second point of the second tangent.
154 : : * \param pt1_tg3 First point of the third tangent.
155 : : * \param pt2_tg3 Second point of the third tangent.
156 : : * \param epsilon Value used to compare point.
157 : : * \param pos (optional) Point to determine which circle use in case of multi return.
158 : : *
159 : : * \see from3Tangents()
160 : : *
161 : : * ### Example
162 : : *
163 : : * \code{.py}
164 : : *
165 : : * # [(0 0), (5 0)] and [(5 5), (10 5)] are parallels
166 : : * QgsCircle.from3TangentsMulti(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5))
167 : : * # [<QgsCircle: Circle (Center: Point (8.53553390593273775 2.5), Radius: 2.5, Azimuth: 0)>, <QgsCircle: Circle (Center: Point (1.46446609406726203 2.49999999999999911), Radius: 2.5, Azimuth: 0)>]
168 : : * QgsCircle.from3TangentsMulti(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5), pos=QgsPoint(2, 0))
169 : : * # [<QgsCircle: Circle (Center: Point (1.46446609406726203 2.49999999999999911), Radius: 2.5, Azimuth: 0)>]
170 : : * QgsCircle.from3TangentsMulti(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(2.5, 0), QgsPoint(7.5, 5), pos=QgsPoint(3, 0))
171 : : * # [<QgsCircle: Circle (Center: Point (8.53553390593273775 2.5), Radius: 2.5, Azimuth: 0)>]
172 : : * # [(0 0), (5 0)], [(5 5), (10 5)] and [(15 5), (20 5)] are parallels
173 : : * QgsCircle.from3TangentsMulti(QgsPoint(0, 0), QgsPoint(5, 0), QgsPoint(5, 5), QgsPoint(10, 5), QgsPoint(15, 5), QgsPoint(20, 5))
174 : : * # []
175 : : * \endcode
176 : : */
177 : : static QVector<QgsCircle> from3TangentsMulti( const QgsPoint &pt1_tg1, const QgsPoint &pt2_tg1,
178 : : const QgsPoint &pt1_tg2, const QgsPoint &pt2_tg2,
179 : : const QgsPoint &pt1_tg3, const QgsPoint &pt2_tg3,
180 : : double epsilon = 1E-8,
181 : : QgsPoint pos = QgsPoint() ) SIP_HOLDGIL;
182 : :
183 : : /**
184 : : * Constructs a circle by an extent (aka bounding box / QgsRectangle).
185 : : * The center point can have m value which is the result from the midpoint
186 : : * operation between \a pt1 and \a pt2. Z dimension is also supported and
187 : : * is retrieved from the first 3D point amongst \a pt1 and \a pt2.
188 : : * Axes are calculated from the 2D distance between \a pt1 and \a pt2.
189 : : * The azimuth always takes the default value.
190 : : * \param pt1 First corner.
191 : : * \param pt2 Second corner.
192 : : */
193 : : static QgsCircle fromExtent( const QgsPoint &pt1, const QgsPoint &pt2 ) SIP_HOLDGIL;
194 : :
195 : : /**
196 : : * Constructs the smallest circle from 3 points.
197 : : * Z and m values are dropped for the center point.
198 : : * The azimuth always takes the default value.
199 : : * If the points are colinear an empty circle is returned.
200 : : * \param pt1 First point.
201 : : * \param pt2 Second point.
202 : : * \param pt3 Third point.
203 : : * \param epsilon Value used to compare point.
204 : : */
205 : : static QgsCircle minimalCircleFrom3Points( const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double epsilon = 1E-8 ) SIP_HOLDGIL;
206 : :
207 : : /**
208 : : * Calculates the intersections points between this circle and an \a other circle.
209 : : *
210 : : * If found, the intersection points will be stored in \a intersection1 and \a intersection2.
211 : : *
212 : : * By default this method does not consider any z values and instead treats the circles as 2-dimensional.
213 : : * If \a useZ is set to TRUE, then an intersection will only occur if the z values of both circles are
214 : : * equal. In this case the points returned for \a intersection1 and \a intersection2 will contain
215 : : * the z value of the circle intersections.
216 : : *
217 : : * \returns number of intersection points found.
218 : : *
219 : : * \since QGIS 3.2
220 : : */
221 : : int intersections( const QgsCircle &other, QgsPoint &intersection1 SIP_OUT, QgsPoint &intersection2 SIP_OUT, bool useZ = false ) const;
222 : :
223 : : /**
224 : : * Calculates the tangent points between this circle and the point \a p.
225 : : *
226 : : * If found, the tangent points will be stored in \a pt1 and \a pt2.
227 : : *
228 : : * Note that this method is 2D only and does not consider the z-value of the circle.
229 : : *
230 : : * \returns TRUE if tangent was found.
231 : : *
232 : : *
233 : : * \see outerTangents() and innerTangents()
234 : : * \since QGIS 3.2
235 : : */
236 : : bool tangentToPoint( const QgsPointXY &p, QgsPointXY &pt1 SIP_OUT, QgsPointXY &pt2 SIP_OUT ) const;
237 : :
238 : : /**
239 : : * Calculates the outer tangent points between this circle
240 : : * and an \a other circle.
241 : : *
242 : : * The outer tangent points correspond to the points at which the two lines
243 : : * which are drawn so that they are tangential to both circles touch
244 : : * the circles.
245 : : *
246 : : * The first tangent line is described by the points
247 : : * stored in \a line1P1 and \a line1P2,
248 : : * and the second line is described by the points stored in \a line2P1
249 : : * and \a line2P2.
250 : : *
251 : : * Returns the number of tangents (either 0 or 2).
252 : : *
253 : : * Note that this method is 2D only and does not consider the z-value of the circle.
254 : : *
255 : : *
256 : : * \see tangentToPoint() and innerTangents()
257 : : * \since QGIS 3.2
258 : : */
259 : : int outerTangents( const QgsCircle &other,
260 : : QgsPointXY &line1P1 SIP_OUT, QgsPointXY &line1P2 SIP_OUT,
261 : : QgsPointXY &line2P1 SIP_OUT, QgsPointXY &line2P2 SIP_OUT ) const;
262 : :
263 : : /**
264 : : * Calculates the inner tangent points between this circle
265 : : * and an \a other circle.
266 : : *
267 : : * The inner tangent points correspond to the points at which the two lines
268 : : * which are drawn so that they are tangential to both circles but on
269 : : * different sides, touching the circles and crossing each other.
270 : : *
271 : : * The first tangent line is described by the points
272 : : * stored in \a line1P1 and \a line1P2,
273 : : * and the second line is described by the points stored in \a line2P1
274 : : * and \a line2P2.
275 : : *
276 : : * Returns the number of tangents (either 0 or 2).
277 : : *
278 : : * Note that this method is 2D only and does not consider the z-value of the circle.
279 : : *
280 : : *
281 : : * \see tangentToPoint() and outerTangents()
282 : : * \since QGIS 3.6
283 : : */
284 : : int innerTangents( const QgsCircle &other,
285 : : QgsPointXY &line1P1 SIP_OUT, QgsPointXY &line1P2 SIP_OUT,
286 : : QgsPointXY &line2P1 SIP_OUT, QgsPointXY &line2P2 SIP_OUT ) const;
287 : :
288 : : double area() const override SIP_HOLDGIL;
289 : : double perimeter() const override SIP_HOLDGIL;
290 : :
291 : : //inherited
292 : : // void setAzimuth(const double azimuth);
293 : : // double azimuth() const {return mAzimuth; }
294 : :
295 : :
296 : : /**
297 : : * Inherited method. Use setRadius instead.
298 : : * \see radius()
299 : : * \see setRadius()
300 : : */
301 : : void setSemiMajorAxis( double semiMajorAxis ) override SIP_HOLDGIL;
302 : :
303 : : /**
304 : : * Inherited method. Use setRadius instead.
305 : : * \see radius()
306 : : * \see setRadius()
307 : : */
308 : : void setSemiMinorAxis( double semiMinorAxis ) override SIP_HOLDGIL;
309 : :
310 : : //! Returns the radius of the circle
311 : 57 : double radius() const SIP_HOLDGIL {return mSemiMajorAxis;}
312 : : //! Sets the radius of the circle
313 : 1 : void setRadius( double radius ) SIP_HOLDGIL
314 : : {
315 : 1 : mSemiMajorAxis = std::fabs( radius );
316 : 1 : mSemiMinorAxis = mSemiMajorAxis;
317 : 1 : }
318 : :
319 : : /**
320 : : * The four quadrants of the ellipse.
321 : : * They are oriented and started from North.
322 : : * \return quadrants defined by four points.
323 : : * \see quadrant()
324 : : */
325 : : QVector<QgsPoint> northQuadrant() const SIP_FACTORY;
326 : :
327 : : /**
328 : : * Returns a circular string from the circle.
329 : : * \param oriented If oriented is TRUE the start point is from azimuth instead from north.
330 : : */
331 : : QgsCircularString *toCircularString( bool oriented = false ) const;
332 : :
333 : : //! Returns TRUE if the circle contains the \a point.
334 : : bool contains( const QgsPoint &point, double epsilon = 1E-8 ) const;
335 : :
336 : : QgsRectangle boundingBox() const override;
337 : :
338 : : QString toString( int pointPrecision = 17, int radiusPrecision = 17, int azimuthPrecision = 2 ) const override;
339 : :
340 : : /**
341 : : * Returns a GML2 representation of the geometry.
342 : : * Since GML2 does not supports curve, it will be converted to a LineString.
343 : : * \param doc DOM document
344 : : * \param precision number of decimal places for coordinates
345 : : * \param ns XML namespace
346 : : * \param axisOrder Axis order for generated GML
347 : : * \see asGml3()
348 : : */
349 : : QDomElement asGml2( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const;
350 : :
351 : : /**
352 : : * Returns a GML3 representation of the geometry.
353 : : *
354 : : * From the GML3 description:
355 : : * A Circle is an arc whose ends coincide to form a simple closed loop.
356 : : * The three control points shall be distinct non-co-linear points for
357 : : * the circle to be unambiguously defined. The arc is simply extended
358 : : * past the third control point until the first control point is encountered.
359 : : *
360 : : * Coordinates are taken from quadrant North, East and South.
361 : : *
362 : : * \param doc DOM document
363 : : * \param precision number of decimal places for coordinates
364 : : * \param ns XML namespace
365 : : * \param axisOrder Axis order for generated GML
366 : : * \see asGml2()
367 : : */
368 : : QDomElement asGml3( QDomDocument &doc, int precision = 17, const QString &ns = "gml", QgsAbstractGeometry::AxisOrder axisOrder = QgsAbstractGeometry::AxisOrder::XY ) const;
369 : :
370 : : #ifdef SIP_RUN
371 : : SIP_PYOBJECT __repr__();
372 : : % MethodCode
373 : : QString str = QStringLiteral( "<QgsCircle: %1>" ).arg( sipCpp->toString() );
374 : : sipRes = PyUnicode_FromString( str.toUtf8().constData() );
375 : : % End
376 : : #endif
377 : : };
378 : :
379 : : #endif // QGSCIRCLE_H
|