Skip to content
Permalink
Browse files

Merge pull request #3341 from nyalldawson/boundary

New method for calculating geometry boundary
  • Loading branch information
nyalldawson committed Jul 28, 2016
2 parents d3af8a1 + 1a4ceb1 commit bc73c56e14b0ef17da36846c990fdf79ec2aeda1
Showing with 542 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. +8 −0 resources/function_help/json/boundary
  12. +7 −1 src/core/geometry/qgsabstractgeometryv2.h
  13. +20 −0 src/core/geometry/qgscurvepolygonv2.cpp
  14. +1 −0 src/core/geometry/qgscurvepolygonv2.h
  15. +15 −0 src/core/geometry/qgscurvev2.cpp
  16. +2 −0 src/core/geometry/qgscurvev2.h
  17. +5 −0 src/core/geometry/qgsgeometrycollectionv2.cpp
  18. +1 −0 src/core/geometry/qgsgeometrycollectionv2.h
  19. +23 −0 src/core/geometry/qgsmulticurvev2.cpp
  20. +3 −0 src/core/geometry/qgsmulticurvev2.h
  21. +1 −0 src/core/geometry/qgsmultilinestringv2.cpp
  22. +5 −0 src/core/geometry/qgsmultipointv2.cpp
  23. +2 −0 src/core/geometry/qgsmultipointv2.h
  24. +36 −0 src/core/geometry/qgsmultipolygonv2.cpp
  25. +2 −1 src/core/geometry/qgsmultipolygonv2.h
  26. +19 −0 src/core/geometry/qgsmultisurfacev2.cpp
  27. +2 −0 src/core/geometry/qgsmultisurfacev2.h
  28. +5 −0 src/core/geometry/qgspointv2.cpp
  29. +1 −0 src/core/geometry/qgspointv2.h
  30. +23 −0 src/core/geometry/qgspolygonv2.cpp
  31. +2 −0 src/core/geometry/qgspolygonv2.h
  32. +16 −0 src/core/qgsexpression.cpp
  33. +5 −0 tests/src/core/testqgsexpression.cpp
  34. +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/;
};
@@ -0,0 +1,8 @@
{
"name": "boundary",
"type": "function",
"description":"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. Some geometry types do not have a defined boundary, eg points or geometry collections, and will return null.",
"arguments": [ {"arg":"geometry","description":"a geometry"} ],
"examples": [ { "expression":"geom_to_wkt(boundary(geom_from_wkt('Polygon((1 1, 0 0, -1 1, 1 1))')))", "returns":"'LineString(1 1,0 0,-1 1,1 1)'"}]
}

@@ -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.

0 comments on commit bc73c56

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