mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Add method to filter vertices for geometries in place, by providing a custom filter function
This commit is contained in:
parent
8341b9b19c
commit
f092c7edb7
@ -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 ).
|
||||
|
Loading…
x
Reference in New Issue
Block a user