Skip to content

Commit

Permalink
Merge pull request #3379 from nyalldawson/processing
Browse files Browse the repository at this point in the history
[FEATURE][processing] New algorithm for offsetting lines
  • Loading branch information
alexbruy authored Aug 11, 2016
2 parents 7ee55a7 + 82f4a82 commit 8a31576
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 1 deletion.
9 changes: 9 additions & 0 deletions python/plugins/processing/algs/help/qgis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,15 @@ qgis:numberofuniquevaluesinclasses: >

The resulting layer contains the same features as the input layer, but with an additional attribute containing the count of unique values for that class.

qgis:offsetline: >
This algorithm offsets lines by a specified distance. Positive distances will offset lines to the left, and negative distances will offset to the right of lines.

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

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:orientedminimumboundingbox: >
This algorithm takes a vector layer and generate a new one with the minimum rectangle that covers all the input features.

Expand Down
106 changes: 106 additions & 0 deletions python/plugins/processing/algs/qgis/OffsetLine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
OffsetLine.py
--------------
Date : July 2016
Copyright : (C) 2016 by Nyall Dawson
Email : nyall dot dawson 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. *
* *
***************************************************************************
"""

__author__ = 'Nyall Dawson'
__date__ = 'July 2016'
__copyright__ = '(C) 2016, Nyall Dawson'

# This will get replaced with a git SHA1 when you do a git archive323

__revision__ = '$Format:%H$'

import os

from qgis.core import QgsGeometry, QgsWkbTypes

from qgis.PyQt.QtGui import QIcon

from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector, ParameterSelection, ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class OffsetLine(GeoAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_LAYER = 'OUTPUT_LAYER'
DISTANCE = 'DISTANCE'
SEGMENTS = 'SEGMENTS'
JOIN_STYLE = 'JOIN_STYLE'
MITRE_LIMIT = 'MITRE_LIMIT'

def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Offset line')
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')

self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_LINE]))
self.addParameter(ParameterNumber(self.DISTANCE,
self.tr('Distance'), default=10.0))
self.addParameter(ParameterNumber(self.SEGMENTS,
self.tr('Segments'), 1, default=8))
self.join_styles = [self.tr('Round'),
'Mitre',
'Bevel']
self.addParameter(ParameterSelection(
self.JOIN_STYLE,
self.tr('Join style'),
self.join_styles))
self.addParameter(ParameterNumber(self.MITRE_LIMIT,
self.tr('Mitre limit'), 1, default=2))

self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Offset')))

def processAlgorithm(self, progress):
layer = dataobjects.getObjectFromUri(
self.getParameterValue(self.INPUT_LAYER))

writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(
layer.fields().toList(),
QgsWkbTypes.LineString,
layer.crs())

distance = self.getParameterValue(self.DISTANCE)
segments = int(self.getParameterValue(self.SEGMENTS))
join_style = self.getParameterValue(self.JOIN_STYLE) + 1
miter_limit = self.getParameterValue(self.MITRE_LIMIT)

features = vector.features(layer)
total = 100.0 / len(features)

for current, input_feature in enumerate(features):
output_feature = input_feature
input_geometry = input_feature.geometry()
if input_geometry:
output_geometry = input_geometry.offsetCurve(distance, segments, join_style, miter_limit)
if not output_geometry:
raise GeoAlgorithmExecutionException(
self.tr('Error calculating line offset'))

output_feature.setGeometry(output_geometry)

writer.addFeature(output_feature)
progress.setPercentage(int(current * total))

del writer
4 changes: 3 additions & 1 deletion python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
from .BoundingBox import BoundingBox
from .Boundary import Boundary
from .PointOnSurface import PointOnSurface
from .OffsetLine import OffsetLine

pluginPath = os.path.normpath(os.path.join(
os.path.split(os.path.dirname(__file__))[0], os.pardir))
Expand Down Expand Up @@ -202,7 +203,8 @@ def __init__(self):
ReverseLineDirection(), SpatialIndex(), DefineProjection(),
RectanglesOvalsDiamondsVariable(),
RectanglesOvalsDiamondsFixed(), MergeLines(),
BoundingBox(), Boundary(), PointOnSurface()
BoundingBox(), Boundary(), PointOnSurface(),
OffsetLine()
]

if hasMatplotlib:
Expand Down
Original file line number Diff line number Diff line change
@@ -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/ line_offset_bevel.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>-2.292893218813453</gml:Y></gml:coord>
<gml:coord><gml:X>10.29289321881345</gml:X><gml:Y>5.707106781186548</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:line_offset_bevel fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,3 8,3 8.292893218813452,3.707106781186547 10.292893218813452,5.707106781186548</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,0 1,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,0 1,2 2,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,2 5,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-2 10,-2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5.292893218813452,-2.292893218813453 9.292893218813452,1.707106781186547</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_bevel>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_bevel fid="lines.6">
</ogr:line_offset_bevel>
</gml:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
@@ -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="line_offset_bevel" type="ogr:line_offset_bevel_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="line_offset_bevel_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Original file line number Diff line number Diff line change
@@ -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/ line_offset_mitre.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>-2.292893218813453</gml:Y></gml:coord>
<gml:coord><gml:X>10.29289321881345</gml:X><gml:Y>5.707106781186548</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:line_offset_mitre fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,3 8,3 8.0,3.414213562373094 10.292893218813452,5.707106781186548</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,0 1,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,0 1,3 2,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,2 5,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-2 10,-2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5.292893218813452,-2.292893218813453 9.292893218813452,1.707106781186547</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_mitre>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_mitre fid="lines.6">
</ogr:line_offset_mitre>
</gml:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
@@ -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="line_offset_mitre" type="ogr:line_offset_mitre_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="line_offset_mitre_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Original file line number Diff line number Diff line change
@@ -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/ line_offset_round_negative.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>4.292893218813452</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>11.707106781186548,4.292893218813452 10.0,2.585786437626905 10,2 9.98078528040323,1.804909677983872 9.923879532511286,1.61731656763491 9.831469612302543,1.444429766980398 9.707106781186548,1.292893218813453 9.555570233019605,1.168530387697455 9.38268343236509,1.076120467488713 9.195090322016128,1.01921471959677 9,1 6,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,-2 -1,-2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>4,3 4,2 3.98078528040323,1.804909677983872 3.923879532511287,1.61731656763491 3.831469612302545,1.444429766980398 3.707106781186547,1.292893218813453 3.555570233019602,1.168530387697455 3.38268343236509,1.076120467488713 3.356009692300209,1.068029076900628 3.195090322016128,1.01921471959677 3,1 3,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,0 3,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>10,-4 7,-4</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>10.707106781186548,0.292893218813453 6.707106781186548,-3.707106781186547</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:line_offset_round_negative>
</gml:featureMember>
<gml:featureMember>
<ogr:line_offset_round_negative fid="lines.6">
</ogr:line_offset_round_negative>
</gml:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
@@ -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="line_offset_round_negative" type="ogr:line_offset_round_negative_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="line_offset_round_negative_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Loading

0 comments on commit 8a31576

Please sign in to comment.