Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add methods to QgsGeometry to convert to/from QPointF and QPolygonF
  • Loading branch information
nyalldawson committed Nov 6, 2014
1 parent b5c9df0 commit 878230a
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 3 deletions.
27 changes: 27 additions & 0 deletions python/core/qgsgeometry.sip
Expand Up @@ -55,6 +55,20 @@ class QgsGeometry
static QgsGeometry* fromMultiPolygon( const QgsMultiPolygon& multipoly ) /Factory/;
/** construct geometry from a rectangle */
static QgsGeometry* fromRect( const QgsRectangle& rect ) /Factory/;
/**Construct geometry from a QPointF
* @param point source QPointF
* @note added in QGIS 2.7
*/
static QgsGeometry* fromQPointF( const QPointF& point ) /Factory/;

/**Construct geometry from a QPolygonF. If the polygon is closed than
* the resultant geometry will be a polygon, if it is open than the
* geometry will be a polyline.
* @param polygon source QPolygonF
* @note added in QGIS 2.7
*/
static QgsGeometry* fromQPolygonF( const QPolygonF& polygon ) /Factory/;

/**
Set the geometry, feeding in a geometry in GEOS format.
This class will take ownership of the buffer.
Expand Down Expand Up @@ -416,6 +430,19 @@ class QgsGeometry
@note added in version 1.1 */
QList<QgsGeometry*> asGeometryCollection() const /Factory/;

/**Return contents of the geometry as a QPointF if wkbType is WKBPoint,
* otherwise returns a null QPointF.
* @note added in QGIS 2.7
*/
QPointF asQPointF() const;

/**Return contents of the geometry as a QPolygonF. If geometry is a linestring,
* then the result will be an open QPolygonF. If the geometry is a polygon,
* then the result will be a closed QPolygonF of the geometry's exterior ring.
* @note added in QGIS 2.7
*/
QPolygonF asQPolygonF() const;

/** delete a ring in polygon or multipolygon.
Ring 0 is outer ring and can't be deleted.
@return true on success
Expand Down
80 changes: 77 additions & 3 deletions src/core/qgsgeometry.cpp
Expand Up @@ -190,14 +190,19 @@ static unsigned int getNumGeosPoints( const GEOSGeometry *geom )
return n;
}

static GEOSGeometry *createGeosPoint( const QgsPoint &point )
static GEOSGeometry *createGeosPoint( const double x, const double y )
{
GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosinit.ctxt, 1, 2 );
GEOSCoordSeq_setX_r( geosinit.ctxt, coord, 0, point.x() );
GEOSCoordSeq_setY_r( geosinit.ctxt, coord, 0, point.y() );
GEOSCoordSeq_setX_r( geosinit.ctxt, coord, 0, x );
GEOSCoordSeq_setY_r( geosinit.ctxt, coord, 0, y );
return GEOSGeom_createPoint_r( geosinit.ctxt, coord );
}

static GEOSGeometry *createGeosPoint( const QgsPoint &point )
{
return createGeosPoint( point.x(), point.y() );
}

static GEOSCoordSequence *createGeosCoordSequence( const QgsPolyline& points )
{
GEOSCoordSequence *coord = 0;
Expand Down Expand Up @@ -509,6 +514,40 @@ QgsGeometry* QgsGeometry::fromRect( const QgsRectangle& rect )
return fromPolygon( polygon );
}

QgsGeometry *QgsGeometry::fromQPointF( const QPointF &point )
{
return fromGeosGeom( createGeosPoint( point.x(), point.y() ) );
}

QgsGeometry *QgsGeometry::fromQPolygonF( const QPolygonF &polygon )
{
if ( polygon.isClosed() )
{
return QgsGeometry::fromPolygon( createPolygonFromQPolygonF( polygon ) );
}
else
{
return QgsGeometry::fromPolyline( createPolylineFromQPolygonF( polygon ) );
}
}

QgsPolygon QgsGeometry::createPolygonFromQPolygonF( const QPolygonF &polygon )
{
QgsPolygon result;
result << createPolylineFromQPolygonF( polygon );
return result;
}

QgsPolyline QgsGeometry::createPolylineFromQPolygonF( const QPolygonF &polygon )
{
QgsPolyline result;
QPolygonF::const_iterator it = polygon.constBegin();
for ( ; it != polygon.constEnd(); ++it )
{
result.append( QgsPoint( *it ) );
}
return result;
}

QgsGeometry & QgsGeometry::operator=( QgsGeometry const & rhs )
{
Expand Down Expand Up @@ -5901,6 +5940,41 @@ QList<QgsGeometry*> QgsGeometry::asGeometryCollection() const
return geomCollection;
}

QPointF QgsGeometry::asQPointF() const
{
QgsPoint point = asPoint();
return point.toQPointF();
}

QPolygonF QgsGeometry::asQPolygonF() const
{
QPolygonF result;
QgsPolyline polyline;
QGis::WkbType type = wkbType();
if ( type == QGis::WKBLineString || type == QGis::WKBLineString25D )
{
polyline = asPolyline();
}
else if ( type == QGis::WKBPolygon || type == QGis::WKBPolygon25D )
{
QgsPolygon polygon = asPolygon();
if ( polygon.size() < 1 )
return result;
polyline = polygon.at( 0 );
}
else
{
return result;
}

QgsPolyline::const_iterator lineIt = polyline.constBegin();
for ( ; lineIt != polyline.constEnd(); ++lineIt )
{
result << lineIt->toQPointF();
}
return result;
}

bool QgsGeometry::deleteRing( int ringNum, int partNum )
{
if ( ringNum <= 0 || partNum < 0 )
Expand Down
30 changes: 30 additions & 0 deletions src/core/qgsgeometry.h
Expand Up @@ -106,6 +106,20 @@ class CORE_EXPORT QgsGeometry
static QgsGeometry* fromMultiPolygon( const QgsMultiPolygon& multipoly );
/** construct geometry from a rectangle */
static QgsGeometry* fromRect( const QgsRectangle& rect );
/**Construct geometry from a QPointF
* @param point source QPointF
* @note added in QGIS 2.7
*/
static QgsGeometry* fromQPointF( const QPointF& point );

/**Construct geometry from a QPolygonF. If the polygon is closed than
* the resultant geometry will be a polygon, if it is open than the
* geometry will be a polyline.
* @param polygon source QPolygonF
* @note added in QGIS 2.7
*/
static QgsGeometry* fromQPolygonF( const QPolygonF& polygon );

/**
Set the geometry, feeding in a geometry in GEOS format.
This class will take ownership of the buffer.
Expand Down Expand Up @@ -436,6 +450,19 @@ class CORE_EXPORT QgsGeometry
/** return contents of the geometry as a list of geometries */
QList<QgsGeometry*> asGeometryCollection() const;

/**Return contents of the geometry as a QPointF if wkbType is WKBPoint,
* otherwise returns a null QPointF.
* @note added in QGIS 2.7
*/
QPointF asQPointF() const;

/**Return contents of the geometry as a QPolygonF. If geometry is a linestring,
* then the result will be an open QPolygonF. If the geometry is a polygon,
* then the result will be a closed QPolygonF of the geometry's exterior ring.
* @note added in QGIS 2.7
*/
QPolygonF asQPolygonF() const;

/** delete a ring in polygon or multipolygon.
Ring 0 is outer ring and can't be deleted.
@return true on success
Expand Down Expand Up @@ -632,6 +659,9 @@ class CORE_EXPORT QgsGeometry
QgsGeometry* convertToLine( bool destMultipart );
/** try to convert the geometry to a polygon */
QgsGeometry* convertToPolygon( bool destMultipart );

static QgsPolyline createPolylineFromQPolygonF( const QPolygonF &polygon );
static QgsPolygon createPolygonFromQPolygonF( const QPolygonF &polygon );
}; // class QgsGeometry

Q_DECLARE_METATYPE( QgsGeometry );
Expand Down
107 changes: 107 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -47,6 +47,12 @@ class TestQgsGeometry: public QObject
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.

void fromQgsPoint();
void fromQPoint();
void fromQPolygonF();
void asQPointF();
void asQPolygonF();

void simplifyCheck1();
void intersectionCheck1();
void intersectionCheck2();
Expand Down Expand Up @@ -178,6 +184,107 @@ void TestQgsGeometry::cleanup()
delete mpPainter;
}

void TestQgsGeometry::fromQgsPoint()
{
QgsPoint point( 1.0, 2.0 );
QgsGeometry* result = QgsGeometry::fromPoint( point );
QCOMPARE( result->wkbType(), QGis::WKBPoint );
QgsPoint resultPoint = result->asPoint();
QCOMPARE( resultPoint, point );
delete result;
}

void TestQgsGeometry::fromQPoint()
{
QPointF point( 1.0, 2.0 );
QgsGeometry* result = QgsGeometry::fromQPointF( point );
QCOMPARE( result->wkbType(), QGis::WKBPoint );
QgsPoint resultPoint = result->asPoint();
QCOMPARE( resultPoint.x(), 1.0 );
QCOMPARE( resultPoint.y(), 2.0 );
delete result;
}

void TestQgsGeometry::fromQPolygonF()
{
//test with a polyline
QPolygonF polyline;
polyline << QPointF( 1.0, 2.0 ) << QPointF( 4.0, 6.0 ) << QPointF( 4.0, 3.0 ) << QPointF( 2.0, 2.0 );
QgsGeometry* result = QgsGeometry::fromQPolygonF( polyline );
QCOMPARE( result->wkbType(), QGis::WKBLineString );
QgsPolyline resultLine = result->asPolyline();
QCOMPARE( resultLine.size(), 4 );
QCOMPARE( resultLine.at( 0 ), QgsPoint( 1.0, 2.0 ) );
QCOMPARE( resultLine.at( 1 ), QgsPoint( 4.0, 6.0 ) );
QCOMPARE( resultLine.at( 2 ), QgsPoint( 4.0, 3.0 ) );
QCOMPARE( resultLine.at( 3 ), QgsPoint( 2.0, 2.0 ) );
delete result;

//test with a closed polygon
QPolygonF polygon;
polygon << QPointF( 1.0, 2.0 ) << QPointF( 4.0, 6.0 ) << QPointF( 4.0, 3.0 ) << QPointF( 2.0, 2.0 ) << QPointF( 1.0, 2.0 );
QgsGeometry* result2 = QgsGeometry::fromQPolygonF( polygon );
QCOMPARE( result2->wkbType(), QGis::WKBPolygon );
QgsPolygon resultPolygon = result2->asPolygon();
QCOMPARE( resultPolygon.size(), 1 );
QCOMPARE( resultPolygon.at( 0 ).at( 0 ), QgsPoint( 1.0, 2.0 ) );
QCOMPARE( resultPolygon.at( 0 ).at( 1 ), QgsPoint( 4.0, 6.0 ) );
QCOMPARE( resultPolygon.at( 0 ).at( 2 ), QgsPoint( 4.0, 3.0 ) );
QCOMPARE( resultPolygon.at( 0 ).at( 3 ), QgsPoint( 2.0, 2.0 ) );
QCOMPARE( resultPolygon.at( 0 ).at( 4 ), QgsPoint( 1.0, 2.0 ) );
delete result2;
}

void TestQgsGeometry::asQPointF()
{
QPointF point( 1.0, 2.0 );
QgsGeometry* geom = QgsGeometry::fromQPointF( point );
QPointF resultPoint = geom->asQPointF();
QCOMPARE( resultPoint, point );
delete geom;

//non point geom
QPointF badPoint = mpPolygonGeometryA->asQPointF();
QVERIFY( badPoint.isNull() );
}

void TestQgsGeometry::asQPolygonF()
{
//test polygon
QPolygonF fromPoly = mpPolygonGeometryA->asQPolygonF();
QVERIFY( fromPoly.isClosed() );
QCOMPARE( fromPoly.size(), 5 );
QCOMPARE( fromPoly.at( 0 ).x(), mPoint1.x() );
QCOMPARE( fromPoly.at( 0 ).y(), mPoint1.y() );
QCOMPARE( fromPoly.at( 1 ).x(), mPoint2.x() );
QCOMPARE( fromPoly.at( 1 ).y(), mPoint2.y() );
QCOMPARE( fromPoly.at( 2 ).x(), mPoint3.x() );
QCOMPARE( fromPoly.at( 2 ).y(), mPoint3.y() );
QCOMPARE( fromPoly.at( 3 ).x(), mPoint4.x() );
QCOMPARE( fromPoly.at( 3 ).y(), mPoint4.y() );
QCOMPARE( fromPoly.at( 4 ).x(), mPoint1.x() );
QCOMPARE( fromPoly.at( 4 ).y(), mPoint1.y() );
//test polyline
QgsPolyline testline;
testline << mPoint1 << mPoint2 << mPoint3;
QgsGeometry* lineGeom = QgsGeometry::fromPolyline( testline );
QPolygonF fromLine = lineGeom->asQPolygonF();
QVERIFY( !fromLine.isClosed() );
QCOMPARE( fromLine.size(), 3 );
QCOMPARE( fromLine.at( 0 ).x(), mPoint1.x() );
QCOMPARE( fromLine.at( 0 ).y(), mPoint1.y() );
QCOMPARE( fromLine.at( 1 ).x(), mPoint2.x() );
QCOMPARE( fromLine.at( 1 ).y(), mPoint2.y() );
QCOMPARE( fromLine.at( 2 ).x(), mPoint3.x() );
QCOMPARE( fromLine.at( 2 ).y(), mPoint3.y() );
delete lineGeom;
//test a bad geometry
QgsGeometry* badGeom = QgsGeometry::fromPoint( mPoint1 );
QPolygonF fromBad = badGeom->asQPolygonF();
QVERIFY( fromBad.isEmpty() );
delete badGeom;
}

void TestQgsGeometry::initTestCase()
{
//
Expand Down

0 comments on commit 878230a

Please sign in to comment.