QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsalgorithmsplitwithlines.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmsplitwithlines.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 #include "qgsvectorlayer.h"
22 
23 QString QgsSplitWithLinesAlgorithm::name() const
24 {
25  return QStringLiteral( "splitwithlines" );
26 }
27 
28 QString QgsSplitWithLinesAlgorithm::displayName() const
29 {
30  return QObject::tr( "Split with lines" );
31 }
32 
33 QStringList QgsSplitWithLinesAlgorithm::tags() const
34 {
35  return QObject::tr( "split,cut,lines" ).split( ',' );
36 }
37 
38 QString QgsSplitWithLinesAlgorithm::group() const
39 {
40  return QObject::tr( "Vector overlay" );
41 }
42 
43 QString QgsSplitWithLinesAlgorithm::groupId() const
44 {
45  return QStringLiteral( "vectoroverlay" );
46 }
47 
48 void QgsSplitWithLinesAlgorithm::initAlgorithm( const QVariantMap & )
49 {
50  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
51  QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon ) );
52  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "LINES" ),
53  QObject::tr( "Split layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
54  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Split" ) ) );
55 }
56 
57 QString QgsSplitWithLinesAlgorithm::shortHelpString() const
58 {
59  return QObject::tr( "This algorithm splits the lines or polygons in one layer using the lines in another layer to define the breaking points. "
60  "Intersection between geometries in both layers are considered as split points." );
61 }
62 
63 QgsSplitWithLinesAlgorithm *QgsSplitWithLinesAlgorithm::createInstance() const
64 {
65  return new QgsSplitWithLinesAlgorithm();
66 }
67 
68 QgsProcessingAlgorithm::Flags QgsSplitWithLinesAlgorithm::flags() const
69 {
72  return f;
73 }
74 
75 bool QgsSplitWithLinesAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
76 {
77  const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
78  if ( !layer )
79  return false;
80 
82  return false;
83 
84  return true;
85 }
86 
87 QVariantMap QgsSplitWithLinesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
88 {
89  std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
90  if ( !source )
91  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
92 
93  std::unique_ptr< QgsFeatureSource > linesSource( parameterAsSource( parameters, QStringLiteral( "LINES" ), context ) );
94  if ( !linesSource )
95  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "LINES" ) ) );
96 
97  bool sameLayer = parameters.value( QStringLiteral( "INPUT" ) ) == parameters.value( QStringLiteral( "LINES" ) );
98 
99  QString dest;
100  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
101  QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
102  if ( !sink )
103  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
104 
105  QMap< QgsFeatureId, QgsGeometry > splitGeoms;
106  QgsFeatureRequest request;
107  request.setNoAttributes();
108  request.setDestinationCrs( source->sourceCrs(), context.transformContext() );
109 
110  QgsFeatureIterator splitLines = linesSource->getFeatures( request );
111  QgsFeature aSplitFeature;
112 
113  QgsSpatialIndex spatialIndex( splitLines, [&]( const QgsFeature & aSplitFeature )-> bool
114  {
115  if ( feedback->isCanceled() )
116  {
117  return false;
118  }
119 
120  splitGeoms.insert( aSplitFeature.id(), aSplitFeature.geometry() );
121  return true;
122  } );
123 
124  QgsFeature outFeat;
125  QgsFeatureIterator features = source->getFeatures();
126 
127  double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
128  int i = 0;
129  QgsFeature inFeatureA;
130  while ( features.nextFeature( inFeatureA ) )
131  {
132  i++;
133  if ( feedback->isCanceled() )
134  {
135  break;
136  }
137 
138  if ( !inFeatureA.hasGeometry() )
139  {
140  sink->addFeature( inFeatureA, QgsFeatureSink::FastInsert );
141  continue;
142  }
143 
144  QgsGeometry inGeom = inFeatureA.geometry();
145  outFeat.setAttributes( inFeatureA.attributes() );
146 
147  QVector< QgsGeometry > inGeoms = inGeom.asGeometryCollection();
148 
149  const QgsFeatureIds lines = qgis::listToSet( spatialIndex.intersects( inGeom.boundingBox() ) );
150  if ( !lines.empty() ) // has intersection of bounding boxes
151  {
152  QVector< QgsGeometry > splittingLines;
153 
154  // use prepared geometries for faster intersection tests
155  std::unique_ptr< QgsGeometryEngine > engine;
156 
157  for ( QgsFeatureId line : lines )
158  {
159  // check if trying to self-intersect
160  if ( sameLayer && inFeatureA.id() == line )
161  continue;
162 
163  QgsGeometry splitGeom = splitGeoms.value( line );
164  if ( !engine )
165  {
166  engine.reset( QgsGeometry::createGeometryEngine( inGeom.constGet() ) );
167  engine->prepareGeometry();
168  }
169 
170  if ( engine->intersects( splitGeom.constGet() ) )
171  {
172  QVector< QgsGeometry > splitGeomParts = splitGeom.asGeometryCollection();
173  splittingLines.append( splitGeomParts );
174  }
175  }
176 
177  if ( !splittingLines.empty() )
178  {
179  for ( const QgsGeometry &splitGeom : qgis::as_const( splittingLines ) )
180  {
181  QgsPointSequence splitterPList;
182  QVector< QgsGeometry > outGeoms;
183 
184  // use prepared geometries for faster intersection tests
185  std::unique_ptr< QgsGeometryEngine > splitGeomEngine( QgsGeometry::createGeometryEngine( splitGeom.constGet() ) );
186  splitGeomEngine->prepareGeometry();
187  while ( !inGeoms.empty() )
188  {
189  if ( feedback->isCanceled() )
190  {
191  break;
192  }
193 
194  QgsGeometry inGeom = inGeoms.takeFirst();
195  if ( inGeom.isNull() )
196  continue;
197 
198  if ( splitGeomEngine->intersects( inGeom.constGet() ) )
199  {
200  QgsGeometry before = inGeom;
201  if ( splitterPList.empty() )
202  {
203  const QgsCoordinateSequence sequence = splitGeom.constGet()->coordinateSequence();
204  for ( const QgsRingSequence &part : sequence )
205  {
206  for ( const QgsPointSequence &ring : part )
207  {
208  for ( const QgsPoint &pt : ring )
209  {
210  splitterPList << pt;
211  }
212  }
213  }
214  }
215 
216  QVector< QgsGeometry > newGeometries;
217  QgsPointSequence topologyTestPoints;
218  QgsGeometry::OperationResult result = inGeom.splitGeometry( splitterPList, newGeometries, false, topologyTestPoints );
219 
220  // splitGeometry: If there are several intersections
221  // between geometry and splitLine, only the first one is considered.
222  if ( result == QgsGeometry::Success ) // split occurred
223  {
224  if ( inGeom.isGeosEqual( before ) )
225  {
226  // bug in splitGeometry: sometimes it returns 0 but
227  // the geometry is unchanged
228  outGeoms.append( inGeom );
229  }
230  else
231  {
232  inGeoms.append( inGeom );
233  inGeoms.append( newGeometries );
234  }
235  }
236  else
237  {
238  outGeoms.append( inGeom );
239  }
240  }
241  else
242  {
243  outGeoms.append( inGeom );
244  }
245 
246  }
247  inGeoms = outGeoms;
248  }
249  }
250  }
251 
252  QVector< QgsGeometry > parts;
253  for ( const QgsGeometry &aGeom : qgis::as_const( inGeoms ) )
254  {
255  if ( feedback->isCanceled() )
256  {
257  break;
258  }
259 
260  bool passed = true;
261  if ( QgsWkbTypes::geometryType( aGeom.wkbType() ) == QgsWkbTypes::LineGeometry )
262  {
263  int numPoints = aGeom.constGet()->nCoordinates();
264 
265  if ( numPoints <= 2 )
266  {
267  if ( numPoints == 2 )
268  passed = !static_cast< const QgsCurve * >( aGeom.constGet() )->isClosed(); // tests if vertex 0 = vertex 1
269  else
270  passed = false; // sometimes splitting results in lines of zero length
271  }
272  }
273 
274  if ( passed )
275  parts.append( aGeom );
276  }
277 
278  for ( const QgsGeometry &g : parts )
279  {
280  outFeat.setGeometry( g );
281  sink->addFeature( outFeat, QgsFeatureSink::FastInsert );
282  }
283 
284  feedback->setProgress( i * step );
285  }
286 
287  QVariantMap outputs;
288  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
289  return outputs;
290 }
291 
292 
293 
295 
296 
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsGeometry::Success
@ Success
Operation succeeded.
Definition: qgsgeometry.h:136
QgsAbstractGeometry::coordinateSequence
virtual QgsCoordinateSequence coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
QgsWkbTypes::multiType
static Type multiType(Type type)
Returns the multi type for a WKB type.
Definition: qgswkbtypes.h:301
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:49
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:75
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsProcessingFeedback
Definition: qgsprocessingfeedback.h:37
qgsalgorithmsplitwithlines.h
QgsProcessing::TypeVectorPolygon
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:50
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsProcessing::TypeVectorLine
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:49
QgsProcessingParameterFeatureSource
Definition: qgsprocessingparameters.h:2612
QgsGeometry::OperationResult
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:134
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:143
QgsGeometry::asGeometryCollection
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
Definition: qgsgeometry.cpp:2526
QgsProcessingParameterFeatureSink
Definition: qgsprocessingparameters.h:2773
QgsGeometry::isGeosEqual
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
Definition: qgsgeometry.cpp:2754
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
qgsgeometryengine.h
QgsProcessingContext
Definition: qgsprocessingcontext.h:43
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:937
QgsSpatialIndex
Definition: qgsspatialindex.h:67
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:135
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:125
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
QgsGeometry::splitGeometry
Q_DECL_DEPRECATED OperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
Definition: qgsgeometry.cpp:819
QgsFeatureRequest::setNoAttributes
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
Definition: qgsfeaturerequest.cpp:197
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:48
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
QgsFeatureSink::RegeneratePrimaryKey
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
Definition: qgsfeaturesink.h:55
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:69
qgsvectorlayer.h
QgsFeedback::isCanceled
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:66
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
Definition: qgsgeometry.cpp:3659
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:44
QgsGeometry
Definition: qgsgeometry.h:122
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:962
QgsFeature
Definition: qgsfeature.h:55
QgsFeatureRequest::setDestinationCrs
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Definition: qgsfeaturerequest.cpp:263
QgsProcessingAlgorithm::flags
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Definition: qgsprocessingalgorithm.cpp:88
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:659
QgsProcessingException
Definition: qgsexception.h:82
QgsProcessingAlgorithm::FlagSupportsInPlaceEdits
@ FlagSupportsInPlaceEdits
Algorithm supports in-place editing.
Definition: qgsprocessingalgorithm.h:77
QgsFeatureSink::FastInsert
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Definition: qgsfeaturesink.h:70
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25