mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Merge pull request #5367 from wonder-sk/vertex-iterator-2
API for traversal of geometry's vertices using iterator pattern
This commit is contained in:
commit
ae4d26a675
@ -463,6 +463,56 @@ Returns the centroid of the geometry
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
|
||||
QgsVertexIterator vertices() const;
|
||||
%Docstring
|
||||
Returns Java-style iterator for traversal of vertices of the geometry
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsVertexIterator
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool hasChildGeometries() const;
|
||||
%Docstring
|
||||
Returns whether the geometry has any child geometries (false for point / curve, true otherwise)
|
||||
.. note::
|
||||
|
||||
used for vertex_iterator implementation
|
||||
.. versionadded:: 3.0
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
virtual int childCount() const;
|
||||
%Docstring
|
||||
Returns number of child geometries (for geometries with child geometries) or child points (for geometries without child geometries - i.e. curve / point)
|
||||
.. note::
|
||||
|
||||
used for vertex_iterator implementation
|
||||
.. versionadded:: 3.0
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const;
|
||||
%Docstring
|
||||
Returns pointer to child geometry (for geometries with child geometries - i.e. geom. collection / polygon)
|
||||
.. note::
|
||||
|
||||
used for vertex_iterator implementation
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsAbstractGeometry
|
||||
%End
|
||||
|
||||
virtual QgsPoint childPoint( int index ) const;
|
||||
%Docstring
|
||||
Returns point at index (for geometries without child geometries - i.e. curve / point)
|
||||
.. note::
|
||||
|
||||
used for vertex_iterator implementation
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsPoint
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
void setZMTypeFromSubGeometry( const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType );
|
||||
@ -531,6 +581,54 @@ struct QgsVertexId
|
||||
|
||||
|
||||
|
||||
class QgsVertexIterator
|
||||
{
|
||||
%Docstring
|
||||
Java-style iterator for traversal of vertices of a geometry
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsabstractgeometry.h"
|
||||
%End
|
||||
public:
|
||||
QgsVertexIterator();
|
||||
|
||||
QgsVertexIterator( const QgsAbstractGeometry *geometry );
|
||||
%Docstring
|
||||
Constructs iterator for the given geometry
|
||||
%End
|
||||
|
||||
bool hasNext() const;
|
||||
%Docstring
|
||||
Find out whether there are more vertices
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
QgsPoint next();
|
||||
%Docstring
|
||||
Return next vertex of the geometry (undefined behavior if hasNext() returns false before calling next())
|
||||
:rtype: QgsPoint
|
||||
%End
|
||||
|
||||
QgsVertexIterator *__iter__();
|
||||
%Docstring
|
||||
:rtype: QgsVertexIterator
|
||||
%End
|
||||
%MethodCode
|
||||
sipRes = sipCpp;
|
||||
%End
|
||||
|
||||
SIP_PYOBJECT __next__();
|
||||
%MethodCode
|
||||
if ( sipCpp->hasNext() )
|
||||
sipRes = sipConvertFromType( new QgsPoint( sipCpp->next() ), sipType_QgsPoint, Py_None );
|
||||
else
|
||||
PyErr_SetString( PyExc_StopIteration, "" );
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -177,6 +177,9 @@ class QgsCurve: QgsAbstractGeometry
|
||||
virtual void clearCache() const;
|
||||
|
||||
|
||||
virtual int childCount() const;
|
||||
virtual QgsPoint childPoint( int index ) const;
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -192,6 +192,10 @@ Adds an interior ring to the geometry (takes ownership)
|
||||
|
||||
virtual QgsCurvePolygon *toCurveType() const /Factory/;
|
||||
|
||||
protected:
|
||||
virtual int childCount() const;
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
@ -241,6 +241,14 @@ Returns true if WKB of the geometry is of WKBMulti* type
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
|
||||
QgsVertexIterator vertices() const;
|
||||
%Docstring
|
||||
Returns Java-style iterator for traversal of vertices of the geometry
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsVertexIterator
|
||||
%End
|
||||
|
||||
double hausdorffDistance( const QgsGeometry &geom ) const;
|
||||
%Docstring
|
||||
Returns the Hausdorff distance between this geometry and ``geom``. This is basically a measure of how similar or dissimilar 2 geometries are.
|
||||
|
@ -168,6 +168,10 @@ Adds a geometry and takes ownership. Returns true in case of success.
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
virtual int childCount() const;
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool wktOmitChildType() const;
|
||||
|
@ -410,6 +410,11 @@ class QgsPoint: QgsAbstractGeometry
|
||||
virtual bool convertTo( QgsWkbTypes::Type type );
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
virtual int childCount() const;
|
||||
virtual QgsPoint childPoint( int index ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -246,6 +246,22 @@ bool QgsAbstractGeometry::convertTo( QgsWkbTypes::Type type )
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsVertexIterator QgsAbstractGeometry::vertices() const
|
||||
{
|
||||
return QgsVertexIterator( this );
|
||||
}
|
||||
|
||||
bool QgsAbstractGeometry::hasChildGeometries() const
|
||||
{
|
||||
return QgsWkbTypes::isMultiType( wkbType() ) || dimension() == 2;
|
||||
}
|
||||
|
||||
QgsPoint QgsAbstractGeometry::childPoint( int index ) const
|
||||
{
|
||||
Q_UNUSED( index );
|
||||
return QgsPoint();
|
||||
}
|
||||
|
||||
bool QgsAbstractGeometry::isEmpty() const
|
||||
{
|
||||
QgsVertexId vId;
|
||||
@ -265,3 +281,112 @@ QgsAbstractGeometry *QgsAbstractGeometry::segmentize( double tolerance, Segmenta
|
||||
return clone();
|
||||
}
|
||||
|
||||
|
||||
QgsAbstractGeometry::vertex_iterator::vertex_iterator( const QgsAbstractGeometry *g, int index )
|
||||
: depth( 0 )
|
||||
{
|
||||
::memset( levels, 0, sizeof( Level ) * 3 ); // make sure we clean up also the padding areas (for memcmp test in operator==)
|
||||
levels[0].g = g;
|
||||
levels[0].index = index;
|
||||
|
||||
digDown(); // go to the leaf level of the first vertex
|
||||
}
|
||||
|
||||
QgsAbstractGeometry::vertex_iterator &QgsAbstractGeometry::vertex_iterator::operator++()
|
||||
{
|
||||
if ( depth == 0 && levels[0].index >= levels[0].g->childCount() )
|
||||
return *this; // end of geometry - nowhere else to go
|
||||
|
||||
Q_ASSERT( !levels[depth].g->hasChildGeometries() ); // we should be at a leaf level
|
||||
|
||||
++levels[depth].index;
|
||||
|
||||
// traverse up if we are at the end in the current level
|
||||
while ( depth > 0 && levels[depth].index >= levels[depth].g->childCount() )
|
||||
{
|
||||
--depth;
|
||||
++levels[depth].index;
|
||||
}
|
||||
|
||||
digDown(); // go to the leaf level again
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
QgsAbstractGeometry::vertex_iterator QgsAbstractGeometry::vertex_iterator::operator++( int )
|
||||
{
|
||||
vertex_iterator it( *this );
|
||||
++*this;
|
||||
return it;
|
||||
}
|
||||
|
||||
QgsPoint QgsAbstractGeometry::vertex_iterator::operator*() const
|
||||
{
|
||||
Q_ASSERT( !levels[depth].g->hasChildGeometries() );
|
||||
return levels[depth].g->childPoint( levels[depth].index );
|
||||
}
|
||||
|
||||
QgsVertexId QgsAbstractGeometry::vertex_iterator::vertexId() const
|
||||
{
|
||||
int part = 0, ring = 0, vertex = levels[depth].index;
|
||||
if ( depth == 0 )
|
||||
{
|
||||
// nothing else to do
|
||||
}
|
||||
else if ( depth == 1 )
|
||||
{
|
||||
if ( QgsWkbTypes::isMultiType( levels[0].g->wkbType() ) )
|
||||
part = levels[0].index;
|
||||
else
|
||||
ring = levels[0].index;
|
||||
}
|
||||
else if ( depth == 2 )
|
||||
{
|
||||
part = levels[0].index;
|
||||
ring = levels[1].index;
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
return QgsVertexId();
|
||||
}
|
||||
|
||||
// get the vertex type: find out from the leaf geometry
|
||||
QgsVertexId::VertexType vertexType = QgsVertexId::SegmentVertex;
|
||||
if ( const QgsCurve *curve = dynamic_cast<const QgsCurve *>( levels[depth].g ) )
|
||||
{
|
||||
QgsPoint p;
|
||||
curve->pointAt( vertex, p, vertexType );
|
||||
}
|
||||
|
||||
return QgsVertexId( part, ring, vertex, vertexType );
|
||||
}
|
||||
|
||||
bool QgsAbstractGeometry::vertex_iterator::operator==( const QgsAbstractGeometry::vertex_iterator &other ) const
|
||||
{
|
||||
if ( depth != other.depth )
|
||||
return false;
|
||||
int res = ::memcmp( levels, other.levels, sizeof( Level ) * ( depth + 1 ) );
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void QgsAbstractGeometry::vertex_iterator::digDown()
|
||||
{
|
||||
if ( levels[depth].g->hasChildGeometries() && levels[depth].index >= levels[depth].g->childCount() )
|
||||
return; // first check we are not already at the end
|
||||
|
||||
// while not "final" depth for the geom: go one level down.
|
||||
while ( levels[depth].g->hasChildGeometries() )
|
||||
{
|
||||
++depth;
|
||||
Q_ASSERT( depth < 3 ); // that's capacity of the levels array
|
||||
levels[depth].index = 0;
|
||||
levels[depth].g = levels[depth - 1].g->childGeometry( levels[depth - 1].index );
|
||||
}
|
||||
}
|
||||
|
||||
QgsPoint QgsVertexIterator::next()
|
||||
{
|
||||
n = i++;
|
||||
return *n;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class QgsMultiCurve;
|
||||
class QgsMultiPointV2;
|
||||
class QgsPoint;
|
||||
struct QgsVertexId;
|
||||
class QgsVertexIterator;
|
||||
class QPainter;
|
||||
class QDomDocument;
|
||||
class QDomElement;
|
||||
@ -463,6 +464,114 @@ class CORE_EXPORT QgsAbstractGeometry
|
||||
*/
|
||||
virtual bool convertTo( QgsWkbTypes::Type type );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* The vertex_iterator class provides STL-style iterator for vertices.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT vertex_iterator
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* A helper structure to keep track of vertex traversal within one level within a geometry.
|
||||
* For example, linestring geometry will have just one level, while multi-polygon has three levels
|
||||
* (part index, ring index, vertex index).
|
||||
*/
|
||||
struct Level
|
||||
{
|
||||
const QgsAbstractGeometry *g; //!< Current geometry
|
||||
int index; //!< Ptr in the current geometry
|
||||
};
|
||||
|
||||
Level levels[3]; //!< Stack of levels - three levels should be sufficient (e.g. part index, ring index, vertex index)
|
||||
int depth; //!< At what depth level are we right now
|
||||
|
||||
void digDown(); //!< Prepare the stack of levels so that it points to a leaf child geometry
|
||||
|
||||
public:
|
||||
//! Create invalid iterator
|
||||
vertex_iterator() : depth( -1 ) {}
|
||||
|
||||
//! Create vertex iterator for a geometry
|
||||
vertex_iterator( const QgsAbstractGeometry *g, int index );
|
||||
|
||||
/**
|
||||
* The prefix ++ operator (++it) advances the iterator to the next vertex and returns an iterator to the new current vertex.
|
||||
* Calling this function on iterator that is already past the last item leads to undefined results.
|
||||
*/
|
||||
vertex_iterator &operator++();
|
||||
|
||||
//! The postfix ++ operator (it++) advances the iterator to the next vertex and returns an iterator to the previously current vertex.
|
||||
vertex_iterator operator++( int );
|
||||
|
||||
//! Returns the current item.
|
||||
QgsPoint operator*() const;
|
||||
|
||||
//! Returns vertex ID of the current item.
|
||||
QgsVertexId vertexId() const;
|
||||
|
||||
bool operator==( const vertex_iterator &other ) const;
|
||||
bool operator!=( const vertex_iterator &other ) const { return !( *this == other ); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns STL-style iterator pointing to the first vertex of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
vertex_iterator vertices_begin() const
|
||||
{
|
||||
return vertex_iterator( this, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
vertex_iterator vertices_end() const
|
||||
{
|
||||
return vertex_iterator( this, childCount() );
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns Java-style iterator for traversal of vertices of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsVertexIterator vertices() const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Returns whether the geometry has any child geometries (false for point / curve, true otherwise)
|
||||
* \note used for vertex_iterator implementation
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual bool hasChildGeometries() const;
|
||||
|
||||
/**
|
||||
* Returns number of child geometries (for geometries with child geometries) or child points (for geometries without child geometries - i.e. curve / point)
|
||||
* \note used for vertex_iterator implementation
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual int childCount() const { return 0; }
|
||||
|
||||
/**
|
||||
* Returns pointer to child geometry (for geometries with child geometries - i.e. geom. collection / polygon)
|
||||
* \note used for vertex_iterator implementation
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const { Q_UNUSED( index ); return nullptr; }
|
||||
|
||||
/**
|
||||
* Returns point at index (for geometries without child geometries - i.e. curve / point)
|
||||
* \note used for vertex_iterator implementation
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QgsPoint childPoint( int index ) const;
|
||||
|
||||
protected:
|
||||
QgsWkbTypes::Type mWkbType = QgsWkbTypes::Unknown;
|
||||
|
||||
@ -554,4 +663,51 @@ inline T qgsgeometry_cast( const QgsAbstractGeometry *geom )
|
||||
|
||||
// clazy:excludeall=qstring-allocations
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief Java-style iterator for traversal of vertices of a geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsVertexIterator
|
||||
{
|
||||
public:
|
||||
QgsVertexIterator(): g( nullptr ) {}
|
||||
|
||||
//! Constructs iterator for the given geometry
|
||||
QgsVertexIterator( const QgsAbstractGeometry *geometry )
|
||||
: g( geometry )
|
||||
, i( g->vertices_begin() )
|
||||
, n( g->vertices_end() )
|
||||
{
|
||||
}
|
||||
|
||||
//! Find out whether there are more vertices
|
||||
bool hasNext() const
|
||||
{
|
||||
return g && g->vertices_end() != i;
|
||||
}
|
||||
|
||||
//! Return next vertex of the geometry (undefined behavior if hasNext() returns false before calling next())
|
||||
QgsPoint next();
|
||||
|
||||
#ifdef SIP_RUN
|
||||
QgsVertexIterator *__iter__();
|
||||
% MethodCode
|
||||
sipRes = sipCpp;
|
||||
% End
|
||||
|
||||
SIP_PYOBJECT __next__();
|
||||
% MethodCode
|
||||
if ( sipCpp->hasNext() )
|
||||
sipRes = sipConvertFromType( new QgsPoint( sipCpp->next() ), sipType_QgsPoint, Py_None );
|
||||
else
|
||||
PyErr_SetString( PyExc_StopIteration, "" );
|
||||
% End
|
||||
#endif
|
||||
|
||||
private:
|
||||
const QgsAbstractGeometry *g;
|
||||
QgsAbstractGeometry::vertex_iterator i, n;
|
||||
};
|
||||
|
||||
#endif //QGSABSTRACTGEOMETRYV2
|
||||
|
@ -156,3 +156,16 @@ void QgsCurve::clearCache() const
|
||||
QgsAbstractGeometry::clearCache();
|
||||
}
|
||||
|
||||
int QgsCurve::childCount() const
|
||||
{
|
||||
return numPoints();
|
||||
}
|
||||
|
||||
QgsPoint QgsCurve::childPoint( int index ) const
|
||||
{
|
||||
QgsPoint point;
|
||||
QgsVertexId::VertexType type;
|
||||
bool res = pointAt( index, point, type );
|
||||
Q_ASSERT( res );
|
||||
return point;
|
||||
}
|
||||
|
@ -184,6 +184,9 @@ class CORE_EXPORT QgsCurve: public QgsAbstractGeometry
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
virtual int childCount() const override;
|
||||
virtual QgsPoint childPoint( int index ) const override;
|
||||
|
||||
private:
|
||||
|
||||
mutable QgsRectangle mBoundingBox;
|
||||
|
@ -989,3 +989,16 @@ QgsCurvePolygon *QgsCurvePolygon::toCurveType() const
|
||||
{
|
||||
return clone();
|
||||
}
|
||||
|
||||
int QgsCurvePolygon::childCount() const
|
||||
{
|
||||
return 1 + mInteriorRings.count();
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsCurvePolygon::childGeometry( int index ) const
|
||||
{
|
||||
if ( index == 0 )
|
||||
return mExteriorRing.get();
|
||||
else
|
||||
return mInteriorRings.at( index - 1 );
|
||||
}
|
||||
|
@ -171,6 +171,10 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
protected:
|
||||
virtual int childCount() const override;
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const override;
|
||||
|
||||
protected:
|
||||
|
||||
std::unique_ptr< QgsCurve > mExteriorRing;
|
||||
|
@ -1551,6 +1551,27 @@ double QgsGeometry::hausdorffDistanceDensify( const QgsGeometry &geom, double de
|
||||
return g.hausdorffDistanceDensify( geom.d->geometry.get(), densifyFraction, &mLastError );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry::vertex_iterator QgsGeometry::vertices_begin() const
|
||||
{
|
||||
if ( !d->geometry )
|
||||
return QgsAbstractGeometry::vertex_iterator();
|
||||
return d->geometry->vertices_begin();
|
||||
}
|
||||
|
||||
QgsAbstractGeometry::vertex_iterator QgsGeometry::vertices_end() const
|
||||
{
|
||||
if ( !d->geometry )
|
||||
return QgsAbstractGeometry::vertex_iterator();
|
||||
return d->geometry->vertices_end();
|
||||
}
|
||||
|
||||
QgsVertexIterator QgsGeometry::vertices() const
|
||||
{
|
||||
if ( !d->geometry )
|
||||
return QgsVertexIterator();
|
||||
return QgsVertexIterator( d->geometry.get() );
|
||||
}
|
||||
|
||||
QgsGeometry QgsGeometry::buffer( double distance, int segments ) const
|
||||
{
|
||||
if ( !d->geometry )
|
||||
|
@ -281,6 +281,27 @@ class CORE_EXPORT QgsGeometry
|
||||
*/
|
||||
double distance( const QgsGeometry &geom ) const;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* Returns STL-style iterator pointing to the first vertex of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsAbstractGeometry::vertex_iterator vertices_begin() const;
|
||||
|
||||
/**
|
||||
* Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsAbstractGeometry::vertex_iterator vertices_end() const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns Java-style iterator for traversal of vertices of the geometry
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsVertexIterator vertices() const;
|
||||
|
||||
/**
|
||||
* Returns the Hausdorff distance between this geometry and \a geom. This is basically a measure of how similar or dissimilar 2 geometries are.
|
||||
*
|
||||
|
@ -733,3 +733,13 @@ bool QgsGeometryCollection::wktOmitChildType() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int QgsGeometryCollection::childCount() const
|
||||
{
|
||||
return mGeometries.count();
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsGeometryCollection::childGeometry( int index ) const
|
||||
{
|
||||
return mGeometries.at( index );
|
||||
}
|
||||
|
@ -157,6 +157,10 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual int childCount() const override;
|
||||
virtual QgsAbstractGeometry *childGeometry( int index ) const override;
|
||||
|
||||
protected:
|
||||
QVector< QgsAbstractGeometry * > mGeometries;
|
||||
|
||||
|
@ -644,3 +644,14 @@ int QgsPoint::dimension() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QgsPoint::childCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QgsPoint QgsPoint::childPoint( int index ) const
|
||||
{
|
||||
Q_ASSERT( index == 0 );
|
||||
return *this;
|
||||
}
|
||||
|
@ -449,6 +449,11 @@ class CORE_EXPORT QgsPoint: public QgsAbstractGeometry
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual int childCount() const override;
|
||||
virtual QgsPoint childPoint( int index ) const override;
|
||||
|
||||
private:
|
||||
double mX;
|
||||
double mY;
|
||||
|
@ -70,6 +70,7 @@ class TestQgsGeometry : public QObject
|
||||
void asVariant(); //test conversion to and from a QVariant
|
||||
void isEmpty();
|
||||
void operatorBool();
|
||||
void vertexIterator();
|
||||
|
||||
// geometry types
|
||||
void point(); //test QgsPointV2
|
||||
@ -415,6 +416,23 @@ void TestQgsGeometry::operatorBool()
|
||||
QVERIFY( !geom );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::vertexIterator()
|
||||
{
|
||||
QgsGeometry geom;
|
||||
QgsVertexIterator it = geom.vertices();
|
||||
QVERIFY( !it.hasNext() );
|
||||
|
||||
QgsPolyline polyline;
|
||||
polyline << QgsPoint( 1, 2 ) << QgsPoint( 3, 4 );
|
||||
QgsGeometry geom2 = QgsGeometry::fromPolyline( polyline );
|
||||
QgsVertexIterator it2 = geom2.vertices();
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 2 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 3, 4 ) );
|
||||
QVERIFY( !it2.hasNext() );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::point()
|
||||
{
|
||||
//test QgsPointV2
|
||||
@ -769,6 +787,20 @@ void TestQgsGeometry::point()
|
||||
QCOMPARE( p22, p21 );
|
||||
QCOMPARE( v, QgsVertexId( 1, 0, 0 ) );
|
||||
|
||||
// vertex iterator
|
||||
QgsAbstractGeometry::vertex_iterator it1 = p21.vertices_begin();
|
||||
QgsAbstractGeometry::vertex_iterator it1end = p21.vertices_end();
|
||||
QCOMPARE( *it1, p21 );
|
||||
QCOMPARE( it1.vertexId(), QgsVertexId( 0, 0, 0 ) );
|
||||
++it1;
|
||||
QCOMPARE( it1, it1end );
|
||||
|
||||
// Java-style iterator
|
||||
QgsVertexIterator it2( &p21 );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), p21 );
|
||||
QVERIFY( !it2.hasNext() );
|
||||
|
||||
//vertexAt - will always be same as point
|
||||
QCOMPARE( p21.vertexAt( QgsVertexId() ), p21 );
|
||||
QCOMPARE( p21.vertexAt( QgsVertexId( 0, 0, 0 ) ), p21 );
|
||||
@ -1895,6 +1927,7 @@ void TestQgsGeometry::circularString()
|
||||
QVERIFY( !l32.nextVertex( v, p ) );
|
||||
v = QgsVertexId( 0, 0, 10 );
|
||||
QVERIFY( !l32.nextVertex( v, p ) );
|
||||
|
||||
//CircularString
|
||||
l32.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
|
||||
v = QgsVertexId( 0, 0, 2 ); //out of range
|
||||
@ -3568,6 +3601,15 @@ void TestQgsGeometry::lineString()
|
||||
QVERIFY( !l32.nextVertex( v, p ) );
|
||||
v = QgsVertexId( 0, 0, 10 );
|
||||
QVERIFY( !l32.nextVertex( v, p ) );
|
||||
|
||||
// vertex iterator on empty linestring
|
||||
QgsAbstractGeometry::vertex_iterator it1 = l32.vertices_begin();
|
||||
QCOMPARE( it1, l32.vertices_end() );
|
||||
|
||||
// Java-style iterator on empty linetring
|
||||
QgsVertexIterator it1x( &l32 );
|
||||
QVERIFY( !it1x.hasNext() );
|
||||
|
||||
//LineString
|
||||
l32.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 11, 12 ) );
|
||||
v = QgsVertexId( 0, 0, 2 ); //out of range
|
||||
@ -3591,6 +3633,24 @@ void TestQgsGeometry::lineString()
|
||||
QCOMPARE( v, QgsVertexId( 1, 0, 1 ) ); //test that part number is maintained
|
||||
QCOMPARE( p, QgsPoint( 11, 12 ) );
|
||||
|
||||
// vertex iterator
|
||||
QgsAbstractGeometry::vertex_iterator it2 = l32.vertices_begin();
|
||||
QCOMPARE( *it2, QgsPoint( 1, 2 ) );
|
||||
QCOMPARE( it2.vertexId(), QgsVertexId( 0, 0, 0 ) );
|
||||
++it2;
|
||||
QCOMPARE( *it2, QgsPoint( 11, 12 ) );
|
||||
QCOMPARE( it2.vertexId(), QgsVertexId( 0, 0, 1 ) );
|
||||
++it2;
|
||||
QCOMPARE( it2, l32.vertices_end() );
|
||||
|
||||
// Java-style iterator
|
||||
QgsVertexIterator it2x( &l32 );
|
||||
QVERIFY( it2x.hasNext() );
|
||||
QCOMPARE( it2x.next(), QgsPoint( 1, 2 ) );
|
||||
QVERIFY( it2x.hasNext() );
|
||||
QCOMPARE( it2x.next(), QgsPoint( 11, 12 ) );
|
||||
QVERIFY( !it2x.hasNext() );
|
||||
|
||||
//LineStringZ
|
||||
l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointZ, 1, 2, 3 ) << QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
|
||||
v = QgsVertexId( 0, 0, -1 );
|
||||
@ -3601,6 +3661,7 @@ void TestQgsGeometry::lineString()
|
||||
QCOMPARE( v, QgsVertexId( 0, 0, 1 ) );
|
||||
QCOMPARE( p, QgsPoint( QgsWkbTypes::PointZ, 11, 12, 13 ) );
|
||||
QVERIFY( !l32.nextVertex( v, p ) );
|
||||
|
||||
//LineStringM
|
||||
l32.setPoints( QgsPointSequence() << QgsPoint( QgsWkbTypes::PointM, 1, 2, 0, 4 ) << QgsPoint( QgsWkbTypes::PointM, 11, 12, 0, 14 ) );
|
||||
v = QgsVertexId( 0, 0, -1 );
|
||||
@ -10336,6 +10397,25 @@ void TestQgsGeometry::multiPoint()
|
||||
QgsVertexId after;
|
||||
// return error - points have no segments
|
||||
QVERIFY( boundaryMP.closestSegment( QgsPoint( 0.5, 0.5 ), closest, after ) < 0 );
|
||||
|
||||
// vertex iterator
|
||||
QgsAbstractGeometry::vertex_iterator it = boundaryMP.vertices_begin();
|
||||
QgsAbstractGeometry::vertex_iterator itEnd = boundaryMP.vertices_end();
|
||||
QCOMPARE( *it, QgsPoint( 0, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 1, 1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( it, itEnd );
|
||||
|
||||
// Java-style iterator
|
||||
QgsVertexIterator it2( &boundaryMP );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
|
||||
QVERIFY( !it2.hasNext() );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::multiLineString()
|
||||
@ -10831,6 +10911,45 @@ void TestQgsGeometry::multiLineString()
|
||||
QCOMPARE( static_cast< QgsPoint *>( mpBoundary->geometryN( 3 ) )->y(), 11.0 );
|
||||
delete boundary;
|
||||
|
||||
// vertex iterator: 2 linestrings with 3 points each
|
||||
QgsAbstractGeometry::vertex_iterator it = multiLine1.vertices_begin();
|
||||
QgsAbstractGeometry::vertex_iterator itEnd = multiLine1.vertices_end();
|
||||
QCOMPARE( *it, QgsPoint( 0, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 1, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 1, 1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10, 10 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 11, 10 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 11, 11 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( it, itEnd );
|
||||
|
||||
// Java-style iterator
|
||||
QgsVertexIterator it2( &multiLine1 );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 11, 10 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 11, 11 ) );
|
||||
QVERIFY( !it2.hasNext() );
|
||||
|
||||
// add a closed string = no boundary
|
||||
QgsLineString boundaryLine3;
|
||||
boundaryLine3.setPoints( QList<QgsPoint>() << QgsPoint( 20, 20 ) << QgsPoint( 21, 20 ) << QgsPoint( 21, 21 ) << QgsPoint( 20, 20 ) );
|
||||
@ -12726,6 +12845,102 @@ void TestQgsGeometry::multiPolygon()
|
||||
QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 1 ), 10.8 );
|
||||
QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 2 ), 10.9 );
|
||||
QCOMPARE( dynamic_cast< QgsLineString * >( multiLineBoundary->geometryN( 3 ) )->yAt( 3 ), 10.8 );
|
||||
|
||||
// vertex iterator: 2 polygons (one with just exterior ring, other with two interior rings)
|
||||
QgsAbstractGeometry::vertex_iterator it = multiPolygon1.vertices_begin();
|
||||
QgsAbstractGeometry::vertex_iterator itEnd = multiPolygon1.vertices_end();
|
||||
QCOMPARE( *it, QgsPoint( 0, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 1, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 1, 1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 0, 0 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 0, 0, 3 ) );
|
||||
++it;
|
||||
// 2nd polygon - exterior ring
|
||||
QCOMPARE( *it, QgsPoint( 10, 10 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 11, 10 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 11, 11 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10, 10 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 0, 3 ) );
|
||||
++it;
|
||||
// 2nd polygon - 1st interior ring
|
||||
QCOMPARE( *it, QgsPoint( 10.1, 10.1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.2, 10.1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.2, 10.2 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.1, 10.1 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 1, 3 ) );
|
||||
++it;
|
||||
// 2nd polygon - 2nd interior ring
|
||||
QCOMPARE( *it, QgsPoint( 10.8, 10.8 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 0 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.9, 10.8 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 1 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.9, 10.9 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 2 ) );
|
||||
++it;
|
||||
QCOMPARE( *it, QgsPoint( 10.8, 10.8 ) );
|
||||
QCOMPARE( it.vertexId(), QgsVertexId( 1, 2, 3 ) );
|
||||
++it;
|
||||
// done!
|
||||
QCOMPARE( it, itEnd );
|
||||
|
||||
// Java-style iterator
|
||||
QgsVertexIterator it2( &multiPolygon1 );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 1, 1 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 0, 0 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
// 2nd polygon - exterior ring
|
||||
QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 11, 10 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 11, 11 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10, 10 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
// 2nd polygon - 1st interior ring
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.1, 10.1 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.2, 10.1 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.2, 10.2 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.1, 10.1 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
// 2nd polygon - 2nd interior ring
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.8, 10.8 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.9, 10.8 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.9, 10.9 ) );
|
||||
QVERIFY( it2.hasNext() );
|
||||
QCOMPARE( it2.next(), QgsPoint( 10.8, 10.8 ) );
|
||||
QVERIFY( !it2.hasNext() );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::geometryCollection()
|
||||
|
@ -85,6 +85,14 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
g = QgsGeometry.fromWkt('MultiPoint ()')
|
||||
self.assertTrue(g.isEmpty())
|
||||
|
||||
def testVertexIterator(self):
|
||||
g = QgsGeometry.fromWkt('Linestring(11 12, 13 14)')
|
||||
it = g.vertices()
|
||||
self.assertEqual(next(it), QgsPoint(11, 12))
|
||||
self.assertEqual(next(it), QgsPoint(13, 14))
|
||||
with self.assertRaises(StopIteration):
|
||||
next(it)
|
||||
|
||||
def testWktPointLoading(self):
|
||||
myWKT = 'Point (10 10)'
|
||||
myGeometry = QgsGeometry.fromWkt(myWKT)
|
||||
|
Loading…
x
Reference in New Issue
Block a user