QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsalgorithmtransect.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmtransect.cpp
3  -------------------------
4  begin : October 2017
5  copyright : (C) 2017 by Loïc Bartoletti
6  email : lbartoletti at tuxfamily dot org
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 "qgsalgorithmtransect.h"
19 #include "qgsmultilinestring.h"
20 #include "qgslinestring.h"
21 
23 
24 QString QgsTransectAlgorithm::name() const
25 {
26  return QStringLiteral( "transect" );
27 }
28 
29 QString QgsTransectAlgorithm::displayName() const
30 {
31  return QObject::tr( "Transect" );
32 }
33 
34 QStringList QgsTransectAlgorithm::tags() const
35 {
36  return QObject::tr( "transect,station,lines,extend," ).split( ',' );
37 }
38 
39 QString QgsTransectAlgorithm::group() const
40 {
41  return QObject::tr( "Vector geometry" );
42 }
43 
44 QString QgsTransectAlgorithm::groupId() const
45 {
46  return QStringLiteral( "vectorgeometry" );
47 }
48 
49 void QgsTransectAlgorithm::initAlgorithm( const QVariantMap & )
50 {
51  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
52  QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
53  std::unique_ptr< QgsProcessingParameterDistance > length = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "LENGTH" ), QObject::tr( "Length of the transect" ),
54  5.0, QStringLiteral( "INPUT" ), false, 0 );
55  length->setIsDynamic( true );
56  length->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "LENGTH" ), QObject::tr( "Length of the transect" ), QgsPropertyDefinition::DoublePositive ) );
57  length->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
58  addParameter( length.release() );
59 
60  std::unique_ptr< QgsProcessingParameterNumber > angle = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "ANGLE" ), QObject::tr( "Angle in degrees from the original line at the vertices" ), QgsProcessingParameterNumber::Double,
61  90.0, false, 0, 360 );
62  angle->setIsDynamic( true );
63  angle->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "ANGLE" ), QObject::tr( "Angle in degrees" ), QgsPropertyDefinition::Double ) );
64  angle->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
65  addParameter( angle.release() );
66 
67  addParameter( new QgsProcessingParameterEnum( QStringLiteral( "SIDE" ), QObject::tr( "Side to create the transects" ), QStringList() << QObject::tr( "Left" ) << QObject::tr( "Right" ) << QObject::tr( "Both" ), false ) );
68  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Transect" ), QgsProcessing::TypeVectorLine ) );
69 
70 }
71 
72 QString QgsTransectAlgorithm::shortHelpString() const
73 {
74 
75  return QObject::tr( "This algorithm creates transects on vertices for (multi)linestring.\n" ) +
76  QObject::tr( "A transect is a line oriented from an angle (by default perpendicular) to the input polylines (at vertices)." ) +
77  QStringLiteral( "\n\n" ) +
78  QObject::tr( "Field(s) from feature(s) are returned in the transect with these new fields:\n" ) +
79  QObject::tr( "- TR_FID: ID of the original feature\n" ) +
80  QObject::tr( "- TR_ID: ID of the transect. Each transect have an unique ID\n" ) +
81  QObject::tr( "- TR_SEGMENT: ID of the segment of the linestring\n" ) +
82  QObject::tr( "- TR_ANGLE: Angle in degrees from the original line at the vertex\n" ) +
83  QObject::tr( "- TR_LENGTH: Total length of the transect returned\n" ) +
84  QObject::tr( "- TR_ORIENT: Side of the transect (only on the left or right of the line, or both side)\n" );
85 
86 }
87 
88 QgsTransectAlgorithm *QgsTransectAlgorithm::createInstance() const
89 {
90  return new QgsTransectAlgorithm();
91 }
92 
93 QVariantMap QgsTransectAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
94 {
95  Side orientation = static_cast< QgsTransectAlgorithm::Side >( parameterAsInt( parameters, QStringLiteral( "SIDE" ), context ) );
96  double angle = fabs( parameterAsDouble( parameters, QStringLiteral( "ANGLE" ), context ) );
97  bool dynamicAngle = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ANGLE" ) );
98  QgsProperty angleProperty;
99  if ( dynamicAngle )
100  angleProperty = parameters.value( QStringLiteral( "ANGLE" ) ).value< QgsProperty >();
101 
102  double length = parameterAsDouble( parameters, QStringLiteral( "LENGTH" ), context );
103  bool dynamicLength = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "LENGTH" ) );
104  QgsProperty lengthProperty;
105  if ( dynamicLength )
106  lengthProperty = parameters.value( QStringLiteral( "LENGTH" ) ).value< QgsProperty >();
107 
108  if ( orientation == QgsTransectAlgorithm::Both )
109  length /= 2.0;
110 
111  std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
112  if ( !source )
113  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
114 
115  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, dynamic_cast< QgsProcessingFeatureSource * >( source.get() ) );
116 
117  QgsFields fields = source->fields();
118 
119  fields.append( QgsField( QStringLiteral( "TR_FID" ), QVariant::Int, QString(), 20 ) );
120  fields.append( QgsField( QStringLiteral( "TR_ID" ), QVariant::Int, QString(), 20 ) );
121  fields.append( QgsField( QStringLiteral( "TR_SEGMENT" ), QVariant::Int, QString(), 20 ) );
122  fields.append( QgsField( QStringLiteral( "TR_ANGLE" ), QVariant::Double, QString(), 5, 2 ) );
123  fields.append( QgsField( QStringLiteral( "TR_LENGTH" ), QVariant::Double, QString(), 20, 6 ) );
124  fields.append( QgsField( QStringLiteral( "TR_ORIENT" ), QVariant::Int, QString(), 1 ) );
125 
127  if ( QgsWkbTypes::hasZ( source->wkbType() ) )
128  outputWkb = QgsWkbTypes::addZ( outputWkb );
129  if ( QgsWkbTypes::hasM( source->wkbType() ) )
130  outputWkb = QgsWkbTypes::addM( outputWkb );
131 
132  QString dest;
133  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields,
134  outputWkb, source->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
135  if ( !sink )
136  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
137 
138  QgsFeatureIterator features = source->getFeatures( );
139 
140  int current = -1;
141  int number = 0;
142  double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
143  QgsFeature feat;
144 
145 
146  while ( features.nextFeature( feat ) )
147  {
148  current++;
149  if ( feedback->isCanceled() )
150  {
151  break;
152  }
153 
154  feedback->setProgress( current * step );
155  if ( !feat.hasGeometry() )
156  continue;
157 
158  QgsGeometry inputGeometry = feat.geometry();
159 
160  if ( dynamicLength || dynamicAngle )
161  {
162  expressionContext.setFeature( feat );
163  }
164 
165  double evaluatedLength = length;
166  if ( dynamicLength )
167  evaluatedLength = lengthProperty.valueAsDouble( context.expressionContext(), length );
168  double evaluatedAngle = angle;
169  if ( dynamicAngle )
170  evaluatedAngle = angleProperty.valueAsDouble( context.expressionContext(), angle );
171 
172  inputGeometry.convertToMultiType();
173  const QgsMultiLineString *multiLine = static_cast< const QgsMultiLineString * >( inputGeometry.constGet() );
174  for ( int id = 0; id < multiLine->numGeometries(); ++id )
175  {
176  const QgsLineString *line = static_cast< const QgsLineString * >( multiLine->geometryN( id ) );
178  while ( it != line->vertices_end() )
179  {
180  QgsVertexId vertexId = it.vertexId();
181  int i = vertexId.vertex;
182  QgsFeature outFeat;
183  QgsAttributes attrs = feat.attributes();
184  attrs << current << number << i + 1 << evaluatedAngle <<
185  ( ( orientation == QgsTransectAlgorithm::Both ) ? evaluatedLength * 2 : evaluatedLength ) <<
186  orientation;
187  outFeat.setAttributes( attrs );
188  double angleAtVertex = line->vertexAngle( vertexId );
189  outFeat.setGeometry( calcTransect( *it, angleAtVertex, evaluatedLength, orientation, evaluatedAngle ) );
190  sink->addFeature( outFeat, QgsFeatureSink::FastInsert );
191  number++;
192  it++;
193  }
194  }
195  }
196 
197  QVariantMap outputs;
198  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
199  return outputs;
200 }
201 
202 
203 QgsGeometry QgsTransectAlgorithm::calcTransect( const QgsPoint &point, const double angleAtVertex, const double length, const QgsTransectAlgorithm::Side orientation, const double angle )
204 {
205  QgsPoint pLeft; // left point of the line
206  QgsPoint pRight; // right point of the line
207 
208  QgsPolyline line;
209 
210  if ( ( orientation == QgsTransectAlgorithm::Right ) || ( orientation == QgsTransectAlgorithm::Both ) )
211  {
212  pLeft = point.project( length, angle + 180.0 / M_PI * angleAtVertex );
213  if ( orientation != QgsTransectAlgorithm::Both )
214  pRight = point;
215  }
216 
217  if ( ( orientation == QgsTransectAlgorithm::Left ) || ( orientation == QgsTransectAlgorithm::Both ) )
218  {
219  pRight = point.project( -length, angle + 180.0 / M_PI * angleAtVertex );
220  if ( orientation != QgsTransectAlgorithm::Both )
221  pLeft = point;
222  }
223 
224  line.append( pLeft );
225  line.append( pRight );
226 
227  return QgsGeometry::fromPolyline( line );
228 }
229 
Wrapper for iterator of features from vector data provider or vector layer.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for providing feedback from a processing algorithm.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QVector< QgsPoint > QgsPolyline
Polyline as represented as a vector of points.
Definition: qgsgeometry.h:64
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Multi line string geometry collection.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
Positive double value (including 0)
Definition: qgsproperty.h:58
vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:906
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
A feature sink output for processing algorithms.
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry...
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1027
An enum based parameter for processing algorithms, allowing for selection from predefined values...
Utility class for identifying a unique vertex within a geometry.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1002
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
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
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.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
int numGeometries() const
Returns the number of geometries within the collection.
The vertex_iterator class provides STL-style iterator for vertices.
A store for object properties.
Definition: qgsproperty.h:229
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
Double value (including negative values)
Definition: qgsproperty.h:57
QgsExpressionContext & expressionContext()
Returns the expression context.
Definition for a property.
Definition: qgsproperty.h:46
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
An input feature source (such as vector layers) parameter for processing algorithms.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
Vector line layers.
Definition: qgsprocessing.h:49
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:956
QgsGeometry geometry
Definition: qgsfeature.h:67
bool nextFeature(QgsFeature &f)
A vector of attributes.
Definition: qgsattributes.h:57
Contains information about the context in which a processing algorithm is executed.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:643
QgsVertexId vertexId() const
Returns vertex ID of the current item.
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...
QgsAttributes attributes
Definition: qgsfeature.h:65