QGIS/python/plugins/processing/algs/qgis/PointsFromLines.py
Nyall Dawson f84d703234 Add method QgsProcessingUtils::mapLayerFromString
Algorithms and other processing code should use this method
(instead of dataobjects.getLayerFromString) to
retrieve layers from a string, as it considers the processing
context and allows resolving strings to temporarily stored layers.

This permits processing models to function correctly when
intermediate results are stored as memory layers. Subsequent
model algorithms can then access these temporary layers as inputs.
All temporary layers will be removed when the context object
is destroyed after the model algorithm is run.
2017-05-02 12:33:04 +10:00

202 lines
7.1 KiB
Python

# -*- coding: utf-8 -*-
"""
***************************************************************************
PointsFromLines.py
---------------------
Date : August 2013
Copyright : (C) 2013 by Alexander Bruy
Email : alexander dot bruy 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. *
* *
***************************************************************************
"""
from builtins import str
from builtins import range
__author__ = 'Alexander Bruy'
__date__ = 'August 2013'
__copyright__ = '(C) 2013, Alexander Bruy'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from osgeo import gdal
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsApplication,
QgsFeature,
QgsFields,
QgsField,
QgsGeometry,
QgsPoint,
QgsWkbTypes,
QgsProcessingUtils)
from processing.tools import vector, raster, dataobjects
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.parameters import ParameterRaster
from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector
class PointsFromLines(GeoAlgorithm):
INPUT_RASTER = 'INPUT_RASTER'
RASTER_BAND = 'RASTER_BAND'
INPUT_VECTOR = 'INPUT_VECTOR'
OUTPUT_LAYER = 'OUTPUT_LAYER'
def icon(self):
return QgsApplication.getThemeIcon("/providerQgis.svg")
def svgIconPath(self):
return QgsApplication.iconPath("providerQgis.svg")
def group(self):
return self.tr('Vector analysis tools')
def name(self):
return 'generatepointspixelcentroidsalongline'
def displayName(self):
return self.tr('Generate points (pixel centroids) along line')
def defineCharacteristics(self):
self.addParameter(ParameterRaster(self.INPUT_RASTER,
self.tr('Raster layer')))
self.addParameter(ParameterVector(self.INPUT_VECTOR,
self.tr('Vector layer'), [dataobjects.TYPE_VECTOR_LINE]))
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Points along line'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
def processAlgorithm(self, context, feedback):
layer = dataobjects.QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_VECTOR), context)
rasterPath = str(self.getParameterValue(self.INPUT_RASTER))
rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly)
geoTransform = rasterDS.GetGeoTransform()
rasterDS = None
fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
fields.append(QgsField('line_id', QVariant.Int, '', 10, 0))
fields.append(QgsField('point_id', QVariant.Int, '', 10, 0))
writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(fields.toList(), QgsWkbTypes.Point,
layer.crs(), context)
outFeature = QgsFeature()
outFeature.setFields(fields)
self.fid = 0
self.lineId = 0
self.pointId = 0
features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
for current, f in enumerate(features):
geom = f.geometry()
if geom.isMultipart():
lines = geom.asMultiPolyline()
for line in lines:
for i in range(len(line) - 1):
p1 = line[i]
p2 = line[i + 1]
(x1, y1) = raster.mapToPixel(p1.x(), p1.y(),
geoTransform)
(x2, y2) = raster.mapToPixel(p2.x(), p2.y(),
geoTransform)
self.buildLine(x1, y1, x2, y2, geoTransform,
writer, outFeature)
else:
points = geom.asPolyline()
for i in range(len(points) - 1):
p1 = points[i]
p2 = points[i + 1]
(x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform)
(x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform)
self.buildLine(x1, y1, x2, y2, geoTransform, writer,
outFeature)
self.pointId = 0
self.lineId += 1
feedback.setProgress(int(current * total))
del writer
def buildLine(self, startX, startY, endX, endY, geoTransform, writer, feature):
if startX == endX:
if startY > endY:
(startY, endY) = (endY, startY)
row = startX
for col in range(startY, endY + 1):
self.createPoint(row, col, geoTransform, writer, feature)
elif startY == endY:
if startX > endX:
(startX, endX) = (endX, startX)
col = startY
for row in range(startX, endX + 1):
self.createPoint(row, col, geoTransform, writer, feature)
else:
width = endX - startX
height = endY - startY
if width < 0:
dx1 = -1
dx2 = -1
else:
dx1 = 1
dx2 = 1
if height < 0:
dy1 = -1
else:
dy1 = 1
dy2 = 0
longest = abs(width)
shortest = abs(height)
if not longest > shortest:
(longest, shortest) = (shortest, longest)
if height < 0:
dy2 = -1
else:
dy2 = 1
dx2 = 0
err = longest / 2
for i in range(longest + 1):
self.createPoint(startX, startY, geoTransform, writer, feature)
err += shortest
if not err < longest:
err = err - longest
startX += dx1
startY += dy1
else:
startX += dx2
startY += dy2
def createPoint(self, pX, pY, geoTransform, writer, feature):
(x, y) = raster.pixelToMap(pX, pY, geoTransform)
feature.setGeometry(QgsGeometry.fromPoint(QgsPoint(x, y)))
feature['id'] = self.fid
feature['line_id'] = self.lineId
feature['point_id'] = self.pointId
self.fid += 1
self.pointId += 1
writer.addFeature(feature)