Skip to content

Commit

Permalink
Improvements to QgsAbstractGeometry::snappedToGrid
Browse files Browse the repository at this point in the history
- Fix loss of coordinates when not rounding a particular dimension
- Don't segmentize curved geometries
- Add extra unit tests
- Make createEmptyWithSameType() protected and skip from Python bindings.
This method relies on low-level manipulation of the returned geometry
which we do not want to expose as public/fixed API
  • Loading branch information
nyalldawson committed Oct 27, 2017
1 parent 3f5b11b commit c67e398
Show file tree
Hide file tree
Showing 48 changed files with 470 additions and 301 deletions.
23 changes: 5 additions & 18 deletions python/core/geometry/qgsabstractgeometry.sip
Expand Up @@ -71,16 +71,6 @@ class QgsAbstractGeometry
virtual ~QgsAbstractGeometry();
QgsAbstractGeometry( const QgsAbstractGeometry &geom );

virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 /Factory/;
%Docstring
Makes a new geometry with the same class and same WKB and transfers ownership.
To create it, the geometry is default constructedand then the WKB is changed.
:return: the new empty geometry. Callee takes ownership.
.. seealso:: clone
.. versionadded:: 3.0
:rtype: QgsAbstractGeometry
%End

virtual QgsAbstractGeometry *clone() const = 0 /Factory/;
%Docstring
Clones the geometry by performing a deep copy
Expand Down Expand Up @@ -412,14 +402,14 @@ Returns the centroid of the geometry
:rtype: QgsAbstractGeometry
%End

virtual QgsAbstractGeometry *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0, double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const = 0 /Factory/;
virtual QgsAbstractGeometry *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const = 0 /Factory/;
%Docstring
Makes a new geometry with all the points or vertices snapped to the closest point of the grid.
It transfers ownership to the callee.
If it couldn't make the gridified geometry it returns None.
Ownership is transferred to the caller.

If the gridified geometry could not be calculated a None will be returned.
It may generate an invalid geometry (in some corner cases).
It can also be thought as rounding the edges and it may be useful for removing errors.
If the geometry is curved, it will be segmentized before gridifying it.
Example:
\code
geometry->snappedToGrid(1, 1);
Expand All @@ -430,10 +420,6 @@ Returns the centroid of the geometry
\param vSpacing Vertical spacing of the grid (y axis). 0 to disable.
\param dSpacing Depth spacing of the grid (z axis). 0 (default) to disable.
\param mSpacing Custom dimension spacing of the grid (m axis). 0 (default) to disable.
\param tolerance In case of segmentation, the tolerance to use (passed to segmentize as is).
\param toleranceType In case of segmentation, the toleranceType to use (passed to segmentize as is).
:return: the segmentized geometry or None if it wasn't possible to make. Caller takes ownership.
.. seealso:: segmentize
.. versionadded:: 3.0
:rtype: QgsAbstractGeometry
%End
Expand Down Expand Up @@ -528,6 +514,7 @@ Returns the centroid of the geometry

protected:


virtual bool hasChildGeometries() const;
%Docstring
Returns whether the geometry has any child geometries (false for point / curve, true otherwise)
Expand Down
31 changes: 25 additions & 6 deletions python/core/geometry/qgscircularstring.sip
Expand Up @@ -25,17 +25,24 @@ class QgsCircularString: QgsCurve
QgsCircularString();

virtual bool operator==( const QgsCurve &other ) const;

virtual bool operator!=( const QgsCurve &other ) const;


virtual QString geometryType() const;

virtual int dimension() const;
virtual QgsCircularString *createEmptyWithSameType() const /Factory/;

virtual QgsCircularString *clone() const /Factory/;

virtual void clear();


virtual bool fromWkb( QgsConstWkbPtr &wkb );

virtual bool fromWkt( const QString &wkt );


virtual QByteArray asWkb() const;

virtual QString asWkt( int precision = 17 ) const;
Expand Down Expand Up @@ -67,10 +74,14 @@ class QgsCircularString: QgsCurve
%End

virtual double length() const;

virtual QgsPoint startPoint() const;

virtual QgsPoint endPoint() const;


virtual QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

%Docstring
Returns a new line string geometry corresponding to a segmentized approximation
of the curve.
Expand All @@ -82,6 +93,9 @@ class QgsCircularString: QgsCurve
:rtype: QgsLineString
%End

virtual QgsCircularString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;


virtual void draw( QPainter &p ) const;

virtual void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform,
Expand All @@ -90,17 +104,15 @@ class QgsCircularString: QgsCurve

virtual void addToPainterPath( QPainterPath &path ) const;


virtual void drawAsPolygon( QPainter &p ) const;


virtual bool insertVertex( QgsVertexId position, const QgsPoint &vertex );

virtual bool moveVertex( QgsVertexId position, const QgsPoint &newPos );

virtual bool deleteVertex( QgsVertexId position );

virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/,
QgsVertexId &vertexAfter /Out/,
bool *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const;
virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, bool *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const;

virtual bool pointAt( int node, QgsPoint &point, QgsVertexId::VertexType &type ) const;

Expand All @@ -120,21 +132,28 @@ class QgsCircularString: QgsCurve

virtual QgsCircularString *reversed() const /Factory/;


virtual bool addZValue( double zValue = 0 );

virtual bool addMValue( double mValue = 0 );


virtual bool dropZValue();

virtual bool dropMValue();


virtual double xAt( int index ) const;

virtual double yAt( int index ) const;


protected:
virtual QgsCircularString *createEmptyWithSameType() const /Factory/;

virtual QgsRectangle calculateBoundingBox() const;


};


Expand Down
34 changes: 28 additions & 6 deletions python/core/geometry/qgscompoundcurve.sip
Expand Up @@ -25,17 +25,24 @@ class QgsCompoundCurve: QgsCurve
~QgsCompoundCurve();

virtual bool operator==( const QgsCurve &other ) const;

virtual bool operator!=( const QgsCurve &other ) const;


virtual QString geometryType() const;

virtual int dimension() const;
virtual QgsCompoundCurve *createEmptyWithSameType() const /Factory/;

virtual QgsCompoundCurve *clone() const /Factory/;

virtual void clear();


virtual bool fromWkb( QgsConstWkbPtr &wkb );

virtual bool fromWkt( const QString &wkt );


virtual QByteArray asWkb() const;

virtual QString asWkt( int precision = 17 ) const;
Expand All @@ -48,14 +55,20 @@ class QgsCompoundCurve: QgsCurve


virtual double length() const;

virtual QgsPoint startPoint() const;

virtual QgsPoint endPoint() const;

virtual void points( QgsPointSequence &pts /Out/ ) const;

virtual int numPoints() const;

virtual bool isEmpty() const;


virtual QgsLineString *curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

%Docstring
Returns a new line string geometry corresponding to a segmentized approximation
of the curve.
Expand All @@ -64,6 +77,9 @@ class QgsCompoundCurve: QgsCurve
:rtype: QgsLineString
%End

virtual QgsCompoundCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;


int nCurves() const;
%Docstring
Returns the number of curves in the geometry.
Expand Down Expand Up @@ -102,18 +118,16 @@ class QgsCompoundCurve: QgsCurve

virtual void drawAsPolygon( QPainter &p ) const;


virtual bool insertVertex( QgsVertexId position, const QgsPoint &vertex );

virtual bool moveVertex( QgsVertexId position, const QgsPoint &newPos );

virtual bool deleteVertex( QgsVertexId position );

virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/,
QgsVertexId &vertexAfter /Out/, bool *leftOf /Out/ = 0,
double epsilon = 4 * DBL_EPSILON ) const;
virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, bool *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const;

virtual bool pointAt( int node, QgsPoint &point, QgsVertexId::VertexType &type ) const;


virtual void sumUpArea( double &sum /Out/ ) const;


Expand All @@ -136,12 +150,17 @@ Appends first point if not already closed.

virtual QgsCompoundCurve *reversed() const /Factory/;


virtual bool addZValue( double zValue = 0 );

virtual bool addMValue( double mValue = 0 );


virtual bool dropZValue();

virtual bool dropMValue();


virtual double xAt( int index ) const;

virtual double yAt( int index ) const;
Expand All @@ -151,6 +170,9 @@ Appends first point if not already closed.

virtual QgsRectangle calculateBoundingBox() const;

virtual QgsCompoundCurve *createEmptyWithSameType() const /Factory/;


};


Expand Down
3 changes: 1 addition & 2 deletions python/core/geometry/qgscurve.sip
Expand Up @@ -126,8 +126,6 @@ class QgsCurve: QgsAbstractGeometry

virtual QgsAbstractGeometry *boundary() const /Factory/;

virtual QgsCurve *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

virtual QgsCurve *segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

Expand Down Expand Up @@ -186,6 +184,7 @@ class QgsCurve: QgsAbstractGeometry
virtual int childCount() const;
virtual QgsPoint childPoint( int index ) const;


};

/************************************************************************
Expand Down
11 changes: 8 additions & 3 deletions python/core/geometry/qgscurvepolygon.sip
Expand Up @@ -35,7 +35,7 @@ class QgsCurvePolygon: QgsSurface
virtual QString geometryType() const;

virtual int dimension() const;
virtual QgsCurvePolygon *createEmptyWithSameType() const /Factory/;

virtual QgsCurvePolygon *clone() const /Factory/;

virtual void clear();
Expand Down Expand Up @@ -64,8 +64,9 @@ class QgsCurvePolygon: QgsSurface
virtual QgsPolygonV2 *surfaceToPolygon() const /Factory/;

virtual QgsAbstractGeometry *boundary() const /Factory/;
virtual QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

virtual QgsCurvePolygon *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;


int numInteriorRings() const;
%Docstring
Expand Down Expand Up @@ -197,9 +198,13 @@ Adds an interior ring to the geometry (takes ownership)
virtual QgsCurvePolygon *toCurveType() const /Factory/;

protected:
virtual QgsCurvePolygon *createEmptyWithSameType() const /Factory/;

virtual int childCount() const;

virtual QgsAbstractGeometry *childGeometry( int index ) const;


protected:


Expand Down
9 changes: 6 additions & 3 deletions python/core/geometry/qgsgeometrycollection.sip
Expand Up @@ -26,7 +26,6 @@ class QgsGeometryCollection: QgsAbstractGeometry
QgsGeometryCollection( const QgsGeometryCollection &c );
virtual ~QgsGeometryCollection();

virtual QgsGeometryCollection *createEmptyWithSameType() const /Factory/;
virtual QgsGeometryCollection *clone() const /Factory/;


Expand All @@ -51,8 +50,8 @@ class QgsGeometryCollection: QgsAbstractGeometry
virtual QString geometryType() const;

virtual void clear();
virtual QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

virtual QgsGeometryCollection *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;
virtual QgsAbstractGeometry *boundary() const /Factory/;

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;
Expand Down Expand Up @@ -175,9 +174,13 @@ Adds a geometry and takes ownership. Returns true in case of success.


protected:
virtual QgsGeometryCollection *createEmptyWithSameType() const /Factory/;

virtual int childCount() const;

virtual QgsAbstractGeometry *childGeometry( int index ) const;


protected:

virtual bool wktOmitChildType() const;
Expand Down
7 changes: 4 additions & 3 deletions python/core/geometry/qgslinestring.sip
Expand Up @@ -170,15 +170,15 @@ Closes the line string by appending the first point to the end of the line, if i
virtual QString geometryType() const;

virtual int dimension() const;
virtual QgsLineString *createEmptyWithSameType() const /Factory/;

virtual QgsLineString *clone() const /Factory/;

virtual void clear();

virtual bool isEmpty() const;

virtual QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0,
double tolerance = M_PI / 180., SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;
virtual QgsLineString *snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const /Factory/;


virtual bool fromWkb( QgsConstWkbPtr &wkb );

Expand Down Expand Up @@ -270,6 +270,7 @@ Closes the line string by appending the first point to the end of the line, if i


protected:
virtual QgsLineString *createEmptyWithSameType() const /Factory/;

virtual QgsRectangle calculateBoundingBox() const;

Expand Down
7 changes: 6 additions & 1 deletion python/core/geometry/qgsmulticurve.sip
Expand Up @@ -21,7 +21,7 @@ class QgsMultiCurve: QgsGeometryCollection
public:
QgsMultiCurve();
virtual QString geometryType() const;
virtual QgsMultiCurve *createEmptyWithSameType() const /Factory/;

virtual QgsMultiCurve *clone() const /Factory/;

virtual void clear();
Expand Down Expand Up @@ -52,6 +52,11 @@ class QgsMultiCurve: QgsGeometryCollection



protected:

virtual QgsMultiCurve *createEmptyWithSameType() const /Factory/;


};


Expand Down

0 comments on commit c67e398

Please sign in to comment.