-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE][processing] Add "segmentize" algorithms
Adds two new algorithms which expose QgsGeometry's methods for segmentizing curved geometries. "Segmentize by maximum distance": The segmentization is performed by specifying the maximum allowed offset distance between the original curve and the segmentized representation. "Segmentize by maximum angle": The segmentization is performed by specifying the maximum allowed radius angle between vertices on the straightened geometry (e.g the angle of the arc created from the original arc center to consective output vertices on the linearized geometry).
- Loading branch information
1 parent
6bd7600
commit 4232b93
Showing
10 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
26 changes: 26 additions & 0 deletions
26
python/plugins/processing/tests/testdata/expected/segmentize_by_angle.gml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<ogr:FeatureCollection | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://ogr.maptools.org/ segmentize_by_angle.xsd" | ||
xmlns:ogr="http://ogr.maptools.org/" | ||
xmlns:gml="http://www.opengis.net/gml"> | ||
<gml:boundedBy> | ||
<gml:Box> | ||
<gml:coord><gml:X>-0.9875563570784498</gml:X><gml:Y>-3.019161406672679</gml:Y></gml:coord> | ||
<gml:coord><gml:X>9.807504202322207</gml:X><gml:Y>4.303079673657821</gml:Y></gml:coord> | ||
</gml:Box> | ||
</gml:boundedBy> | ||
|
||
<gml:featureMember> | ||
<ogr:segmentize_by_angle fid="1"> | ||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.98755635707845,-0.974075743913436 -0.696095751086827,0.344850591369106 -0.005888714481605,1.50594068665349 1.01349196457716,2.39215679681429 2.25929283346249,2.91416844211677 3.60593731102726,3.0193569100738 4.91768379222303,2.6971192154796 6.06230838593327,1.97993688007214</gml:coordinates></gml:LineString></ogr:geometryProperty> | ||
<ogr:id>1</ogr:id> | ||
</ogr:segmentize_by_angle> | ||
</gml:featureMember> | ||
<gml:featureMember> | ||
<ogr:segmentize_by_angle fid="2"> | ||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6.91442741208296,-3.01916140667268 6.32475035835957,-2.4284524156428 5.95800750896124,-1.67868190262791 5.8536814658075,-0.850568253126039 6.0230037052269,-0.033264075350454 6.44774542579607,0.68524174270488 7.08218001471432,1.22759669304234 7.85800585857777,1.53541222183353 8.69169952127193,1.57554969254374 9.49350766456267,1.34368800721371 9.74057664392659,1.88754171095694 9.80750420232221,2.48112458938787 9.68773977279365,3.06633943289311 9.39300535646221,3.58590805730082 8.95214822603083,3.98897743369522 8.40831748509891,4.23609695307115 7.81474082890195,4.30307967365782 7.22951485804922,4.18336962947338 6.70991884580703,3.88868349864743</gml:coordinates></gml:LineString></ogr:geometryProperty> | ||
<ogr:id>2</ogr:id> | ||
</ogr:segmentize_by_angle> | ||
</gml:featureMember> | ||
</ogr:FeatureCollection> |
30 changes: 30 additions & 0 deletions
30
python/plugins/processing/tests/testdata/expected/segmentize_by_angle.xsd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?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="segmentize_by_angle" type="ogr:segmentize_by_angle_Type" substitutionGroup="gml:_Feature"/> | ||
<xs:complexType name="segmentize_by_angle_Type"> | ||
<xs:complexContent> | ||
<xs:extension base="gml:AbstractFeatureType"> | ||
<xs:sequence> | ||
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> | ||
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1"> | ||
<xs:simpleType> | ||
<xs:restriction base="xs:integer"> | ||
<xs:totalDigits value="10"/> | ||
</xs:restriction> | ||
</xs:simpleType> | ||
</xs:element> | ||
</xs:sequence> | ||
</xs:extension> | ||
</xs:complexContent> | ||
</xs:complexType> | ||
</xs:schema> |
26 changes: 26 additions & 0 deletions
26
python/plugins/processing/tests/testdata/expected/segmentize_by_distance.gml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<ogr:FeatureCollection | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://ogr.maptools.org/ segmentize_by_distance.xsd" | ||
xmlns:ogr="http://ogr.maptools.org/" | ||
xmlns:gml="http://www.opengis.net/gml"> | ||
<gml:boundedBy> | ||
<gml:Box> | ||
<gml:coord><gml:X>-0.9875563570784498</gml:X><gml:Y>-3.019161406672679</gml:Y></gml:coord> | ||
<gml:coord><gml:X>9.794917283570138</gml:X><gml:Y>4.303894025825194</gml:Y></gml:coord> | ||
</gml:Box> | ||
</gml:boundedBy> | ||
|
||
<gml:featureMember> | ||
<ogr:segmentize_by_distance fid="1"> | ||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.98755635707845,-0.974075743913436 -0.212652411335007,1.23725667259743 1.61554353037206,2.70291924637298 3.94247675733233,2.9783261066885 6.06230838593327,1.97993688007214</gml:coordinates></gml:LineString></ogr:geometryProperty> | ||
<ogr:id>1</ogr:id> | ||
</ogr:segmentize_by_distance> | ||
</gml:featureMember> | ||
<gml:featureMember> | ||
<ogr:segmentize_by_distance fid="2"> | ||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6.91442741208296,-3.01916140667268 5.90638239076692,-1.47558750786245 6.20570477434748,0.34352800709968 7.65518199185988,1.48273428429481 9.49350766456267,1.34368800721371 9.79491728357014,2.63050854973142 9.18843697294715,3.80478981923308 7.96465191909257,4.30389402582519 6.70991884580703,3.88868349864743</gml:coordinates></gml:LineString></ogr:geometryProperty> | ||
<ogr:id>2</ogr:id> | ||
</ogr:segmentize_by_distance> | ||
</gml:featureMember> | ||
</ogr:FeatureCollection> |
30 changes: 30 additions & 0 deletions
30
python/plugins/processing/tests/testdata/expected/segmentize_by_distance.xsd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?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="segmentize_by_distance" type="ogr:segmentize_by_distance_Type" substitutionGroup="gml:_Feature"/> | ||
<xs:complexType name="segmentize_by_distance_Type"> | ||
<xs:complexContent> | ||
<xs:extension base="gml:AbstractFeatureType"> | ||
<xs:sequence> | ||
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> | ||
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1"> | ||
<xs:simpleType> | ||
<xs:restriction base="xs:integer"> | ||
<xs:totalDigits value="10"/> | ||
</xs:restriction> | ||
</xs:simpleType> | ||
</xs:element> | ||
</xs:sequence> | ||
</xs:extension> | ||
</xs:complexContent> | ||
</xs:complexType> | ||
</xs:schema> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/*************************************************************************** | ||
qgsalgorithmsegmentize.cpp | ||
--------------------- | ||
begin : March 2018 | ||
copyright : (C) 2018 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. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsalgorithmsegmentize.h" | ||
|
||
///@cond PRIVATE | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::name() const | ||
{ | ||
return QStringLiteral( "segmentizebymaxdistance" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::displayName() const | ||
{ | ||
return QObject::tr( "Segmentize by maximum distance" ); | ||
} | ||
|
||
QStringList QgsSegmentizeByMaximumDistanceAlgorithm::tags() const | ||
{ | ||
return QObject::tr( "straighten,linearize,densify,curves,curved,circular" ).split( ',' ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::group() const | ||
{ | ||
return QObject::tr( "Vector geometry" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::groupId() const | ||
{ | ||
return QStringLiteral( "vectorgeometry" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::outputName() const | ||
{ | ||
return QObject::tr( "Segmentized" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumDistanceAlgorithm::shortHelpString() const | ||
{ | ||
return QObject::tr( "This algorithm segmentizes a geometry by converting curved sections to linear sections.\n\n" | ||
"The segmentization is performed by specifying the maximum allowed offset distance between the original" | ||
"curve and the segmentized representation.\n\n" | ||
"Non-curved geometries will be retained without change." ); | ||
} | ||
|
||
QgsSegmentizeByMaximumDistanceAlgorithm *QgsSegmentizeByMaximumDistanceAlgorithm::createInstance() const | ||
{ | ||
return new QgsSegmentizeByMaximumDistanceAlgorithm(); | ||
} | ||
|
||
QList<int> QgsSegmentizeByMaximumDistanceAlgorithm::inputLayerTypes() const | ||
{ | ||
return QList<int>() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; | ||
} | ||
|
||
void QgsSegmentizeByMaximumDistanceAlgorithm::initParameters( const QVariantMap & ) | ||
{ | ||
std::unique_ptr< QgsProcessingParameterNumber > tolerance = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DISTANCE" ), | ||
QObject::tr( "Maximum offset distance" ), QgsProcessingParameterNumber::Double, | ||
1.0, false, 0, 10000000.0 ); | ||
tolerance->setIsDynamic( true ); | ||
tolerance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Maximum offset distance" ), QgsPropertyDefinition::DoublePositive ) ); | ||
tolerance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( tolerance.release() ); | ||
} | ||
|
||
bool QgsSegmentizeByMaximumDistanceAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
mTolerance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); | ||
mDynamicTolerance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); | ||
if ( mDynamicTolerance ) | ||
mToleranceProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >(); | ||
|
||
return true; | ||
} | ||
|
||
QgsFeatureList QgsSegmentizeByMaximumDistanceAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
QgsFeature f = feature; | ||
if ( f.hasGeometry() ) | ||
{ | ||
QgsGeometry geometry = f.geometry(); | ||
double tolerance = mTolerance; | ||
if ( mDynamicTolerance ) | ||
tolerance = mToleranceProperty.valueAsDouble( context.expressionContext(), tolerance ); | ||
geometry.convertToStraightSegment( tolerance, QgsAbstractGeometry::MaximumDifference ); | ||
f.setGeometry( geometry ); | ||
} | ||
return QgsFeatureList() << f; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::name() const | ||
{ | ||
return QStringLiteral( "segmentizebymaxangle" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::displayName() const | ||
{ | ||
return QObject::tr( "Segmentize by maximum angle" ); | ||
} | ||
|
||
QStringList QgsSegmentizeByMaximumAngleAlgorithm::tags() const | ||
{ | ||
return QObject::tr( "straighten,linearize,densify,curves,curved,circular,angle" ).split( ',' ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::group() const | ||
{ | ||
return QObject::tr( "Vector geometry" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::groupId() const | ||
{ | ||
return QStringLiteral( "vectorgeometry" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::outputName() const | ||
{ | ||
return QObject::tr( "Segmentized" ); | ||
} | ||
|
||
QString QgsSegmentizeByMaximumAngleAlgorithm::shortHelpString() const | ||
{ | ||
return QObject::tr( "This algorithm segmentizes a geometry by converting curved sections to linear sections.\n\n" | ||
"The segmentization is performed by specifying the maximum allowed radius angle between vertices" | ||
"on the straightened geometry (e.g the angle of the arc created from the original arc center to consective" | ||
"output vertices on the linearized geometry).\n\n" | ||
"Non-curved geometries will be retained without change." ); | ||
} | ||
|
||
QgsSegmentizeByMaximumAngleAlgorithm *QgsSegmentizeByMaximumAngleAlgorithm::createInstance() const | ||
{ | ||
return new QgsSegmentizeByMaximumAngleAlgorithm(); | ||
} | ||
|
||
QList<int> QgsSegmentizeByMaximumAngleAlgorithm::inputLayerTypes() const | ||
{ | ||
return QList<int>() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; | ||
} | ||
|
||
void QgsSegmentizeByMaximumAngleAlgorithm::initParameters( const QVariantMap & ) | ||
{ | ||
std::unique_ptr< QgsProcessingParameterNumber > tolerance = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ANGLE" ), | ||
QObject::tr( "Maximum angle between vertices (degrees)" ), QgsProcessingParameterNumber::Double, | ||
5.0, false, 0, 360.0 ); | ||
tolerance->setIsDynamic( true ); | ||
tolerance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ANGLE" ), QObject::tr( "Maximum angle between vertices (degrees)" ), QgsPropertyDefinition::DoublePositive ) ); | ||
tolerance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( tolerance.release() ); | ||
} | ||
|
||
bool QgsSegmentizeByMaximumAngleAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
mTolerance = parameterAsDouble( parameters, QStringLiteral( "ANGLE" ), context ); | ||
mDynamicTolerance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ANGLE" ) ); | ||
if ( mDynamicTolerance ) | ||
mToleranceProperty = parameters.value( QStringLiteral( "ANGLE" ) ).value< QgsProperty >(); | ||
|
||
return true; | ||
} | ||
|
||
QgsFeatureList QgsSegmentizeByMaximumAngleAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
QgsFeature f = feature; | ||
if ( f.hasGeometry() ) | ||
{ | ||
QgsGeometry geometry = f.geometry(); | ||
double tolerance = mTolerance; | ||
if ( mDynamicTolerance ) | ||
tolerance = mToleranceProperty.valueAsDouble( context.expressionContext(), tolerance ); | ||
geometry.convertToStraightSegment( M_PI * tolerance / 180.0, QgsAbstractGeometry::MaximumAngle ); | ||
f.setGeometry( geometry ); | ||
} | ||
return QgsFeatureList() << f; | ||
} | ||
|
||
///@endcond | ||
|
||
|
Oops, something went wrong.