mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[FEATURE][processing] Native c++ snap to grid algorithm
With support for snapping Z/M values, keeping curves
This commit is contained in:
parent
c67e39812d
commit
4372ac2658
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
@ -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(),
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
105
src/analysis/processing/qgsalgorithmsnaptogrid.cpp
Normal file
105
src/analysis/processing/qgsalgorithmsnaptogrid.cpp
Normal 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 ¶meters, 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
|
||||
|
||||
|
61
src/analysis/processing/qgsalgorithmsnaptogrid.h
Normal file
61
src/analysis/processing/qgsalgorithmsnaptogrid.h
Normal 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 ¶meters, 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
|
||||
|
||||
|
@ -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() );
|
||||
|
@ -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)
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user