Skip to content

Commit

Permalink
Merge pull request #3341 from nyalldawson/boundary
Browse files Browse the repository at this point in the history
New method for calculating geometry boundary
  • Loading branch information
nyalldawson committed Jul 28, 2016
2 parents d3af8a1 + 1a4ceb1 commit bc73c56
Show file tree
Hide file tree
Showing 34 changed files with 542 additions and 2 deletions.
7 changes: 7 additions & 0 deletions python/core/geometry/qgsabstractgeometryv2.sip
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions python/core/geometry/qgscurvepolygonv2.sip
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions python/core/geometry/qgscurvev2.sip
Expand Up @@ -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*/
Expand Down
1 change: 1 addition & 0 deletions python/core/geometry/qgsgeometrycollectionv2.sip
Expand Up @@ -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/ );
Expand Down
2 changes: 2 additions & 0 deletions python/core/geometry/qgsmulticurvev2.sip
Expand Up @@ -26,4 +26,6 @@ class QgsMultiCurveV2: public QgsGeometryCollectionV2
* @note added in QGIS 2.14
*/
QgsMultiCurveV2* reversed() const /Factory/;

virtual QgsAbstractGeometryV2* boundary() const /Factory/;
};
2 changes: 2 additions & 0 deletions python/core/geometry/qgsmultipointv2.sip
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions python/core/geometry/qgsmultipolygonv2.sip
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions python/core/geometry/qgsmultisurfacev2.sip
Expand Up @@ -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/;
};
1 change: 1 addition & 0 deletions python/core/geometry/qgspointv2.sip
Expand Up @@ -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 );
Expand Down
1 change: 1 addition & 0 deletions python/core/geometry/qgspolygonv2.sip
Expand Up @@ -35,4 +35,5 @@ class QgsPolygonV2: public QgsCurvePolygonV2
//overridden to handle LineString25D rings
virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ );

virtual QgsAbstractGeometryV2* boundary() const /Factory/;
};
8 changes: 8 additions & 0 deletions resources/function_help/json/boundary
@@ -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)'"}]
}

8 changes: 7 additions & 1 deletion src/core/geometry/qgsabstractgeometryv2.h
Expand Up @@ -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.
Expand Down
20 changes: 20 additions & 0 deletions src/core/geometry/qgscurvepolygonv2.cpp
Expand Up @@ -23,6 +23,7 @@
#include "qgslinestringv2.h"
#include "qgspolygonv2.h"
#include "qgswkbptr.h"
#include "qgsmulticurvev2.h"
#include <QPainter>
#include <QPainterPath>

Expand Down Expand Up @@ -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 )
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgscurvepolygonv2.h
Expand Up @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions src/core/geometry/qgscurvev2.cpp
Expand Up @@ -18,6 +18,7 @@
#include "qgscurvev2.h"
#include "qgslinestringv2.h"
#include "qgspointv2.h"
#include "qgsmultipointv2.h"

QgsCurveV2::QgsCurveV2(): QgsAbstractGeometryV2()
{}
Expand Down Expand Up @@ -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 );
Expand Down
2 changes: 2 additions & 0 deletions src/core/geometry/qgscurvev2.h
Expand Up @@ -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*/
Expand Down
5 changes: 5 additions & 0 deletions src/core/geometry/qgsgeometrycollectionv2.cpp
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgsgeometrycollectionv2.h
Expand Up @@ -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 );
Expand Down
23 changes: 23 additions & 0 deletions src/core/geometry/qgsmulticurvev2.cpp
Expand Up @@ -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()
Expand Down Expand Up @@ -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;
}
3 changes: 3 additions & 0 deletions src/core/geometry/qgsmulticurvev2.h
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/core/geometry/qgsmultilinestringv2.cpp
Expand Up @@ -118,3 +118,4 @@ QgsAbstractGeometryV2* QgsMultiLineStringV2::toCurveType() const
}
return multiCurve;
}

5 changes: 5 additions & 0 deletions src/core/geometry/qgsmultipointv2.cpp
Expand Up @@ -105,3 +105,8 @@ bool QgsMultiPointV2::addGeometry( QgsAbstractGeometryV2* g )
setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiPoint );
return QgsGeometryCollectionV2::addGeometry( g );
}

QgsAbstractGeometryV2* QgsMultiPointV2::boundary() const
{
return nullptr;
}
2 changes: 2 additions & 0 deletions src/core/geometry/qgsmultipointv2.h
Expand Up @@ -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; }
Expand Down
36 changes: 36 additions & 0 deletions src/core/geometry/qgsmultipolygonv2.cpp
Expand Up @@ -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()
Expand Down Expand Up @@ -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;
}
3 changes: 2 additions & 1 deletion src/core/geometry/qgsmultipolygonv2.h
Expand Up @@ -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; }
Expand Down
19 changes: 19 additions & 0 deletions src/core/geometry/qgsmultisurfacev2.cpp
Expand Up @@ -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()
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions src/core/geometry/qgsmultisurfacev2.h
Expand Up @@ -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
5 changes: 5 additions & 0 deletions src/core/geometry/qgspointv2.cpp
Expand Up @@ -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.
Expand Down

0 comments on commit bc73c56

Please sign in to comment.