QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsalgorithmpointsalonggeometry.cpp
Go to the documentation of this file.
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 
19 #include "qgsgeometrycollection.h"
20 #include "qgscurve.h"
21 #include "qgsapplication.h"
22 
24 
25 QString QgsPointsAlongGeometryAlgorithm::name() const
26 {
27  return QStringLiteral( "pointsalonglines" );
28 }
29 
30 QString QgsPointsAlongGeometryAlgorithm::displayName() const
31 {
32  return QObject::tr( "Points along geometry" );
33 }
34 
35 QStringList QgsPointsAlongGeometryAlgorithm::tags() const
36 {
37  return QObject::tr( "create,interpolate,points,lines,regular,distance,by" ).split( ',' );
38 }
39 
40 QString QgsPointsAlongGeometryAlgorithm::group() const
41 {
42  return QObject::tr( "Vector geometry" );
43 }
44 
45 QString QgsPointsAlongGeometryAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectorgeometry" );
48 }
49 
50 QString QgsPointsAlongGeometryAlgorithm::outputName() const
51 {
52  return QObject::tr( "Interpolated points" );
53 }
54 
55 QString QgsPointsAlongGeometryAlgorithm::shortHelpString() const
56 {
57  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 QString QgsPointsAlongGeometryAlgorithm::shortDescription() const
65 {
66  return QObject::tr( "Creates regularly spaced points along line features." );
67 }
68 
69 QList<int> QgsPointsAlongGeometryAlgorithm::inputLayerTypes() const
70 {
72 }
73 
74 QgsProcessing::SourceType QgsPointsAlongGeometryAlgorithm::outputLayerType() const
75 {
77 }
78 
79 QgsWkbTypes::Type QgsPointsAlongGeometryAlgorithm::outputWkbType( QgsWkbTypes::Type inputType ) const
80 {
82  if ( QgsWkbTypes::hasZ( inputType ) )
83  out = QgsWkbTypes::addZ( out );
84  if ( QgsWkbTypes::hasM( inputType ) )
85  out = QgsWkbTypes::addM( out );
86  return out;
87 }
88 
89 QgsFields QgsPointsAlongGeometryAlgorithm::outputFields( const QgsFields &inputFields ) const
90 {
91  QgsFields output = inputFields;
92  output.append( QgsField( QStringLiteral( "distance" ), QVariant::Double ) );
93  output.append( QgsField( QStringLiteral( "angle" ), QVariant::Double ) );
94  return output;
95 }
96 
97 QgsPointsAlongGeometryAlgorithm *QgsPointsAlongGeometryAlgorithm::createInstance() const
98 {
99  return new QgsPointsAlongGeometryAlgorithm();
100 }
101 
102 void QgsPointsAlongGeometryAlgorithm::initParameters( const QVariantMap & )
103 {
104  std::unique_ptr< QgsProcessingParameterDistance> distance = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ),
105  QObject::tr( "Distance" ), 1.0, QStringLiteral( "INPUT" ), false, 0 );
106  distance->setIsDynamic( true );
107  distance->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance" ), QgsPropertyDefinition::DoublePositive ) );
108  distance->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
109  addParameter( distance.release() );
110 
111  std::unique_ptr< QgsProcessingParameterDistance> startOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "START_OFFSET" ),
112  QObject::tr( "Start offset" ), 0.0, QStringLiteral( "INPUT" ), false, 0 );
113  startOffset->setIsDynamic( true );
114  startOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "START_OFFSET" ), QObject::tr( "Start offset" ), QgsPropertyDefinition::DoublePositive ) );
115  startOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
116  addParameter( startOffset.release() );
117 
118  std::unique_ptr< QgsProcessingParameterDistance> endOffset = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "END_OFFSET" ),
119  QObject::tr( "End offset" ), 0.0, QStringLiteral( "INPUT" ), false, 0 );
120  endOffset->setIsDynamic( true );
121  endOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "END_OFFSET" ), QObject::tr( "End offset" ), QgsPropertyDefinition::DoublePositive ) );
122  endOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
123  addParameter( endOffset.release() );
124 }
125 
126 QIcon QgsPointsAlongGeometryAlgorithm::icon() const
127 {
128  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmExtractVertices.svg" ) );
129 }
130 
131 QString QgsPointsAlongGeometryAlgorithm::svgIconPath() const
132 {
133  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmExtractVertices.svg" ) );
134 }
135 
136 QgsProcessingFeatureSource::Flag QgsPointsAlongGeometryAlgorithm::sourceFlags() const
137 {
138  // skip geometry checks - this algorithm doesn't care about invalid geometries
140 }
141 
142 QgsFeatureSink::SinkFlags QgsPointsAlongGeometryAlgorithm::sinkFlags() const
143 {
145 }
146 
147 bool QgsPointsAlongGeometryAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
148 {
149  mDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
150  mDynamicDistance = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
151  if ( mDynamicDistance )
152  mDistanceProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
153 
154  mStartOffset = parameterAsDouble( parameters, QStringLiteral( "START_OFFSET" ), context );
155  mDynamicStartOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "START_OFFSET" ) );
156  if ( mDynamicStartOffset )
157  mStartOffsetProperty = parameters.value( QStringLiteral( "START_OFFSET" ) ).value< QgsProperty >();
158 
159  mEndOffset = parameterAsDouble( parameters, QStringLiteral( "END_OFFSET" ), context );
160  mDynamicEndOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "END_OFFSET" ) );
161  if ( mDynamicEndOffset )
162  mEndOffsetProperty = parameters.value( QStringLiteral( "END_OFFSET" ) ).value< QgsProperty >();
163 
164  return true;
165 }
166 
167 QgsFeatureList QgsPointsAlongGeometryAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
168 {
169  QgsFeature f = feature;
170  if ( f.hasGeometry() )
171  {
172  const QgsGeometry geometry = f.geometry();
173 
174  double distance = mDistance;
175  if ( mDynamicDistance )
176  distance = mDistanceProperty.valueAsDouble( context.expressionContext(), distance );
177  if ( distance <= 0 )
178  return QgsFeatureList();
179 
180  double startOffset = mStartOffset;
181  if ( mDynamicStartOffset )
182  startOffset = mStartOffsetProperty.valueAsDouble( context.expressionContext(), startOffset );
183 
184  double endOffset = mEndOffset;
185  if ( mDynamicEndOffset )
186  endOffset = mEndOffsetProperty.valueAsDouble( context.expressionContext(), endOffset );
187 
188  const double totalLength = geometry.type() == QgsWkbTypes::PolygonGeometry ? geometry.constGet()->perimeter()
189  : geometry.length() - endOffset;
190 
191  double currentDistance = startOffset;
192  QgsFeatureList out;
193  out.reserve( static_cast< int >( std::ceil( ( totalLength - startOffset ) / distance ) ) );
194  while ( currentDistance <= totalLength )
195  {
196  const QgsGeometry point = geometry.interpolate( currentDistance );
197  const double angle = ( 180 / M_PI ) * geometry.interpolateAngle( currentDistance );
198  QgsFeature outputFeature;
199  outputFeature.setGeometry( point );
200  QgsAttributes outAttr = f.attributes();
201  outAttr << currentDistance << angle;
202  outputFeature.setAttributes( outAttr );
203  out.append( outputFeature );
204  currentDistance += distance;
205  if ( feedback->isCanceled() ) // better check here -- a ridiculously small distance might take forever
206  break;
207  }
208  return out;
209  }
210  else
211  {
212  QgsAttributes outAttr = f.attributes();
213  outAttr << QVariant() << QVariant();
214  f.setAttributes( outAttr );
215  return QgsFeatureList() << f;
216  }
217 }
218 
220 
221 
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
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:135
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
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:124
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double length() const
Returns the planar, 2-dimensional length of geometry.
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
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.
static bool isDynamic(const QVariantMap &parameters, const QString &name)
Returns true if the parameter with matching name is a dynamic parameter, and must be evaluated once f...
SourceType
Data source types enum.
Definition: qgsprocessing.h:46
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
Definition for a property.
Definition: qgsproperty.h:48
@ DoublePositive
Positive double value (including 0)
Definition: qgsproperty.h:59
A store for object properties.
Definition: qgsproperty.h:232
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1100
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:1146
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1050
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1171
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:736