QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  std::unique_ptr< QgsProcessingParameterString > prefix = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "INTERSECT_FIELDS_PREFIX" ), QObject::tr( "Intersect fields prefix" ), QString(), false, true );
67  prefix->setFlags( prefix->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
68  addParameter( prefix.release() );
69 
70  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Intersections" ), QgsProcessing::TypeVectorPoint ) );
71 }
72 
73 QString QgsLineIntersectionAlgorithm::shortHelpString() const
74 {
75  return QObject::tr( "This algorithm creates point features where the lines in the Intersect layer intersect the lines in the Input layer." );
76 }
77 
78 QgsLineIntersectionAlgorithm *QgsLineIntersectionAlgorithm::createInstance() const
79 {
80  return new QgsLineIntersectionAlgorithm();
81 }
82 
83 QVariantMap QgsLineIntersectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
84 {
85  std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
86  if ( !sourceA )
87  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
88 
89  std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "INTERSECT" ), context ) );
90  if ( !sourceB )
91  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INTERSECT" ) ) );
92 
93  const QStringList fieldsA = parameterAsFields( parameters, QStringLiteral( "INPUT_FIELDS" ), context );
94  const QStringList fieldsB = parameterAsFields( parameters, QStringLiteral( "INTERSECT_FIELDS" ), context );
95 
96  QgsAttributeList fieldIndicesA = QgsProcessingUtils::fieldNamesToIndices( fieldsA, sourceA->fields() );
97  QgsAttributeList fieldIndicesB = QgsProcessingUtils::fieldNamesToIndices( fieldsB, sourceB->fields() );
98 
99  QString intersectFieldsPrefix = parameterAsString( parameters, QStringLiteral( "INTERSECT_FIELDS_PREFIX" ), context );
101  QgsProcessingUtils::indicesToFields( fieldIndicesA, sourceA->fields() ),
102  QgsProcessingUtils::indicesToFields( fieldIndicesB, sourceB->fields() ),
103  intersectFieldsPrefix );
104 
105  QString dest;
106  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, QgsWkbTypes::Point, sourceA->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
107  if ( !sink )
108  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
109 
110  QgsSpatialIndex spatialIndex( sourceB->getFeatures( QgsFeatureRequest().setNoAttributes().setDestinationCrs( sourceA->sourceCrs(), context.transformContext() ) ), feedback );
111  QgsFeature outFeature;
112  QgsFeatureIterator features = sourceA->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( fieldIndicesA ) );
113  double step = sourceA->featureCount() > 0 ? 100.0 / sourceA->featureCount() : 1;
114  int i = 0;
115  QgsFeature inFeatureA;
116  while ( features.nextFeature( inFeatureA ) )
117  {
118  i++;
119  if ( feedback->isCanceled() )
120  {
121  break;
122  }
123 
124  if ( !inFeatureA.hasGeometry() )
125  continue;
126 
127  QgsGeometry inGeom = inFeatureA.geometry();
128  QgsFeatureIds lines = spatialIndex.intersects( inGeom.boundingBox() ).toSet();
129  if ( !lines.empty() )
130  {
131  // use prepared geometries for faster intersection tests
132  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( inGeom.constGet() ) );
133  engine->prepareGeometry();
134 
136  request.setDestinationCrs( sourceA->sourceCrs(), context.transformContext() );
137  request.setSubsetOfAttributes( fieldIndicesB );
138 
139  QgsFeature inFeatureB;
140  QgsFeatureIterator featuresB = sourceB->getFeatures( request );
141  while ( featuresB.nextFeature( inFeatureB ) )
142  {
143  if ( feedback->isCanceled() )
144  {
145  break;
146  }
147 
148  QgsGeometry tmpGeom = inFeatureB.geometry();
149  if ( engine->intersects( tmpGeom.constGet() ) )
150  {
151  QgsMultiPointXY points;
152  QgsGeometry intersectGeom = inGeom.intersection( tmpGeom );
153  QgsAttributes outAttributes;
154  for ( int a : qgis::as_const( fieldIndicesA ) )
155  {
156  outAttributes.append( inFeatureA.attribute( a ) );
157  }
158  for ( int b : qgis::as_const( fieldIndicesB ) )
159  {
160  outAttributes.append( inFeatureB.attribute( b ) );
161  }
163  {
164  const QVector<QgsGeometry> geomCollection = intersectGeom.asGeometryCollection();
165  for ( const QgsGeometry &part : geomCollection )
166  {
167  if ( part.type() == QgsWkbTypes::PointGeometry )
168  {
169  if ( part.isMultipart() )
170  {
171  points = part.asMultiPoint();
172  }
173  else
174  {
175  points.append( part.asPoint() );
176  }
177  }
178  }
179  }
180  else if ( intersectGeom.type() == QgsWkbTypes::PointGeometry )
181  {
182  if ( intersectGeom.isMultipart() )
183  {
184  points = intersectGeom.asMultiPoint();
185  }
186  else
187  {
188  points.append( intersectGeom.asPoint() );
189  }
190  }
191  for ( const QgsPointXY &j : qgis::as_const( points ) )
192  {
193  outFeature.setGeometry( QgsGeometry::fromPointXY( j ) );
194  outFeature.setAttributes( outAttributes );
195  sink->addFeature( outFeature, QgsFeatureSink::FastInsert );
196  }
197  }
198  }
199  }
200 
201  feedback->setProgress( i * step );
202 
203  }
204 
205  QVariantMap outputs;
206  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
207  return outputs;
208 }
209 
211 
212 
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.
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.
Parameter is an advanced parameter which should be hidden from users by default.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
A vector layer or feature source field parameter for processing algorithms.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:79
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
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...
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 QList< int > fieldNamesToIndices(const QStringList &fieldNames, const QgsFields &fields)
Returns a list of field indices parsed from the given list of field names.
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
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsFields indicesToFields(const QList< int > &indices, const QgsFields &fields)
Returns a subset of fields based on the indices of desired fields.
A spatial index for QgsFeature objects.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Vector point layers.
Definition: qgsprocessing.h:48
An input feature source (such as vector layers) parameter for processing algorithms.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Vector line layers.
Definition: qgsprocessing.h:49
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:115
QgsGeometry geometry
Definition: qgsfeature.h:67
QList< int > QgsAttributeList
Definition: qgsfield.h:27
bool nextFeature(QgsFeature &f)
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
A vector of attributes.
Definition: qgsattributes.h:57
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:430
Contains information about the context in which a processing algorithm is executed.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.