[FEATURE][processing] Native c++ snap to grid algorithm

With support for snapping Z/M values, keeping curves
This commit is contained in:
Nyall Dawson 2017-10-27 15:13:50 +10:00
parent c67e39812d
commit 4372ac2658
18 changed files with 234 additions and 245 deletions

View File

@ -514,6 +514,17 @@ Returns the centroid of the geometry
protected:
virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 /Factory/;
%Docstring
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
To create it, the geometry is default constructed and then the WKB is changed.
.. seealso:: clone()
.. versionadded:: 3.0
.. note::
Not available in Python bindings
:rtype: QgsAbstractGeometry
%End
virtual bool hasChildGeometries() const;
%Docstring

View File

@ -665,6 +665,21 @@ Returns true if WKB of the geometry is of WKBMulti* type
:rtype: QgsGeometry
%End
QgsGeometry snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const;
%Docstring
Returns a new geometry with all points or vertices snapped to the closest point of the grid.
If the gridified geometry could not be calculated (or was totally collapsed) an empty geometry will be returned.
Note that snapping to grid 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.
\param hSpacing Horizontal spacing of the grid (x axis). 0 to disable.
\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.
.. versionadded:: 3.0
:rtype: QgsGeometry
%End
bool intersects( const QgsRectangle &r ) const;
%Docstring
Tests for intersection with a rectangle (uses GEOS)

View File

@ -510,9 +510,6 @@ qgis:snapgeometries: >
Vertices will be inserted or removed as required to make the geometries match the reference geometries.
qgis:snappointstogrid: >
This algorithm modifies the position of points in a vector layer, so they fall in the coordinates of a grid.
qgis:splitwithlines: >
This algorithm splits the lines or polygons in one layer using the lines in another layer to define the breaking points. Intersection between geometries in both layers are considered as split points.

View File

@ -1,174 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
Gridify.py
---------------------
Date : May 2010
Copyright : (C) 2010 by Michael Minn
Email : pyqgis at michaelminn dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Michael Minn'
__date__ = 'May 2010'
__copyright__ = '(C) 2010, Michael Minn'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.core import (QgsGeometry,
QgsFeature,
QgsFeatureSink,
QgsPointXY,
QgsWkbTypes,
QgsApplication,
QgsProcessingException,
QgsProcessingParameterNumber)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
class Gridify(QgisFeatureBasedAlgorithm):
HSPACING = 'HSPACING'
VSPACING = 'VSPACING'
def group(self):
return self.tr('Vector geometry')
def __init__(self):
super().__init__()
self.h_spacing = None
self.v_spacing = None
def initParameters(self, config=None):
self.addParameter(QgsProcessingParameterNumber(self.HSPACING,
self.tr('Horizontal spacing'), type=QgsProcessingParameterNumber.Double, minValue=0.0, defaultValue=0.1))
self.addParameter(QgsProcessingParameterNumber(self.VSPACING,
self.tr('Vertical spacing'), type=QgsProcessingParameterNumber.Double, minValue=0.0, defaultValue=0.1))
def name(self):
return 'snappointstogrid'
def displayName(self):
return self.tr('Snap points to grid')
def outputName(self):
return self.tr('Snapped')
def prepareAlgorithm(self, parameters, context, feedback):
self.h_spacing = self.parameterAsDouble(parameters, self.HSPACING, context)
self.v_spacing = self.parameterAsDouble(parameters, self.VSPACING, context)
if self.h_spacing <= 0 or self.v_spacing <= 0:
raise QgsProcessingException(
self.tr('Invalid grid spacing: {0}/{1}').format(self.h_spacing, self.v_spacing))
return True
def processFeature(self, feature, feedback):
if feature.hasGeometry():
geom = feature.geometry()
geomType = QgsWkbTypes.flatType(geom.wkbType())
newGeom = None
if geomType == QgsWkbTypes.Point:
points = self._gridify([geom.asPoint()], self.h_spacing, self.v_spacing)
newGeom = QgsGeometry.fromPoint(points[0])
elif geomType == QgsWkbTypes.MultiPoint:
points = self._gridify(geom.asMultiPoint(), self.h_spacing, self.v_spacing)
newGeom = QgsGeometry.fromMultiPoint(points)
elif geomType == QgsWkbTypes.LineString:
points = self._gridify(geom.asPolyline(), self.h_spacing, self.v_spacing)
if len(points) < 2:
feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id()))
newGeom = None
else:
newGeom = QgsGeometry.fromPolylineXY(points)
elif geomType == QgsWkbTypes.MultiLineString:
polyline = []
for line in geom.asMultiPolyline():
points = self._gridify(line, self.h_spacing, self.v_spacing)
if len(points) > 1:
polyline.append(points)
if len(polyline) <= 0:
feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id()))
newGeom = None
else:
newGeom = QgsGeometry.fromMultiPolyline(polyline)
elif geomType == QgsWkbTypes.Polygon:
polygon = []
for line in geom.asPolygon():
points = self._gridify(line, self.h_spacing, self.v_spacing)
if len(points) > 1:
polygon.append(points)
if len(polygon) <= 0:
feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id()))
newGeom = None
else:
newGeom = QgsGeometry.fromPolygon(polygon)
elif geomType == QgsWkbTypes.MultiPolygon:
multipolygon = []
for polygon in geom.asMultiPolygon():
newPolygon = []
for line in polygon:
points = self._gridify(line, self.h_spacing, self.v_spacing)
if len(points) > 2:
newPolygon.append(points)
if len(newPolygon) > 0:
multipolygon.append(newPolygon)
if len(multipolygon) <= 0:
feedback.reportError(self.tr('Failed to gridify feature with FID {0}').format(feature.id()))
newGeom = None
else:
newGeom = QgsGeometry.fromMultiPolygon(multipolygon)
if newGeom is not None:
feature.setGeometry(newGeom)
else:
feature.clearGeometry()
return feature
def _gridify(self, points, hSpacing, vSpacing):
nPoints = []
for p in points:
nPoints.append(QgsPointXY(round(p.x() / hSpacing, 0) * hSpacing,
round(p.y() / vSpacing, 0) * vSpacing))
i = 0
# Delete overlapping points
while i < len(nPoints) - 2:
if nPoints[i] == nPoints[i + 1]:
nPoints.pop(i + 1)
else:
i += 1
i = 0
# Delete line points that go out and return to the same place
while i < len(nPoints) - 3:
if nPoints[i] == nPoints[i + 2]:
nPoints.pop(i + 1)
nPoints.pop(i + 1)
# Step back to catch arcs
if i > 0:
i -= 1
else:
i += 1
i = 0
# Delete overlapping start/end points
while len(nPoints) > 1 and nPoints[0] == nPoints[len(nPoints) - 1]:
nPoints.pop(len(nPoints) - 1)
return nPoints

View File

@ -73,7 +73,6 @@ from .FindProjection import FindProjection
from .FixedDistanceBuffer import FixedDistanceBuffer
from .GeometryConvert import GeometryConvert
from .GeometryByExpression import GeometryByExpression
from .Gridify import Gridify
from .GridLine import GridLine
from .GridPolygon import GridPolygon
from .Heatmap import Heatmap
@ -200,7 +199,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
FixedDistanceBuffer(),
GeometryByExpression(),
GeometryConvert(),
Gridify(),
GridLine(),
GridPolygon(),
Heatmap(),

View File

@ -1,16 +0,0 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>gridify_lines</Name>
<ElementPath>gridify_lines</ElementPath>
<!--LINESTRING-->
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>7</FeatureCount>
<ExtentXMin>2.00000</ExtentXMin>
<ExtentXMax>12.00000</ExtentXMax>
<ExtentYMin>-4.00000</ExtentYMin>
<ExtentYMax>4.00000</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>

View File

@ -1,23 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xsi:schemaLocation="http://ogr.maptools.org/ gridify_lines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>2</gml:X><gml:Y>-4</gml:Y></gml:coord>
<gml:coord><gml:X>12</gml:X><gml:Y>4</gml:Y></gml:coord>
<gml:coord><gml:X>-2</gml:X><gml:Y>-4</gml:Y></gml:coord>
<gml:coord><gml:X>12</gml:X><gml:Y>6</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>
<gml:featureMember>
<ogr:gridify_lines fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 8,2 8,4 12,4</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 10,2 10,4 12,6</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:gridify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_lines fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-2,-2 2,-2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:gridify_lines>
</gml:featureMember>
<gml:featureMember>
@ -27,6 +28,7 @@
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_lines fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>4,2 6,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:gridify_lines>
</gml:featureMember>
<gml:featureMember>
@ -36,7 +38,7 @@
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_lines fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-4 10,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-4 10,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:gridify_lines>
</gml:featureMember>
<gml:featureMember>

View File

@ -1,32 +0,0 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>gridify_polys</Name>
<ElementPath>gridify_polys</ElementPath>
<!--POLYGON-->
<GeometryType>3</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>6</FeatureCount>
<ExtentXMin>0.00000</ExtentXMin>
<ExtentXMax>10.00000</ExtentXMax>
<ExtentYMin>-4.00000</ExtentYMin>
<ExtentYMax>6.00000</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>name</Name>
<ElementPath>name</ElementPath>
<Type>String</Type>
<Width>5</Width>
</PropertyDefn>
<PropertyDefn>
<Name>intval</Name>
<ElementPath>intval</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
<PropertyDefn>
<Name>floatval</Name>
<ElementPath>floatval</ElementPath>
<Type>Real</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xsi:schemaLocation="http://ogr.maptools.org/ gridify_polys.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-0</gml:X><gml:Y>-4</gml:Y></gml:coord>
<gml:coord><gml:X>-2</gml:X><gml:Y>-4</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>
<gml:featureMember>
<ogr:gridify_polys fid="polys.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0,0 0,4 4,4 4,2 2,2 2,0 0,0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-2,-2 -2,4 4,4 4,2 2,2 2,-2 -2,-2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>aaaaa</ogr:name>
<ogr:intval>33</ogr:intval>
<ogr:floatval>44.123456</ogr:floatval>
@ -21,6 +21,7 @@
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_polys fid="polys.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,6 6,4 4,4 6,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>Aaaaa</ogr:name>
<ogr:intval>-33</ogr:intval>
<ogr:floatval>0</ogr:floatval>
@ -28,14 +29,13 @@
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_polys fid="polys.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,4 2,6 4,6 4,4 2,4</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>bbaaa</ogr:name>
<ogr:floatval>0.123</ogr:floatval>
</ogr:gridify_polys>
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_polys fid="polys.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,0 10,0 10,-4 6,-4 6,0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,2 10,2 10,-4 6,-4 6,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>8,0 8,-2 10,-2 10,0 8,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>ASDF</ogr:name>
<ogr:intval>0</ogr:intval>
</ogr:gridify_polys>
@ -48,7 +48,7 @@
</gml:featureMember>
<gml:featureMember>
<ogr:gridify_polys fid="polys.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,2 6,0 6,-4 2,0 2,2 4,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,2 6,2 6,-4 2,-2 2,2 4,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>elim</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>

View File

@ -2413,7 +2413,7 @@ tests:
name: expected/lines_to_polygon.gml
type: vector
- algorithm: qgis:snappointstogrid
- algorithm: native:snappointstogrid
name: Gridify polys
params:
INPUT:
@ -2426,7 +2426,7 @@ tests:
name: expected/gridify_polys.gml
type: vector
- algorithm: qgis:snappointstogrid
- algorithm: native:snappointstogrid
name: Gridify lines
params:
INPUT:

View File

@ -53,6 +53,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmsaveselectedfeatures.cpp
processing/qgsalgorithmsimplify.cpp
processing/qgsalgorithmsmooth.cpp
processing/qgsalgorithmsnaptogrid.cpp
processing/qgsalgorithmsplitwithlines.cpp
processing/qgsalgorithmstringconcatenation.cpp
processing/qgsalgorithmsubdivide.cpp

View File

@ -0,0 +1,105 @@
/***************************************************************************
qgsalgorithmsnaptogrid.cpp
--------------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmsnaptogrid.h"
///@cond PRIVATE
QString QgsSnapToGridAlgorithm::name() const
{
return QStringLiteral( "snappointstogrid" );
}
QString QgsSnapToGridAlgorithm::displayName() const
{
return QObject::tr( "Snap points to grid" );
}
QStringList QgsSnapToGridAlgorithm::tags() const
{
return QObject::tr( "snapped,grid,simplify,round,precision" ).split( ',' );
}
QString QgsSnapToGridAlgorithm::group() const
{
return QObject::tr( "Vector geometry" );
}
QString QgsSnapToGridAlgorithm::outputName() const
{
return QObject::tr( "Snapped" );
}
QString QgsSnapToGridAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm modifies the coordinates of geometries in a vector layer, so that all points "
"or vertices are snapped to the closest point of the grid.\n\n"
"If the snapped geometry could not be calculated (or was totally collapsed) then the feature's"
"geometry will be cleared.\n\n"
"Note that snapping to grid may generate an invalid geometry in some corner cases.\n\n"
"Snapping can be performed on the X, Y, Z or M axis. A grid spacing of 0 for any axis will"
"disable snapping for that axis." );
}
QgsSnapToGridAlgorithm *QgsSnapToGridAlgorithm::createInstance() const
{
return new QgsSnapToGridAlgorithm();
}
void QgsSnapToGridAlgorithm::initParameters( const QVariantMap & )
{
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "HSPACING" ),
QObject::tr( "X Grid Spacing" ), QgsProcessingParameterNumber::Double,
1, false, 0 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "VSPACING" ),
QObject::tr( "Y Grid Spacing" ), QgsProcessingParameterNumber::Double,
1, false, 0 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "ZSPACING" ),
QObject::tr( "Z Grid Spacing" ), QgsProcessingParameterNumber::Double,
0, false, 0 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MSPACING" ),
QObject::tr( "M Grid Spacing" ), QgsProcessingParameterNumber::Double,
0, false, 0 ) );
}
bool QgsSnapToGridAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mIntervalX = parameterAsDouble( parameters, QStringLiteral( "HSPACING" ), context );
mIntervalY = parameterAsDouble( parameters, QStringLiteral( "VSPACING" ), context );
mIntervalZ = parameterAsDouble( parameters, QStringLiteral( "ZSPACING" ), context );
mIntervalM = parameterAsDouble( parameters, QStringLiteral( "MSPACING" ), context );
return true;
}
QgsFeature QgsSnapToGridAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback )
{
QgsFeature f = feature;
if ( f.hasGeometry() )
{
QgsGeometry outputGeometry = f.geometry().snappedToGrid( mIntervalX, mIntervalY, mIntervalZ, mIntervalM );
if ( !outputGeometry )
{
feedback->reportError( QObject::tr( "Error snapping geometry %1" ).arg( feature.id() ) );
}
f.setGeometry( outputGeometry );
}
return f;
}
///@endcond

View File

@ -0,0 +1,61 @@
/***************************************************************************
qgsalgorithmsnaptogrid.h
---------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMSNAPTOGRID_H
#define QGSALGORITHMSNAPTOGRID_H
#define SIP_NO_FILE
#include "qgis.h"
#include "qgsprocessingalgorithm.h"
///@cond PRIVATE
/**
* Native snap to grid algorithm.
*/
class QgsSnapToGridAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{
public:
QgsSnapToGridAlgorithm() = default;
QString name() const override;
QString displayName() const override;
virtual QStringList tags() const override;
QString group() const override;
QString shortHelpString() const override;
QgsSnapToGridAlgorithm *createInstance() const override SIP_FACTORY;
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
protected:
QString outputName() const override;
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
private:
double mIntervalX = 0.0;
double mIntervalY = 0.0;
double mIntervalZ = 0.0;
double mIntervalM = 0.0;
};
///@endcond PRIVATE
#endif // QGSALGORITHMSNAPTOGRID_H

View File

@ -48,6 +48,7 @@
#include "qgsalgorithmsaveselectedfeatures.h"
#include "qgsalgorithmsimplify.h"
#include "qgsalgorithmsmooth.h"
#include "qgsalgorithmsnaptogrid.h"
#include "qgsalgorithmsplitwithlines.h"
#include "qgsalgorithmstringconcatenation.h"
#include "qgsalgorithmsubdivide.h"
@ -122,6 +123,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsSelectByLocationAlgorithm() );
addAlgorithm( new QgsSimplifyAlgorithm() );
addAlgorithm( new QgsSmoothAlgorithm() );
addAlgorithm( new QgsSnapToGridAlgorithm() );
addAlgorithm( new QgsSplitWithLinesAlgorithm() );
addAlgorithm( new QgsStringConcatenationAlgorithm() );
addAlgorithm( new QgsSubdivideAlgorithm() );

View File

@ -583,7 +583,6 @@ class CORE_EXPORT QgsAbstractGeometry
protected:
#ifndef SIP_RUN
/**
* Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
* To create it, the geometry is default constructed and then the WKB is changed.
@ -592,7 +591,6 @@ class CORE_EXPORT QgsAbstractGeometry
* \note Not available in Python bindings
*/
virtual QgsAbstractGeometry *createEmptyWithSameType() const = 0 SIP_FACTORY;
#endif
/**
* Returns whether the geometry has any child geometries (false for point / curve, true otherwise)

View File

@ -1073,6 +1073,15 @@ QgsGeometry QgsGeometry::orthogonalize( double tolerance, int maxIterations, dou
return engine.orthogonalize( tolerance, maxIterations, angleThreshold );
}
QgsGeometry QgsGeometry::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
{
if ( !d->geometry )
{
return QgsGeometry();
}
return QgsGeometry( d->geometry->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) );
}
bool QgsGeometry::intersects( const QgsRectangle &r ) const
{
QgsGeometry g = fromRect( r );

View File

@ -729,6 +729,20 @@ class CORE_EXPORT QgsGeometry
*/
QgsGeometry orthogonalize( double tolerance = 1.0E-8, int maxIterations = 1000, double angleThreshold = 15.0 ) const;
/**
* Returns a new geometry with all points or vertices snapped to the closest point of the grid.
*
* If the gridified geometry could not be calculated (or was totally collapsed) an empty geometry will be returned.
* Note that snapping to grid 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.
* \param hSpacing Horizontal spacing of the grid (x axis). 0 to disable.
* \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.
* \since 3.0
*/
QgsGeometry snappedToGrid( double hSpacing, double vSpacing, double dSpacing = 0, double mSpacing = 0 ) const;
//! Tests for intersection with a rectangle (uses GEOS)
bool intersects( const QgsRectangle &r ) const;

View File

@ -15820,8 +15820,6 @@ void TestQgsGeometry::snappedToGrid()
std::unique_ptr<QgsAbstractGeometry> snapped { curve.constGet()->snappedToGrid( 1, 1 ) };
QCOMPARE( snapped->asWkt(), QStringLiteral( "CompoundCurve ((59 402, 68 415),CircularString (68 415, 27 505, 27 406))" ) );
}
}
QGSTEST_MAIN( TestQgsGeometry )