Skip to content

Commit 8dab2cd

Browse files
committed
[FEATURE][processing] New algorithm to extend lines
Allows extending linestrings by a set distance at the start and end of the line
1 parent 2b54582 commit 8dab2cd

File tree

8 files changed

+229
-1
lines changed

8 files changed

+229
-1
lines changed

python/plugins/processing/algs/help/qgis.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ qgis:exportaddgeometrycolumns: >
158158

159159
Depending on the geometry type of the vector layer, the attributes added to the table will be different.
160160

161+
qgis:extendlines: >
162+
This algorithms extends line geometries by a specified amount at the start and end of the line. Lines are extended using the bearing of the first and last segment in the line.
163+
161164
qgis:extractbyattribute: >
162165
This algorithms creates a new vector layer that only contains matching features from an input layer. The criteria for adding features to the resulting layer is defined based on the values of an attribute from the input layer.
163166

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
ExtendLines.py
6+
--------------------
7+
Date : October 2016
8+
Copyright : (C) 2016 by Nyall Dawson
9+
Email : nyall dot dawson at gmail dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
__author__ = 'Nyall Dawson'
21+
__date__ = 'October 2016'
22+
__copyright__ = '(C) 2016, Nyall Dawson'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive323
25+
26+
__revision__ = '$Format:%H$'
27+
28+
29+
from processing.core.GeoAlgorithm import GeoAlgorithm
30+
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
31+
from processing.core.parameters import ParameterVector, ParameterNumber
32+
from processing.core.outputs import OutputVector
33+
from processing.tools import dataobjects, vector
34+
35+
36+
class ExtendLines(GeoAlgorithm):
37+
38+
INPUT_LAYER = 'INPUT_LAYER'
39+
OUTPUT_LAYER = 'OUTPUT_LAYER'
40+
START_DISTANCE = 'START_DISTANCE'
41+
END_DISTANCE = 'END_DISTANCE'
42+
43+
def defineCharacteristics(self):
44+
self.name, self.i18n_name = self.trAlgorithm('Extend lines')
45+
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')
46+
47+
self.addParameter(ParameterVector(self.INPUT_LAYER,
48+
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
49+
self.addParameter(ParameterNumber(self.START_DISTANCE,
50+
self.tr('Start distance'), default=0.0))
51+
self.addParameter(ParameterNumber(self.END_DISTANCE,
52+
self.tr('End distance'), default=0.0))
53+
54+
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Extended lines')))
55+
56+
def processAlgorithm(self, progress):
57+
layer = dataobjects.getObjectFromUri(
58+
self.getParameterValue(self.INPUT_LAYER))
59+
60+
writer = self.getOutputFromName(
61+
self.OUTPUT_LAYER).getVectorWriter(
62+
layer.fields(),
63+
layer.wkbType(),
64+
layer.crs())
65+
66+
start_distance = self.getParameterValue(self.START_DISTANCE)
67+
end_distance = self.getParameterValue(self.END_DISTANCE)
68+
69+
features = vector.features(layer)
70+
total = 100.0 / len(features)
71+
72+
for current, input_feature in enumerate(features):
73+
output_feature = input_feature
74+
input_geometry = input_feature.geometry()
75+
if input_geometry:
76+
output_geometry = input_geometry.extendLine(start_distance, end_distance)
77+
if not output_geometry:
78+
raise GeoAlgorithmExecutionException(
79+
self.tr('Error calculating extended line'))
80+
81+
output_feature.setGeometry(output_geometry)
82+
83+
writer.addFeature(output_feature)
84+
progress.setPercentage(int(current * total))
85+
86+
del writer

python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
from .TinInterpolationAttribute import TinInterpolationAttribute
172172
from .ZonalStatisticsQgis import ZonalStatisticsQgis
173173
from .RemoveNullGeometry import RemoveNullGeometry
174+
from .ExtendLines import ExtendLines
174175

175176
pluginPath = os.path.normpath(os.path.join(
176177
os.path.split(os.path.dirname(__file__))[0], os.pardir))
@@ -232,7 +233,7 @@ def __init__(self):
232233
ReliefAuto(), ZonalStatisticsQgis(),
233234
IdwInterpolationZValue(), IdwInterpolationAttribute(),
234235
TinInterpolationZValue(), TinInterpolationAttribute(),
235-
RemoveNullGeometry(), ExtractByExpression()
236+
RemoveNullGeometry(), ExtractByExpression(), ExtendLines()
236237
]
237238

238239
if hasMatplotlib:
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extend_lines</Name>
4+
<ElementPath>extend_lines</ElementPath>
5+
<GeometryType>2</GeometryType>
6+
<SRSName>EPSG:4326</SRSName>
7+
<DatasetSpecificInfo>
8+
<FeatureCount>7</FeatureCount>
9+
<ExtentXMin>-1.10000</ExtentXMin>
10+
<ExtentXMax>11.14142</ExtentXMax>
11+
<ExtentYMin>-3.07071</ExtentYMin>
12+
<ExtentYMax>5.14142</ExtentYMax>
13+
</DatasetSpecificInfo>
14+
</GMLFeatureClass>
15+
</GMLFeatureClassList>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-1.1</gml:X><gml:Y>-3.070710678118655</gml:Y></gml:coord>
10+
<gml:coord><gml:X>11.14142135623731</gml:X><gml:Y>5.141421356237309</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extend_lines fid="lines.0">
16+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5.9,2.0 9,2 9,3 11.141421356237309,5.141421356237309</gml:coordinates></gml:LineString></ogr:geometryProperty>
17+
</ogr:extend_lines>
18+
</gml:featureMember>
19+
<gml:featureMember>
20+
<ogr:extend_lines fid="lines.1">
21+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1.1,-1.0 1.2,-1.0</gml:coordinates></gml:LineString></ogr:geometryProperty>
22+
</ogr:extend_lines>
23+
</gml:featureMember>
24+
<gml:featureMember>
25+
<ogr:extend_lines fid="lines.2">
26+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2.0,-0.1 2,2 3,2 3.0,3.2</gml:coordinates></gml:LineString></ogr:geometryProperty>
27+
</ogr:extend_lines>
28+
</gml:featureMember>
29+
<gml:featureMember>
30+
<ogr:extend_lines fid="lines.3">
31+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2.9,1.0 5.2,1.0</gml:coordinates></gml:LineString></ogr:geometryProperty>
32+
</ogr:extend_lines>
33+
</gml:featureMember>
34+
<gml:featureMember>
35+
<ogr:extend_lines fid="lines.4">
36+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6.9,-3.0 10.2,-3.0</gml:coordinates></gml:LineString></ogr:geometryProperty>
37+
</ogr:extend_lines>
38+
</gml:featureMember>
39+
<gml:featureMember>
40+
<ogr:extend_lines fid="lines.5">
41+
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5.929289321881345,-3.070710678118655 10.141421356237309,1.141421356237309</gml:coordinates></gml:LineString></ogr:geometryProperty>
42+
</ogr:extend_lines>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:extend_lines fid="lines.6">
46+
</ogr:extend_lines>
47+
</gml:featureMember>
48+
</ogr:FeatureCollection>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extend_multilines</Name>
4+
<ElementPath>extend_multilines</ElementPath>
5+
<GeometryType>5</GeometryType>
6+
<SRSName>EPSG:4326</SRSName>
7+
<DatasetSpecificInfo>
8+
<FeatureCount>4</FeatureCount>
9+
<ExtentXMin>-1.20000</ExtentXMin>
10+
<ExtentXMax>5.98034</ExtentXMax>
11+
<ExtentYMin>-1.00000</ExtentYMin>
12+
<ExtentYMax>4.13130</ExtentYMax>
13+
</DatasetSpecificInfo>
14+
</GMLFeatureClass>
15+
</GMLFeatureClassList>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-1.2</gml:X><gml:Y>-1</gml:Y></gml:coord>
10+
<gml:coord><gml:X>5.980337387043503</gml:X><gml:Y>4.131303337656388</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extend_multilines fid="lines.1">
16+
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>-1.2,-1.0 1.4,-1.0</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
17+
</ogr:extend_multilines>
18+
</gml:featureMember>
19+
<gml:featureMember>
20+
<ogr:extend_multilines fid="lines.2">
21+
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>2.8,1.0 5.4,1.0</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>5.027602565068266,2.614750056493599 4.993163391936403,0.600058428279599</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
22+
</ogr:extend_multilines>
23+
</gml:featureMember>
24+
<gml:featureMember>
25+
<ogr:extend_multilines fid="lines.3">
26+
</ogr:extend_multilines>
27+
</gml:featureMember>
28+
<gml:featureMember>
29+
<ogr:extend_multilines fid="lines.4">
30+
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>2.0,-0.2 2,2 3,2 3.0,3.4</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>2.744420970065991,4.041450058619024 5.859334643361299,4.131303337656388</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>2.800042438915868,3.004119922970864 5.980337387043503,2.938593167493973</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
31+
</ogr:extend_multilines>
32+
</gml:featureMember>
33+
</ogr:FeatureCollection>

python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,3 +1225,30 @@ tests:
12251225
OUTPUT:
12261226
name: expected/extract_expression.gml
12271227
type: vector
1228+
1229+
- algorithm: qgis:extendlines
1230+
name: Extend lines
1231+
params:
1232+
END_DISTANCE: 0.2
1233+
INPUT_LAYER:
1234+
name: lines.gml
1235+
type: vector
1236+
START_DISTANCE: 0.1
1237+
results:
1238+
OUTPUT_LAYER:
1239+
name: expected/extend_lines.gml
1240+
type: vector
1241+
1242+
1243+
- algorithm: qgis:extendlines
1244+
name: Extend multilines
1245+
params:
1246+
END_DISTANCE: 0.4
1247+
INPUT_LAYER:
1248+
name: multilines.gml
1249+
type: vector
1250+
START_DISTANCE: 0.2
1251+
results:
1252+
OUTPUT_LAYER:
1253+
name: expected/extend_multilines.gml
1254+
type: vector

0 commit comments

Comments
 (0)