QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsalgorithmlineintersection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmlineintersection.cpp
3  ---------------------
4  begin : April 2017
5  copyright : (C) 2017 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 "qgsgeometryengine.h"
20 
22 
23 QString QgsLineIntersectionAlgorithm::name() const
24 {
25  return QStringLiteral( "lineintersections" );
26 }
27 
28 QString QgsLineIntersectionAlgorithm::displayName() const
29 {
30  return QObject::tr( "Line intersections" );
31 }
32 
33 QStringList QgsLineIntersectionAlgorithm::tags() const
34 {
35  return QObject::tr( "line,intersection" ).split( ',' );
36 }
37 
38 QString QgsLineIntersectionAlgorithm::group() const
39 {
40  return QObject::tr( "Vector overlay" );
41 }
42 
43 QString QgsLineIntersectionAlgorithm::groupId() const
44 {
45  return QStringLiteral( "vectoroverlay" );
46 }
47 
48 void QgsLineIntersectionAlgorithm::initAlgorithm( const QVariantMap & )
49 {
50  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
51  QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
52  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INTERSECT" ),
53  QObject::tr( "Intersect layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
54 
55  addParameter( new QgsProcessingParameterField(
56  QStringLiteral( "INPUT_FIELDS" ),
57  QObject::tr( "Input fields to keep (leave empty to keep all fields)" ), QVariant(),
58  QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any,
59  true, true ) );
60  addParameter( new QgsProcessingParameterField(
61  QStringLiteral( "INTERSECT_FIELDS" ),
62  QObject::tr( "Intersect fields to keep (leave empty to keep all fields)" ), QVariant(),
63  QStringLiteral( "INTERSECT" ), QgsProcessingParameterField::Any,
64  true, true ) );
65 
66  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Intersections" ), QgsProcessing::TypeVectorPoint ) );
67 }
68 
69 QString QgsLineIntersectionAlgorithm::shortHelpString() const
70 {
71  return QObject::tr( "This algorithm creates point features where the lines in the Intersect layer intersect the lines in the Input layer." );
72 }
73 
74 QgsLineIntersectionAlgorithm *QgsLineIntersectionAlgorithm::createInstance() const
75 {
76  return new QgsLineIntersectionAlgorithm();
77 }
78 
79 QVariantMap QgsLineIntersectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
80 {
81  std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
82  if ( !sourceA )
83  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
84 
85  std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) );
86  if ( !sourceB )
87  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) );
88 
89  const QStringList fieldsA = parameterAsFields( parameters, QStringLiteral( "INPUT_FIELDS" ), context );
90  const QStringList fieldsB = parameterAsFields( parameters, QStringLiteral( "INTERSECT_FIELDS" ), context );
91 
92  QgsFields outFieldsA;
93  QgsAttributeList fieldsAIndices;
94 
95  if ( fieldsA.empty() )
96  {
97  outFieldsA = sourceA->fields();
98  for ( int i = 0; i < outFieldsA.count(); ++i )
99  {
100  fieldsAIndices << i;
101  }
102  }
103  else
104  {
105  for ( const QString &field : fieldsA )
106  {
107  int index = sourceA->fields().lookupField( field );
108  if ( index >= 0 )
109  {
110  fieldsAIndices << index;
111  outFieldsA.append( sourceA->fields().at( index ) );
112  }
113  }
114  }
115 
116  QgsFields outFieldsB;
117  QgsAttributeList fieldsBIndices;
118 
119  if ( fieldsB.empty() )
120  {
121  outFieldsB = sourceB->fields();
122  for ( int i = 0; i < outFieldsB.count(); ++i )
123  {
124  fieldsBIndices << i;
125  }
126  }
127  else
128  {
129  for ( const QString &field : fieldsB )
130  {
131  int index = sourceB->fields().lookupField( field );
132  if ( index >= 0 )
133  {
134  fieldsBIndices << index;
135  outFieldsB.append( sourceB->fields().at( index ) );
136  }
137  }
138  }
139 
140  QgsFields outFields = QgsProcessingUtils::combineFields( outFieldsA, outFieldsB );
141 
142  QString dest;
143  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, QgsWkbTypes::Point, sourceA->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
144  if ( !sink )
145  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
146 
147  QgsSpatialIndex spatialIndex( sourceB->getFeatures( QgsFeatureRequest().setNoAttributes().setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ) ), feedback );
148  QgsFeature outFeature;
149  QgsFeatureIterator features = sourceA->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldsAIndices ) );
150  double step = sourceA->featureCount() > 0 ? 100.0 / sourceA->featureCount() : 1;
151  int i = 0;
152  QgsFeature inFeatureA;
153  while ( features.nextFeature( inFeatureA ) )
154  {
155  i++;
156  if ( feedback->isCanceled() )
157  {
158  break;
159  }
160 
161  if ( !inFeatureA.hasGeometry() )
162  continue;
163 
164  QgsGeometry inGeom = inFeatureA.geometry();
165  QgsFeatureIds lines = spatialIndex.intersects( inGeom.boundingBox() ).toSet();
166  if ( !lines.empty() )
167  {
168  // use prepared geometries for faster intersection tests
169  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( inGeom.constGet() ) );
170  engine->prepareGeometry();
171 
173  request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() );
174  request.setSubsetOfAttributes( fieldsBIndices );
175 
176  QgsFeature inFeatureB;
177  QgsFeatureIterator featuresB = sourceB->getFeatures( request );
178  while ( featuresB.nextFeature( inFeatureB ) )
179  {
180  if ( feedback->isCanceled() )
181  {
182  break;
183  }
184 
185  QgsGeometry tmpGeom = inFeatureB.geometry();
186  if ( engine->intersects( tmpGeom.constGet() ) )
187  {
188  QgsMultiPointXY points;
189  QgsGeometry intersectGeom = inGeom.intersection( tmpGeom );
190  QgsAttributes outAttributes;
191  for ( int a : qgis::as_const( fieldsAIndices ) )
192  {
193  outAttributes.append( inFeatureA.attribute( a ) );
194  }
195  for ( int b : qgis::as_const( fieldsBIndices ) )
196  {
197  outAttributes.append( inFeatureB.attribute( b ) );
198  }
200  {
201  const QVector<QgsGeometry> geomCollection = intersectGeom.asGeometryCollection();
202  for ( const QgsGeometry &part : geomCollection )
203  {
204  if ( part.type() == QgsWkbTypes::PointGeometry )
205  {
206  if ( part.isMultipart() )
207  {
208  points = part.asMultiPoint();
209  }
210  else
211  {
212  points.append( part.asPoint() );
213  }
214  }
215  }
216  }
217  else if ( intersectGeom.type() == QgsWkbTypes::PointGeometry )
218  {
219  if ( intersectGeom.isMultipart() )
220  {
221  points = intersectGeom.asMultiPoint();
222  }
223  else
224  {
225  points.append( intersectGeom.asPoint() );
226  }
227  }
228  for ( const QgsPointXY &j : qgis::as_const( points ) )
229  {
230  outFeature.setGeometry( QgsGeometry::fromPointXY( j ) );
231  outFeature.setAttributes( outAttributes );
232  sink->addFeature( outFeature, QgsFeatureSink::FastInsert );
233  }
234  }
235  }
236  }
237 
238  feedback->setProgress( i * step );
239 
240  }
241 
242  QVariantMap outputs;
243  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
244  return outputs;
245 }
246 
248 
249 
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
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...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
Base class for providing feedback from a processing algorithm.
A vector layer or feature source field parameter for processing algorithms.
A class to represent a 2D point.
Definition: qgspointxy.h:43
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:74
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
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.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB)
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
This class wraps a request for features to a vector layer (or directly its vector data provider)...
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
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:320
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
A spatial index for QgsFeature objects.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
Vector point layers.
Definition: qgsprocessing.h:48
An input feature source (such as vector layers) parameter for processing algorithms.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
Vector line layers.
Definition: qgsprocessing.h:49
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsMultiPointXY asMultiPoint() const
Returns contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty lis...
QgsGeometry geometry
Definition: qgsfeature.h:67
QList< int > QgsAttributeList
Definition: qgsfield.h:27
bool nextFeature(QgsFeature &f)
A vector of attributes.
Definition: qgsattributes.h:57
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:565
Contains information about the context in which a processing algorithm is executed.
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.