Skip to content

Commit 0e2ef06

Browse files
Bernhard Ströblnyalldawson
Bernhard Ströbl
authored andcommittedNov 23, 2016
[processing] [FEATURE] SplitWithLines
Rename algorithm SplitLinesWithLines to SplitWithLines Accept polygon as input, too Use only selected lines to split with (if processing is set to use selection only) Issue log message if trying to split multi geometries Update help
1 parent 986acab commit 0e2ef06

File tree

6 files changed

+302
-7
lines changed

6 files changed

+302
-7
lines changed
 

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,8 @@ qgis:snapgeometriestolayer: >
495495
qgis:snappointstogrid: >
496496
This algorithm modifies the position of points in a vector layer, so they fall in the coordinates of a grid.
497497

498-
499-
qgis:splitlineswithlines: >
500-
This algorithm splits the lines in a line layer using the lines in another line layer to define the breaking points. Intersection between geometries in both layers are considered as split points.
498+
qgis:splitwithlines: >
499+
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.
501500

502501
qgis:splitvectorlayer: >
503502
This algorithm takes a vector layer and an attribute and generates a set of vector layers in an output folder. Each of the layers created in that folder contains all features from the input layer with the same value for the specified attribute.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
from .SelectByExpression import SelectByExpression
142142
from .SelectByAttributeSum import SelectByAttributeSum
143143
from .HypsometricCurves import HypsometricCurves
144+
from .SplitWithLines import SplitWithLines
144145
from .SplitLinesWithLines import SplitLinesWithLines
145146
from .FieldsMapper import FieldsMapper
146147
from .Datasources2Vrt import Datasources2Vrt
@@ -226,7 +227,7 @@ def __init__(self):
226227
PostGISExecuteSQL(), ImportIntoPostGIS(),
227228
SetVectorStyle(), SetRasterStyle(),
228229
SelectByExpression(), HypsometricCurves(),
229-
SplitLinesWithLines(), CreateConstantRaster(),
230+
SplitWithLines(), SplitLinesWithLines(), CreateConstantRaster(),
230231
FieldsMapper(), SelectByAttributeSum(), Datasources2Vrt(),
231232
CheckValidity(), OrientedMinimumBoundingBox(), Smooth(),
232233
ReverseLineDirection(), SpatialIndex(), DefineProjection(),

‎python/plugins/processing/algs/qgis/SplitLinesWithLines.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
"""
44
***************************************************************************
5-
SplitLines.py
5+
SplitLinesWithLines.py
6+
DEPRECATED, replaced by SplitWithLines.py
67
---------------------
78
Date : November 2014
8-
Revised : February 2016
9+
Revised : November 2016
910
Copyright : (C) 2014 by Bernhard Ströbl
1011
Email : bernhard dot stroebl at jena dot de
1112
***************************************************************************
@@ -17,7 +18,6 @@
1718
* *
1819
***************************************************************************
1920
"""
20-
from builtins import next
2121

2222
__author__ = 'Bernhard Ströbl'
2323
__date__ = 'November 2014'
@@ -43,6 +43,11 @@ class SplitLinesWithLines(GeoAlgorithm):
4343

4444
OUTPUT = 'OUTPUT'
4545

46+
def __init__(self):
47+
GeoAlgorithm.__init__(self)
48+
# this algorithm is deprecated - use SplitWithLines instead
49+
self.showInToolbox = False
50+
4651
def defineCharacteristics(self):
4752
self.name, self.i18n_name = self.trAlgorithm('Split lines with lines')
4853
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
SplitWithLines.py
6+
---------------------
7+
Date : November 2014
8+
Revised : November 2016
9+
Copyright : (C) 2014 by Bernhard Ströbl
10+
Email : bernhard dot stroebl at jena dot de
11+
***************************************************************************
12+
* *
13+
* This program is free software; you can redistribute it and/or modify *
14+
* it under the terms of the GNU General Public License as published by *
15+
* the Free Software Foundation; either version 2 of the License, or *
16+
* (at your option) any later version. *
17+
* *
18+
***************************************************************************
19+
"""
20+
21+
__author__ = 'Bernhard Ströbl'
22+
__date__ = 'November 2014'
23+
__copyright__ = '(C) 2014, Bernhard Ströbl'
24+
25+
# This will get replaced with a git SHA1 when you do a git archive
26+
27+
__revision__ = '$Format:%H$'
28+
29+
from qgis.core import QgsFeatureRequest, QgsFeature, QgsGeometry, QgsSpatialIndex, QgsWkbTypes, QgsMessageLog
30+
from processing.core.GeoAlgorithm import GeoAlgorithm
31+
from processing.core.parameters import ParameterVector
32+
from processing.core.outputs import OutputVector
33+
from processing.core.ProcessingLog import ProcessingLog
34+
from processing.tools import dataobjects
35+
from processing.tools import vector
36+
37+
38+
class SplitWithLines(GeoAlgorithm):
39+
40+
INPUT_A = 'INPUT_A'
41+
INPUT_B = 'INPUT_B'
42+
43+
OUTPUT = 'OUTPUT'
44+
45+
def defineCharacteristics(self):
46+
self.name, self.i18n_name = self.trAlgorithm('Split with lines')
47+
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
48+
self.addParameter(ParameterVector(self.INPUT_A,
49+
self.tr('Input layer, single geometries only'), [dataobjects.TYPE_VECTOR_POLYGON,
50+
dataobjects.TYPE_VECTOR_LINE]))
51+
self.addParameter(ParameterVector(self.INPUT_B,
52+
self.tr('Split layer'), [dataobjects.TYPE_VECTOR_LINE]))
53+
54+
self.addOutput(OutputVector(self.OUTPUT, self.tr('Split')))
55+
56+
def processAlgorithm(self, progress):
57+
layerA = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_A))
58+
splitLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_B))
59+
60+
sameLayer = self.getParameterValue(self.INPUT_A) == self.getParameterValue(self.INPUT_B)
61+
fieldList = layerA.fields()
62+
63+
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList,
64+
layerA.wkbType(), layerA.crs())
65+
66+
spatialIndex = QgsSpatialIndex()
67+
splitGeoms = {}
68+
request = QgsFeatureRequest()
69+
request.setSubsetOfAttributes([])
70+
71+
for aSplitFeature in vector.features(splitLayer, request):
72+
splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
73+
spatialIndex.insertFeature(aSplitFeature)
74+
# honor the case that user has selection on split layer and has setting "use selection"
75+
76+
outFeat = QgsFeature()
77+
features = vector.features(layerA)
78+
79+
if len(features) == 0:
80+
total = 100
81+
else:
82+
total = 100.0 / float(len(features))
83+
84+
multiGeoms = 0 # how many multi geometries were encountered
85+
86+
for current, inFeatA in enumerate(features):
87+
inGeom = inFeatA.geometry()
88+
89+
if inGeom.isMultipart():
90+
multiGeoms += 1
91+
# MultiGeometries are not allowed because the result of a splitted part cannot be clearly defined:
92+
# 1) add both new parts as new features
93+
# 2) store one part as a new feature and the other one as part of the multi geometry
94+
# 2a) which part should be which, seems arbitrary
95+
else:
96+
attrsA = inFeatA.attributes()
97+
outFeat.setAttributes(attrsA)
98+
inGeoms = [inGeom]
99+
lines = spatialIndex.intersects(inGeom.boundingBox())
100+
101+
if len(lines) > 0: # has intersection of bounding boxes
102+
splittingLines = []
103+
104+
for i in lines:
105+
try:
106+
splitGeom = splitGeoms[i]
107+
except:
108+
continue
109+
110+
# check if trying to self-intersect
111+
if sameLayer:
112+
if inFeatA.id() == i:
113+
continue
114+
115+
engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
116+
engine.prepareGeometry()
117+
118+
if engine.intersects(splitGeom.geometry()):
119+
splittingLines.append(splitGeom)
120+
121+
if len(splittingLines) > 0:
122+
for splitGeom in splittingLines:
123+
splitterPList = None
124+
outGeoms = []
125+
126+
while len(inGeoms) > 0:
127+
inGeom = inGeoms.pop()
128+
engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
129+
engine.prepareGeometry()
130+
inPoints = vector.extractPoints(inGeom)
131+
132+
if engine.intersects(splitGeom.geometry()):
133+
if splitterPList == None:
134+
splitterPList = vector.extractPoints(splitGeom)
135+
136+
try:
137+
result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False)
138+
except:
139+
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
140+
self.tr('Geometry exception while splitting'))
141+
result = 1
142+
143+
# splitGeometry: If there are several intersections
144+
# between geometry and splitLine, only the first one is considered.
145+
if result == 0: # split occurred
146+
147+
if inPoints == vector.extractPoints(inGeom):
148+
# bug in splitGeometry: sometimes it returns 0 but
149+
# the geometry is unchanged
150+
QgsMessageLog.logMessage("appending")
151+
outGeoms.append(inGeom)
152+
else:
153+
inGeoms.append(inGeom)
154+
155+
for aNewGeom in newGeometries:
156+
inGeoms.append(aNewGeom)
157+
else:
158+
QgsMessageLog.logMessage("appending else")
159+
outGeoms.append(inGeom)
160+
else:
161+
outGeoms.append(inGeom)
162+
163+
inGeoms = outGeoms
164+
165+
for aGeom in inGeoms:
166+
passed = True
167+
168+
if QgsWkbTypes.geometryType( aGeom.wkbType() ) == QgsWkbTypes.LineGeometry \
169+
and not QgsWkbTypes.isMultiType( aGeom.wkbType() ):
170+
passed = len(aGeom.asPolyline()) > 2
171+
172+
if not passed:
173+
passed = (len(aGeom.asPolyline()) == 2 and
174+
aGeom.asPolyline()[0] != aGeom.asPolyline()[1])
175+
# sometimes splitting results in lines of zero length
176+
177+
if passed:
178+
outFeat.setGeometry(aGeom)
179+
writer.addFeature(outFeat)
180+
181+
progress.setPercentage(int(current * total))
182+
183+
if multiGeoms > 0:
184+
ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
185+
self.tr('Feature geometry error: %s input features ignored due to multi-geometry.') % str(multiGeoms))
186+
187+
del writer
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>polys_split_with_lines</Name>
4+
<ElementPath>polys_split_with_lines</ElementPath>
5+
<!--POLYGON-->
6+
<GeometryType>3</GeometryType>
7+
<SRSName>GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>7</FeatureCount>
10+
<ExtentXMin>-1.00000</ExtentXMin>
11+
<ExtentXMax>10.00000</ExtentXMax>
12+
<ExtentYMin>-3.00000</ExtentYMin>
13+
<ExtentYMax>6.00000</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
<PropertyDefn>
16+
<Name>fid</Name>
17+
<ElementPath>fid</ElementPath>
18+
<Type>String</Type>
19+
<Width>7</Width>
20+
</PropertyDefn>
21+
<PropertyDefn>
22+
<Name>name</Name>
23+
<ElementPath>name</ElementPath>
24+
<Type>String</Type>
25+
<Width>5</Width>
26+
</PropertyDefn>
27+
<PropertyDefn>
28+
<Name>intval</Name>
29+
<ElementPath>intval</ElementPath>
30+
<Type>Integer</Type>
31+
</PropertyDefn>
32+
<PropertyDefn>
33+
<Name>floatval</Name>
34+
<ElementPath>floatval</ElementPath>
35+
<Type>Real</Type>
36+
</PropertyDefn>
37+
</GMLFeatureClass>
38+
</GMLFeatureClassList>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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>10</gml:X><gml:Y>6</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:polys_split_with_lines fid="polys.0">
16+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
17+
<ogr:name>aaaaa</ogr:name>
18+
<ogr:intval>33</ogr:intval>
19+
<ogr:floatval>44.123456</ogr:floatval>
20+
</ogr:polys_split_with_lines>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:polys_split_with_lines fid="polys.1">
24+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
25+
<ogr:name>Aaaaa</ogr:name>
26+
<ogr:intval>-33</ogr:intval>
27+
<ogr:floatval>0</ogr:floatval>
28+
</ogr:polys_split_with_lines>
29+
</gml:featureMember>
30+
<gml:featureMember>
31+
<ogr:polys_split_with_lines fid="polys.2">
32+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,6 3,6 3,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
33+
<ogr:name>bbaaa</ogr:name>
34+
<ogr:floatval>0.123</ogr:floatval>
35+
</ogr:polys_split_with_lines>
36+
</gml:featureMember>
37+
<gml:featureMember>
38+
<ogr:polys_split_with_lines fid="polys.3">
39+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,-3 7,-2 9,-2 9,0 10,1 10,-3 6,-3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
40+
<ogr:name>ASDF</ogr:name>
41+
<ogr:intval>0</ogr:intval>
42+
</ogr:polys_split_with_lines>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:polys_split_with_lines fid="polys.3">
46+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,-2 6,-3 6,1 10,1 9,0 7,0 7,-2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
47+
<ogr:name>ASDF</ogr:name>
48+
<ogr:intval>0</ogr:intval>
49+
</ogr:polys_split_with_lines>
50+
</gml:featureMember>
51+
<gml:featureMember>
52+
<ogr:polys_split_with_lines fid="polys.4">
53+
<ogr:intval>120</ogr:intval>
54+
<ogr:floatval>-100291.43213</ogr:floatval>
55+
</ogr:polys_split_with_lines>
56+
</gml:featureMember>
57+
<gml:featureMember>
58+
<ogr:polys_split_with_lines fid="polys.5">
59+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
60+
<ogr:name>elim</ogr:name>
61+
<ogr:intval>2</ogr:intval>
62+
<ogr:floatval>3.33</ogr:floatval>
63+
</ogr:polys_split_with_lines>
64+
</gml:featureMember>
65+
</ogr:FeatureCollection>

0 commit comments

Comments
 (0)
Please sign in to comment.