Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3380 from nyalldawson/processing
[processing] Offset curve follow ups
  • Loading branch information
alexbruy committed Aug 11, 2016
2 parents 8a31576 + 5025c82 commit a72485c
Show file tree
Hide file tree
Showing 18 changed files with 659 additions and 32 deletions.
8 changes: 8 additions & 0 deletions python/plugins/processing/algs/help/qgis.yaml
Expand Up @@ -167,6 +167,14 @@ qgis:fieldcalculator: >
qgis:fixeddistancebuffer: >
This algorithm computes a buffer area for all the features in an input layer, using a fixed distance.

The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.

The end cap style parameter controls how line endings are handled in the buffer.

The join style parameter specifies whether round, mitre or beveled joins should be used when offseting corners in a line.

The mitre limit parameter is only applicable for mitre join styles, and controls the maximum distance from the offset curve to use when creating a mitred join.

qgis:frequencyanalysis: >
This algorithms generates a table with frequency analysis of the values of a selected attribute from an input vector layer

Expand Down
30 changes: 12 additions & 18 deletions python/plugins/processing/algs/qgis/Buffer.py
Expand Up @@ -32,15 +32,12 @@


def buffering(progress, writer, distance, field, useField, layer, dissolve,
segments):
segments, endCapStyle=1, joinStyle=1, mitreLimit=2):

if useField:
field = layer.fieldNameIndex(field)

outFeat = QgsFeature()
inFeat = QgsFeature()
inGeom = QgsGeometry()
outGeom = QgsGeometry()

current = 0
features = vector.features(layer)
Expand All @@ -49,6 +46,7 @@ def buffering(progress, writer, distance, field, useField, layer, dissolve,
# With dissolve
if dissolve:
first = True
buffered_geometries = []
for inFeat in features:
attrs = inFeat.attributes()
if useField:
Expand All @@ -57,23 +55,19 @@ def buffering(progress, writer, distance, field, useField, layer, dissolve,
value = distance

inGeom = inFeat.geometry()
if inGeom.isEmpty() or inGeom.isGeosEmpty():
if not inGeom:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has empty geometry. Skipping...'.format(inFeat.id()))
continue
if not inGeom.isGeosValid():
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has invalid geometry. Skipping...'.format(inFeat.id()))
continue
outGeom = inGeom.buffer(float(value), segments)
if first:
tempGeom = QgsGeometry(outGeom)
first = False
else:
tempGeom = tempGeom.combine(outGeom)
buffered_geometries.append(inGeom.buffer(float(value), segments, endCapStyle, joinStyle, mitreLimit))

current += 1
progress.setPercentage(int(current * total))

outFeat.setGeometry(tempGeom)
final_geometry = QgsGeometry.unaryUnion(buffered_geometries)
outFeat.setGeometry(final_geometry)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)
else:
Expand All @@ -85,15 +79,15 @@ def buffering(progress, writer, distance, field, useField, layer, dissolve,
else:
value = distance
inGeom = inFeat.geometry()
outFeat = QgsFeature()
if inGeom.isEmpty() or inGeom.isGeosEmpty():
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has empty geometry. Skipping...'.format(inFeat.id()))
continue
if not inGeom.isGeosValid():
pass
elif not inGeom.isGeosValid():
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has invalid geometry. Skipping...'.format(inFeat.id()))
continue

outGeom = inGeom.buffer(float(value), segments)
outFeat.setGeometry(outGeom)
else:
outGeom = inGeom.buffer(float(value), segments, endCapStyle, joinStyle, mitreLimit)
outFeat.setGeometry(outGeom)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)
current += 1
Expand Down
26 changes: 25 additions & 1 deletion python/plugins/processing/algs/qgis/FixedDistanceBuffer.py
Expand Up @@ -35,6 +35,8 @@
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterSelection

from processing.core.outputs import OutputVector
from . import Buffer as buff
from processing.tools import dataobjects
Expand All @@ -50,6 +52,9 @@ class FixedDistanceBuffer(GeoAlgorithm):
DISTANCE = 'DISTANCE'
SEGMENTS = 'SEGMENTS'
DISSOLVE = 'DISSOLVE'
END_CAP_STYLE = 'END_CAP_STYLE'
JOIN_STYLE = 'JOIN_STYLE'
MITRE_LIMIT = 'MITRE_LIMIT'

def getIcon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'buffer.png'))
Expand All @@ -65,6 +70,22 @@ def defineCharacteristics(self):
self.tr('Segments'), 1, default=5))
self.addParameter(ParameterBoolean(self.DISSOLVE,
self.tr('Dissolve result'), False))
self.end_cap_styles = [self.tr('Round'),
'Flat',
'Square']
self.addParameter(ParameterSelection(
self.END_CAP_STYLE,
self.tr('End cap style'),
self.end_cap_styles, default=0))
self.join_styles = [self.tr('Round'),
'Mitre',
'Bevel']
self.addParameter(ParameterSelection(
self.JOIN_STYLE,
self.tr('Join style'),
self.join_styles, default=0))
self.addParameter(ParameterNumber(self.MITRE_LIMIT,
self.tr('Mitre limit'), 1, default=2))

self.addOutput(OutputVector(self.OUTPUT, self.tr('Buffer')))

Expand All @@ -73,10 +94,13 @@ def processAlgorithm(self, progress):
distance = self.getParameterValue(self.DISTANCE)
dissolve = self.getParameterValue(self.DISSOLVE)
segments = int(self.getParameterValue(self.SEGMENTS))
end_cap_style = self.getParameterValue(self.END_CAP_STYLE) + 1
join_style = self.getParameterValue(self.JOIN_STYLE) + 1
miter_limit = self.getParameterValue(self.MITRE_LIMIT)

writer = self.getOutputFromName(
self.OUTPUT).getVectorWriter(layer.fields().toList(),
QgsWkbTypes.Polygon, layer.crs())

buff.buffering(progress, writer, distance, None, False, layer,
dissolve, segments)
dissolve, segments, end_cap_style, join_style, miter_limit)
48 changes: 48 additions & 0 deletions python/plugins/processing/tests/testdata/expected/buffer_lines.gml
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ buffer_lines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-2</gml:X><gml:Y>-4</gml:Y></gml:coord>
<gml:coord><gml:X>11.98768834059514</gml:X><gml:Y>5.987688340595138</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:buffer_lines fid="lines.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,3 8.034074173710932,3.258819045102521 8.133974596215561,3.5 8.292893218813452,3.707106781186547 10.292893218813452,5.707106781186548 10.546009500260457,5.891006524188368 10.843565534959772,5.987688340595138 11.156434465040231,5.987688340595137 11.453990499739549,5.891006524188367 11.707106781186548,5.707106781186548 11.891006524188368,5.453990499739547 11.987688340595138,5.156434465040232 11.987688340595138,4.843565534959771 11.891006524188368,4.546009500260455 11.70710678118655,4.292893218813454 10.0,2.585786437626905 10,2 9.951056516295154,1.690983005625053 9.809016994374948,1.412214747707527 9.587785252292472,1.190983005625053 9.309016994374948,1.048943483704846 9,1 6,1 5.690983005625051,1.048943483704847 5.412214747707526,1.190983005625053 5.190983005625052,1.412214747707528 5.048943483704846,1.690983005625053 5,2 5.048943483704846,2.309016994374947 5.190983005625052,2.587785252292472 5.412214747707526,2.809016994374947 5.690983005625051,2.951056516295153 6,3 8,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,0 1.309016994374949,-0.048943483704847 1.587785252292474,-0.190983005625053 1.809016994374948,-0.412214747707527 1.951056516295154,-0.690983005625053 2,-1 1.951056516295154,-1.309016994374947 1.809016994374948,-1.587785252292472 1.587785252292474,-1.809016994374947 1.309016994374949,-1.951056516295153 1,-2 -1,-2 -1.309016994374949,-1.951056516295153 -1.587785252292474,-1.809016994374947 -1.809016994374948,-1.587785252292472 -1.951056516295154,-1.309016994374947 -2,-1 -1.951056516295154,-0.690983005625053 -1.809016994374948,-0.412214747707528 -1.587785252292474,-0.190983005625053 -1.309016994374949,-0.048943483704847 -1,0 1,0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 1.048943483704846,2.309016994374947 1.190983005625053,2.587785252292473 1.412214747707527,2.809016994374947 1.690983005625053,2.951056516295154 2,3 2.048943483704847,3.309016994374949 2.190983005625053,3.587785252292474 2.412214747707528,3.809016994374948 2.690983005625053,3.951056516295154 3,4 3.309016994374947,3.951056516295154 3.587785252292472,3.809016994374948 3.809016994374947,3.587785252292474 3.951056516295153,3.309016994374949 4,3 4,2 3.951056516295154,1.690983005625053 3.809016994374947,1.412214747707527 3.587785252292473,1.190983005625053 3.309016994374947,1.048943483704846 3,1 3,0 2.951056516295153,-0.309016994374949 2.809016994374947,-0.587785252292474 2.587785252292472,-0.809016994374948 2.309016994374947,-0.951056516295154 2,-1 1.690983005625053,-0.951056516295154 1.412214747707528,-0.809016994374948 1.190983005625054,-0.587785252292475 1.048943483704847,-0.309016994374949 1,0 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,2 5.309016994374948,1.951056516295153 5.587785252292474,1.809016994374947 5.809016994374947,1.587785252292473 5.951056516295154,1.309016994374947 6,1 5.951056516295154,0.690983005625053 5.809016994374948,0.412214747707528 5.587785252292474,0.190983005625054 5.309016994374949,0.048943483704847 5,0 3,0 2.690983005625051,0.048943483704847 2.412214747707526,0.190983005625053 2.190983005625052,0.412214747707528 2.048943483704846,0.690983005625053 2,1 2.048943483704846,1.309016994374947 2.190983005625052,1.587785252292472 2.412214747707526,1.809016994374947 2.690983005625051,1.951056516295153 3,2 5,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.4">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>10,-2 10.309016994374948,-2.048943483704847 10.587785252292472,-2.190983005625053 10.809016994374948,-2.412214747707528 10.951056516295154,-2.690983005625053 11,-3 10.951056516295154,-3.309016994374947 10.809016994374948,-3.587785252292472 10.587785252292475,-3.809016994374947 10.30901699437495,-3.951056516295153 10,-4 7,-4 6.690983005625051,-3.951056516295153 6.412214747707526,-3.809016994374947 6.190983005625052,-3.587785252292472 6.048943483704846,-3.309016994374947 6,-3 6.048943483704846,-2.690983005625053 6.190983005625052,-2.412214747707528 6.412214747707526,-2.190983005625053 6.690983005625051,-2.048943483704847 7,-2 10,-2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>9.292893218813452,1.707106781186547 9.546009500260457,1.891006524188368 9.843565534959772,1.987688340595138 10.156434465040231,1.987688340595138 10.453990499739549,1.891006524188368 10.707106781186548,1.707106781186547 10.891006524188368,1.453990499739547 10.987688340595138,1.156434465040232 10.987688340595138,0.84356553495977 10.891006524188368,0.546009500260455 10.70710678118655,0.292893218813454 6.707106781186548,-3.707106781186547 6.453990499739546,-3.891006524188368 6.15643446504023,-3.987688340595138 5.843565534959769,-3.987688340595138 5.546009500260453,-3.891006524188368 5.292893218813452,-3.707106781186547 5.108993475811633,-3.453990499739548 5.012311659404863,-3.156434465040232 5.012311659404862,-2.843565534959771 5.108993475811631,-2.546009500260455 5.29289321881345,-2.292893218813454 9.292893218813452,1.707106781186547</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines fid="lines.6">
</ogr:buffer_lines>
</gml:featureMember>
</ogr:FeatureCollection>
23 changes: 23 additions & 0 deletions python/plugins/processing/tests/testdata/expected/buffer_lines.xsd
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="buffer_lines" type="ogr:buffer_lines_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="buffer_lines_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ buffer_lines_flat.xsd"
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>-4</gml:Y></gml:coord>
<gml:coord><gml:X>11.70710678118655</gml:X><gml:Y>5.707106781186548</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,3 8.034074173710932,3.258819045102521 8.133974596215561,3.5 8.292893218813452,3.707106781186547 10.292893218813452,5.707106781186548 11.707106781186548,4.292893218813452 10.0,2.585786437626905 10,2 9.951056516295154,1.690983005625053 9.809016994374948,1.412214747707527 9.587785252292472,1.190983005625053 9.309016994374948,1.048943483704846 9,1 6,1 6,3 8,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,0 1,-2 -1,-2 -1,0 1,0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 1.048943483704846,2.309016994374947 1.190983005625053,2.587785252292473 1.412214747707527,2.809016994374947 1.690983005625053,2.951056516295154 2,3 4,3 4,2 3.951056516295154,1.690983005625053 3.809016994374947,1.412214747707527 3.587785252292473,1.190983005625053 3.309016994374947,1.048943483704846 3,1 3,0 1,0 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,2 5,0 3,0 3,2 5,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.4">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>10,-2 10,-4 7,-4 7,-2 10,-2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>9.292893218813452,1.707106781186547 10.707106781186548,0.292893218813453 6.707106781186548,-3.707106781186547 5.292893218813452,-2.292893218813453 9.292893218813452,1.707106781186547</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:buffer_lines_flat>
</gml:featureMember>
<gml:featureMember>
<ogr:buffer_lines_flat fid="lines.6">
</ogr:buffer_lines_flat>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="buffer_lines_flat" type="ogr:buffer_lines_flat_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="buffer_lines_flat_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

0 comments on commit a72485c

Please sign in to comment.