Skip to content

Commit

Permalink
Add method to transform vertices of QgsGeometry/QgsAbstractGeometry
Browse files Browse the repository at this point in the history
in place using a custom lambda function
  • Loading branch information
nyalldawson committed Jul 30, 2018
1 parent df1832f commit d09faf4
Show file tree
Hide file tree
Showing 18 changed files with 265 additions and 0 deletions.
1 change: 1 addition & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1595,6 +1595,7 @@ was performed on the geometry.
%End



static QgsGeometry fromQPointF( QPointF point );
%Docstring
Construct geometry from a QPointF
Expand Down
5 changes: 5 additions & 0 deletions src/core/geometry/qgsabstractgeometry.cpp
Expand Up @@ -240,6 +240,11 @@ void QgsAbstractGeometry::filterVertices( const std::function<bool ( const QgsPo
// Ideally this would be pure virtual, but SIP has issues with that
}

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

QgsVertexIterator QgsAbstractGeometry::vertices() const
{
return QgsVertexIterator( this );
Expand Down
16 changes: 16 additions & 0 deletions src/core/geometry/qgsabstractgeometry.h
Expand Up @@ -586,6 +586,22 @@ class CORE_EXPORT QgsAbstractGeometry
*/
virtual void filterVertices( const std::function< bool( const QgsPoint & ) > &filter );

/**
* Transforms the vertices from the geometry in place, applying the \a transform function
* to every vertex.
*
* Depending on the \a transform used, this may result in an invalid geometry.
*
* Transform functions are not permitted to alter the dimensionality of vertices. If
* a transform which adds (or removes) z/m values is desired, first call the corresponding
* addZValue() or addMValue() function to change the geometry's dimensionality and then
* transform.
*
* \note Not available in Python bindings
* \since QGIS 3.4
*/
virtual void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform );

/**
* \ingroup core
* The vertex_iterator class provides STL-style iterator for vertices.
Expand Down
28 changes: 28 additions & 0 deletions src/core/geometry/qgscircularstring.cpp
Expand Up @@ -592,6 +592,34 @@ void QgsCircularString::filterVertices( const std::function<bool ( const QgsPoin
clearCache();
}

void QgsCircularString::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
{
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;

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();
QgsPoint res = transform( QgsPoint( x, y, z, m ) );
*srcX++ = res.x();
*srcY++ = res.y();
if ( hasM )
*srcM++ = res.m();
if ( hasZ )
*srcZ++ = res.z();
}
clearCache();
}

void QgsCircularString::points( QgsPointSequence &pts ) const
{
pts.clear();
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgscircularstring.h
Expand Up @@ -128,6 +128,7 @@ class CORE_EXPORT QgsCircularString: public QgsCurve

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

/**
* Cast the \a geom to a QgsCircularString.
Expand Down
9 changes: 9 additions & 0 deletions src/core/geometry/qgscompoundcurve.cpp
Expand Up @@ -782,6 +782,15 @@ void QgsCompoundCurve::filterVertices( const std::function<bool ( const QgsPoint
clearCache();
}

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

void QgsCompoundCurve::sumUpArea( double &sum ) const
{
for ( const QgsCurve *curve : mCurves )
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgscompoundcurve.h
Expand Up @@ -128,6 +128,7 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve

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

/**
* Cast the \a geom to a QgsCompoundCurve.
Expand Down
12 changes: 12 additions & 0 deletions src/core/geometry/qgscurvepolygon.cpp
Expand Up @@ -1186,6 +1186,18 @@ void QgsCurvePolygon::filterVertices( const std::function<bool ( const QgsPoint
clearCache();
}

void QgsCurvePolygon::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
{
if ( mExteriorRing )
mExteriorRing->transformVertices( transform );

for ( QgsCurve *curve : qgis::as_const( mInteriorRings ) )
{
curve->transformVertices( transform );
}
clearCache();
}

int QgsCurvePolygon::childCount() const
{
return 1 + mInteriorRings.count();
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgscurvepolygon.h
Expand Up @@ -180,6 +180,7 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface

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

/**
* Cast the \a geom to a QgsCurvePolygon.
Expand Down
10 changes: 10 additions & 0 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -2599,6 +2599,16 @@ void QgsGeometry::filterVertices( const std::function<bool ( const QgsPoint & )>
d->geometry->filterVertices( filter );
}

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

detach();

d->geometry->transformVertices( transform );
}

void QgsGeometry::convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output )
{
output.clear();
Expand Down
16 changes: 16 additions & 0 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1548,6 +1548,22 @@ class CORE_EXPORT QgsGeometry
*/
void filterVertices( const std::function< bool( const QgsPoint & ) > &filter ) SIP_SKIP;

/**
* Transforms the vertices from the geometry in place, applying the \a transform function
* to every vertex.
*
* Depending on the \a transform used, this may result in an invalid geometry.
*
* Transform functions are not permitted to alter the dimensionality of vertices. If
* a transform which adds (or removes) z/m values is desired, first call the corresponding
* addZValue() or addMValue() function to change the geometry's dimensionality and then
* transform.
*
* \note Not available in Python bindings
* \since QGIS 3.4
*/
void transformVertices( const std::function< QgsPoint( const QgsPoint & ) > &transform ) SIP_SKIP;

/**
* Construct geometry from a QPointF
* \param point source QPointF
Expand Down
10 changes: 10 additions & 0 deletions src/core/geometry/qgsgeometrycollection.cpp
Expand Up @@ -830,6 +830,16 @@ void QgsGeometryCollection::filterVertices( const std::function<bool ( const Qgs
clearCache();
}

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

void QgsGeometryCollection::swapXy()
{
for ( QgsAbstractGeometry *geom : qgis::as_const( mGeometries ) )
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgsgeometrycollection.h
Expand Up @@ -150,6 +150,7 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry

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

/**
* Cast the \a geom to a QgsGeometryCollection.
Expand Down
28 changes: 28 additions & 0 deletions src/core/geometry/qgslinestring.cpp
Expand Up @@ -1346,3 +1346,31 @@ void QgsLineString::filterVertices( const std::function<bool ( const QgsPoint &

clearCache();
}

void QgsLineString::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
{
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;

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();
QgsPoint res = transform( QgsPoint( x, y, z, m ) );
*srcX++ = res.x();
*srcY++ = res.y();
if ( hasM )
*srcM++ = res.m();
if ( hasZ )
*srcZ++ = res.z();
}
clearCache();
}
1 change: 1 addition & 0 deletions src/core/geometry/qgslinestring.h
Expand Up @@ -328,6 +328,7 @@ class CORE_EXPORT QgsLineString: public QgsCurve

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

/**
* Cast the \a geom to a QgsLineString.
Expand Down
12 changes: 12 additions & 0 deletions src/core/geometry/qgspoint.cpp
Expand Up @@ -573,6 +573,18 @@ void QgsPoint::filterVertices( const std::function<bool ( const QgsPoint & )> &
// no meaning for points
}

void QgsPoint::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
{
QgsPoint res = transform( *this );
mX = res.x();
mY = res.y();
if ( is3D() )
mZ = res.z();
if ( isMeasure() )
mM = res.m();
clearCache();
}

double QgsPoint::distance3D( double x, double y, double z ) const
{
double zDistSquared = 0.0;
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgspoint.h
Expand Up @@ -477,6 +477,7 @@ class CORE_EXPORT QgsPoint: public QgsAbstractGeometry
#ifndef SIP_RUN

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

/**
* Cast the \a geom to a QgsPoint.
Expand Down

0 comments on commit d09faf4

Please sign in to comment.