Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmpointsalonggeometry.cpp 3 : : --------------------- 4 : : begin : June 2019 5 : : copyright : (C) 2019 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 : : 18 : : #include "qgsalgorithmpointsalonggeometry.h" 19 : : #include "qgsgeometrycollection.h" 20 : : #include "qgscurve.h" 21 : : #include "qgsapplication.h" 22 : : 23 : : ///@cond PRIVATE 24 : : 25 : 0 : QString QgsPointsAlongGeometryAlgorithm::name() const 26 : : { 27 : 0 : return QStringLiteral( "pointsalonglines" ); 28 : : } 29 : : 30 : 0 : QString QgsPointsAlongGeometryAlgorithm::displayName() const 31 : : { 32 : 0 : return QObject::tr( "Points along geometry" ); 33 : : } 34 : : 35 : 0 : QStringList QgsPointsAlongGeometryAlgorithm::tags() const 36 : : { 37 : 0 : return QObject::tr( "create,interpolate,points,lines,regular,distance,by" ).split( ',' ); 38 : 0 : } 39 : : 40 : 0 : QString QgsPointsAlongGeometryAlgorithm::group() const 41 : : { 42 : 0 : return QObject::tr( "Vector geometry" ); 43 : : } 44 : : 45 : 0 : QString QgsPointsAlongGeometryAlgorithm::groupId() const 46 : : { 47 : 0 : return QStringLiteral( "vectorgeometry" ); 48 : : } 49 : : 50 : 0 : QString QgsPointsAlongGeometryAlgorithm::outputName() const 51 : : { 52 : 0 : return QObject::tr( "Interpolated points" ); 53 : : } 54 : : 55 : 0 : QString QgsPointsAlongGeometryAlgorithm::shortHelpString() const 56 : : { 57 : 0 : return QObject::tr( "This algorithm creates a points layer, with points distributed along the lines of an " 58 : : "input vector layer. The distance between points (measured along the line) is defined as a parameter.\n\n" 59 : : "Start and end offset distances can be defined, so the first and last point will not fall exactly on the line's " 60 : : "first and last nodes. These start and end offsets are defined as distances, measured along the line from the first and last " 61 : : "nodes of the lines." ); 62 : : } 63 : : 64 : 0 : QString QgsPointsAlongGeometryAlgorithm::shortDescription() const 65 : : { 66 : 0 : return QObject::tr( "Creates regularly spaced points along line features." ); 67 : : } 68 : : 69 : 0 : QList<int> QgsPointsAlongGeometryAlgorithm::inputLayerTypes() const 70 : : { 71 : 0 : return QList<int>() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; 72 : 0 : } 73 : : 74 : 0 : QgsProcessing::SourceType QgsPointsAlongGeometryAlgorithm::outputLayerType() const 75 : : { 76 : 0 : return QgsProcessing::TypeVectorPoint; 77 : : } 78 : : 79 : 0 : QgsWkbTypes::Type QgsPointsAlongGeometryAlgorithm::outputWkbType( QgsWkbTypes::Type inputType ) const 80 : : { 81 : 0 : QgsWkbTypes::Type out = QgsWkbTypes::Point; 82 : 0 : if ( QgsWkbTypes::hasZ( inputType ) ) 83 : 0 : out = QgsWkbTypes::addZ( out ); 84 : 0 : if ( QgsWkbTypes::hasM( inputType ) ) 85 : 0 : out = QgsWkbTypes::addM( out ); 86 : 0 : return out; 87 : : } 88 : : 89 : 0 : QgsFields QgsPointsAlongGeometryAlgorithm::outputFields( const QgsFields &inputFields ) const 90 : : { 91 : 0 : QgsFields output = inputFields; 92 : 0 : output.append( QgsField( QStringLiteral( "distance" ), QVariant::Double ) ); 93 : 0 : output.append( QgsField( QStringLiteral( "angle" ), QVariant::Double ) ); 94 : 0 : return output; 95 : 0 : } 96 : : 97 : 0 : QgsPointsAlongGeometryAlgorithm *QgsPointsAlongGeometryAlgorithm::createInstance() const 98 : : { 99 : 0 : return new QgsPointsAlongGeometryAlgorithm(); 100 : 0 : } 101 : : 102 : 0 : void QgsPointsAlongGeometryAlgorithm::initParameters( const QVariantMap & ) 103 : : { 104 : 0 : std::unique_ptr< QgsProcessingParameterDistance> distance = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ), 105 : 0 : QObject::tr( "Distance" ), 1.0, QStringLiteral( "INPUT" ), false, 0 ); 106 : 0 : distance->setIsDynamic( true ); 107 : 0 : distance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance" ), QgsPropertyDefinition::DoublePositive ) ); 108 : 0 : distance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); 109 : 0 : addParameter( distance.release() ); 110 : : 111 : 0 : std::unique_ptr< QgsProcessingParameterDistance> startOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "START_OFFSET" ), 112 : 0 : QObject::tr( "Start offset" ), 0.0, QStringLiteral( "INPUT" ), false, 0 ); 113 : 0 : startOffset->setIsDynamic( true ); 114 : 0 : startOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "START_OFFSET" ), QObject::tr( "Start offset" ), QgsPropertyDefinition::DoublePositive ) ); 115 : 0 : startOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); 116 : 0 : addParameter( startOffset.release() ); 117 : : 118 : 0 : std::unique_ptr< QgsProcessingParameterDistance> endOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "END_OFFSET" ), 119 : 0 : QObject::tr( "End offset" ), 0.0, QStringLiteral( "INPUT" ), false, 0 ); 120 : 0 : endOffset->setIsDynamic( true ); 121 : 0 : endOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "END_OFFSET" ), QObject::tr( "End offset" ), QgsPropertyDefinition::DoublePositive ) ); 122 : 0 : endOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); 123 : 0 : addParameter( endOffset.release() ); 124 : 0 : } 125 : : 126 : 0 : QIcon QgsPointsAlongGeometryAlgorithm::icon() const 127 : : { 128 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmExtractVertices.svg" ) ); 129 : 0 : } 130 : : 131 : 0 : QString QgsPointsAlongGeometryAlgorithm::svgIconPath() const 132 : : { 133 : 0 : return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmExtractVertices.svg" ) ); 134 : 0 : } 135 : : 136 : 0 : QgsProcessingFeatureSource::Flag QgsPointsAlongGeometryAlgorithm::sourceFlags() const 137 : : { 138 : : // skip geometry checks - this algorithm doesn't care about invalid geometries 139 : 0 : return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks; 140 : : } 141 : : 142 : 0 : QgsFeatureSink::SinkFlags QgsPointsAlongGeometryAlgorithm::sinkFlags() const 143 : : { 144 : 0 : return QgsFeatureSink::RegeneratePrimaryKey; 145 : : } 146 : : 147 : 0 : bool QgsPointsAlongGeometryAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) 148 : : { 149 : 0 : mDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); 150 : 0 : mDynamicDistance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); 151 : 0 : if ( mDynamicDistance ) 152 : 0 : mDistanceProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >(); 153 : : 154 : 0 : mStartOffset = parameterAsDouble( parameters, QStringLiteral( "START_OFFSET" ), context ); 155 : 0 : mDynamicStartOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "START_OFFSET" ) ); 156 : 0 : if ( mDynamicStartOffset ) 157 : 0 : mStartOffsetProperty = parameters.value( QStringLiteral( "START_OFFSET" ) ).value< QgsProperty >(); 158 : : 159 : 0 : mEndOffset = parameterAsDouble( parameters, QStringLiteral( "END_OFFSET" ), context ); 160 : 0 : mDynamicEndOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "END_OFFSET" ) ); 161 : 0 : if ( mDynamicEndOffset ) 162 : 0 : mEndOffsetProperty = parameters.value( QStringLiteral( "END_OFFSET" ) ).value< QgsProperty >(); 163 : : 164 : 0 : return true; 165 : 0 : } 166 : : 167 : 0 : QgsFeatureList QgsPointsAlongGeometryAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 168 : : { 169 : 0 : QgsFeature f = feature; 170 : 0 : if ( f.hasGeometry() ) 171 : : { 172 : 0 : const QgsGeometry geometry = f.geometry(); 173 : : 174 : 0 : double distance = mDistance; 175 : 0 : if ( mDynamicDistance ) 176 : 0 : distance = mDistanceProperty.valueAsDouble( context.expressionContext(), distance ); 177 : 0 : if ( distance <= 0 ) 178 : 0 : return QgsFeatureList(); 179 : : 180 : 0 : double startOffset = mStartOffset; 181 : 0 : if ( mDynamicStartOffset ) 182 : 0 : startOffset = mStartOffsetProperty.valueAsDouble( context.expressionContext(), startOffset ); 183 : : 184 : 0 : double endOffset = mEndOffset; 185 : 0 : if ( mDynamicEndOffset ) 186 : 0 : endOffset = mEndOffsetProperty.valueAsDouble( context.expressionContext(), endOffset ); 187 : : 188 : 0 : const double totalLength = geometry.type() == QgsWkbTypes::PolygonGeometry ? geometry.constGet()->perimeter() 189 : 0 : : geometry.length() - endOffset; 190 : : 191 : 0 : double currentDistance = startOffset; 192 : 0 : QgsFeatureList out; 193 : 0 : out.reserve( static_cast< int >( std::ceil( ( totalLength - startOffset ) / distance ) ) ); 194 : 0 : while ( currentDistance <= totalLength ) 195 : : { 196 : 0 : const QgsGeometry point = geometry.interpolate( currentDistance ); 197 : 0 : const double angle = ( 180 / M_PI ) * geometry.interpolateAngle( currentDistance ); 198 : 0 : QgsFeature outputFeature; 199 : 0 : outputFeature.setGeometry( point ); 200 : 0 : QgsAttributes outAttr = f.attributes(); 201 : 0 : outAttr << currentDistance << angle; 202 : 0 : outputFeature.setAttributes( outAttr ); 203 : 0 : out.append( outputFeature ); 204 : 0 : currentDistance += distance; 205 : 0 : if ( feedback->isCanceled() ) // better check here -- a ridiculously small distance might take forever 206 : 0 : break; 207 : 0 : } 208 : 0 : return out; 209 : 0 : } 210 : : else 211 : : { 212 : 0 : QgsAttributes outAttr = f.attributes(); 213 : 0 : outAttr << QVariant() << QVariant(); 214 : 0 : f.setAttributes( outAttr ); 215 : 0 : return QgsFeatureList() << f; 216 : 0 : } 217 : 0 : } 218 : : 219 : : ///@endcond 220 : : 221 : :