Skip to content
Permalink
Browse files

Add method to QgsAbstractGeometryV2 for boundary

Returns the closure of the combinatorial boundary of the
geometry (ie the topological boundary of the geometry).
For instance, a polygon geometry will have a boundary
consisting of the linestrings for each ring in the polygon.

Follows OGC / SQL/MM specs for boundary calculation
  • Loading branch information
nyalldawson committed Jul 27, 2016
1 parent d3af8a1 commit 85f37eebb3685db6005842b40ac5b39b35a77122
Showing with 513 additions and 2 deletions.
  1. +7 −0 python/core/geometry/qgsabstractgeometryv2.sip
  2. +2 −0 python/core/geometry/qgscurvepolygonv2.sip
  3. +2 −0 python/core/geometry/qgscurvev2.sip
  4. +1 −0 python/core/geometry/qgsgeometrycollectionv2.sip
  5. +2 −0 python/core/geometry/qgsmulticurvev2.sip
  6. +2 −0 python/core/geometry/qgsmultipointv2.sip
  7. +2 −0 python/core/geometry/qgsmultipolygonv2.sip
  8. +2 −0 python/core/geometry/qgsmultisurfacev2.sip
  9. +1 −0 python/core/geometry/qgspointv2.sip
  10. +1 −0 python/core/geometry/qgspolygonv2.sip
  11. +7 −1 src/core/geometry/qgsabstractgeometryv2.h
  12. +20 −0 src/core/geometry/qgscurvepolygonv2.cpp
  13. +1 −0 src/core/geometry/qgscurvepolygonv2.h
  14. +15 −0 src/core/geometry/qgscurvev2.cpp
  15. +2 −0 src/core/geometry/qgscurvev2.h
  16. +5 −0 src/core/geometry/qgsgeometrycollectionv2.cpp
  17. +1 −0 src/core/geometry/qgsgeometrycollectionv2.h
  18. +23 −0 src/core/geometry/qgsmulticurvev2.cpp
  19. +3 −0 src/core/geometry/qgsmulticurvev2.h
  20. +1 −0 src/core/geometry/qgsmultilinestringv2.cpp
  21. +5 −0 src/core/geometry/qgsmultipointv2.cpp
  22. +2 −0 src/core/geometry/qgsmultipointv2.h
  23. +36 −0 src/core/geometry/qgsmultipolygonv2.cpp
  24. +2 −1 src/core/geometry/qgsmultipolygonv2.h
  25. +19 −0 src/core/geometry/qgsmultisurfacev2.cpp
  26. +2 −0 src/core/geometry/qgsmultisurfacev2.h
  27. +5 −0 src/core/geometry/qgspointv2.cpp
  28. +1 −0 src/core/geometry/qgspointv2.h
  29. +23 −0 src/core/geometry/qgspolygonv2.cpp
  30. +2 −0 src/core/geometry/qgspolygonv2.h
  31. +316 −0 tests/src/core/testqgsgeometry.cpp
@@ -130,6 +130,13 @@ class QgsAbstractGeometryV2
*/
bool isMeasure() const;

/** Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the geometry).
* For instance, a polygon geometry will have a boundary consisting of the linestrings for each ring in the polygon.
* @returns boundary for geometry. May be null for some geometry types.
* @note added in QGIS 3.0
*/
virtual QgsAbstractGeometryV2* boundary() const = 0;

//import

/** Sets the geometry from a WKB string.
@@ -29,6 +29,8 @@ class QgsCurvePolygonV2: public QgsSurfaceV2
virtual double area() const;
virtual double perimeter() const;
QgsPolygonV2* surfaceToPolygon() const;
virtual QgsAbstractGeometryV2* boundary() const /Factory/;


//curve polygon interface
int numInteriorRings() const;
@@ -75,6 +75,8 @@ class QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual QgsCurveV2* reversed() const = 0 /Factory/;

virtual QgsAbstractGeometryV2* boundary() const /Factory/;

/** Returns a geometry without curves. Caller takes ownership
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
@@ -30,6 +30,7 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2
virtual int dimension() const;
virtual QString geometryType() const;
virtual void clear();
virtual QgsAbstractGeometryV2* boundary() const /Factory/;

/** Adds a geometry and takes ownership. Returns true in case of success.*/
virtual bool addGeometry( QgsAbstractGeometryV2* g /Transfer/ );
@@ -26,4 +26,6 @@ class QgsMultiCurveV2: public QgsGeometryCollectionV2
* @note added in QGIS 2.14
*/
QgsMultiCurveV2* reversed() const /Factory/;

virtual QgsAbstractGeometryV2* boundary() const /Factory/;
};
@@ -20,6 +20,8 @@ class QgsMultiPointV2: public QgsGeometryCollectionV2
/** Adds a geometry and takes ownership. Returns true in case of success*/
virtual bool addGeometry( QgsAbstractGeometryV2* g );

virtual QgsAbstractGeometryV2* boundary() const /Factory/;

protected:

virtual bool wktOmitChildType() const;
@@ -24,6 +24,8 @@ class QgsMultiPolygonV2: public QgsMultiSurfaceV2
@return the converted geometry. Caller takes ownership*/
QgsAbstractGeometryV2* toCurveType() const /Factory/;

virtual QgsAbstractGeometryV2* boundary() const /Factory/;

protected:

virtual bool wktOmitChildType() const;
@@ -20,6 +20,8 @@ class QgsMultiSurfaceV2: public QgsGeometryCollectionV2
/** Adds a geometry and takes ownership. Returns true in case of success*/
virtual bool addGeometry( QgsAbstractGeometryV2* g );

virtual QgsAbstractGeometryV2* boundary() const /Factory/;

/** Returns a geometry without curves. Caller takes ownership*/
QgsAbstractGeometryV2* segmentize() const /Factory/;
};
@@ -157,6 +157,7 @@ class QgsPointV2: public QgsAbstractGeometryV2
bool transformZ = false );
void transform( const QTransform& t );
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const;
virtual QgsAbstractGeometryV2* boundary() const /Factory/;

//low-level editing
virtual bool insertVertex( QgsVertexId position, const QgsPointV2& vertex );
@@ -35,4 +35,5 @@ class QgsPolygonV2: public QgsCurvePolygonV2
//overridden to handle LineString25D rings
virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ );

virtual QgsAbstractGeometryV2* boundary() const /Factory/;
};
@@ -111,10 +111,16 @@ class CORE_EXPORT QgsAbstractGeometryV2
virtual bool isValid() const = 0;
virtual QgsMultiPointV2* locateAlong() const = 0;
virtual QgsMultiCurveV2* locateBetween() const = 0;
virtual QgsCurveV2* boundary() const = 0;
virtual QgsRectangle envelope() const = 0;
#endif

/** Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the geometry).
* For instance, a polygon geometry will have a boundary consisting of the linestrings for each ring in the polygon.
* @returns boundary for geometry. May be null for some geometry types.
* @note added in QGIS 3.0
*/
virtual QgsAbstractGeometryV2* boundary() const = 0;

//import

/** Sets the geometry from a WKB string.
@@ -23,6 +23,7 @@
#include "qgslinestringv2.h"
#include "qgspolygonv2.h"
#include "qgswkbptr.h"
#include "qgsmulticurvev2.h"
#include <QPainter>
#include <QPainterPath>

@@ -420,6 +421,25 @@ QgsPolygonV2* QgsCurvePolygonV2::surfaceToPolygon() const
return polygon;
}

QgsAbstractGeometryV2* QgsCurvePolygonV2::boundary() const
{
if ( mInteriorRings.isEmpty() )
{
return mExteriorRing->clone();
}
else
{
QgsMultiCurveV2* multiCurve = new QgsMultiCurveV2();
multiCurve->addGeometry( mExteriorRing->clone() );
int nInteriorRings = mInteriorRings.size();
for ( int i = 0; i < nInteriorRings; ++i )
{
multiCurve->addGeometry( mInteriorRings.at( i )->clone() );
}
return multiCurve;
}
}

QgsPolygonV2* QgsCurvePolygonV2::toPolygon( double tolerance, SegmentationToleranceType toleranceType ) const
{
if ( !mExteriorRing )
@@ -55,6 +55,7 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2
virtual double area() const override;
virtual double perimeter() const override;
QgsPolygonV2* surfaceToPolygon() const override;
virtual QgsAbstractGeometryV2* boundary() const override;

//curve polygon interface
int numInteriorRings() const;
@@ -18,6 +18,7 @@
#include "qgscurvev2.h"
#include "qgslinestringv2.h"
#include "qgspointv2.h"
#include "qgsmultipointv2.h"

QgsCurveV2::QgsCurveV2(): QgsAbstractGeometryV2()
{}
@@ -80,6 +81,20 @@ bool QgsCurveV2::nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const
return pointAt( id.vertex, vertex, id.type );
}

QgsAbstractGeometryV2* QgsCurveV2::boundary() const
{
if ( isEmpty() )
return nullptr;

if ( isClosed() )
return nullptr;

QgsMultiPointV2* multiPoint = new QgsMultiPointV2();
multiPoint->addGeometry( new QgsPointV2( startPoint() ) );
multiPoint->addGeometry( new QgsPointV2( endPoint() ) );
return multiPoint;
}

QgsCurveV2* QgsCurveV2::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
{
return curveToLine( tolerance, toleranceType );
@@ -102,6 +102,8 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual QgsCurveV2* reversed() const = 0;

virtual QgsAbstractGeometryV2* boundary() const override;

/** Returns a geometry without curves. Caller takes ownership
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
@@ -75,6 +75,11 @@ void QgsGeometryCollectionV2::clear()
clearCache(); //set bounding box invalid
}

QgsAbstractGeometryV2*QgsGeometryCollectionV2::boundary() const
{
return nullptr;
}

int QgsGeometryCollectionV2::numGeometries() const
{
return mGeometries.size();
@@ -54,6 +54,7 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2
virtual int dimension() const override;
virtual QString geometryType() const override { return "GeometryCollection"; }
virtual void clear() override;
virtual QgsAbstractGeometryV2* boundary() const override;

/** Adds a geometry and takes ownership. Returns true in case of success.*/
virtual bool addGeometry( QgsAbstractGeometryV2* g );
@@ -20,6 +20,7 @@ email : marco.hugentobler at sourcepole dot com
#include "qgscompoundcurvev2.h"
#include "qgsgeometryutils.h"
#include "qgslinestringv2.h"
#include "qgsmultipointv2.h"

QgsMultiCurveV2::QgsMultiCurveV2()
: QgsGeometryCollectionV2()
@@ -125,3 +126,25 @@ QgsMultiCurveV2* QgsMultiCurveV2::reversed() const
}
return reversedMultiCurve;
}

QgsAbstractGeometryV2* QgsMultiCurveV2::boundary() const
{
QgsMultiPointV2* multiPoint = new QgsMultiPointV2();
for ( int i = 0; i < mGeometries.size(); ++i )
{
if ( QgsCurveV2* curve = dynamic_cast<QgsCurveV2*>( mGeometries.at( i ) ) )
{
if ( !curve->isClosed() )
{
multiPoint->addGeometry( new QgsPointV2( curve->startPoint() ) );
multiPoint->addGeometry( new QgsPointV2( curve->endPoint() ) );
}
}
}
if ( multiPoint->numGeometries() == 0 )
{
delete multiPoint;
return nullptr;
}
return multiPoint;
}
@@ -47,6 +47,9 @@ class CORE_EXPORT QgsMultiCurveV2: public QgsGeometryCollectionV2
* @note added in QGIS 2.14
*/
QgsMultiCurveV2* reversed() const;

virtual QgsAbstractGeometryV2* boundary() const override;

};

#endif // QGSMULTICURVEV2_H
@@ -118,3 +118,4 @@ QgsAbstractGeometryV2* QgsMultiLineStringV2::toCurveType() const
}
return multiCurve;
}

@@ -105,3 +105,8 @@ bool QgsMultiPointV2::addGeometry( QgsAbstractGeometryV2* g )
setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiPoint );
return QgsGeometryCollectionV2::addGeometry( g );
}

QgsAbstractGeometryV2* QgsMultiPointV2::boundary() const
{
return nullptr;
}
@@ -44,6 +44,8 @@ class CORE_EXPORT QgsMultiPointV2: public QgsGeometryCollectionV2
/** Adds a geometry and takes ownership. Returns true in case of success*/
virtual bool addGeometry( QgsAbstractGeometryV2* g ) override;

virtual QgsAbstractGeometryV2* boundary() const override;

protected:

virtual bool wktOmitChildType() const override { return true; }
@@ -20,6 +20,7 @@ email : marco.hugentobler at sourcepole dot com
#include "qgslinestringv2.h"
#include "qgspolygonv2.h"
#include "qgscurvepolygonv2.h"
#include "qgsmultilinestringv2.h"

QgsMultiPolygonV2::QgsMultiPolygonV2()
: QgsMultiSurfaceV2()
@@ -133,3 +134,38 @@ QgsAbstractGeometryV2* QgsMultiPolygonV2::toCurveType() const
}
return multiSurface;
}

QgsAbstractGeometryV2* QgsMultiPolygonV2::boundary() const
{
QgsMultiLineStringV2* multiLine = new QgsMultiLineStringV2();
for ( int i = 0; i < mGeometries.size(); ++i )
{
if ( QgsPolygonV2* polygon = dynamic_cast<QgsPolygonV2*>( mGeometries.at( i ) ) )
{
QgsAbstractGeometryV2* polygonBoundary = polygon->boundary();

if ( QgsLineStringV2* lineStringBoundary = dynamic_cast< QgsLineStringV2* >( polygonBoundary ) )
{
multiLine->addGeometry( lineStringBoundary );
}
else if ( QgsMultiLineStringV2* multiLineStringBoundary = dynamic_cast< QgsMultiLineStringV2* >( polygonBoundary ) )
{
for ( int j = 0; j < multiLineStringBoundary->numGeometries(); ++j )
{
multiLine->addGeometry( multiLineStringBoundary->geometryN( j )->clone() );
}
delete multiLineStringBoundary;
}
else
{
delete polygonBoundary;
}
}
}
if ( multiLine->numGeometries() == 0 )
{
delete multiLine;
return nullptr;
}
return multiLine;
}
@@ -40,14 +40,15 @@ class CORE_EXPORT QgsMultiPolygonV2: public QgsMultiSurfaceV2
QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const override;
QString asJSON( int precision = 17 ) const override;


/** Adds a geometry and takes ownership. Returns true in case of success*/
virtual bool addGeometry( QgsAbstractGeometryV2* g ) override;

/** Returns the geometry converted to the more generic curve type QgsMultiSurfaceV2
@return the converted geometry. Caller takes ownership*/
QgsAbstractGeometryV2* toCurveType() const override;

virtual QgsAbstractGeometryV2* boundary() const override;

protected:

virtual bool wktOmitChildType() const override { return true; }
@@ -21,6 +21,7 @@ email : marco.hugentobler at sourcepole dot com
#include "qgslinestringv2.h"
#include "qgspolygonv2.h"
#include "qgscurvepolygonv2.h"
#include "qgsmulticurvev2.h"

QgsMultiSurfaceV2::QgsMultiSurfaceV2()
: QgsGeometryCollectionV2()
@@ -132,3 +133,21 @@ bool QgsMultiSurfaceV2::addGeometry( QgsAbstractGeometryV2* g )
setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiSurface );
return QgsGeometryCollectionV2::addGeometry( g );
}

QgsAbstractGeometryV2* QgsMultiSurfaceV2::boundary() const
{
QgsMultiCurveV2* multiCurve = new QgsMultiCurveV2();
for ( int i = 0; i < mGeometries.size(); ++i )
{
if ( QgsSurfaceV2* surface = dynamic_cast<QgsSurfaceV2*>( mGeometries.at( i ) ) )
{
multiCurve->addGeometry( surface->boundary() );
}
}
if ( multiCurve->numGeometries() == 0 )
{
delete multiCurve;
return nullptr;
}
return multiCurve;
}
@@ -43,6 +43,8 @@ class CORE_EXPORT QgsMultiSurfaceV2: public QgsGeometryCollectionV2

/** Adds a geometry and takes ownership. Returns true in case of success*/
virtual bool addGeometry( QgsAbstractGeometryV2* g ) override;

virtual QgsAbstractGeometryV2* boundary() const override;
};

#endif // QGSMULTISURFACEV2_H
@@ -281,6 +281,11 @@ QgsCoordinateSequenceV2 QgsPointV2::coordinateSequence() const
return cs;
}

QgsAbstractGeometryV2* QgsPointV2::boundary() const
{
return nullptr;
}

/***************************************************************************
* This class is considered CRITICAL and any change MUST be accompanied with
* full unit tests.
@@ -170,6 +170,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2
bool transformZ = false ) override;
void transform( const QTransform& t ) override;
virtual QgsCoordinateSequenceV2 coordinateSequence() const override;
virtual QgsAbstractGeometryV2* boundary() const override;

//low-level editing
virtual bool insertVertex( QgsVertexId position, const QgsPointV2& vertex ) override { Q_UNUSED( position ); Q_UNUSED( vertex ); return false; }

0 comments on commit 85f37ee

Please sign in to comment.
You can’t perform that action at this time.