mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Merge pull request #4870 from nyalldawson/algs3
Port 4 more algs to new API
This commit is contained in:
commit
3a2710efe5
@ -27,24 +27,22 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsWkbTypes,
|
||||
QgsFeatureSink,
|
||||
QgsProcessingUtils)
|
||||
from qgis.core import (QgsFeatureSink,
|
||||
QgsProcessing,
|
||||
QgsProcessingException,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterVector, ParameterSelection, ParameterNumber
|
||||
from processing.core.outputs import OutputVector
|
||||
from processing.tools import dataobjects
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class OffsetLine(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
INPUT = 'INPUT'
|
||||
OUTPUT = 'OUTPUT'
|
||||
DISTANCE = 'DISTANCE'
|
||||
SEGMENTS = 'SEGMENTS'
|
||||
JOIN_STYLE = 'JOIN_STYLE'
|
||||
@ -57,23 +55,29 @@ class OffsetLine(QgisAlgorithm):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(ParameterVector(self.INPUT_LAYER,
|
||||
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
|
||||
self.addParameter(ParameterNumber(self.DISTANCE,
|
||||
self.tr('Distance'), default=10.0))
|
||||
self.addParameter(ParameterNumber(self.SEGMENTS,
|
||||
self.tr('Segments'), 1, default=8))
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
|
||||
[QgsProcessing.TypeVectorLine]))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
|
||||
self.tr('Distance'),
|
||||
type=QgsProcessingParameterNumber.Double,
|
||||
defaultValue=10.0))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS,
|
||||
self.tr('Segments'),
|
||||
type=QgsProcessingParameterNumber.Integer,
|
||||
minValue=1, defaultValue=8))
|
||||
self.join_styles = [self.tr('Round'),
|
||||
'Mitre',
|
||||
'Bevel']
|
||||
self.addParameter(ParameterSelection(
|
||||
self.addParameter(QgsProcessingParameterEnum(
|
||||
self.JOIN_STYLE,
|
||||
self.tr('Join style'),
|
||||
self.join_styles))
|
||||
self.addParameter(ParameterNumber(self.MITRE_LIMIT,
|
||||
self.tr('Mitre limit'), 1, default=2))
|
||||
options=self.join_styles))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.MITRE_LIMIT,
|
||||
self.tr('Mitre limit'), type=QgsProcessingParameterNumber.Double,
|
||||
minValue=1, defaultValue=2))
|
||||
|
||||
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Offset'), datatype=[dataobjects.TYPE_VECTOR_LINE]))
|
||||
self.addParameter(
|
||||
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Offset'), QgsProcessing.TypeVectorLine))
|
||||
|
||||
def name(self):
|
||||
return 'offsetline'
|
||||
@ -82,31 +86,33 @@ class OffsetLine(QgisAlgorithm):
|
||||
return self.tr('Offset line')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
source.fields(), source.wkbType(), source.sourceCrs())
|
||||
|
||||
writer = self.getOutputFromName(
|
||||
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), QgsWkbTypes.LineString, layer.crs(), context)
|
||||
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
|
||||
segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
|
||||
join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
|
||||
miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context)
|
||||
|
||||
distance = self.getParameterValue(self.DISTANCE)
|
||||
segments = int(self.getParameterValue(self.SEGMENTS))
|
||||
join_style = self.getParameterValue(self.JOIN_STYLE) + 1
|
||||
miter_limit = self.getParameterValue(self.MITRE_LIMIT)
|
||||
|
||||
features = QgsProcessingUtils.getFeatures(layer, context)
|
||||
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
output_feature = input_feature
|
||||
input_geometry = input_feature.geometry()
|
||||
if input_geometry:
|
||||
output_geometry = input_geometry.offsetCurve(distance, segments, join_style, miter_limit)
|
||||
if not output_geometry:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error calculating line offset'))
|
||||
|
||||
output_feature.setGeometry(output_geometry)
|
||||
|
||||
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
del writer
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
@ -25,21 +25,19 @@ __copyright__ = '(C) 2016, Nyall Dawson'
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsFeatureSink,
|
||||
QgsProcessingUtils,
|
||||
QgsProcessingParameterDefinition)
|
||||
from qgis.core import (QgsFeatureSink,
|
||||
QgsProcessingException,
|
||||
QgsProcessing,
|
||||
QgsProcessingParameterDefinition,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterVector, ParameterNumber
|
||||
from processing.core.outputs import OutputVector
|
||||
from processing.tools import dataobjects
|
||||
|
||||
|
||||
class Orthogonalize(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
INPUT = 'INPUT'
|
||||
OUTPUT = 'OUTPUT'
|
||||
MAX_ITERATIONS = 'MAX_ITERATIONS'
|
||||
DISTANCE_THRESHOLD = 'DISTANCE_THRESHOLD'
|
||||
ANGLE_TOLERANCE = 'ANGLE_TOLERANCE'
|
||||
@ -54,20 +52,24 @@ class Orthogonalize(QgisAlgorithm):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(ParameterVector(self.INPUT_LAYER,
|
||||
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE,
|
||||
dataobjects.TYPE_VECTOR_POLYGON]))
|
||||
self.addParameter(ParameterNumber(self.ANGLE_TOLERANCE,
|
||||
self.tr('Maximum angle tolerance (degrees)'),
|
||||
0.0, 45.0, 15.0))
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
|
||||
[QgsProcessing.TypeVectorLine,
|
||||
QgsProcessing.TypeVectorPolygon]))
|
||||
|
||||
max_iterations = ParameterNumber(self.MAX_ITERATIONS,
|
||||
self.tr('Maximum algorithm iterations'),
|
||||
1, 10000, 1000)
|
||||
self.addParameter(QgsProcessingParameterNumber(self.ANGLE_TOLERANCE,
|
||||
self.tr('Maximum angle tolerance (degrees)'),
|
||||
type=QgsProcessingParameterNumber.Double,
|
||||
minValue=0.0, maxValue=45.0, defaultValue=15.0))
|
||||
|
||||
max_iterations = QgsProcessingParameterNumber(self.MAX_ITERATIONS,
|
||||
self.tr('Maximum algorithm iterations'),
|
||||
type=QgsProcessingParameterNumber.Integer,
|
||||
minValue=1, maxValue=10000, defaultValue=1000)
|
||||
max_iterations.setFlags(max_iterations.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
|
||||
self.addParameter(max_iterations)
|
||||
|
||||
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Orthogonalized')))
|
||||
self.addParameter(
|
||||
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Orthogonalized')))
|
||||
|
||||
def name(self):
|
||||
return 'orthogonalize'
|
||||
@ -76,27 +78,31 @@ class Orthogonalize(QgisAlgorithm):
|
||||
return self.tr('Orthogonalize')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
|
||||
max_iterations = self.getParameterValue(self.MAX_ITERATIONS)
|
||||
angle_tolerance = self.getParameterValue(self.ANGLE_TOLERANCE)
|
||||
writer = self.getOutputFromName(
|
||||
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context)
|
||||
angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context)
|
||||
|
||||
features = QgsProcessingUtils.getFeatures(layer, context)
|
||||
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
source.fields(), source.wkbType(), source.sourceCrs())
|
||||
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
output_feature = input_feature
|
||||
input_geometry = input_feature.geometry()
|
||||
if input_geometry:
|
||||
output_geometry = input_geometry.orthogonalize(1.0e-8, max_iterations, angle_tolerance)
|
||||
if not output_geometry:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error orthogonalizing geometry'))
|
||||
|
||||
output_feature.setGeometry(output_geometry)
|
||||
|
||||
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
del writer
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
@ -27,25 +27,29 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.core import QgsWkbTypes, QgsField, NULL, QgsFeatureSink, QgsProcessingUtils
|
||||
from qgis.core import (QgsWkbTypes,
|
||||
QgsField,
|
||||
NULL,
|
||||
QgsFeatureSink,
|
||||
QgsProcessing,
|
||||
QgsProcessingException,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.PyQt.QtGui import QIcon
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterVector, ParameterNumber
|
||||
from processing.core.outputs import OutputVector
|
||||
from processing.tools import dataobjects
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class PoleOfInaccessibility(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
INPUT = 'INPUT'
|
||||
TOLERANCE = 'TOLERANCE'
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
OUTPUT = 'OUTPUT'
|
||||
|
||||
def icon(self):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'centroids.png'))
|
||||
@ -60,12 +64,15 @@ class PoleOfInaccessibility(QgisAlgorithm):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(ParameterVector(self.INPUT_LAYER,
|
||||
self.tr('Input layer'),
|
||||
[dataobjects.TYPE_VECTOR_POLYGON]))
|
||||
self.addParameter(ParameterNumber(self.TOLERANCE,
|
||||
self.tr('Tolerance (layer units)'), default=1.0, minValue=0.0))
|
||||
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Point'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
|
||||
[QgsProcessing.TypeVectorPolygon]))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE,
|
||||
self.tr('Tolerance (layer units)'),
|
||||
type=QgsProcessingParameterNumber.Double,
|
||||
defaultValue=1.0, minValue=0.0))
|
||||
|
||||
self.addParameter(
|
||||
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Point'), QgsProcessing.TypeVectorPoint))
|
||||
|
||||
def name(self):
|
||||
return 'poleofinaccessibility'
|
||||
@ -74,25 +81,27 @@ class PoleOfInaccessibility(QgisAlgorithm):
|
||||
return self.tr('Pole of Inaccessibility')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
|
||||
tolerance = self.getParameterValue(self.TOLERANCE)
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
|
||||
|
||||
fields = layer.fields()
|
||||
fields = source.fields()
|
||||
fields.append(QgsField('dist_pole', QVariant.Double))
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
fields, QgsWkbTypes.Point, source.sourceCrs())
|
||||
|
||||
writer = self.getOutputFromName(
|
||||
self.OUTPUT_LAYER).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)
|
||||
|
||||
features = QgsProcessingUtils.getFeatures(layer, context)
|
||||
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
output_feature = input_feature
|
||||
input_geometry = input_feature.geometry()
|
||||
if input_geometry:
|
||||
output_geometry, distance = input_geometry.poleOfInaccessibility(tolerance)
|
||||
if not output_geometry:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error calculating pole of inaccessibility'))
|
||||
attrs = input_feature.attributes()
|
||||
attrs.append(distance)
|
||||
@ -104,7 +113,7 @@ class PoleOfInaccessibility(QgisAlgorithm):
|
||||
attrs.append(NULL)
|
||||
output_feature.setAttributes(attrs)
|
||||
|
||||
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
del writer
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
@ -70,15 +70,19 @@ from .LinesToPolygons import LinesToPolygons
|
||||
from .MeanCoords import MeanCoords
|
||||
from .Merge import Merge
|
||||
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
|
||||
from .OffsetLine import OffsetLine
|
||||
from .Orthogonalize import Orthogonalize
|
||||
from .PointDistance import PointDistance
|
||||
from .PointOnSurface import PointOnSurface
|
||||
from .PointsInPolygon import PointsInPolygon
|
||||
from .PointsLayerFromTable import PointsLayerFromTable
|
||||
from .PoleOfInaccessibility import PoleOfInaccessibility
|
||||
from .PolygonsToLines import PolygonsToLines
|
||||
from .PostGISExecuteSQL import PostGISExecuteSQL
|
||||
from .RandomExtract import RandomExtract
|
||||
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
|
||||
from .RegularPoints import RegularPoints
|
||||
from .ReverseLineDirection import ReverseLineDirection
|
||||
from .Ruggedness import Ruggedness
|
||||
from .SaveSelectedFeatures import SaveSelectedFeatures
|
||||
from .SelectByAttribute import SelectByAttribute
|
||||
@ -139,13 +143,11 @@ from .ZonalStatistics import ZonalStatistics
|
||||
# from .FieldsMapper import FieldsMapper
|
||||
# from .Datasources2Vrt import Datasources2Vrt
|
||||
# from .OrientedMinimumBoundingBox import OrientedMinimumBoundingBox
|
||||
# from .ReverseLineDirection import ReverseLineDirection
|
||||
# from .SpatialIndex import SpatialIndex
|
||||
# from .DefineProjection import DefineProjection
|
||||
# from .RectanglesOvalsDiamondsVariable import RectanglesOvalsDiamondsVariable
|
||||
# from .RectanglesOvalsDiamondsFixed import RectanglesOvalsDiamondsFixed
|
||||
# from .MergeLines import MergeLines
|
||||
# from .OffsetLine import OffsetLine
|
||||
# from .Translate import Translate
|
||||
# from .SingleSidedBuffer import SingleSidedBuffer
|
||||
# from .PointsAlongGeometry import PointsAlongGeometry
|
||||
@ -155,9 +157,7 @@ from .ZonalStatistics import ZonalStatistics
|
||||
# from .ExtendLines import ExtendLines
|
||||
# from .ExtractSpecificNodes import ExtractSpecificNodes
|
||||
# from .GeometryByExpression import GeometryByExpression
|
||||
# from .PoleOfInaccessibility import PoleOfInaccessibility
|
||||
# from .RasterCalculator import RasterCalculator
|
||||
# from .Orthogonalize import Orthogonalize
|
||||
# from .ShortestPathPointToPoint import ShortestPathPointToPoint
|
||||
# from .ShortestPathPointToLayer import ShortestPathPointToLayer
|
||||
# from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
|
||||
@ -211,19 +211,16 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
# SplitWithLines(), CreateConstantRaster(),
|
||||
# FieldsMapper(), SelectByAttributeSum(), Datasources2Vrt(),
|
||||
# OrientedMinimumBoundingBox(),
|
||||
# ReverseLineDirection(), SpatialIndex(), DefineProjection(),
|
||||
# SpatialIndex(), DefineProjection(),
|
||||
# RectanglesOvalsDiamondsVariable(),
|
||||
# RectanglesOvalsDiamondsFixed(), MergeLines(),
|
||||
# OffsetLine(), Translate(),
|
||||
# Translate(),
|
||||
# SingleSidedBuffer(), PointsAlongGeometry(),
|
||||
# Slope(), Ruggedness(), Hillshade(),
|
||||
# Relief(),
|
||||
# IdwInterpolation(), TinInterpolation(),
|
||||
# ExtendLines(), ExtractSpecificNodes(),
|
||||
# GeometryByExpression(),
|
||||
# PoleOfInaccessibility(),
|
||||
#
|
||||
# RasterCalculator(), Heatmap(), Orthogonalize(),
|
||||
# RasterCalculator(),
|
||||
# ShortestPathPointToPoint(), ShortestPathPointToLayer(),
|
||||
# ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
|
||||
# ServiceAreaFromLayer(), TruncateTable(), Polygonize(),
|
||||
@ -260,15 +257,19 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
MeanCoords(),
|
||||
Merge(),
|
||||
NearestNeighbourAnalysis(),
|
||||
OffsetLine(),
|
||||
Orthogonalize(),
|
||||
PointDistance(),
|
||||
PointOnSurface(),
|
||||
PointsInPolygon(),
|
||||
PointsLayerFromTable(),
|
||||
PoleOfInaccessibility(),
|
||||
PolygonsToLines(),
|
||||
PostGISExecuteSQL(),
|
||||
RandomExtract(),
|
||||
RandomExtractWithinSubsets(),
|
||||
RegularPoints(),
|
||||
ReverseLineDirection(),
|
||||
Ruggedness(),
|
||||
SaveSelectedFeatures(),
|
||||
SelectByAttribute(),
|
||||
|
@ -25,22 +25,20 @@ __copyright__ = '(C) 2015, Nyall Dawson'
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsGeometry,
|
||||
from qgis.core import (QgsGeometry,
|
||||
QgsFeature,
|
||||
QgsFeatureSink,
|
||||
QgsProcessingUtils)
|
||||
QgsProcessingException,
|
||||
QgsProcessing,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterVector
|
||||
from processing.core.outputs import OutputVector
|
||||
from processing.tools import dataobjects
|
||||
|
||||
|
||||
class ReverseLineDirection(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
INPUT = 'INPUT'
|
||||
OUTPUT = 'OUTPUT'
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector geometry tools')
|
||||
@ -49,9 +47,10 @@ class ReverseLineDirection(QgisAlgorithm):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(ParameterVector(self.INPUT_LAYER,
|
||||
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
|
||||
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Reversed'), datatype=[dataobjects.TYPE_VECTOR_LINE]))
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
|
||||
[QgsProcessing.TypeVectorLine]))
|
||||
self.addParameter(
|
||||
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Reversed'), QgsProcessing.TypeVectorLine))
|
||||
|
||||
def name(self):
|
||||
return 'reverselinedirection'
|
||||
@ -60,30 +59,28 @@ class ReverseLineDirection(QgisAlgorithm):
|
||||
return self.tr('Reverse line direction')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
|
||||
writer = self.getOutputFromName(
|
||||
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
source.fields(), source.wkbType(), source.sourceCrs())
|
||||
|
||||
outFeat = QgsFeature()
|
||||
|
||||
features = QgsProcessingUtils.getFeatures(layer, context)
|
||||
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
for current, inFeat in enumerate(features):
|
||||
inGeom = inFeat.geometry()
|
||||
attrs = inFeat.attributes()
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
outGeom = None
|
||||
if not inGeom.isNull():
|
||||
outFeat = inFeat
|
||||
if inFeat.geometry():
|
||||
inGeom = inFeat.geometry()
|
||||
reversedLine = inGeom.geometry().reversed()
|
||||
if not reversedLine:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error reversing line'))
|
||||
outGeom = QgsGeometry(reversedLine)
|
||||
|
||||
outFeat.setGeometry(outGeom)
|
||||
outFeat.setAttributes(attrs)
|
||||
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
|
||||
outFeat.setGeometry(outGeom)
|
||||
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
del writer
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
16
python/plugins/processing/tests/testdata/expected/lines_reversed.gfs
vendored
Normal file
16
python/plugins/processing/tests/testdata/expected/lines_reversed.gfs
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>lines_reversed</Name>
|
||||
<ElementPath>lines_reversed</ElementPath>
|
||||
<!--LINESTRING-->
|
||||
<GeometryType>2</GeometryType>
|
||||
<SRSName>EPSG:4326</SRSName>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>7</FeatureCount>
|
||||
<ExtentXMin>-1.00000</ExtentXMin>
|
||||
<ExtentXMax>11.00000</ExtentXMax>
|
||||
<ExtentYMin>-3.00000</ExtentYMin>
|
||||
<ExtentYMax>5.00000</ExtentYMax>
|
||||
</DatasetSpecificInfo>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
48
python/plugins/processing/tests/testdata/expected/lines_reversed.gml
vendored
Normal file
48
python/plugins/processing/tests/testdata/expected/lines_reversed.gml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>11</gml:X><gml:Y>5</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.0">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>11,5 9,3 9,2 6,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.1">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,-1 -1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.2">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,3 3,2 2,2 2,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.3">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,1 3,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.4">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>10,-3 7,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.5">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>10,1 6,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:lines_reversed fid="lines.6">
|
||||
</ogr:lines_reversed>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
@ -13,12 +13,12 @@
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:multiline_offset fid="lines.1">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,0 1,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>-1,0 1,0</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
|
||||
</ogr:multiline_offset>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:multiline_offset fid="lines.2">
|
||||
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>3,2 5,2</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>6.024038190337471,2.397687750474408 5.999853929301003,0.982908479841009</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
|
||||
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>3,2 5,2</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>6.02403819033747,2.39768775047441 5.999853929301,0.982908479841009</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
|
||||
</ogr:multiline_offset>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
@ -27,7 +27,7 @@
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:multiline_offset fid="lines.4">
|
||||
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>1,0 1,2 1.01921471959677,2.195090322016128 1.076120467488713,2.38268343236509 1.168530387697455,2.555570233019602 1.292893218813453,2.707106781186547 1.444429766980398,2.831469612302545 1.61731656763491,2.923879532511287 1.804909677983872,2.98078528040323 2,3</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>2.915503652020259,5.046801099766013 5.430666799812965,5.119353882875417</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>3.020599614854323,3.999787805420657 5.601021879729563,3.946620818856359</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
|
||||
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>1,0 1,2 1.01921471959677,2.19509032201613 1.07612046748871,2.38268343236509 1.16853038769745,2.5555702330196 1.29289321881345,2.70710678118655 1.4444297669804,2.83146961230255 1.61731656763491,2.92387953251129 1.80490967798387,2.98078528040323 2,3</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>2.91550365202026,5.04680109976601 5.43066679981296,5.11935388287542</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>3.02059961485432,3.99978780542066 5.60102187972956,3.94662081885636</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
|
||||
</ogr:multiline_offset>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
||||
|
@ -555,96 +555,110 @@ tests:
|
||||
name: expected/point_on_line.gml
|
||||
type: vector
|
||||
|
||||
# - algorithm: qgis:offsetline
|
||||
# name: Offset line positive
|
||||
# params:
|
||||
# DISTANCE: 1.0
|
||||
# INPUT_LAYER:
|
||||
# name: lines.gml
|
||||
# type: vector
|
||||
# JOIN_STYLE: '0'
|
||||
# MITRE_LIMIT: 2
|
||||
# SEGMENTS: 8
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/line_offset_round_positive.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:offsetline
|
||||
# name: Offset line negative
|
||||
# params:
|
||||
# DISTANCE: -1.0
|
||||
# INPUT_LAYER:
|
||||
# name: lines.gml
|
||||
# type: vector
|
||||
# JOIN_STYLE: '0'
|
||||
# MITRE_LIMIT: 2
|
||||
# SEGMENTS: 8
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/line_offset_round_negative.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:offsetline
|
||||
# name: Offset line mitre
|
||||
# params:
|
||||
# DISTANCE: 1.0
|
||||
# INPUT_LAYER:
|
||||
# name: lines.gml
|
||||
# type: vector
|
||||
# JOIN_STYLE: '1'
|
||||
# MITRE_LIMIT: 2
|
||||
# SEGMENTS: 4
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/line_offset_mitre.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:offsetline
|
||||
# name: Offset line bevel
|
||||
# params:
|
||||
# DISTANCE: 1.0
|
||||
# INPUT_LAYER:
|
||||
# name: lines.gml
|
||||
# type: vector
|
||||
# JOIN_STYLE: '2'
|
||||
# MITRE_LIMIT: 2
|
||||
# SEGMENTS: 8
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/line_offset_bevel.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:offsetline
|
||||
# name: Offset multilines
|
||||
# params:
|
||||
# DISTANCE: 1.0
|
||||
# INPUT_LAYER:
|
||||
# name: multilines.gml
|
||||
# type: vector
|
||||
# JOIN_STYLE: '0'
|
||||
# MITRE_LIMIT: 2
|
||||
# SEGMENTS: 8
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/multiline_offset.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
- algorithm: qgis:reverselinedirection
|
||||
name: Reverse line direction
|
||||
params:
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/lines_reversed.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:offsetline
|
||||
name: Offset line positive
|
||||
params:
|
||||
DISTANCE: 1.0
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
JOIN_STYLE: '0'
|
||||
MITRE_LIMIT: 2
|
||||
SEGMENTS: 8
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/line_offset_round_positive.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:offsetline
|
||||
name: Offset line negative
|
||||
params:
|
||||
DISTANCE: -1.0
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
JOIN_STYLE: '0'
|
||||
MITRE_LIMIT: 2
|
||||
SEGMENTS: 8
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/line_offset_round_negative.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:offsetline
|
||||
name: Offset line mitre
|
||||
params:
|
||||
DISTANCE: 1.0
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
JOIN_STYLE: '1'
|
||||
MITRE_LIMIT: 2
|
||||
SEGMENTS: 4
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/line_offset_mitre.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:offsetline
|
||||
name: Offset line bevel
|
||||
params:
|
||||
DISTANCE: 1.0
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
JOIN_STYLE: '2'
|
||||
MITRE_LIMIT: 2
|
||||
SEGMENTS: 8
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/line_offset_bevel.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:offsetline
|
||||
name: Offset multilines
|
||||
params:
|
||||
DISTANCE: 1.0
|
||||
INPUT:
|
||||
name: multilines.gml
|
||||
type: vector
|
||||
JOIN_STYLE: '0'
|
||||
MITRE_LIMIT: 2
|
||||
SEGMENTS: 8
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/multiline_offset.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
# - algorithm: qgis:fixeddistancebuffer
|
||||
# name: Buffer polygons using bevel
|
||||
# params:
|
||||
@ -1481,21 +1495,21 @@ tests:
|
||||
name: expected/snap_internal.gml
|
||||
type: vector
|
||||
|
||||
# - algorithm: qgis:poleofinaccessibility
|
||||
# name: Pole of inaccessibility (polygons)
|
||||
# params:
|
||||
# INPUT_LAYER:
|
||||
# name: polys.gml
|
||||
# type: vector
|
||||
# TOLERANCE: 1.0e-05
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/pole_inaccessibility_polys.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
- algorithm: qgis:poleofinaccessibility
|
||||
name: Pole of inaccessibility (polygons)
|
||||
params:
|
||||
INPUT:
|
||||
name: polys.gml
|
||||
type: vector
|
||||
TOLERANCE: 1.0e-05
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/pole_inaccessibility_polys.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: native:extractbyattribute
|
||||
name: Extract by attribute (is null)
|
||||
params:
|
||||
@ -1945,34 +1959,34 @@ tests:
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:orthogonalize
|
||||
# name: Orthogonalize polys
|
||||
# params:
|
||||
# INPUT_LAYER:
|
||||
# name: custom/polys_to_orth.gml
|
||||
# type: vector
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/orthagonal_polys.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
#
|
||||
# - algorithm: qgis:orthogonalize
|
||||
# name: Orthogonalize lines
|
||||
# params:
|
||||
# INPUT_LAYER:
|
||||
# name: custom/lines_to_orth.gml
|
||||
# type: vector
|
||||
# results:
|
||||
# OUTPUT_LAYER:
|
||||
# name: expected/orthagonal_lines.gml
|
||||
# type: vector
|
||||
# compare:
|
||||
# geometry:
|
||||
# precision: 7
|
||||
|
||||
- algorithm: qgis:orthogonalize
|
||||
name: Orthogonalize polys
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/polys_to_orth.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/orthagonal_polys.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
- algorithm: qgis:orthogonalize
|
||||
name: Orthogonalize lines
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/lines_to_orth.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/orthagonal_lines.gml
|
||||
type: vector
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
|
||||
|
||||
- algorithm: native:reprojectlayer
|
||||
|
@ -155,25 +155,10 @@ Cell *getCentroidCell( const QgsPolygonV2 *polygon )
|
||||
return new Cell( x / area, y / area, 0.0, polygon );
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision, double *distanceFromBoundary ) const
|
||||
QgsPoint surfacePoleOfInaccessibility( const QgsSurface *surface, double precision, double &distanceFromBoundary )
|
||||
{
|
||||
if ( distanceFromBoundary )
|
||||
*distanceFromBoundary = DBL_MAX;
|
||||
|
||||
if ( !mGeometry || mGeometry->isEmpty() )
|
||||
return QgsGeometry();
|
||||
|
||||
if ( precision <= 0 )
|
||||
return QgsGeometry();
|
||||
|
||||
const QgsSurface *surface = dynamic_cast< const QgsSurface * >( mGeometry );
|
||||
if ( !surface )
|
||||
return QgsGeometry();
|
||||
|
||||
std::unique_ptr< QgsPolygonV2 > segmentizedPoly;
|
||||
const QgsPolygonV2 *polygon = dynamic_cast< const QgsPolygonV2 * >( mGeometry );
|
||||
const QgsPolygonV2 *polygon = dynamic_cast< const QgsPolygonV2 * >( surface );
|
||||
if ( !polygon )
|
||||
{
|
||||
segmentizedPoly.reset( static_cast< QgsPolygonV2 *>( surface->segmentize() ) );
|
||||
@ -187,7 +172,7 @@ QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision,
|
||||
double cellSize = qMin( bounds.width(), bounds.height() );
|
||||
|
||||
if ( qgsDoubleNear( cellSize, 0.0 ) )
|
||||
return QgsGeometry( new QgsPoint( bounds.xMinimum(), bounds.yMinimum() ) );
|
||||
return QgsPoint( bounds.xMinimum(), bounds.yMinimum() );
|
||||
|
||||
double h = cellSize / 2.0;
|
||||
std::priority_queue< Cell *, std::vector<Cell *>, GreaterThanByMax > cellQueue;
|
||||
@ -238,15 +223,70 @@ QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision,
|
||||
cellQueue.push( new Cell( currentCell->x + h, currentCell->y + h, h, polygon ) );
|
||||
}
|
||||
|
||||
if ( distanceFromBoundary )
|
||||
*distanceFromBoundary = bestCell->d;
|
||||
distanceFromBoundary = bestCell->d;
|
||||
|
||||
return QgsGeometry( new QgsPoint( bestCell->x, bestCell->y ) );
|
||||
return QgsPoint( bestCell->x, bestCell->y );
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision, double *distanceFromBoundary ) const
|
||||
{
|
||||
if ( distanceFromBoundary )
|
||||
*distanceFromBoundary = DBL_MAX;
|
||||
|
||||
if ( !mGeometry || mGeometry->isEmpty() )
|
||||
return QgsGeometry();
|
||||
|
||||
if ( precision <= 0 )
|
||||
return QgsGeometry();
|
||||
|
||||
if ( const QgsGeometryCollection *gc = dynamic_cast< const QgsGeometryCollection *>( mGeometry ) )
|
||||
{
|
||||
int numGeom = gc->numGeometries();
|
||||
double maxDist = 0;
|
||||
QgsPoint bestPoint;
|
||||
bool found = false;
|
||||
for ( int i = 0; i < numGeom; ++i )
|
||||
{
|
||||
const QgsSurface *surface = dynamic_cast< const QgsSurface * >( gc->geometryN( i ) );
|
||||
if ( !surface )
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
double dist = DBL_MAX;
|
||||
QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
|
||||
if ( dist > maxDist )
|
||||
{
|
||||
maxDist = dist;
|
||||
bestPoint = p;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
return QgsGeometry();
|
||||
|
||||
if ( distanceFromBoundary )
|
||||
*distanceFromBoundary = maxDist;
|
||||
return QgsGeometry( new QgsPoint( bestPoint ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const QgsSurface *surface = dynamic_cast< const QgsSurface * >( mGeometry );
|
||||
if ( !surface )
|
||||
return QgsGeometry();
|
||||
|
||||
double dist = DBL_MAX;
|
||||
QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
|
||||
if ( distanceFromBoundary )
|
||||
*distanceFromBoundary = dist;
|
||||
return QgsGeometry( new QgsPoint( p ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// helpers for orthogonalize
|
||||
// adapted from original code in potlach/id osm editor
|
||||
// adapted from original code in potlatch/id osm editor
|
||||
|
||||
bool dotProductWithinAngleTolerance( double dotProduct, double lowerThreshold, double upperThreshold )
|
||||
{
|
||||
|
@ -5451,6 +5451,13 @@ void TestQgsGeometry::poleOfInaccessibility()
|
||||
point = curved.poleOfInaccessibility( 0.01 ).asPoint();
|
||||
QGSCOMPARENEAR( point.x(), -0.4324, 0.0001 );
|
||||
QGSCOMPARENEAR( point.y(), -0.2434, 0.0001 );
|
||||
|
||||
// multipolygon
|
||||
QgsGeometry multiPoly = QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon (((0 0, 10 0, 10 10, 0 10, 0 0)),((30 30, 50 30, 50 60, 30 60, 30 30)))" ) );
|
||||
point = multiPoly.poleOfInaccessibility( 0.01, &distance ).asPoint();
|
||||
QGSCOMPARENEAR( point.x(), 40, 0.0001 );
|
||||
QGSCOMPARENEAR( point.y(), 45, 0.0001 );
|
||||
QGSCOMPARENEAR( distance, 10.0, 0.00001 );
|
||||
}
|
||||
|
||||
void TestQgsGeometry::makeValid()
|
||||
|
Loading…
x
Reference in New Issue
Block a user