QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsregularpolygon.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsregularpolygon.cpp
3 --------------
4 begin : May 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#include "qgsregularpolygon.h"
19#include "qgsgeometryutils.h"
20
21#include <memory>
22
23QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &center, const double radius, const double azimuth, const unsigned int numSides, const ConstructionOption circle )
24 : mCenter( center )
25{
26 // TODO: inclination
27
28 if ( numSides >= 3 )
29 {
30 mNumberSides = numSides;
31
32 switch ( circle )
33 {
34 case InscribedCircle:
35 {
36 mRadius = std::fabs( radius );
37 mFirstVertex = mCenter.project( mRadius, azimuth );
38 break;
39 }
41 {
42 mRadius = apothemToRadius( std::fabs( radius ), numSides );
43 mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
44 break;
45 }
46 }
47
48 }
49
50}
51
52QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &center, const QgsPoint &pt1, const unsigned int numSides, const ConstructionOption circle )
53 : mCenter( center )
54{
55 if ( numSides >= 3 )
56 {
57 mNumberSides = numSides;
58
59 switch ( circle )
60 {
61 case InscribedCircle:
62 {
63 mFirstVertex = pt1;
64 mRadius = center.distance( pt1 );
65 break;
66 }
68 {
69 mRadius = apothemToRadius( center.distance( pt1 ), numSides );
70 const double azimuth = center.azimuth( pt1 );
71 // TODO: inclination
72 mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
73 break;
74 }
75 }
76
77 }
78
79}
80
81QgsRegularPolygon::QgsRegularPolygon( const QgsPoint &pt1, const QgsPoint &pt2, const unsigned int numSides )
82{
83 if ( numSides >= 3 )
84 {
85 mNumberSides = numSides;
86
87 const double azimuth = pt1.azimuth( pt2 );
88 const QgsPoint pm = QgsGeometryUtils::midpoint( pt1, pt2 );
89 const double length = pt1.distance( pm );
90
91 const double angle = ( 180 - ( 360 / numSides ) ) / 2.0;
92 const double hypothenuse = length / std::cos( angle * M_PI / 180 );
93 // TODO: inclination
94
95 mCenter = pt1.project( hypothenuse, azimuth + angle );
96 mFirstVertex = pt1;
97 mRadius = std::fabs( hypothenuse );
98 }
99}
100
102{
103 return ( ( mCenter == rp.mCenter ) &&
104 ( mFirstVertex == rp.mFirstVertex ) &&
105 ( mNumberSides == rp.mNumberSides )
106 );
107}
108
110{
111 return !operator==( rp );
112}
113
115{
116 return ( ( mNumberSides < 3 ) ||
117 ( mCenter.isEmpty() ) ||
118 ( mFirstVertex.isEmpty() ) ||
119 ( mCenter == mFirstVertex )
120 );
121}
122
124{
125 const double azimuth = mFirstVertex.isEmpty() ? 0 : mCenter.azimuth( mFirstVertex );
126 // TODO: double inclination = mCenter.inclination(mFirstVertex);
127 mCenter = center;
128 mFirstVertex = center.project( mRadius, azimuth );
129}
130
131void QgsRegularPolygon::setRadius( const double radius )
132{
133 mRadius = std::fabs( radius );
134 const double azimuth = mFirstVertex.isEmpty() ? 0 : mCenter.azimuth( mFirstVertex );
135 // TODO: double inclination = mCenter.inclination(mFirstVertex);
136 mFirstVertex = mCenter.project( mRadius, azimuth );
137}
138
140{
141 const double azimuth = mCenter.azimuth( mFirstVertex );
142 // TODO: double inclination = mCenter.inclination(firstVertex);
143 mFirstVertex = firstVertex;
144 mCenter = mFirstVertex.project( mRadius, azimuth );
145}
146
147void QgsRegularPolygon::setNumberSides( const unsigned int numSides )
148{
149 if ( numSides >= 3 )
150 {
151 mNumberSides = numSides;
152 }
153}
154
156{
158 if ( isEmpty() )
159 {
160 return pts;
161 }
162
163 double azimuth = mCenter.azimuth( mFirstVertex );
164 const double azimuth_add = centralAngle();
165 // TODO: inclination
166
167 unsigned int n = 1;
168 while ( n <= mNumberSides )
169 {
170 pts.push_back( mCenter.project( mRadius, azimuth ) );
171 azimuth += azimuth_add;
172 if ( ( azimuth_add > 0 ) && ( azimuth > 180.0 ) )
173 {
174 azimuth -= 360.0;
175 }
176
177 n++;
178 }
179
180 return pts;
181}
182
184{
185 std::unique_ptr<QgsPolygon> polygon( new QgsPolygon() );
186 if ( isEmpty() )
187 {
188 return polygon.release();
189 }
190
191 polygon->setExteriorRing( toLineString() );
192
193 return polygon.release();
194}
195
197{
198 std::unique_ptr<QgsLineString> ext( new QgsLineString() );
199 if ( isEmpty() )
200 {
201 return ext.release();
202 }
203
205 pts = points();
206
207 ext->setPoints( pts );
208 ext->addVertex( pts.at( 0 ) ); //close regular polygon
209
210 return ext.release();
211}
212
214{
215 if ( isEmpty() || ( mNumberSides != 3 ) )
216 {
217 return QgsTriangle();
218 }
219
221 pts = points();
222
223 return QgsTriangle( pts.at( 0 ), pts.at( 1 ), pts.at( 2 ) );
224}
225
226QVector<QgsTriangle> QgsRegularPolygon::triangulate() const
227{
228 QVector<QgsTriangle> l_tri;
229 if ( isEmpty() )
230 {
231 return l_tri;
232 }
233
235 pts = points();
236
237 unsigned int n = 0;
238 while ( n < mNumberSides - 1 )
239 {
240 l_tri.append( QgsTriangle( pts.at( n ), pts.at( n + 1 ), mCenter ) );
241 n++;
242 }
243 l_tri.append( QgsTriangle( pts.at( n ), pts.at( 0 ), mCenter ) );
244
245 return l_tri;
246}
247
249{
250 // TODO: inclined circle
251 return QgsCircle( mCenter, apothem() );
252}
253
255{
256 // TODO: inclined circle
257 return QgsCircle( mCenter, mRadius );
258}
259
260QString QgsRegularPolygon::toString( int pointPrecision, int radiusPrecision, int anglePrecision ) const
261{
262 QString rep;
263 if ( isEmpty() )
264 rep = QStringLiteral( "Empty" );
265 else
266 rep = QStringLiteral( "RegularPolygon (Center: %1, First Vertex: %2, Radius: %3, Azimuth: %4)" )
267 .arg( mCenter.asWkt( pointPrecision ), 0, 's' )
268 .arg( mFirstVertex.asWkt( pointPrecision ), 0, 's' )
269 .arg( qgsDoubleToString( mRadius, radiusPrecision ), 0, 'f' )
270 .arg( qgsDoubleToString( mCenter.azimuth( mFirstVertex ), anglePrecision ), 0, 'f' );
271 // TODO: inclination
272 // .arg( qgsDoubleToString( mCenter.inclination(mFirstVertex), anglePrecision ), 0, 'f' );
273
274 return rep;
275}
276
278{
279 if ( isEmpty() )
280 {
281 return 0.0;
282 }
283
284 return ( mRadius * mRadius * mNumberSides * std::sin( centralAngle() * M_PI / 180.0 ) ) / 2;
285}
286
288{
289 if ( isEmpty() )
290 {
291 return 0.0;
292 }
293
294 return length() * mNumberSides;
295}
296
298{
299 if ( isEmpty() )
300 {
301 return 0.0;
302 }
303
304 return mRadius * 2 * std::sin( M_PI / mNumberSides );
305}
306
307double QgsRegularPolygon::apothemToRadius( const double apothem, const unsigned int numSides ) const
308{
309 return apothem / std::cos( M_PI / numSides );
310}
311
312double QgsRegularPolygon::interiorAngle( const unsigned int nbSides ) const
313{
314 return ( nbSides - 2 ) * 180 / nbSides;
315}
316
317double QgsRegularPolygon::centralAngle( const unsigned int nbSides ) const
318{
319 return 360.0 / nbSides;
320}
321
323{
324 return interiorAngle( mNumberSides );
325}
326
328{
329 return centralAngle( mNumberSides );
330}
Circle geometry type.
Definition: qgscircle.h:44
static QgsPoint midpoint(const QgsPoint &pt1, const QgsPoint &pt2) SIP_HOLDGIL
Returns a middle point between points pt1 and pt2.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:343
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Definition: qgspoint.cpp:735
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Definition: qgspoint.cpp:264
double azimuth(const QgsPoint &other) const SIP_HOLDGIL
Calculates Cartesian azimuth between this point and other one (clockwise in degree,...
Definition: qgspoint.cpp:716
Polygon geometry type.
Definition: qgspolygon.h:34
Regular Polygon geometry type.
QgsPointSequence points() const
Returns a list including the vertices of the regular polygon.
double radius() const SIP_HOLDGIL
Returns the radius.
QString toString(int pointPrecision=17, int radiusPrecision=17, int anglePrecision=2) const
Returns a string representation of the regular polygon.
QgsPoint firstVertex() const SIP_HOLDGIL
Returns the first vertex (corner) of the regular polygon.
double length() const SIP_HOLDGIL
Returns the length of a side.
void setCenter(const QgsPoint &center) SIP_HOLDGIL
Sets the center point.
QgsLineString * toLineString() const
Returns as a linestring.
double interiorAngle() const SIP_HOLDGIL
Returns the measure of the interior angles in degrees.
bool isEmpty() const SIP_HOLDGIL
A regular polygon is empty if radius equal to 0 or number of sides < 3.
ConstructionOption
A regular polygon can be constructed inscribed in a circle or circumscribed about a circle.
@ CircumscribedCircle
Circumscribed about a circle (the radius is the distance from the center to the midpoints of the side...
@ InscribedCircle
Inscribed in a circle (the radius is the distance between the center and vertices)
double perimeter() const SIP_HOLDGIL
Returns the perimeter.
QgsCircle circumscribedCircle() const SIP_HOLDGIL
Returns the circumscribed circle.
bool operator==(const QgsRegularPolygon &rp) const SIP_HOLDGIL
QgsPoint center() const SIP_HOLDGIL
Returns the center point of the regular polygon.
QgsTriangle toTriangle() const
Returns as a triangle.
void setNumberSides(unsigned int numberSides) SIP_HOLDGIL
Sets the number of sides.
QgsCircle inscribedCircle() const SIP_HOLDGIL
Returns the inscribed circle.
QgsPolygon * toPolygon() const
Returns as a polygon.
void setRadius(double radius) SIP_HOLDGIL
Sets the radius.
void setFirstVertex(const QgsPoint &firstVertex) SIP_HOLDGIL
Sets the first vertex.
double apothem() const SIP_HOLDGIL
Returns the apothem of the regular polygon.
QgsRegularPolygon() SIP_HOLDGIL=default
Constructor for QgsRegularPolygon.
double centralAngle() const SIP_HOLDGIL
Returns the measure of the central angle (the angle subtended at the center of the polygon by one of ...
QVector< QgsTriangle > triangulate() const
Returns a triangulation (vertices from sides to the center) of the regular polygon.
bool operator!=(const QgsRegularPolygon &rp) const SIP_HOLDGIL
double area() const SIP_HOLDGIL
Returns the area.
Triangle geometry type.
Definition: qgstriangle.h:34
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:2466
QVector< QgsPoint > QgsPointSequence