Branch data Line data Source code
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 : : 18 : : #include "qgsalgorithmextractspecificvertices.h" 19 : : 20 : : #include "qgsabstractgeometry.h" 21 : : #include "qgsgeometryutils.h" 22 : : 23 : : ///@cond PRIVATE 24 : : 25 : 0 : QString QgsExtractSpecificVerticesAlgorithm::name() const 26 : : { 27 : 0 : return QStringLiteral( "extractspecificvertices" ); 28 : : } 29 : : 30 : 0 : QString QgsExtractSpecificVerticesAlgorithm::displayName() const 31 : : { 32 : 0 : return QObject::tr( "Extract specific vertices" ); 33 : : } 34 : : 35 : 0 : QStringList QgsExtractSpecificVerticesAlgorithm::tags() const 36 : : { 37 : 0 : return QObject::tr( "points,vertex,nodes" ).split( ',' ); 38 : 0 : } 39 : : 40 : 0 : QString QgsExtractSpecificVerticesAlgorithm::group() const 41 : : { 42 : 0 : return QObject::tr( "Vector geometry" ); 43 : : } 44 : : 45 : 0 : QString QgsExtractSpecificVerticesAlgorithm::groupId() const 46 : : { 47 : 0 : return QStringLiteral( "vectorgeometry" ); 48 : : } 49 : : 50 : 0 : QString QgsExtractSpecificVerticesAlgorithm::shortHelpString() const 51 : : { 52 : 0 : 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 : 0 : "to each point are the same ones associated to the line or polygon that the point belongs to." ) + 56 : 0 : QStringLiteral( "\n\n" ) + 57 : 0 : 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 : 0 : "e.g., an index of -1 corresponds to the last vertex, -2 corresponds to the second last vertex, etc." ) + 61 : 0 : QStringLiteral( "\n\n" ) + 62 : 0 : 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 : 0 : } 66 : : 67 : 0 : QString QgsExtractSpecificVerticesAlgorithm::outputName() const 68 : : { 69 : 0 : return QObject::tr( "Vertices" ); 70 : : } 71 : : 72 : 0 : QgsExtractSpecificVerticesAlgorithm *QgsExtractSpecificVerticesAlgorithm::createInstance() const 73 : : { 74 : 0 : return new QgsExtractSpecificVerticesAlgorithm(); 75 : : } 76 : : 77 : 0 : QgsProcessing::SourceType QgsExtractSpecificVerticesAlgorithm::outputLayerType() const 78 : : { 79 : 0 : return QgsProcessing::TypeVectorPoint; 80 : : } 81 : : 82 : 0 : QgsFields QgsExtractSpecificVerticesAlgorithm::outputFields( const QgsFields &inputFields ) const 83 : : { 84 : 0 : QgsFields outputFields = inputFields; 85 : 0 : outputFields.append( QgsField( QStringLiteral( "vertex_pos" ), QVariant::Int ) ); 86 : 0 : outputFields.append( QgsField( QStringLiteral( "vertex_index" ), QVariant::Int ) ); 87 : 0 : outputFields.append( QgsField( QStringLiteral( "vertex_part" ), QVariant::Int ) ); 88 : 0 : if ( mGeometryType == QgsWkbTypes::PolygonGeometry ) 89 : : { 90 : 0 : outputFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QVariant::Int ) ); 91 : 0 : } 92 : 0 : outputFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QVariant::Int ) ); 93 : 0 : outputFields.append( QgsField( QStringLiteral( "distance" ), QVariant::Double ) ); 94 : 0 : outputFields.append( QgsField( QStringLiteral( "angle" ), QVariant::Double ) ); 95 : : 96 : 0 : return outputFields; 97 : 0 : } 98 : : 99 : 0 : QgsWkbTypes::Type QgsExtractSpecificVerticesAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const 100 : : { 101 : 0 : QgsWkbTypes::Type outputWkbType = QgsWkbTypes::Point; 102 : 0 : if ( QgsWkbTypes::hasM( inputWkbType ) ) 103 : : { 104 : 0 : outputWkbType = QgsWkbTypes::addM( outputWkbType ); 105 : 0 : } 106 : 0 : if ( QgsWkbTypes::hasZ( inputWkbType ) ) 107 : : { 108 : 0 : outputWkbType = QgsWkbTypes::addZ( outputWkbType ); 109 : 0 : } 110 : : 111 : 0 : return outputWkbType; 112 : : } 113 : : 114 : 0 : QgsProcessingFeatureSource::Flag QgsExtractSpecificVerticesAlgorithm::sourceFlags() const 115 : : { 116 : 0 : return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks; 117 : : } 118 : : 119 : 0 : QgsFeatureSink::SinkFlags QgsExtractSpecificVerticesAlgorithm::sinkFlags() const 120 : : { 121 : 0 : return QgsFeatureSink::RegeneratePrimaryKey; 122 : : } 123 : : 124 : 0 : void QgsExtractSpecificVerticesAlgorithm::initParameters( const QVariantMap & ) 125 : : { 126 : 0 : addParameter( new QgsProcessingParameterString( QStringLiteral( "VERTICES" ), QObject::tr( "Vertex indices" ), QStringLiteral( "0" ) ) ); 127 : 0 : } 128 : : 129 : 0 : bool QgsExtractSpecificVerticesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 130 : : { 131 : 0 : std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); 132 : 0 : mGeometryType = QgsWkbTypes::geometryType( source->wkbType() ); 133 : : 134 : 0 : 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 : 0 : const QStringList verticesList = verticesString.split( ',', Qt::SkipEmptyParts ); 139 : : #endif 140 : 0 : for ( const QString &vertex : verticesList ) 141 : : { 142 : 0 : bool ok = false; 143 : 0 : int i = vertex.toInt( &ok ); 144 : 0 : if ( ok ) 145 : : { 146 : 0 : mIndices << i; 147 : 0 : } 148 : : else 149 : : { 150 : 0 : throw QgsProcessingException( QObject::tr( "'%1' is not a valid vertex index" ).arg( vertex ) ); 151 : : } 152 : : } 153 : : 154 : : return true; 155 : 0 : } 156 : : 157 : 0 : QgsFeatureList QgsExtractSpecificVerticesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * ) 158 : : { 159 : 0 : QgsFeatureList outputFeatures; 160 : : 161 : 0 : QgsFeature f = feature; 162 : 0 : QgsGeometry inputGeom = f.geometry(); 163 : 0 : if ( inputGeom.isNull() ) 164 : : { 165 : 0 : QgsAttributes attrs = f.attributes(); 166 : 0 : attrs << QVariant() 167 : 0 : << QVariant() 168 : 0 : << QVariant(); 169 : 0 : if ( mGeometryType == QgsWkbTypes::PolygonGeometry ) 170 : : { 171 : 0 : attrs << QVariant(); 172 : 0 : } 173 : 0 : attrs << QVariant() 174 : 0 : << QVariant() 175 : 0 : << QVariant(); 176 : : 177 : 0 : f.setAttributes( attrs ); 178 : 0 : outputFeatures << f; 179 : 0 : } 180 : : else 181 : : { 182 : : int vertexIndex; 183 : 0 : int totalVertices = inputGeom.constGet()->nCoordinates(); 184 : 0 : for ( int vertex : mIndices ) 185 : : { 186 : 0 : if ( vertex < 0 ) 187 : : { 188 : 0 : vertexIndex = totalVertices + vertex; 189 : 0 : } 190 : : else 191 : : { 192 : 0 : vertexIndex = vertex; 193 : : } 194 : : 195 : 0 : if ( vertexIndex < 0 || vertexIndex >= totalVertices ) 196 : 0 : continue; 197 : : 198 : 0 : QgsVertexId vertexId; 199 : 0 : inputGeom.vertexIdFromVertexNr( vertexIndex, vertexId ); 200 : : 201 : 0 : double distance = inputGeom.distanceToVertex( vertexIndex ); 202 : 0 : double angle = inputGeom.angleAtVertex( vertexIndex ) * 180 / M_PI; 203 : : 204 : 0 : QgsFeature outFeature = QgsFeature(); 205 : 0 : QgsAttributes attrs = f.attributes(); 206 : 0 : attrs << vertex 207 : 0 : << vertexIndex 208 : 0 : << vertexId.part; 209 : 0 : if ( mGeometryType == QgsWkbTypes::PolygonGeometry ) 210 : : { 211 : 0 : attrs << vertexId.ring; 212 : 0 : } 213 : 0 : attrs << vertexId.vertex 214 : 0 : << distance 215 : 0 : << angle; 216 : : 217 : 0 : outFeature.setAttributes( attrs ); 218 : 0 : QgsPoint point = inputGeom.vertexAt( vertexIndex ); 219 : 0 : outFeature.setGeometry( QgsGeometry( point.clone() ) ); 220 : 0 : outputFeatures << outFeature; 221 : 0 : } 222 : : } 223 : : 224 : 0 : return outputFeatures; 225 : 0 : } 226 : : 227 : : ///@endcond