QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsalgorithmextractspecificvertices.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmextractspecificvertices.cpp
3  --------------------------
4  begin : November 2019
5  copyright : (C) 2019 by Alexander Bruy
6  email : alexander dot bruy 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 
20 #include "qgsabstractgeometry.h"
21 #include "qgsgeometryutils.h"
22 
24 
25 QString QgsExtractSpecificVerticesAlgorithm::name() const
26 {
27  return QStringLiteral( "extractspecificvertices" );
28 }
29 
30 QString QgsExtractSpecificVerticesAlgorithm::displayName() const
31 {
32  return QObject::tr( "Extract specific vertices" );
33 }
34 
35 QStringList QgsExtractSpecificVerticesAlgorithm::tags() const
36 {
37  return QObject::tr( "points,vertex,nodes" ).split( ',' );
38 }
39 
40 QString QgsExtractSpecificVerticesAlgorithm::group() const
41 {
42  return QObject::tr( "Vector geometry" );
43 }
44 
45 QString QgsExtractSpecificVerticesAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectorgeometry" );
48 }
49 
50 QString QgsExtractSpecificVerticesAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "This algorithm takes a line or polygon layer and generates a point layer with points "
53  "representing specific vertices in the input lines or polygons. For instance, this algorithm "
54  "can be used to extract the first or last vertices in the geometry. The attributes associated "
55  "to each point are the same ones associated to the line or polygon that the point belongs to." ) +
56  QStringLiteral( "\n\n" ) +
57  QObject::tr( "The vertex indices parameter accepts a comma separated string specifying the indices of the "
58  "vertices to extract. The first vertex corresponds to an index of 0, the second vertex has an "
59  "index of 1, etc. Negative indices can be used to find vertices at the end of the geometry, "
60  "e.g., an index of -1 corresponds to the last vertex, -2 corresponds to the second last vertex, etc." ) +
61  QStringLiteral( "\n\n" ) +
62  QObject::tr( "Additional fields are added to the points indicating the specific vertex position (e.g., 0, -1, etc), "
63  "the original vertex index, the vertex’s part and its index within the part (as well as its ring for "
64  "polygons), distance along the original geometry and bisector angle of vertex for the original geometry." );
65 }
66 
67 QString QgsExtractSpecificVerticesAlgorithm::outputName() const
68 {
69  return QObject::tr( "Vertices" );
70 }
71 
72 QgsExtractSpecificVerticesAlgorithm *QgsExtractSpecificVerticesAlgorithm::createInstance() const
73 {
74  return new QgsExtractSpecificVerticesAlgorithm();
75 }
76 
77 QgsProcessing::SourceType QgsExtractSpecificVerticesAlgorithm::outputLayerType() const
78 {
80 }
81 
82 QgsFields QgsExtractSpecificVerticesAlgorithm::outputFields( const QgsFields &inputFields ) const
83 {
84  QgsFields outputFields = inputFields;
85  outputFields.append( QgsField( QStringLiteral( "vertex_pos" ), QVariant::Int ) );
86  outputFields.append( QgsField( QStringLiteral( "vertex_index" ), QVariant::Int ) );
87  outputFields.append( QgsField( QStringLiteral( "vertex_part" ), QVariant::Int ) );
88  if ( mGeometryType == QgsWkbTypes::PolygonGeometry )
89  {
90  outputFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QVariant::Int ) );
91  }
92  outputFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QVariant::Int ) );
93  outputFields.append( QgsField( QStringLiteral( "distance" ), QVariant::Double ) );
94  outputFields.append( QgsField( QStringLiteral( "angle" ), QVariant::Double ) );
95 
96  return outputFields;
97 }
98 
99 QgsWkbTypes::Type QgsExtractSpecificVerticesAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
100 {
101  QgsWkbTypes::Type outputWkbType = QgsWkbTypes::Point;
102  if ( QgsWkbTypes::hasM( inputWkbType ) )
103  {
104  outputWkbType = QgsWkbTypes::addM( outputWkbType );
105  }
106  if ( QgsWkbTypes::hasZ( inputWkbType ) )
107  {
108  outputWkbType = QgsWkbTypes::addZ( outputWkbType );
109  }
110 
111  return outputWkbType;
112 }
113 
114 QgsProcessingFeatureSource::Flag QgsExtractSpecificVerticesAlgorithm::sourceFlags() const
115 {
117 }
118 
119 QgsFeatureSink::SinkFlags QgsExtractSpecificVerticesAlgorithm::sinkFlags() const
120 {
122 }
123 
124 void QgsExtractSpecificVerticesAlgorithm::initParameters( const QVariantMap & )
125 {
126  addParameter( new QgsProcessingParameterString( QStringLiteral( "VERTICES" ), QObject::tr( "Vertex indices" ), QStringLiteral( "0" ) ) );
127 }
128 
129 bool QgsExtractSpecificVerticesAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
130 {
131  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
132  mGeometryType = QgsWkbTypes::geometryType( source->wkbType() );
133 
134  const QString verticesString = parameterAsString( parameters, QStringLiteral( "VERTICES" ), context );
135 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
136  const QStringList verticesList = verticesString.split( ',', QString::SkipEmptyParts );
137 #else
138  const QStringList verticesList = verticesString.split( ',', Qt::SkipEmptyParts );
139 #endif
140  for ( const QString &vertex : verticesList )
141  {
142  bool ok = false;
143  const int i = vertex.toInt( &ok );
144  if ( ok )
145  {
146  mIndices << i;
147  }
148  else
149  {
150  throw QgsProcessingException( QObject::tr( "'%1' is not a valid vertex index" ).arg( vertex ) );
151  }
152  }
153 
154  return true;
155 }
156 
157 QgsFeatureList QgsExtractSpecificVerticesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
158 {
159  QgsFeatureList outputFeatures;
160 
161  QgsFeature f = feature;
162  const QgsGeometry inputGeom = f.geometry();
163  if ( inputGeom.isNull() )
164  {
165  QgsAttributes attrs = f.attributes();
166  attrs << QVariant()
167  << QVariant()
168  << QVariant();
169  if ( mGeometryType == QgsWkbTypes::PolygonGeometry )
170  {
171  attrs << QVariant();
172  }
173  attrs << QVariant()
174  << QVariant()
175  << QVariant();
176 
177  f.setAttributes( attrs );
178  outputFeatures << f;
179  }
180  else
181  {
182  int vertexIndex;
183  const int totalVertices = inputGeom.constGet()->nCoordinates();
184  for ( const int vertex : mIndices )
185  {
186  if ( vertex < 0 )
187  {
188  vertexIndex = totalVertices + vertex;
189  }
190  else
191  {
192  vertexIndex = vertex;
193  }
194 
195  if ( vertexIndex < 0 || vertexIndex >= totalVertices )
196  continue;
197 
198  QgsVertexId vertexId;
199  inputGeom.vertexIdFromVertexNr( vertexIndex, vertexId );
200 
201  const double distance = inputGeom.distanceToVertex( vertexIndex );
202  const double angle = inputGeom.angleAtVertex( vertexIndex ) * 180 / M_PI;
203 
204  QgsFeature outFeature = QgsFeature();
205  QgsAttributes attrs = f.attributes();
206  attrs << vertex
207  << vertexIndex
208  << vertexId.part;
209  if ( mGeometryType == QgsWkbTypes::PolygonGeometry )
210  {
211  attrs << vertexId.ring;
212  }
213  attrs << vertexId.vertex
214  << distance
215  << angle;
216 
217  outFeature.setAttributes( attrs );
218  const QgsPoint point = inputGeom.vertexAt( vertexIndex );
219  outFeature.setGeometry( QgsGeometry( point.clone() ) );
220  outputFeatures << outFeature;
221  }
222  }
223 
224  return outputFeatures;
225 }
226 
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
A vector of attributes.
Definition: qgsattributes.h:58
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
QgsGeometry geometry
Definition: qgsfeature.h:67
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
QgsPoint * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgspoint.cpp:104
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Flag
Flags controlling how QgsProcessingFeatureSource fetches features.
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
A string parameter for processing algorithms.
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:31
int vertex
Vertex number.
Definition: qgsvertexid.h:95
int part
Part number.
Definition: qgsvertexid.h:89
int ring
Ring number.
Definition: qgsvertexid.h:92