Skip to content

Commit 9fa4e77

Browse files
committed
[FEATURE][processing] Extract nodes algorithm now saves node
index, distance along line and angle at node Also correctly handles null geometries
1 parent 986b531 commit 9fa4e77

11 files changed

+1088
-15
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ qgis:extractbylocation: >
166166
qgis:extractnodes: >
167167
This algorithm takes a line or polygon layer and generates a point layer with points representing the nodes in the input lines or polygons. The attributes associated to each point are the same ones associated to the line or polygon that the point belongs to.
168168

169+
Additional fields are added to the nodes indicating the node index (beginning at 0), distance along original geometry and bisector angle of node for original geometry.
170+
169171
qgis:fieldcalculator: >
170172
This algorithm computes a new vector layer with the same features of the input layer, but with an additional attribute. The values of this new attribute are computed from each feature using a mathematical formula, based on te properties and attributes of the feature.
171173

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

+26-15
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
__revision__ = '$Format:%H$'
2727

2828
import os
29+
import math
2930

3031
from qgis.PyQt.QtGui import QIcon
32+
from qgis.PyQt.QtCore import QVariant
3133

32-
from qgis.core import Qgis, QgsFeature, QgsGeometry, QgsWkbTypes
34+
from qgis.core import QgsFeature, QgsGeometry, QgsWkbTypes, QgsField
3335

3436
from processing.core.GeoAlgorithm import GeoAlgorithm
3537
from processing.core.parameters import ParameterVector
@@ -61,25 +63,34 @@ def processAlgorithm(self, progress):
6163
layer = dataobjects.getObjectFromUri(
6264
self.getParameterValue(self.INPUT))
6365

64-
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
65-
layer.fields().toList(), QgsWkbTypes.Point, layer.crs())
66+
fields = layer.fields()
67+
fields.append(QgsField('node_index', QVariant.Int))
68+
fields.append(QgsField('distance', QVariant.Double))
69+
fields.append(QgsField('angle', QVariant.Double))
6670

67-
outFeat = QgsFeature()
68-
inGeom = QgsGeometry()
69-
outGeom = QgsGeometry()
71+
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
72+
fields, QgsWkbTypes.Point, layer.crs())
7073

7174
features = vector.features(layer)
7275
total = 100.0 / len(features)
7376
for current, f in enumerate(features):
74-
inGeom = f.geometry()
75-
attrs = f.attributes()
76-
77-
points = vector.extractPoints(inGeom)
78-
outFeat.setAttributes(attrs)
79-
80-
for i in points:
81-
outFeat.setGeometry(outGeom.fromPoint(i))
82-
writer.addFeature(outFeat)
77+
input_geometry = f.geometry()
78+
if not input_geometry:
79+
writer.addFeature(f)
80+
else:
81+
points = vector.extractPoints(input_geometry)
82+
83+
for i, point in enumerate(points):
84+
distance = input_geometry.distanceToVertex(i)
85+
angle = math.degrees(input_geometry.angleAtVertex(i))
86+
attrs = f.attributes()
87+
attrs.append(i)
88+
attrs.append(distance)
89+
attrs.append(angle)
90+
output_feature = QgsFeature()
91+
output_feature.setAttributes(attrs)
92+
output_feature.setGeometry(QgsGeometry.fromPoint(point))
93+
writer.addFeature(output_feature)
8394

8495
progress.setPercentage(int(current * total))
8596

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extract_nodes_lines</Name>
4+
<ElementPath>extract_nodes_lines</ElementPath>
5+
<GeometryType>1</GeometryType>
6+
<SRSName>EPSG:4326</SRSName>
7+
<DatasetSpecificInfo>
8+
<FeatureCount>17</FeatureCount>
9+
<ExtentXMin>-1.00000</ExtentXMin>
10+
<ExtentXMax>11.00000</ExtentXMax>
11+
<ExtentYMin>-3.00000</ExtentYMin>
12+
<ExtentYMax>5.00000</ExtentYMax>
13+
</DatasetSpecificInfo>
14+
<PropertyDefn>
15+
<Name>distance</Name>
16+
<ElementPath>distance</ElementPath>
17+
<Type>Real</Type>
18+
</PropertyDefn>
19+
<PropertyDefn>
20+
<Name>angle</Name>
21+
<ElementPath>angle</ElementPath>
22+
<Type>Real</Type>
23+
</PropertyDefn>
24+
</GMLFeatureClass>
25+
</GMLFeatureClassList>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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</gml:X><gml:Y>-3</gml:Y></gml:coord>
10+
<gml:coord><gml:X>11</gml:X><gml:Y>5</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extract_nodes_lines fid="lines.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>6,2</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:node_index>0</ogr:node_index>
18+
<ogr:distance>0</ogr:distance>
19+
<ogr:angle>90</ogr:angle>
20+
</ogr:extract_nodes_lines>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:extract_nodes_lines fid="lines.0">
24+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>9,2</gml:coordinates></gml:Point></ogr:geometryProperty>
25+
<ogr:node_index>1</ogr:node_index>
26+
<ogr:distance>3</ogr:distance>
27+
<ogr:angle>45</ogr:angle>
28+
</ogr:extract_nodes_lines>
29+
</gml:featureMember>
30+
<gml:featureMember>
31+
<ogr:extract_nodes_lines fid="lines.0">
32+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>9,3</gml:coordinates></gml:Point></ogr:geometryProperty>
33+
<ogr:node_index>2</ogr:node_index>
34+
<ogr:distance>4</ogr:distance>
35+
<ogr:angle>22.5</ogr:angle>
36+
</ogr:extract_nodes_lines>
37+
</gml:featureMember>
38+
<gml:featureMember>
39+
<ogr:extract_nodes_lines fid="lines.0">
40+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>11,5</gml:coordinates></gml:Point></ogr:geometryProperty>
41+
<ogr:node_index>3</ogr:node_index>
42+
<ogr:distance>6.82842712474619</ogr:distance>
43+
<ogr:angle>45</ogr:angle>
44+
</ogr:extract_nodes_lines>
45+
</gml:featureMember>
46+
<gml:featureMember>
47+
<ogr:extract_nodes_lines fid="lines.1">
48+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>-1,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
49+
<ogr:node_index>0</ogr:node_index>
50+
<ogr:distance>0</ogr:distance>
51+
<ogr:angle>90</ogr:angle>
52+
</ogr:extract_nodes_lines>
53+
</gml:featureMember>
54+
<gml:featureMember>
55+
<ogr:extract_nodes_lines fid="lines.1">
56+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
57+
<ogr:node_index>1</ogr:node_index>
58+
<ogr:distance>2</ogr:distance>
59+
<ogr:angle>90</ogr:angle>
60+
</ogr:extract_nodes_lines>
61+
</gml:featureMember>
62+
<gml:featureMember>
63+
<ogr:extract_nodes_lines fid="lines.2">
64+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,0</gml:coordinates></gml:Point></ogr:geometryProperty>
65+
<ogr:node_index>0</ogr:node_index>
66+
<ogr:distance>0</ogr:distance>
67+
<ogr:angle>0</ogr:angle>
68+
</ogr:extract_nodes_lines>
69+
</gml:featureMember>
70+
<gml:featureMember>
71+
<ogr:extract_nodes_lines fid="lines.2">
72+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
73+
<ogr:node_index>1</ogr:node_index>
74+
<ogr:distance>2</ogr:distance>
75+
<ogr:angle>45</ogr:angle>
76+
</ogr:extract_nodes_lines>
77+
</gml:featureMember>
78+
<gml:featureMember>
79+
<ogr:extract_nodes_lines fid="lines.2">
80+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,2</gml:coordinates></gml:Point></ogr:geometryProperty>
81+
<ogr:node_index>2</ogr:node_index>
82+
<ogr:distance>3</ogr:distance>
83+
<ogr:angle>45</ogr:angle>
84+
</ogr:extract_nodes_lines>
85+
</gml:featureMember>
86+
<gml:featureMember>
87+
<ogr:extract_nodes_lines fid="lines.2">
88+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
89+
<ogr:node_index>3</ogr:node_index>
90+
<ogr:distance>4</ogr:distance>
91+
<ogr:angle>0</ogr:angle>
92+
</ogr:extract_nodes_lines>
93+
</gml:featureMember>
94+
<gml:featureMember>
95+
<ogr:extract_nodes_lines fid="lines.3">
96+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,1</gml:coordinates></gml:Point></ogr:geometryProperty>
97+
<ogr:node_index>0</ogr:node_index>
98+
<ogr:distance>0</ogr:distance>
99+
<ogr:angle>90</ogr:angle>
100+
</ogr:extract_nodes_lines>
101+
</gml:featureMember>
102+
<gml:featureMember>
103+
<ogr:extract_nodes_lines fid="lines.3">
104+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,1</gml:coordinates></gml:Point></ogr:geometryProperty>
105+
<ogr:node_index>1</ogr:node_index>
106+
<ogr:distance>2</ogr:distance>
107+
<ogr:angle>90</ogr:angle>
108+
</ogr:extract_nodes_lines>
109+
</gml:featureMember>
110+
<gml:featureMember>
111+
<ogr:extract_nodes_lines fid="lines.4">
112+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-3</gml:coordinates></gml:Point></ogr:geometryProperty>
113+
<ogr:node_index>0</ogr:node_index>
114+
<ogr:distance>0</ogr:distance>
115+
<ogr:angle>90</ogr:angle>
116+
</ogr:extract_nodes_lines>
117+
</gml:featureMember>
118+
<gml:featureMember>
119+
<ogr:extract_nodes_lines fid="lines.4">
120+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>10,-3</gml:coordinates></gml:Point></ogr:geometryProperty>
121+
<ogr:node_index>1</ogr:node_index>
122+
<ogr:distance>3</ogr:distance>
123+
<ogr:angle>90</ogr:angle>
124+
</ogr:extract_nodes_lines>
125+
</gml:featureMember>
126+
<gml:featureMember>
127+
<ogr:extract_nodes_lines fid="lines.5">
128+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>6,-3</gml:coordinates></gml:Point></ogr:geometryProperty>
129+
<ogr:node_index>0</ogr:node_index>
130+
<ogr:distance>0</ogr:distance>
131+
<ogr:angle>45</ogr:angle>
132+
</ogr:extract_nodes_lines>
133+
</gml:featureMember>
134+
<gml:featureMember>
135+
<ogr:extract_nodes_lines fid="lines.5">
136+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>10,1</gml:coordinates></gml:Point></ogr:geometryProperty>
137+
<ogr:node_index>1</ogr:node_index>
138+
<ogr:distance>5.65685424949238</ogr:distance>
139+
<ogr:angle>45</ogr:angle>
140+
</ogr:extract_nodes_lines>
141+
</gml:featureMember>
142+
<gml:featureMember>
143+
<ogr:extract_nodes_lines fid="lines.6">
144+
</ogr:extract_nodes_lines>
145+
</gml:featureMember>
146+
</ogr:FeatureCollection>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extract_nodes_multilines</Name>
4+
<ElementPath>extract_nodes_multilines</ElementPath>
5+
<GeometryType>1</GeometryType>
6+
<SRSName>EPSG:4326</SRSName>
7+
<DatasetSpecificInfo>
8+
<FeatureCount>15</FeatureCount>
9+
<ExtentXMin>-1.00000</ExtentXMin>
10+
<ExtentXMax>5.58042</ExtentXMax>
11+
<ExtentYMin>-1.00000</ExtentYMin>
12+
<ExtentYMax>4.11977</ExtentYMax>
13+
</DatasetSpecificInfo>
14+
<PropertyDefn>
15+
<Name>distance</Name>
16+
<ElementPath>distance</ElementPath>
17+
<Type>Real</Type>
18+
</PropertyDefn>
19+
<PropertyDefn>
20+
<Name>angle</Name>
21+
<ElementPath>angle</ElementPath>
22+
<Type>Real</Type>
23+
</PropertyDefn>
24+
</GMLFeatureClass>
25+
</GMLFeatureClassList>

0 commit comments

Comments
 (0)