New geometry class: QgsRegularPolygon (#4502)

This commit is contained in:
lbartoletti 2017-05-10 14:23:28 +02:00 committed by Nyall Dawson
parent 55cb855003
commit 13c1318a5f
16 changed files with 1095 additions and 18 deletions

View File

@ -393,6 +393,7 @@
%Include geometry/qgspointv2.sip
%Include geometry/qgspolygon.sip
%Include geometry/qgsrectangle.sip
%Include geometry/qgsregularpolygon.sip
%Include geometry/qgssurface.sip
%Include geometry/qgstriangle.sip
%Include geometry/qgswkbtypes.sip

View File

@ -189,11 +189,11 @@ The circumference of the ellipse using first approximation of Ramanujan.
:rtype: list of QgsPointV2
%End
virtual void points( QgsPointSequence &pts, unsigned int segments = 36 ) const;
virtual QgsPointSequence points( unsigned int segments = 36 ) const;
%Docstring
Returns a list of points into ``pts``, with segmentation from ``segments``.
\param pts List of points returned.
Returns a list of points with segmentation from ``segments``.
\param segments Number of segments used to segment geometry.
:rtype: QgsPointSequence
%End
virtual QgsPolygonV2 *toPolygon( unsigned int segments = 36 ) const /Factory/;

View File

@ -0,0 +1,232 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsregularpolygon.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsRegularPolygon
{
%Docstring
Regular Polygon geometry type.
A regular polygon is a polygon that is equiangular (all angles are equal in measure) and equilateral (all sides have the same length).
The regular polygon is defined by a center point with a number of sides/vertices, a radius and the first vertex.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsregularpolygon.h"
%End
public:
enum ConstructionOption
{
InscribedCircle,
CircumscribedCircle
};
QgsRegularPolygon();
QgsRegularPolygon( const QgsPointV2 &center, const double radius, const double azimuth, const int numberSides, const ConstructionOption circle );
%Docstring
Constructs a regular polygon by ``center`` and parameters for the first vertex. An empty regular polygon is returned if ``numberSides`` < 3 or ``ConstructionOption`` isn't valid.
\param center The center of the regular polygon.
\param radius Distance from the center and the first vertex or sides (see ``ConstructionOption``).
\param azimuth Angle in degrees started from the North to the first vertex.
\param numberSides Number of sides of the regular polygon.
.. seealso:: ConstructionOption
%End
QgsRegularPolygon( const QgsPointV2 &center, const QgsPointV2 &pt1, const int numberSides, const ConstructionOption circle );
%Docstring
Constructs a regular polygon by ``center`` and another point.
\param center The center of the regular polygon.
\param pt1 The first vertex if the polygon is inscribed in circle or the midpoint of a side if the polygon is circumscribed about circle.
\param numberSides Number of sides of the regular polygon.
\param circle Option to create the polygon inscribed in circle (the radius is the distance between the center and vertices) or circumscribed about circle (the radius is the distance from the center to the midpoints of the sides).
%End
QgsRegularPolygon( const QgsPointV2 &pt1, const QgsPointV2 &pt2, const int numberSides );
%Docstring
Constructs a regular polygon by two points of the first side.
\param pt1 The first vertex of the first side, also first vertex of the regular polygon.
\param pt2 The second vertex of the first side.
\param numberSides Number of sides of the regular polygon.
%End
bool operator ==( const QgsRegularPolygon &rp ) const;
bool operator !=( const QgsRegularPolygon &rp ) const;
bool isEmpty() const;
%Docstring
A regular polygon is empty if radius equal to 0 or number of sides < 3
:rtype: bool
%End
QgsPointV2 center() const;
%Docstring
Returns the center point of the regular polygon.
.. seealso:: setCenter()
:rtype: QgsPointV2
%End
double radius() const;
%Docstring
Returns the radius.
This is also the radius of the circumscribing circle.
.. seealso:: apothem()
.. seealso:: setRadius()
:rtype: float
%End
QgsPointV2 firstVertex() const;
%Docstring
Returns the first vertex (corner) of the regular polygon.
.. seealso:: setFirstVertex()
:rtype: QgsPointV2
%End
double apothem() const;
%Docstring
Returns the apothem of the regular polygon.
The apothem is the radius of the inscribed circle.
.. seealso:: radius()
:rtype: float
%End
int numberSides() const;
%Docstring
Returns the number of sides of the regular polygon.
.. seealso:: setNumberSides()
:rtype: int
%End
void setCenter( const QgsPointV2 &center );
%Docstring
Sets the center point.
Radius is unchanged. The first vertex is reprojected from the new center.
.. seealso:: center()
%End
void setRadius( const double radius );
%Docstring
Sets the radius.
Center is unchanged. The first vertex is reprojected from the center with the new radius.
.. seealso:: radius()
%End
void setFirstVertex( const QgsPointV2 &firstVertex );
%Docstring
Sets the first vertex.
Radius is unchanged. The center is reprojected from the new first vertex.
.. seealso:: firstVertex()
%End
void setNumberSides( const int numberSides );
%Docstring
Sets the number of sides.
If numberSides < 3, the number of sides is unchanged.
.. seealso:: numberSides()
%End
QgsPointSequence points( ) const;
%Docstring
Returns a list including the vertices of the regular polygon.
:rtype: QgsPointSequence
%End
QgsPolygonV2 *toPolygon( ) const /Factory/;
%Docstring
Returns as a polygon.
:rtype: QgsPolygonV2
%End
QgsLineString *toLineString( ) const /Factory/;
%Docstring
Returns as a linestring.
:rtype: QgsLineString
%End
QgsTriangle toTriangle( ) const;
%Docstring
Returns as a triangle.
An empty triangle is returned if the regular polygon is empty or if the number of sides is different from 3.
:rtype: QgsTriangle
%End
QList<QgsTriangle> triangulate( ) const;
%Docstring
Returns a triangulation (vertices from sides to the center) of the regular polygon.
An empty list is returned if the regular polygon is empty.
:rtype: list of QgsTriangle
%End
QgsCircle inscribedCircle( ) const;
%Docstring
Returns the inscribed circle
:rtype: QgsCircle
%End
QgsCircle circumscribedCircle( ) const;
%Docstring
Returns the circumscribed circle
:rtype: QgsCircle
%End
QString toString( int pointPrecision = 17, int radiusPrecision = 17, int anglePrecision = 2 ) const;
%Docstring
Returns a string representation of the regular polygon.
Members will be truncated to the specified precision.
:rtype: str
%End
double interiorAngle( ) const;
%Docstring
Returns the measure of the interior angles in degrees.
:rtype: float
%End
double centralAngle( ) const;
%Docstring
Returns the measure of the central angle (the angle subtended at the center of the polygon by one of its sides) in degrees.
:rtype: float
%End
double area( ) const;
%Docstring
Returns the area.
Returns 0 if the regular polygon is empty.
:rtype: float
%End
double perimeter( ) const;
%Docstring
Returns the perimeter.
Returns 0 if the regular polygon is empty.
:rtype: float
%End
double length( ) const;
%Docstring
Returns the length of a side.
Returns 0 if the regular polygon is empty.
:rtype: float
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsregularpolygon.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -49,6 +49,14 @@ class QgsTriangle : QgsPolygonV2
\param p3 third point
%End
bool operator==( const QgsTriangle &other ) const;
%Docstring
:rtype: bool
%End
bool operator!=( const QgsTriangle &other ) const;
%Docstring
:rtype: bool
%End
virtual QString geometryType() const;
virtual QgsTriangle *clone() const /Factory/;

View File

@ -5,8 +5,8 @@
"variableLenArguments": true,
"arguments": [
{"arg":"center", "description": "center point of the ellipse"},
{"arg":"semi-major axis", "description": "semi-major axis of the ellipse"},
{"arg":"semi-minor axis", "description": "semi-minor axis of the ellipse"},
{"arg":"semi_major_axis", "description": "semi-major axis of the ellipse"},
{"arg":"semi_minor_axis", "description": "semi-minor axis of the ellipse"},
{"arg":"azimuth", "description": "orientation of the ellipse"},
{"arg":"segment", "description": "optional argument for polygon segmentation. By default this value is 36"}],
"examples": [ { "expression":"geom_to_wkt(make_ellipse(make_point(10,10), 5, 2, 90, 4))", "returns":"'Polygon ((15 10, 10 8, 5 10, 10 12, 15 10))'"},

View File

@ -0,0 +1,14 @@
{
"name": "make_regular_polygon",
"type": "function",
"description": "Creates a regular polygon.",
"variableLenArguments": true,
"arguments": [
{"arg":"center", "description": "center of the regular polygon"},
{"arg":"radius", "description": "second point. The first if the regular polygon is inscribed. The midpoint of the first side if the regular polygon is circumscribed."},
{"arg":"number_sides", "description": "Number of sides/edges of the regular polygon"},
{"arg":"circle", "description": "Optional argument to construct the regular polygon. By default this value is 0. Value can be 0 (inscribed) or 1 (circumscribed)"}],
"examples": [ { "expression":"geom_to_wkt(make_regular_polygon(make_point(0,0), make_point(0,5), 5))", "returns":"'Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))'"},
{ "expression":"geom_to_wkt(make_regular_polygon(make_point(0,0), project(make_point(0,0), 4.0451, radians(36)), 5))", "returns":"'Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))'"}
]
}

View File

@ -406,6 +406,7 @@ SET(QGIS_CORE_SRCS
geometry/qgspointv2.cpp
geometry/qgspolygon.cpp
geometry/qgsrectangle.cpp
geometry/qgsregularpolygon.cpp
geometry/qgstriangle.cpp
geometry/qgswkbptr.cpp
geometry/qgswkbtypes.cpp
@ -974,6 +975,7 @@ SET(QGIS_CORE_HDRS
geometry/qgspointv2.h
geometry/qgspolygon.h
geometry/qgsrectangle.h
geometry/qgsregularpolygon.h
geometry/qgstriangle.h
geometry/qgssurface.h
geometry/qgswkbptr.h

View File

@ -184,12 +184,13 @@ QVector<QgsPointV2> QgsEllipse::quadrant() const
return quad;
}
void QgsEllipse::points( QgsPointSequence &pts, unsigned int segments ) const
QgsPointSequence QgsEllipse::points( unsigned int segments ) const
{
pts.clear();
QgsPointSequence pts;
if ( segments < 3 )
{
return;
return pts;
}
@ -214,6 +215,8 @@ void QgsEllipse::points( QgsPointSequence &pts, unsigned int segments ) const
mSemiMinorAxis * sin( *it ) * cos( azimuth );
pts.push_back( QgsPointV2( pType, x, y, z, m ) );
}
return pts;
}
QgsPolygonV2 *QgsEllipse::toPolygon( unsigned int segments ) const
@ -238,7 +241,7 @@ QgsLineString *QgsEllipse::toLineString( unsigned int segments ) const
}
QgsPointSequence pts;
points( pts, segments );
pts = points( segments );
ext->setPoints( pts );

View File

@ -176,11 +176,10 @@ class CORE_EXPORT QgsEllipse
*/
virtual QVector<QgsPointV2> quadrant() const;
/** Returns a list of points into \a pts, with segmentation from \a segments.
* \param pts List of points returned.
/** Returns a list of points with segmentation from \a segments.
* \param segments Number of segments used to segment geometry.
*/
virtual void points( QgsPointSequence &pts, unsigned int segments = 36 ) const;
virtual QgsPointSequence points( unsigned int segments = 36 ) const;
/** Returns a segmented polygon.
* \param segments Number of segments used to segment geometry.

View File

@ -0,0 +1,351 @@
/***************************************************************************
qgsregularpolygon.cpp
--------------
begin : May 2017
copyright : (C) 2017 by Loîc Bartoletti
email : lbartoletti at tuxfamily dot org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsregularpolygon.h"
#include "qgsgeometryutils.h"
#include <memory>
QgsRegularPolygon::QgsRegularPolygon()
: mCenter( QgsPointV2() )
, mFirstVertex( QgsPointV2() )
, mNumberSides( 0 )
, mRadius( 0.0 )
{
}
QgsRegularPolygon::QgsRegularPolygon( const QgsPointV2 &center, const double radius, const double azimuth, const int numSides, const ConstructionOption circle )
: mCenter( center )
, mFirstVertex( QgsPointV2() )
, mNumberSides( 0 )
, mRadius( 0.0 )
{
// TODO: inclination
if ( numSides >= 3 )
{
mNumberSides = numSides;
switch ( circle )
{
case InscribedCircle:
{
mRadius = qAbs( radius );
mFirstVertex = mCenter.project( mRadius, azimuth );
break;
}
case CircumscribedCircle:
{
mRadius = apothemToRadius( qAbs( radius ), numSides );
mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
break;
}
default:
break;
}
}
}
QgsRegularPolygon::QgsRegularPolygon( const QgsPointV2 &center, const QgsPointV2 &pt1, const int numSides, const ConstructionOption circle )
: mCenter( center )
, mFirstVertex( QgsPointV2() )
, mNumberSides( 0 )
, mRadius( 0.0 )
{
if ( numSides >= 3 )
{
mNumberSides = numSides;
switch ( circle )
{
case InscribedCircle:
{
mFirstVertex = pt1;
mRadius = center.distance( pt1 );
break;
}
case CircumscribedCircle:
{
mRadius = apothemToRadius( center.distance( pt1 ), numSides );
double azimuth = center.azimuth( pt1 );
// TODO: inclination
mFirstVertex = mCenter.project( mRadius, azimuth - centralAngle( numSides ) / 2 );
break;
}
default:
break;
}
}
}
QgsRegularPolygon::QgsRegularPolygon( const QgsPointV2 &pt1, const QgsPointV2 &pt2, const int numSides )
: mCenter( QgsPointV2() )
, mFirstVertex( QgsPointV2() )
, mNumberSides( 0 )
, mRadius( 0.0 )
{
if ( numSides >= 3 )
{
mNumberSides = numSides;
double azimuth = pt1.azimuth( pt2 );
QgsPointV2 pm = QgsGeometryUtils::midpoint( pt1, pt2 );
double length = pt1.distance( pm );
double angle = ( 180 - ( 360 / numSides ) ) / 2.0;
double hypothenuse = length / cos( angle * M_PI / 180 );
// TODO: inclination
mCenter = pt1.project( hypothenuse, azimuth + angle );
mFirstVertex = pt1;
mRadius = qAbs( hypothenuse );
}
}
bool QgsRegularPolygon::operator ==( const QgsRegularPolygon &rp ) const
{
return ( ( mCenter == rp.mCenter ) &&
( mFirstVertex == rp.mFirstVertex ) &&
( mNumberSides == rp.mNumberSides )
);
}
bool QgsRegularPolygon::operator !=( const QgsRegularPolygon &rp ) const
{
return !operator==( rp );
}
bool QgsRegularPolygon::isEmpty() const
{
return ( ( mNumberSides < 3 ) ||
( mCenter == mFirstVertex )
);
}
void QgsRegularPolygon::setCenter( const QgsPointV2 &center )
{
double azimuth = mCenter.azimuth( mFirstVertex );
// TODO: double inclination = mCenter.inclination(mFirstVertex);
mCenter = center;
mFirstVertex = center.project( mRadius, azimuth );
}
void QgsRegularPolygon::setRadius( const double radius )
{
mRadius = qAbs( radius );
double azimuth = mCenter.azimuth( mFirstVertex );
// TODO: double inclination = mCenter.inclination(mFirstVertex);
mFirstVertex = mCenter.project( mRadius, azimuth );
}
void QgsRegularPolygon::setFirstVertex( const QgsPointV2 &firstVertex )
{
double azimuth = mCenter.azimuth( mFirstVertex );
// TODO: double inclination = mCenter.inclination(firstVertex);
mFirstVertex = firstVertex;
mCenter = mFirstVertex.project( mRadius, azimuth );
}
void QgsRegularPolygon::setNumberSides( const int numSides )
{
if ( numSides >= 3 )
{
mNumberSides = numSides;
}
}
QgsPointSequence QgsRegularPolygon::points( ) const
{
QgsPointSequence pts;
if ( isEmpty() )
{
return pts;
}
double azimuth = mCenter.azimuth( mFirstVertex );
double azimuth_add = centralAngle();
// TODO: inclination
unsigned int n = 1;
while ( n <= mNumberSides )
{
pts.push_back( mCenter.project( mRadius, azimuth ) );
azimuth += azimuth_add;
if ( ( azimuth_add > 0 ) && ( azimuth > 180.0 ) )
{
azimuth -= 360.0;
}
n++;
}
return pts;
}
QgsPolygonV2 *QgsRegularPolygon::toPolygon() const
{
std::unique_ptr<QgsPolygonV2> polygon( new QgsPolygonV2() );
if ( isEmpty() )
{
return polygon.release();
}
polygon->setExteriorRing( toLineString( ) );
return polygon.release();
}
QgsLineString *QgsRegularPolygon::toLineString() const
{
std::unique_ptr<QgsLineString> ext( new QgsLineString() );
if ( isEmpty() )
{
return ext.release();
}
QgsPointSequence pts;
pts = points( );
ext->setPoints( pts );
return ext.release();
}
QgsTriangle QgsRegularPolygon::toTriangle() const
{
if ( isEmpty() || ( mNumberSides != 3 ) )
{
return QgsTriangle();
}
QgsPointSequence pts;
pts = points( );
return QgsTriangle( pts.at( 0 ), pts.at( 1 ), pts.at( 2 ) );
}
QList<QgsTriangle> QgsRegularPolygon::triangulate() const
{
QList<QgsTriangle> l_tri;
if ( isEmpty() )
{
return l_tri;
}
QgsPointSequence pts;
pts = points( );
unsigned int n = 0;
while ( n < mNumberSides - 1 )
{
l_tri.append( QgsTriangle( pts.at( n ), pts.at( n + 1 ), mCenter ) );
n++;
}
l_tri.append( QgsTriangle( pts.at( n ), pts.at( 0 ), mCenter ) );
return l_tri;
}
QgsCircle QgsRegularPolygon::inscribedCircle() const
{
// TODO: inclined circle
return QgsCircle( mCenter, apothem() );
}
QgsCircle QgsRegularPolygon::circumscribedCircle() const
{
// TODO: inclined circle
return QgsCircle( mCenter, mRadius );
}
QString QgsRegularPolygon::toString( int pointPrecision, int radiusPrecision, int anglePrecision ) const
{
QString rep;
if ( isEmpty() )
rep = QStringLiteral( "Empty" );
else
rep = QStringLiteral( "RegularPolygon (Center: %1, First Vertex: %2, Radius: %3, Azimuth: %4)" )
.arg( mCenter.asWkt( pointPrecision ), 0, 's' )
.arg( mFirstVertex.asWkt( pointPrecision ), 0, 's' )
.arg( qgsDoubleToString( mRadius, radiusPrecision ), 0, 'f' )
.arg( qgsDoubleToString( mCenter.azimuth( mFirstVertex ), anglePrecision ), 0, 'f' );
// TODO: inclination
// .arg( qgsDoubleToString( mCenter.inclination(mFirstVertex), anglePrecision ), 0, 'f' );
return rep;
}
double QgsRegularPolygon::area() const
{
if ( isEmpty() )
{
return 0.0;
}
return ( mRadius * mRadius * mNumberSides * sin( centralAngle() * M_PI / 180.0 ) ) / 2 ;
}
double QgsRegularPolygon::perimeter() const
{
if ( isEmpty() )
{
return 0.0;
}
return length() * mNumberSides;
}
double QgsRegularPolygon::length() const
{
if ( isEmpty() )
{
return 0.0;
}
return mRadius * 2 * sin( M_PI / mNumberSides );
}
double QgsRegularPolygon::apothemToRadius( const double apothem, const unsigned int numSides ) const
{
return apothem / cos( M_PI / numSides );
}
double QgsRegularPolygon::interiorAngle( const unsigned int nbSides ) const
{
return ( nbSides - 2 ) * 180 / nbSides;
}
double QgsRegularPolygon::centralAngle( const unsigned int nbSides ) const
{
return 360.0 / nbSides;
}
double QgsRegularPolygon::interiorAngle() const
{
return interiorAngle( mNumberSides );
}
double QgsRegularPolygon::centralAngle() const
{
return centralAngle( mNumberSides );
}

View File

@ -0,0 +1,217 @@
/***************************************************************************
qgsregularpolygon.h
--------------
begin : May 2017
copyright : (C) 2017 by Loîc Bartoletti
email : lbartoletti at tuxfamily dot org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSREGULARPOLYGON_H
#define QGSREGULARPOLYGON_H
#include <QString>
#include "qgis_core.h"
#include "qgspointv2.h"
#include "qgspolygon.h"
#include "qgslinestring.h"
#include "qgscircle.h"
#include "qgstriangle.h"
/** \ingroup core
* \class QgsRegularPolygon
* \brief Regular Polygon geometry type.
*
* A regular polygon is a polygon that is equiangular (all angles are equal in measure) and equilateral (all sides have the same length).
* The regular polygon is defined by a center point with a number of sides/vertices, a radius and the first vertex.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsRegularPolygon
{
public:
/**
* A regular polygon can be constructed inscribed in a circle or circumscribed about a circle.
*
*/
enum ConstructionOption
{
InscribedCircle, //<! Inscribed in a circle (the radius is the distance between the center and vertices)
CircumscribedCircle //<! Circumscribed about a circle (the radius is the distance from the center to the midpoints of the sides)
};
QgsRegularPolygon();
/** Constructs a regular polygon by \a center and parameters for the first vertex. An empty regular polygon is returned if \a numberSides < 3 or \a ConstructionOption isn't valid.
* \param center The center of the regular polygon.
* \param radius Distance from the center and the first vertex or sides (see \a ConstructionOption).
* \param azimuth Angle in degrees started from the North to the first vertex.
* \param numberSides Number of sides of the regular polygon.
* \param circle Option to create the polygon. \see ConstructionOption
*/
QgsRegularPolygon( const QgsPointV2 &center, const double radius, const double azimuth, const int numberSides, const ConstructionOption circle );
/** Constructs a regular polygon by \a center and another point.
* \param center The center of the regular polygon.
* \param pt1 The first vertex if the polygon is inscribed in circle or the midpoint of a side if the polygon is circumscribed about circle.
* \param numberSides Number of sides of the regular polygon.
* \param circle Option to create the polygon inscribed in circle (the radius is the distance between the center and vertices) or circumscribed about circle (the radius is the distance from the center to the midpoints of the sides).
*/
QgsRegularPolygon( const QgsPointV2 &center, const QgsPointV2 &pt1, const int numberSides, const ConstructionOption circle );
/** Constructs a regular polygon by two points of the first side.
* \param pt1 The first vertex of the first side, also first vertex of the regular polygon.
* \param pt2 The second vertex of the first side.
* \param numberSides Number of sides of the regular polygon.
*/
QgsRegularPolygon( const QgsPointV2 &pt1, const QgsPointV2 &pt2, const int numberSides );
bool operator ==( const QgsRegularPolygon &rp ) const;
bool operator !=( const QgsRegularPolygon &rp ) const;
//! A regular polygon is empty if radius equal to 0 or number of sides < 3
bool isEmpty() const;
/** Returns the center point of the regular polygon.
* \see setCenter()
*/
QgsPointV2 center() const { return mCenter; }
/** Returns the radius.
* This is also the radius of the circumscribing circle.
* \see apothem()
* \see setRadius()
*/
double radius() const { return mRadius; }
/** Returns the first vertex (corner) of the regular polygon.
* \see setFirstVertex()
*/
QgsPointV2 firstVertex() const { return mFirstVertex; }
/** Returns the apothem of the regular polygon.
* The apothem is the radius of the inscribed circle.
* \see radius()
*/
double apothem() const { return mRadius * cos( M_PI / mNumberSides ); }
/** Returns the number of sides of the regular polygon.
* \see setNumberSides()
*/
int numberSides() const { return mNumberSides; }
/** Sets the center point.
* Radius is unchanged. The first vertex is reprojected from the new center.
* \see center()
*/
void setCenter( const QgsPointV2 &center );
/** Sets the radius.
* Center is unchanged. The first vertex is reprojected from the center with the new radius.
* \see radius()
*/
void setRadius( const double radius );
/** Sets the first vertex.
* Radius is unchanged. The center is reprojected from the new first vertex.
* \see firstVertex()
*/
void setFirstVertex( const QgsPointV2 &firstVertex );
/** Sets the number of sides.
* If numberSides < 3, the number of sides is unchanged.
* \see numberSides()
*/
void setNumberSides( const int numberSides );
/** Returns a list including the vertices of the regular polygon.
*/
QgsPointSequence points( ) const;
/** Returns as a polygon.
*/
QgsPolygonV2 *toPolygon( ) const SIP_FACTORY;
/** Returns as a linestring.
*/
QgsLineString *toLineString( ) const SIP_FACTORY;
/** Returns as a triangle.
* An empty triangle is returned if the regular polygon is empty or if the number of sides is different from 3.
*/
QgsTriangle toTriangle( ) const;
/** Returns a triangulation (vertices from sides to the center) of the regular polygon.
* An empty list is returned if the regular polygon is empty.
*/
QList<QgsTriangle> triangulate( ) const;
/** Returns the inscribed circle
*/
QgsCircle inscribedCircle( ) const;
/** Returns the circumscribed circle
*/
QgsCircle circumscribedCircle( ) const;
/**
* Returns a string representation of the regular polygon.
* Members will be truncated to the specified precision.
*/
QString toString( int pointPrecision = 17, int radiusPrecision = 17, int anglePrecision = 2 ) const;
/** Returns the measure of the interior angles in degrees.
*/
double interiorAngle( ) const;
/** Returns the measure of the central angle (the angle subtended at the center of the polygon by one of its sides) in degrees.
*/
double centralAngle( ) const;
/** Returns the area.
* Returns 0 if the regular polygon is empty.
*/
double area( ) const;
/** Returns the perimeter.
* Returns 0 if the regular polygon is empty.
*/
double perimeter( ) const;
/** Returns the length of a side.
* Returns 0 if the regular polygon is empty.
*/
double length( ) const;
private:
QgsPointV2 mCenter;
QgsPointV2 mFirstVertex;
unsigned int mNumberSides;
double mRadius;
/** Convenient method to convert an apothem to a radius.
*/
double apothemToRadius( const double apothem, const unsigned int numberSides ) const;
/** Convenient method for interiorAngle used by constructors.
*/
double interiorAngle( const unsigned int nbSides ) const;
/** Convenient method for centralAngle used by constructors.
*/
double centralAngle( const unsigned int nbSides ) const;
};
#endif // QGSREGULARPOLYGON_H

View File

@ -85,6 +85,28 @@ QgsTriangle::QgsTriangle( const QPointF p1, const QPointF p2, const QPointF p3 )
setExteriorRing( ext );
}
bool QgsTriangle::operator==( const QgsTriangle &other ) const
{
if ( isEmpty() && other.isEmpty() )
{
return true;
}
else if ( isEmpty() || other.isEmpty() )
{
return false;
}
return ( ( vertexAt( 0 ) == other.vertexAt( 0 ) ) &&
( vertexAt( 1 ) == other.vertexAt( 1 ) ) &&
( vertexAt( 2 ) == other.vertexAt( 2 ) )
);
}
bool QgsTriangle::operator!=( const QgsTriangle &other ) const
{
return !operator==( other );
}
void QgsTriangle::clear()
{
QgsCurvePolygon::clear();

View File

@ -58,8 +58,8 @@ class CORE_EXPORT QgsTriangle : public QgsPolygonV2
*/
explicit QgsTriangle( const QPointF p1, const QPointF p2, const QPointF p3 );
// inherited: bool operator==( const QgsTriangle& other ) const;
// inherited: bool operator!=( const QgsTriangle& other ) const;
bool operator==( const QgsTriangle &other ) const;
bool operator!=( const QgsTriangle &other ) const;
virtual QString geometryType() const override { return QStringLiteral( "Triangle" ); }
virtual QgsTriangle *clone() const override SIP_FACTORY;

View File

@ -48,6 +48,7 @@
#include "qgstriangle.h"
#include "qgscircle.h"
#include "qgsellipse.h"
#include "qgsregularpolygon.h"
#include "qgsmultipoint.h"
#include "qgsmultilinestring.h"
#include "qgscurvepolygon.h"
@ -2270,6 +2271,45 @@ static QVariant fcnMakeEllipse( const QVariantList &values, const QgsExpressionC
return QVariant::fromValue( QgsGeometry( elp.toPolygon( segment ) ) );
}
static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
{
QgsGeometry pt1 = getGeometry( values.at( 0 ), parent );
if ( pt1.isNull() )
return QVariant();
if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
return QVariant();
QgsGeometry pt2 = getGeometry( values.at( 1 ), parent );
if ( pt2.isNull() )
return QVariant();
if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
return QVariant();
unsigned int nbEdges = static_cast<unsigned int>( getIntValue( values.at( 2 ), parent ) );
if ( nbEdges < 3 )
{
parent->setEvalErrorString( QObject::tr( "Number of edges/sides must be greater than 2" ) );
return QVariant();
}
QgsRegularPolygon::ConstructionOption option = static_cast< QgsRegularPolygon::ConstructionOption >( getIntValue( values.at( 3 ), parent ) );
if ( ( option < QgsRegularPolygon::InscribedCircle ) || ( option > QgsRegularPolygon::CircumscribedCircle ) )
{
parent->setEvalErrorString( QObject::tr( "Option can be 0 (inscribed) or 1 (circumscribed)" ) );
return QVariant();
}
QgsPointV2 *center = static_cast< QgsPointV2 * >( pt1.geometry() );
QgsPointV2 *corner = static_cast< QgsPointV2 * >( pt2.geometry() );
QgsRegularPolygon rp = QgsRegularPolygon( *center, *corner, nbEdges, option );
return QVariant::fromValue( QgsGeometry( rp.toPolygon( ) ) );
}
static QVariant pointAt( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent ) // helper function
{
FEAT_FROM_CONTEXT( context, f );
@ -4132,11 +4172,17 @@ const QList<QgsExpression::Function *> &QgsExpression::Functions()
fcnMakeCircle, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "make_ellipse" ), ParameterList()
<< Parameter( QStringLiteral( "geometry" ) )
<< Parameter( QStringLiteral( "semi-major axis" ) )
<< Parameter( QStringLiteral( "semi-minor axis" ) )
<< Parameter( QStringLiteral( "semi_major_axis" ) )
<< Parameter( QStringLiteral( "semi_minor_axis" ) )
<< Parameter( QStringLiteral( "azimuth" ) )
<< Parameter( QStringLiteral( "segments" ), true, 36 ),
fcnMakeEllipse, QStringLiteral( "GeometryGroup" ) );
fcnMakeEllipse, QStringLiteral( "GeometryGroup" ) )
<< new StaticFunction( QStringLiteral( "make_regular_polygon" ), ParameterList()
<< Parameter( QStringLiteral( "geometry" ) )
<< Parameter( QStringLiteral( "geometry" ) )
<< Parameter( QStringLiteral( "number_sides" ) )
<< Parameter( QStringLiteral( "circle" ), true, 0 ),
fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) );
StaticFunction *xAtFunc = new StaticFunction( QStringLiteral( "$x_at" ), 1, fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) );
xAtFunc->setIsStatic( false );

View File

@ -784,6 +784,15 @@ class TestQgsExpression: public QObject
QTest::newRow( "make_ellipse null" ) << "make_ellipse(NULL, 5, 2, 0)" << false << QVariant();
QTest::newRow( "make_ellipse bad" ) << "make_ellipse(make_line(make_point(1,2), make_point(3,4)), 5, 2, 0)" << false << QVariant();
QTest::newRow( "make_ellipse" ) << "geom_to_wkt(make_ellipse(make_point(10,10), 5, 2, 90, 4))" << false << QVariant( "Polygon ((15 10, 10 8, 5 10, 10 12, 15 10))" );
QTest::newRow( "make_regular_polygon not geom (center)" ) << "make_regular_polygon('a', make_point(0,5), 5)" << true << QVariant();
QTest::newRow( "make_regular_polygon not geom (vertice)" ) << "make_regular_polygon(make_point(0,0), 'a', 5)" << true << QVariant();
QTest::newRow( "make_regular_polygon bad (center)" ) << "make_regular_polygon(make_line(make_point(1,2), make_point(3,4)), make_point(0,5), 5)" << false << QVariant();
QTest::newRow( "make_regular_polygon bad (vertice)" ) << "make_regular_polygon(make_point(0,0), make_line(make_point(1,2), make_point(3,4)), 5)" << false << QVariant();
QTest::newRow( "make_regular_polygon bad (numEdges < 3)" ) << "make_regular_polygon(make_point(0,0), make_point(0,5), 2)" << true << QVariant();
QTest::newRow( "make_regular_polygon bad (invalid option)" ) << "make_regular_polygon(make_point(0,0), make_point(0,5), 5, 5)" << true << QVariant();
QTest::newRow( "make_regular_polygon bad (numEdges < 3)" ) << "make_regular_polygon(make_point(0,0), make_point(0,5), 2)" << true << QVariant();
QTest::newRow( "make_regular_polygon" ) << "geom_to_wkt(make_regular_polygon(make_point(0,0), make_point(0,5), 5), 2)" << false << QVariant( "Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))" );
QTest::newRow( "make_regular_polygon" ) << "geom_to_wkt(make_regular_polygon(make_point(0,0), project(make_point(0,0), 4.0451, radians(36)), 5, 1), 2)" << false << QVariant( "Polygon ((0 5, 4.76 1.55, 2.94 -4.05, -2.94 -4.05, -4.76 1.55, 0 5))" );
QTest::newRow( "x point" ) << "x(make_point(2.2,4.4))" << false << QVariant( 2.2 );
QTest::newRow( "y point" ) << "y(make_point(2.2,4.4))" << false << QVariant( 4.4 );
QTest::newRow( "z point" ) << "z(make_point(2.2,4.4,6.6))" << false << QVariant( 6.6 );

View File

@ -37,6 +37,7 @@
#include "qgstriangle.h"
#include "qgscircle.h"
#include "qgsellipse.h"
#include "qgsregularpolygon.h"
#include "qgsmultipoint.h"
#include "qgsmultilinestring.h"
#include "qgsmultipolygon.h"
@ -76,6 +77,7 @@ class TestQgsGeometry : public QObject
void triangle();
void circle();
void ellipse();
void regularPolygon();
void compoundCurve(); //test QgsCompoundCurve
void multiPoint();
void multiLineString();
@ -3492,6 +3494,14 @@ void TestQgsGeometry::triangle()
QVERIFY( t3.exteriorRing() );
QVERIFY( !t3.interiorRing( 0 ) );
// equality
QVERIFY( QgsTriangle() == QgsTriangle( ) ); // empty
QVERIFY( QgsTriangle() == QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 0, 5 ), QgsPointV2( 0, 10 ) ) ); // empty
QVERIFY( QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 0, 5 ), QgsPointV2( 0, 10 ) ) == QgsTriangle() ); // empty
QVERIFY( QgsTriangle() != QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 5, 5 ), QgsPointV2( 0, 10 ) ) );
QVERIFY( QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 5, 5 ), QgsPointV2( 0, 10 ) ) != QgsTriangle() );
QVERIFY( QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 5, 5 ), QgsPointV2( 0, 10 ) ) != QgsTriangle( QgsPointV2( 0, 10 ), QgsPointV2( 5, 5 ), QgsPointV2( 0, 0 ) ) );
// clone
QgsTriangle *t4 = t3.clone();
QCOMPARE( t3, *t4 );
@ -3918,7 +3928,7 @@ void TestQgsGeometry::ellipse()
//test conversion
// points
QgsPointSequence pts;
QgsEllipse( QgsPointV2( 0, 0 ), 5, 2, 0 ).points( pts, 4 );
pts = QgsEllipse( QgsPointV2( 0, 0 ), 5, 2, 0 ).points( 4 );
q = QgsEllipse( QgsPointV2( 0, 0 ), 5, 2, 0 ).quadrant();
QCOMPARE( pts.length(), 4 );
QGSCOMPARENEARPOINT( q.at( 0 ), pts.at( 0 ), 2 );
@ -4204,6 +4214,169 @@ void TestQgsGeometry::circle()
QGSCOMPARENEAR( 31.4159, QgsCircle( QgsPointV2( 0, 0 ), 5 ).perimeter(), 0.0001 );
}
void TestQgsGeometry::regularPolygon()
{
// constructors
QgsRegularPolygon rp1 = QgsRegularPolygon();
QCOMPARE( rp1.center(), QgsPointV2() );
QCOMPARE( rp1.firstVertex(), QgsPointV2() );
QCOMPARE( rp1.numberSides(), 0 );
QCOMPARE( rp1.radius(), 0.0 );
QVERIFY( rp1.isEmpty() );
QgsRegularPolygon rp2;
QgsRegularPolygon( QgsPointV2(), 5, 0, 2, QgsRegularPolygon::InscribedCircle );
QVERIFY( rp2.isEmpty() );
QgsRegularPolygon( QgsPointV2(), 5, 0, 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
QVERIFY( rp2.isEmpty() );
rp2 = QgsRegularPolygon( QgsPointV2(), 5, 0, 5, QgsRegularPolygon::InscribedCircle );
QVERIFY( !rp2.isEmpty() );
QCOMPARE( rp2.center(), QgsPointV2() );
QCOMPARE( rp2.firstVertex(), QgsPointV2( 0, 5 ) );
QCOMPARE( rp2.numberSides(), 5 );
QCOMPARE( rp2.radius(), 5.0 );
QGSCOMPARENEAR( rp2.apothem(), 4.0451, 10E-4 );
QVERIFY( rp2 == QgsRegularPolygon( QgsPointV2(), -5, 0, 5, QgsRegularPolygon::InscribedCircle ) );
QgsRegularPolygon rp3 = QgsRegularPolygon( QgsPointV2(), rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle );
QVERIFY( rp2 == rp3 );
QVERIFY( rp2 == QgsRegularPolygon( QgsPointV2(), -rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
QVERIFY( rp1 != rp3 );
QVERIFY( rp1 != QgsRegularPolygon( QgsPointV2( 5, 5 ), rp2.apothem(), 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
QVERIFY( rp1 != QgsRegularPolygon( QgsPointV2( 0, 0 ), 5, 36.0, 5, QgsRegularPolygon::CircumscribedCircle ) );
QVERIFY( rp1 != QgsRegularPolygon( QgsPointV2( 0, 0 ), 5, 36.0, 5, QgsRegularPolygon::InscribedCircle ) );
QgsRegularPolygon rp4 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 5 ), 2, QgsRegularPolygon::InscribedCircle );
QVERIFY( rp4.isEmpty() );
rp4 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 5 ), 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
QVERIFY( rp4.isEmpty() );
rp4 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 5 ), 5, QgsRegularPolygon::InscribedCircle );
QVERIFY( rp4 == rp2 );
QgsRegularPolygon rp5 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 0 ).project( rp2.apothem(), 36.0 ), 2, QgsRegularPolygon::CircumscribedCircle );
QVERIFY( rp5.isEmpty() );
rp5 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 0 ).project( rp2.apothem(), 36.0 ), 5, static_cast< QgsRegularPolygon::ConstructionOption >( 4 ) );
QVERIFY( rp5.isEmpty() );
rp5 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 0 ).project( rp2.apothem(), 36.0 ), 5, QgsRegularPolygon::CircumscribedCircle );
QVERIFY( rp5 == rp2 );
QgsRegularPolygon rp6 = QgsRegularPolygon( QgsPointV2( 0, 5 ), QgsPointV2( 0, 0 ).project( 5.0, 72 ), 5 );
QVERIFY( rp6 == rp2 );
// setters and getters
QgsRegularPolygon rp7 = QgsRegularPolygon();
rp7.setCenter( QgsPointV2( 5, 5 ) );
QVERIFY( rp7.isEmpty() );
QCOMPARE( rp7.center(), QgsPointV2( 5, 5 ) );
rp7.setNumberSides( 2 );
QVERIFY( rp7.isEmpty() );
QCOMPARE( rp7.numberSides(), 0 );
rp7.setNumberSides( 5 );
QVERIFY( rp7.isEmpty() );
QCOMPARE( rp7.numberSides(), 5 );
rp7.setNumberSides( 2 );
QVERIFY( rp7.isEmpty() );
QCOMPARE( rp7.numberSides(), 5 );
rp7.setNumberSides( 3 );
QVERIFY( rp7.isEmpty() );
QCOMPARE( rp7.numberSides(), 3 );
rp7.setRadius( -6 );
QVERIFY( !rp7.isEmpty() );
QCOMPARE( rp7.radius(), 6.0 );
QCOMPARE( rp7.firstVertex(), rp7.center().project( 6, 0 ) );
rp7.setFirstVertex( QgsPointV2( 4, 4 ) );
QCOMPARE( rp7.firstVertex(), QgsPointV2( 4, 4 ) );
QCOMPARE( rp7.radius(), rp7.center().distance3D( QgsPointV2( 4, 4 ) ) );
rp7 = QgsRegularPolygon( QgsPointV2(), QgsPointV2( 0, 5 ), 5, QgsRegularPolygon::InscribedCircle );
rp7.setCenter( QgsPointV2( 5, 5 ) );
QCOMPARE( rp7.radius(), 5.0 );
QCOMPARE( rp7.firstVertex(), QgsPointV2( 5, 10 ) );
rp7.setNumberSides( 3 );
QCOMPARE( rp7.radius(), 5.0 );
QCOMPARE( rp7.firstVertex(), QgsPointV2( 5, 10 ) );
rp7.setNumberSides( 2 );
QCOMPARE( rp7.radius(), 5.0 );
QCOMPARE( rp7.firstVertex(), QgsPointV2( 5, 10 ) );
// measures
QGSCOMPARENEAR( rp1.length(), 0.0, 10e-4 );
QGSCOMPARENEAR( rp1.area(), 0.0, 10e-4 );
QGSCOMPARENEAR( rp1.perimeter(), 0.0, 10e-4 );
QGSCOMPARENEAR( rp2.length(), 5.8779, 10e-4 );
QGSCOMPARENEAR( rp2.area(), 59.4410, 10e-4 );
QGSCOMPARENEAR( rp2.perimeter(), 29.3893, 10e-4 );
QCOMPARE( rp2.interiorAngle(), 108.0 );
QCOMPARE( rp2.centralAngle(), 72.0 );
QgsRegularPolygon rp8 = QgsRegularPolygon( QgsPointV2( 0, 0 ), QgsPointV2( 5, 0 ), 5 );
QGSCOMPARENEAR( rp8.area(), 43.0119, 10e-4 );
QCOMPARE( rp8.perimeter(), 25.0 );
QCOMPARE( rp8.length(), 5.0 );
QCOMPARE( rp8.interiorAngle(), 108.0 );
QCOMPARE( rp8.centralAngle(), 72.0 );
rp8.setNumberSides( 4 );
QCOMPARE( rp8.interiorAngle(), 90.0 );
QCOMPARE( rp8.centralAngle(), 90.0 );
rp8.setNumberSides( 3 );
QCOMPARE( rp8.interiorAngle(), 60.0 );
QCOMPARE( rp8.centralAngle(), 120.0 );
//test conversions
// circle
QVERIFY( QgsCircle( QgsPointV2( 0, 0 ), 5 ) == rp2.circumscribedCircle() );
QVERIFY( rp2.inscribedCircle() == QgsRegularPolygon( QgsPointV2( 0, 0 ), rp2.apothem(), 36.0, 5, QgsRegularPolygon::InscribedCircle ).circumscribedCircle() );
// triangle
QCOMPARE( QgsTriangle(), rp2.toTriangle() );
QCOMPARE( QgsTriangle(), QgsRegularPolygon().toTriangle() );
QgsRegularPolygon rp9 = QgsRegularPolygon( QgsPointV2( 0, 0 ), 5, 0, 3, QgsRegularPolygon::InscribedCircle );
QVERIFY( QgsCircle( QgsPointV2( 0, 0 ), 5 ) == rp9.toTriangle().circumscribedCircle() );
QgsRegularPolygon rp10 = QgsRegularPolygon( QgsPointV2( 0, 0 ), QgsPointV2( 0, 4 ), 4 );
QList<QgsTriangle> rp10_tri = rp10.triangulate();
QCOMPARE( rp10_tri.length(), ( int )rp10.numberSides() );
QVERIFY( rp10_tri.at( 0 ) == QgsTriangle( QgsPointV2( 0, 0 ), QgsPointV2( 0, 4 ), rp10.center() ) );
QVERIFY( rp10_tri.at( 1 ) == QgsTriangle( QgsPointV2( 0, 4 ), QgsPointV2( 4, 4 ), rp10.center() ) );
QVERIFY( rp10_tri.at( 2 ) == QgsTriangle( QgsPointV2( 4, 4 ), QgsPointV2( 4, 0 ), rp10.center() ) );
QVERIFY( rp10_tri.at( 3 ) == QgsTriangle( QgsPointV2( 4, 0 ), QgsPointV2( 0, 0 ), rp10.center() ) );
// polygon
QgsPointSequence ptsPol;
std::unique_ptr< QgsPolygonV2 > pol( new QgsPolygonV2() );
pol.reset( rp10.toPolygon( ) );
QCOMPARE( pol->numInteriorRings(), 0 );
QCOMPARE( pol->exteriorRing()->numPoints(), 5 );
pol->exteriorRing()->points( ptsPol );
QCOMPARE( ptsPol.length(), 5 );
QVERIFY( ptsPol.at( 0 ) == QgsPointV2( 0, 0 ) );
QVERIFY( ptsPol.at( 1 ) == QgsPointV2( 0, 4 ) );
QVERIFY( ptsPol.at( 2 ) == QgsPointV2( 4, 4 ) );
QVERIFY( ptsPol.at( 3 ) == QgsPointV2( 4, 0 ) );
QVERIFY( ptsPol.at( 4 ) == QgsPointV2( 0, 0 ) );
ptsPol.pop_back();
std::unique_ptr< QgsLineString > l( new QgsLineString() );
l.reset( rp10.toLineString( ) );
QCOMPARE( l->numPoints(), 4 );
QgsPointSequence pts_l;
l->points( pts_l );
QCOMPARE( ptsPol, pts_l );
//test toString
QCOMPARE( rp1.toString(), QString( "Empty" ) );
QCOMPARE( rp2.toString(), QString( "RegularPolygon (Center: Point (0 0), First Vertex: Point (0 5), Radius: 5, Azimuth: 0)" ) );
}
void TestQgsGeometry::compoundCurve()
{
//test that area of a compound curve ring is equal to a closed linestring with the same vertices