QGIS API Documentation 4.3.0-Master (52aa6503bed)
Loading...
Searching...
No Matches
qgsalgorithmconcavehullbyfeature.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmconcavehullbyfeature.cpp
3 ---------------------
4 begin : May 2025
5 copyright : (C) 2025 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
21#include "qgsgeos.h"
22
23#include <QString>
24
25using namespace Qt::StringLiterals;
26
28
29QString QgsConcaveHullByFeatureAlgorithm::name() const
30{
31 return u"concavehullbyfeature"_s;
32}
33
34QString QgsConcaveHullByFeatureAlgorithm::displayName() const
35{
36 return QObject::tr( "Concave hull (by feature)" );
37}
38
39QStringList QgsConcaveHullByFeatureAlgorithm::tags() const
40{
41 return QObject::tr( "concave,hull,bounds,bounding,convex" ).split( ',' );
42}
43
44QString QgsConcaveHullByFeatureAlgorithm::group() const
45{
46 return QObject::tr( "Vector geometry" );
47}
48
49QString QgsConcaveHullByFeatureAlgorithm::groupId() const
50{
51 return u"vectorgeometry"_s;
52}
53
54QString QgsConcaveHullByFeatureAlgorithm::outputName() const
55{
56 return QObject::tr( "Concave hulls" );
57}
58
59QString QgsConcaveHullByFeatureAlgorithm::shortHelpString() const
60{
61 return QObject::tr( "This algorithm calculates the concave hull for each feature in an input layer." )
62 + u"\n\n"_s
63 + QObject::tr( "For point and line layers, a concave hull is a polygon which contains all the vertices of the input geometries, but is a better approximation than the convex hull to the area occupied by the input." )
64 + u"\n\n"_s
65 + QObject::tr(
66 "When the input is a polygon layer, the algorithm operates differently: it computes a concave hull that respects the interior of the input polygons. The concave hull does not intersect "
67 "the polygon interiors. The computed hull also fills the empty space between the polygons within a multi-polygon feature."
68 )
69 + u"\n\n"_s
70 + QObject::tr( "See the 'Concave hull (by layer)' algorithm for a concave hull calculation which covers the whole layer or grouped subsets of features." );
71}
72
73QString QgsConcaveHullByFeatureAlgorithm::shortDescription() const
74{
75 return QObject::tr( "Calculates the concave hull for each feature in an input layer." );
76}
77
78QgsConcaveHullByFeatureAlgorithm *QgsConcaveHullByFeatureAlgorithm::createInstance() const
79{
80 return new QgsConcaveHullByFeatureAlgorithm();
81}
82
83void QgsConcaveHullByFeatureAlgorithm::initParameters( const QVariantMap & )
84{
85 auto alphaParam
86 = std::make_unique<QgsProcessingParameterNumber>( u"ALPHA"_s, QObject::tr( "Threshold (0-1, where 1 is equivalent with Convex Hull)" ), Qgis::ProcessingNumberParameterType::Double, 0.3, false, 0, 1 );
87 alphaParam->setHelp(
88 QObject::tr(
89 "Controls the concaveness of the computed hull. A value of 1 produces the convex hull, while a value closer to 0 produces a highly concave hull. For point and line layers, this value "
90 "represents the target percentage of the convex hull area. For polygon layers, it specifies the maximum edge length as a fraction of the difference between the longest and shortest edge "
91 "lengths in the empty space between polygons."
92 )
93 );
94 addParameter( alphaParam.release() );
95
96 auto holesParam = std::make_unique<QgsProcessingParameterBoolean>( u"HOLES"_s, QObject::tr( "Allow holes" ), true );
97 holesParam->setHelp( QObject::tr( "Controls whether the computed concave hull is allowed to contain holes." ) );
98 addParameter( holesParam.release() );
99}
100
101QList<int> QgsConcaveHullByFeatureAlgorithm::inputLayerTypes() const
102{
103 return QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) << static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon );
104}
105
106QgsFields QgsConcaveHullByFeatureAlgorithm::outputFields( const QgsFields &inputFields ) const
107{
108 QgsFields newFields;
109 newFields.append( QgsField( u"area"_s, QMetaType::Type::Double, QString(), 20, 6 ) );
110 newFields.append( QgsField( u"perimeter"_s, QMetaType::Type::Double, QString(), 20, 6 ) );
111 return QgsProcessingUtils::combineFields( inputFields, newFields );
112}
113
114bool QgsConcaveHullByFeatureAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
115{
116#if GEOS_VERSION_NUM < GEOS_COMPUTE_VERSION( 3, 11, 0 )
117 throw QgsProcessingException( QObject::tr( "This algorithm requires a QGIS build based on GEOS 3.11 or later" ) );
118#endif
119 mPercentage = parameterAsDouble( parameters, u"ALPHA"_s, context );
120 mAllowHoles = parameterAsBool( parameters, u"HOLES"_s, context );
121 return true;
122}
123
124QgsFeatureList QgsConcaveHullByFeatureAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback )
125{
126 QGS_MARK_ALGORITHM_SOURCE
127
128 QgsFeature f = feature;
129 if ( f.hasGeometry() )
130 {
131 QgsGeometry outputGeometry;
132 if ( f.geometry().type() == Qgis::GeometryType::Point )
133 {
134 const QgsAbstractGeometry *inputGeometry = f.geometry().constGet();
136 if ( !collection || collection->numGeometries() == 1 )
137 {
138 feedback->reportError( QObject::tr( "Cannot calculate concave hull for a single point feature (%1) (try 'Concave hull (by layer)' algorithm instead)." ).arg( f.id() ) );
139 f.clearGeometry();
140 }
141 else
142 {
143 outputGeometry = f.geometry().concaveHull( mPercentage, mAllowHoles );
144 if ( outputGeometry.isNull() && !outputGeometry.lastError().isEmpty() )
145 feedback->reportError( outputGeometry.lastError() );
146 f.setGeometry( outputGeometry );
147 }
148 }
149 else if ( f.geometry().type() == Qgis::GeometryType::Line )
150 {
151 outputGeometry = f.geometry().concaveHull( mPercentage, mAllowHoles );
152 if ( outputGeometry.isNull() && !outputGeometry.lastError().isEmpty() )
153 feedback->reportError( outputGeometry.lastError() );
154 f.setGeometry( outputGeometry );
155 }
156 else if ( f.geometry().type() == Qgis::GeometryType::Polygon )
157 {
158 outputGeometry = f.geometry().concaveHullOfPolygons( mPercentage, mAllowHoles );
159 if ( outputGeometry.isNull() && !outputGeometry.lastError().isEmpty() )
160 feedback->reportError( outputGeometry.lastError() );
161 f.setGeometry( outputGeometry );
162 }
163
164 if ( outputGeometry.type() == Qgis::GeometryType::Polygon )
165 {
166 QgsAttributes attrs = f.attributes();
167 attrs << outputGeometry.constGet()->area() << outputGeometry.constGet()->perimeter();
168 f.setAttributes( attrs );
169 }
170 else
171 {
172 if ( outputGeometry.type() == Qgis::GeometryType::Line )
173 {
174 feedback->pushWarning( QObject::tr( "Concave hull for feature %1 resulted in a linestring, ignoring" ).arg( f.id() ) );
175 }
176 else if ( outputGeometry.type() == Qgis::GeometryType::Point )
177 {
178 feedback->pushWarning( QObject::tr( "Concave hull for feature %1 resulted in a point, ignoring" ).arg( f.id() ) );
179 }
180 QgsAttributes attrs = f.attributes();
181 attrs << QVariant() << QVariant();
182 f.setAttributes( attrs );
183 }
184 }
185 return QgsFeatureList() << f;
186}
187
@ VectorPoint
Vector point layers.
Definition qgis.h:3772
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3774
@ VectorLine
Vector line layers.
Definition qgis.h:3773
@ Point
Points.
Definition qgis.h:400
@ Line
Lines.
Definition qgis.h:401
@ Polygon
Polygons.
Definition qgis.h:402
@ Double
Double/float values.
Definition qgis.h:4067
Abstract base class for all geometries.
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
A vector of attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:45
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:75
int numGeometries() const
Returns the number of geometries within the collection.
A geometry is the spatial representation of a feature.
QgsGeometry concaveHullOfPolygons(double lengthRatio, bool allowHoles=false, bool isTight=false, QgsFeedback *feedback=nullptr) const
Constructs a concave hull of a set of polygons, respecting the polygons as constraints.
QgsGeometry concaveHull(double targetPercent, bool allowHoles=false, QgsFeedback *feedback=nullptr) const
Returns a possibly concave polygon that contains all the points in the geometry.
QString lastError() const
Returns an error string referring to the last error encountered either when this geometry was created...
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Qgis::GeometryType type
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QList< QgsFeature > QgsFeatureList