Skip to content
Permalink
Browse files

Add method to filter vertices for geometries in place, by providing a…

… custom filter function
  • Loading branch information
nyalldawson committed May 29, 2018
1 parent 8341b9b commit f092c7edb7fcd11da1ab2b45e546c59663be0418
@@ -158,6 +158,7 @@ Sets the circular string's points
virtual double yAt( int index ) const;



virtual QgsCircularString *createEmptyWithSameType() const /Factory/;


@@ -162,6 +162,7 @@ Appends first point if not already closed.
virtual double yAt( int index ) const;



virtual QgsCompoundCurve *createEmptyWithSameType() const /Factory/;


@@ -201,6 +201,7 @@ Returns approximate rotation angle for a vertex. Usually average angle between a
virtual QgsCurvePolygon *toCurveType() const /Factory/;



virtual QgsCurvePolygon *createEmptyWithSameType() const /Factory/;


@@ -1588,6 +1588,7 @@ was performed on the geometry.
.. versionadded:: 3.0
%End


static QgsGeometry fromQPointF( QPointF point );
%Docstring
Construct geometry from a QPointF
@@ -345,6 +345,8 @@ class QgsShapeburstFillSymbolLayer : QgsFillSymbolLayer
~QgsShapeburstFillSymbolLayer();




static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) /Factory/;


@@ -246,6 +246,11 @@ bool QgsAbstractGeometry::convertTo( QgsWkbTypes::Type type )
return true;
}

void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> & )
{
// Ideally this would be pure virtual, but SIP has issues with that
}

QgsVertexIterator QgsAbstractGeometry::vertices() const
{
return QgsVertexIterator( this );
@@ -569,6 +569,18 @@ class CORE_EXPORT QgsAbstractGeometry

#ifndef SIP_RUN

/**
* Filters the vertices from the geometry in place, removing any which do not return true for the \a filter function
* check. Has no meaning when called on a single point geometry.
*
* Depending on the \a filter used, this may result in an invalid geometry. However, CurvePolygon rings which are no longer
* valid rings will be automatically removed after filtering.
*
* \since QGIS 3.2
* \note Not available in Python bindings
*/
virtual void filterVertices( const std::function< bool( const QgsPoint & ) > &filter );

/**
* \ingroup core
* The vertex_iterator class provides STL-style iterator for vertices.
@@ -546,6 +546,52 @@ double QgsCircularString::yAt( int index ) const
return 0.0;
}

void QgsCircularString::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
bool hasZ = is3D();
bool hasM = isMeasure();
int size = mX.size();

double *srcX = mX.data(); // clazy:exclude=detaching-member
double *srcY = mY.data(); // clazy:exclude=detaching-member
double *srcM = hasM ? mM.data() : nullptr; // clazy:exclude=detaching-member
double *srcZ = hasZ ? mZ.data() : nullptr; // clazy:exclude=detaching-member

double *destX = srcX;
double *destY = srcY;
double *destM = srcM;
double *destZ = srcZ;

int filteredPoints = 0;
for ( int i = 0; i < size; ++i )
{
double x = *srcX++;
double y = *srcY++;
double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();

if ( filter( QgsPoint( x, y, z, m ) ) )
{
filteredPoints++;
*destX++ = x;
*destY++ = y;
if ( hasM )
*destM++ = m;
if ( hasZ )
*destZ++ = z;
}
}

mX.resize( filteredPoints );
mY.resize( filteredPoints );
if ( hasZ )
mZ.resize( filteredPoints );
if ( hasM )
mM.resize( filteredPoints );

clearCache();
}

void QgsCircularString::points( QgsPointSequence &pts ) const
{
pts.clear();
@@ -125,7 +125,9 @@ class CORE_EXPORT QgsCircularString: public QgsCurve
void swapXy() override;
double xAt( int index ) const override;
double yAt( int index ) const override;

#ifndef SIP_RUN
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsCircularString.
@@ -773,6 +773,15 @@ double QgsCompoundCurve::yAt( int index ) const
return 0.0;
}

void QgsCompoundCurve::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
for ( QgsCurve *curve : qgis::as_const( mCurves ) )
{
curve->filterVertices( filter );
}
clearCache();
}

void QgsCompoundCurve::sumUpArea( double &sum ) const
{
for ( const QgsCurve *curve : mCurves )
@@ -125,7 +125,9 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve

double xAt( int index ) const override;
double yAt( int index ) const override;

#ifndef SIP_RUN
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsCompoundCurve.
@@ -1174,6 +1174,31 @@ QgsCurvePolygon *QgsCurvePolygon::toCurveType() const
return clone();
}

void QgsCurvePolygon::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
if ( mExteriorRing )
mExteriorRing->filterVertices( filter );

QVector<QgsCurve *> filteredRings;
filteredRings.reserve( mInteriorRings.size() );
for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
{
curve->filterVertices( filter );

if ( !curve->isRing() )
{
// remove invalid rings
delete curve;
}
else
{
filteredRings << curve;
}
}
mInteriorRings = filteredRings;
clearCache();
}

int QgsCurvePolygon::childCount() const
{
return 1 + mInteriorRings.count();
@@ -153,7 +153,9 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
void swapXy() override;

QgsCurvePolygon *toCurveType() const override SIP_FACTORY;

#ifndef SIP_RUN
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsCurvePolygon.
@@ -2574,6 +2574,16 @@ QString QgsGeometry::lastError() const
return mLastError;
}

void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
if ( !d->geometry )
return;

detach();

d->geometry->filterVertices( filter );
}

void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
{
output.clear();
@@ -1529,6 +1529,18 @@ class CORE_EXPORT QgsGeometry
*/
QString lastError() const;

/**
* Filters the vertices from the geometry in place, removing any which do not return true for the \a filter function
* check. Has no effect when called on a single point geometry.
*
* Depending on the \a filter used, this may result in an invalid geometry. However, CurvePolygon rings which are no longer
* valid rings will be automatically removed after filtering.
*
* \since QGIS 3.2
* \note Not available in Python bindings
*/
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) SIP_SKIP;

/**
* Construct geometry from a QPointF
* \param point source QPointF
@@ -830,6 +830,16 @@ bool QgsGeometryCollection::dropMValue()
return true;
}

void QgsGeometryCollection::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
for ( QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
{
if ( geom )
geom->filterVertices( filter );
}
clearCache();
}

void QgsGeometryCollection::swapXy()
{
for ( QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
@@ -143,6 +143,7 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
QgsGeometryCollection *toCurveType() const override SIP_FACTORY;

#ifndef SIP_RUN
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsGeometryCollection.
@@ -1329,3 +1329,49 @@ bool QgsLineString::convertTo( QgsWkbTypes::Type type )
return QgsCurve::convertTo( type );
}
}

void QgsLineString::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
{
bool hasZ = is3D();
bool hasM = isMeasure();
int size = mX.size();

double *srcX = mX.data();
double *srcY = mY.data();
double *srcM = hasM ? mM.data() : nullptr;
double *srcZ = hasZ ? mZ.data() : nullptr;

double *destX = srcX;
double *destY = srcY;
double *destM = srcM;
double *destZ = srcZ;

int filteredPoints = 0;
for ( int i = 0; i < size; ++i )
{
double x = *srcX++;
double y = *srcY++;
double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();

if ( filter( QgsPoint( x, y, z, m ) ) )
{
filteredPoints++;
*destX++ = x;
*destY++ = y;
if ( hasM )
*destM++ = m;
if ( hasZ )
*destZ++ = z;
}
}

mX.resize( filteredPoints );
mY.resize( filteredPoints );
if ( hasZ )
mZ.resize( filteredPoints );
if ( hasM )
mM.resize( filteredPoints );

clearCache();
}
@@ -268,6 +268,7 @@ class CORE_EXPORT QgsLineString: public QgsCurve
bool convertTo( QgsWkbTypes::Type type ) override;

#ifndef SIP_RUN
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsLineString.
@@ -592,6 +592,10 @@ bool QgsPoint::convertTo( QgsWkbTypes::Type type )
return false;
}

void QgsPoint::filterVertices( const std::function<bool ( const QgsPoint & )> & )
{
// no meaning for points
}

QPointF QgsPoint::toQPointF() const
{
@@ -440,6 +440,8 @@ class CORE_EXPORT QgsPoint: public QgsAbstractGeometry

#ifndef SIP_RUN

void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) override;

/**
* Cast the \a geom to a QgsPoint.
* Should be used by qgsgeometry_cast<QgsPoint *>( geometry ).

0 comments on commit f092c7e

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