QGIS API Documentation  3.21.0-Master (909859188c)
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 
23 QgsRegularPolygon::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 
52 QgsRegularPolygon::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 
81 QgsRegularPolygon::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 
131 void 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 
139 void QgsRegularPolygon::setFirstVertex( const QgsPoint &firstVertex )
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 
147 void QgsRegularPolygon::setNumberSides( const unsigned int numSides )
148 {
149  if ( numSides >= 3 )
150  {
151  mNumberSides = numSides;
152  }
153 }
154 
156 {
157  QgsPointSequence pts;
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 
204  QgsPointSequence pts;
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 
220  QgsPointSequence pts;
221  pts = points();
222 
223  return QgsTriangle( pts.at( 0 ), pts.at( 1 ), pts.at( 2 ) );
224 }
225 
226 QVector<QgsTriangle> QgsRegularPolygon::triangulate() const
227 {
228  QVector<QgsTriangle> l_tri;
229  if ( isEmpty() )
230  {
231  return l_tri;
232  }
233 
234  QgsPointSequence pts;
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 
260 QString 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 
307 double QgsRegularPolygon::apothemToRadius( const double apothem, const unsigned int numSides ) const
308 {
309  return apothem / std::cos( M_PI / numSides );
310 }
311 
312 double QgsRegularPolygon::interiorAngle( const unsigned int nbSides ) const
313 {
314  return ( nbSides - 2 ) * 180 / nbSides;
315 }
316 
317 double 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:44
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:1060
QVector< QgsPoint > QgsPointSequence