QGIS API Documentation  2.99.0-Master (8ec3eaf)
qgsgeometryanalyzer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometryanalyzer.cpp - QGIS Tools for vector geometry analysis
3  -------------------
4  begin : 19 March 2009
5  copyright : (C) Carson Farmer
6  email : [email protected]
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 "qgsgeometryanalyzer.h"
19 
20 #include "qgsapplication.h"
21 #include "qgsfields.h"
22 #include "qgsfeature.h"
23 #include "qgsfeatureiterator.h"
24 #include "qgslogger.h"
26 #include "qgsvectorfilewriter.h"
27 #include "qgsvectordataprovider.h"
28 #include "qgsdistancearea.h"
29 #include "qgis.h"
30 #include "qgsvectorlayer.h"
31 
32 #include <QProgressDialog>
33 
35  const QString& shapefileName,
36  double tolerance,
37  bool onlySelectedFeatures,
38  QProgressDialog *p )
39 {
40  if ( !layer )
41  {
42  return false;
43  }
44 
45  QgsVectorDataProvider* dp = layer->dataProvider();
46  if ( !dp )
47  {
48  return false;
49  }
50 
51  QgsWkbTypes::Type outputType = dp->wkbType();
52  QgsCoordinateReferenceSystem crs = layer->crs();
53 
54  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
55  QgsFeature currentFeature;
56 
57  //take only selection
58  if ( onlySelectedFeatures )
59  {
60  //use QgsVectorLayer::featureAtId
61  const QgsFeatureIds selection = layer->selectedFeatureIds();
62  if ( p )
63  {
64  p->setMaximum( selection.size() );
65  }
66 
67  int processedFeatures = 0;
68  QgsFeatureIds::const_iterator it = selection.constBegin();
69  for ( ; it != selection.constEnd(); ++it )
70  {
71  if ( p )
72  {
73  p->setValue( processedFeatures );
74  }
75 
76  if ( p && p->wasCanceled() )
77  {
78  break;
79  }
80  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
81  {
82  continue;
83  }
84  simplifyFeature( currentFeature, &vWriter, tolerance );
85  ++processedFeatures;
86  }
87 
88  if ( p )
89  {
90  p->setValue( selection.size() );
91  }
92  }
93  //take all features
94  else
95  {
96  QgsFeatureIterator fit = layer->getFeatures();
97 
98  int featureCount = layer->featureCount();
99  if ( p )
100  {
101  p->setMaximum( featureCount );
102  }
103  int processedFeatures = 0;
104 
105  while ( fit.nextFeature( currentFeature ) )
106  {
107  if ( p )
108  {
109  p->setValue( processedFeatures );
110  }
111  if ( p && p->wasCanceled() )
112  {
113  break;
114  }
115  simplifyFeature( currentFeature, &vWriter, tolerance );
116  ++processedFeatures;
117  }
118  if ( p )
119  {
120  p->setValue( featureCount );
121  }
122  }
123 
124  return true;
125 }
126 
127 void QgsGeometryAnalyzer::simplifyFeature( QgsFeature& f, QgsVectorFileWriter* vfw, double tolerance )
128 {
129  if ( !f.hasGeometry() )
130  {
131  return;
132  }
133 
134  QgsGeometry featureGeometry = f.geometry();
135 
136  // simplify feature
137  QgsGeometry tmpGeometry = featureGeometry.simplify( tolerance );
138 
139  QgsFeature newFeature;
140  newFeature.setGeometry( tmpGeometry );
141  newFeature.setAttributes( f.attributes() );
142 
143  //add it to vector file writer
144  if ( vfw )
145  {
146  vfw->addFeature( newFeature );
147  }
148 }
149 
150 bool QgsGeometryAnalyzer::centroids( QgsVectorLayer* layer, const QString& shapefileName,
151  bool onlySelectedFeatures, QProgressDialog* p )
152 {
153  if ( !layer )
154  {
155  QgsDebugMsg( "No layer passed to centroids" );
156  return false;
157  }
158 
159  QgsVectorDataProvider* dp = layer->dataProvider();
160  if ( !dp )
161  {
162  QgsDebugMsg( "No data provider for layer passed to centroids" );
163  return false;
164  }
165 
167  QgsCoordinateReferenceSystem crs = layer->crs();
168 
169  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
170  QgsFeature currentFeature;
171 
172  //take only selection
173  if ( onlySelectedFeatures )
174  {
175  //use QgsVectorLayer::featureAtId
176  const QgsFeatureIds selection = layer->selectedFeatureIds();
177  if ( p )
178  {
179  p->setMaximum( selection.size() );
180  }
181 
182  int processedFeatures = 0;
183  QgsFeatureIds::const_iterator it = selection.constBegin();
184  for ( ; it != selection.constEnd(); ++it )
185  {
186  if ( p )
187  {
188  p->setValue( processedFeatures );
189  }
190 
191  if ( p && p->wasCanceled() )
192  {
193  break;
194  }
195  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
196  {
197  continue;
198  }
199  centroidFeature( currentFeature, &vWriter );
200  ++processedFeatures;
201  }
202 
203  if ( p )
204  {
205  p->setValue( selection.size() );
206  }
207  }
208  //take all features
209  else
210  {
211  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
212 
213  int featureCount = layer->featureCount();
214  if ( p )
215  {
216  p->setMaximum( featureCount );
217  }
218  int processedFeatures = 0;
219 
220  while ( fit.nextFeature( currentFeature ) )
221  {
222  if ( p )
223  {
224  p->setValue( processedFeatures );
225  }
226  if ( p && p->wasCanceled() )
227  {
228  break;
229  }
230  centroidFeature( currentFeature, &vWriter );
231  ++processedFeatures;
232  }
233  if ( p )
234  {
235  p->setValue( featureCount );
236  }
237  }
238 
239  return true;
240 }
241 
242 
243 void QgsGeometryAnalyzer::centroidFeature( QgsFeature& f, QgsVectorFileWriter* vfw )
244 {
245  if ( !f.hasGeometry() )
246  {
247  return;
248  }
249 
250  QgsGeometry featureGeometry = f.geometry();
251  QgsFeature newFeature;
252  newFeature.setGeometry( featureGeometry.centroid() );
253  newFeature.setAttributes( f.attributes() );
254 
255  //add it to vector file writer
256  if ( vfw )
257  {
258  vfw->addFeature( newFeature );
259  }
260 }
261 
263  const QString& shapefileName,
264  bool onlySelectedFeatures,
265  QProgressDialog * )
266 {
267  if ( !layer )
268  {
269  return false;
270  }
271 
272  QgsVectorDataProvider* dp = layer->dataProvider();
273  if ( !dp )
274  {
275  return false;
276  }
277 
279  QgsCoordinateReferenceSystem crs = layer->crs();
280 
281  QgsFields fields;
282  fields.append( QgsField( QStringLiteral( "MINX" ), QVariant::Double ) );
283  fields.append( QgsField( QStringLiteral( "MINY" ), QVariant::Double ) );
284  fields.append( QgsField( QStringLiteral( "MAXX" ), QVariant::Double ) );
285  fields.append( QgsField( QStringLiteral( "MAXY" ), QVariant::Double ) );
286  fields.append( QgsField( QStringLiteral( "CNTX" ), QVariant::Double ) );
287  fields.append( QgsField( QStringLiteral( "CNTY" ), QVariant::Double ) );
288  fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) );
289  fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) );
290  fields.append( QgsField( QStringLiteral( "HEIGHT" ), QVariant::Double ) );
291  fields.append( QgsField( QStringLiteral( "WIDTH" ), QVariant::Double ) );
292 
293  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs );
294 
295  QgsRectangle rect;
296  if ( onlySelectedFeatures ) // take only selection
297  {
298  rect = layer->boundingBoxOfSelected();
299  }
300  else
301  {
302  rect = layer->extent();
303  }
304 
305  double minx = rect.xMinimum();
306  double miny = rect.yMinimum();
307  double maxx = rect.xMaximum();
308  double maxy = rect.yMaximum();
309  double height = rect.height();
310  double width = rect.width();
311  double cntx = minx + ( width / 2.0 );
312  double cnty = miny + ( height / 2.0 );
313  double area = width * height;
314  double perim = ( 2 * width ) + ( 2 * height );
315 
316  QgsFeature feat;
317  QgsAttributes attrs( 10 );
318  attrs[0] = QVariant( minx );
319  attrs[1] = QVariant( miny );
320  attrs[2] = QVariant( maxx );
321  attrs[3] = QVariant( maxy );
322  attrs[4] = QVariant( cntx );
323  attrs[5] = QVariant( cnty );
324  attrs[6] = QVariant( area );
325  attrs[7] = QVariant( perim );
326  attrs[8] = QVariant( height );
327  attrs[9] = QVariant( width );
328  feat.setAttributes( attrs );
329  feat.setGeometry( QgsGeometry::fromRect( rect ) );
330  vWriter.addFeature( feat );
331  return true;
332 }
333 
334 QList<double> QgsGeometryAnalyzer::simpleMeasure( QgsGeometry& mpGeometry )
335 {
336  QList<double> list;
337  double perim;
338  if ( mpGeometry.wkbType() == QgsWkbTypes::Point )
339  {
340  QgsPoint pt = mpGeometry.asPoint();
341  list.append( pt.x() );
342  list.append( pt.y() );
343  }
344  else
345  {
346  QgsDistanceArea measure;
347  list.append( measure.measureArea( mpGeometry ) );
348  if ( mpGeometry.type() == QgsWkbTypes::PolygonGeometry )
349  {
350  perim = perimeterMeasure( mpGeometry, measure );
351  list.append( perim );
352  }
353  }
354  return list;
355 }
356 
357 double QgsGeometryAnalyzer::perimeterMeasure( const QgsGeometry& geometry, QgsDistanceArea& measure )
358 {
359  return measure.measurePerimeter( geometry );
360 }
361 
362 bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer* layer, const QString& shapefileName,
363  bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p )
364 {
365  if ( !layer )
366  {
367  return false;
368  }
369  QgsVectorDataProvider* dp = layer->dataProvider();
370  if ( !dp )
371  {
372  return false;
373  }
374  bool useField = false;
375  if ( uniqueIdField == -1 )
376  {
377  uniqueIdField = 0;
378  }
379  else
380  {
381  useField = true;
382  }
383  QgsFields fields;
384  fields.append( QgsField( QStringLiteral( "UID" ), QVariant::String ) );
385  fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) );
386  fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) );
387 
389  QgsCoordinateReferenceSystem crs = layer->crs();
390 
391  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs );
392  QgsFeature currentFeature;
393  QgsGeometry dissolveGeometry; //dissolve geometry
394  QMultiMap<QString, QgsFeatureId> map;
395 
396  if ( onlySelectedFeatures )
397  {
398  //use QgsVectorLayer::featureAtId
399  const QgsFeatureIds selection = layer->selectedFeatureIds();
400  QgsFeatureIds::const_iterator it = selection.constBegin();
401  for ( ; it != selection.constEnd(); ++it )
402  {
403 #if 0
404  if ( p )
405  {
406  p->setValue( processedFeatures );
407  }
408  if ( p && p->wasCanceled() )
409  {
410  // break; // it may be better to do something else here?
411  return false;
412  }
413 #endif
414  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
415  {
416  continue;
417  }
418  map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
419  }
420  }
421  else
422  {
423  QgsFeatureIterator fit = layer->getFeatures();
424  while ( fit.nextFeature( currentFeature ) )
425  {
426 #if 0
427  if ( p )
428  {
429  p->setValue( processedFeatures );
430  }
431  if ( p && p->wasCanceled() )
432  {
433  // break; // it may be better to do something else here?
434  return false;
435  }
436 #endif
437  map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
438  }
439  }
440 
441  QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin();
442  while ( jt != map.constEnd() )
443  {
444  QString currentKey = jt.key();
445  int processedFeatures = 0;
446  //take only selection
447  if ( onlySelectedFeatures )
448  {
449  //use QgsVectorLayer::featureAtId
450  const QgsFeatureIds selection = layer->selectedFeatureIds();
451  if ( p )
452  {
453  p->setMaximum( selection.size() );
454  }
455  processedFeatures = 0;
456  while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
457  {
458  if ( p && p->wasCanceled() )
459  {
460  break;
461  }
462  if ( selection.contains( jt.value() ) )
463  {
464  if ( p )
465  {
466  p->setValue( processedFeatures );
467  }
468  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
469  {
470  continue;
471  }
472  convexFeature( currentFeature, processedFeatures, dissolveGeometry );
473  ++processedFeatures;
474  }
475  ++jt;
476  }
477  QList<double> values;
478  if ( dissolveGeometry.isEmpty() )
479  {
480  QgsDebugMsg( "no dissolved geometry - should not happen" );
481  return false;
482  }
483  dissolveGeometry = dissolveGeometry.convexHull();
484  values = simpleMeasure( dissolveGeometry );
485  QgsAttributes attributes( 3 );
486  attributes[0] = QVariant( currentKey );
487  attributes[1] = values.at( 0 );
488  attributes[2] = values.at( 1 );
489  QgsFeature dissolveFeature;
490  dissolveFeature.setAttributes( attributes );
491  dissolveFeature.setGeometry( dissolveGeometry );
492  vWriter.addFeature( dissolveFeature );
493  }
494  //take all features
495  else
496  {
497  int featureCount = layer->featureCount();
498  if ( p )
499  {
500  p->setMaximum( featureCount );
501  }
502  processedFeatures = 0;
503  while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
504  {
505  if ( p )
506  {
507  p->setValue( processedFeatures );
508  }
509 
510  if ( p && p->wasCanceled() )
511  {
512  break;
513  }
514  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
515  {
516  continue;
517  }
518  convexFeature( currentFeature, processedFeatures, dissolveGeometry );
519  ++processedFeatures;
520  ++jt;
521  }
522  QList<double> values;
523  if ( dissolveGeometry.isEmpty() )
524  {
525  QgsDebugMsg( "no dissolved geometry - should not happen" );
526  return false;
527  }
528  dissolveGeometry = dissolveGeometry.convexHull();
529  // values = simpleMeasure( tmpGeometry );
530  values = simpleMeasure( dissolveGeometry );
531  QgsAttributes attributes;
532  attributes[0] = QVariant( currentKey );
533  attributes[1] = QVariant( values[ 0 ] );
534  attributes[2] = QVariant( values[ 1 ] );
535  QgsFeature dissolveFeature;
536  dissolveFeature.setAttributes( attributes );
537  dissolveFeature.setGeometry( dissolveGeometry );
538  vWriter.addFeature( dissolveFeature );
539  }
540  }
541  return true;
542 }
543 
544 
545 void QgsGeometryAnalyzer::convexFeature( QgsFeature& f, int nProcessedFeatures, QgsGeometry& dissolveGeometry )
546 {
547  if ( !f.hasGeometry() )
548  {
549  return;
550  }
551 
552  QgsGeometry featureGeometry = f.geometry();
553  QgsGeometry convexGeometry = featureGeometry.convexHull();
554 
555  if ( nProcessedFeatures == 0 )
556  {
557  dissolveGeometry = convexGeometry;
558  }
559  else
560  {
561  dissolveGeometry = dissolveGeometry.combine( convexGeometry );
562  }
563 }
564 
565 bool QgsGeometryAnalyzer::dissolve( QgsVectorLayer* layer, const QString& shapefileName,
566  bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p )
567 {
568  if ( !layer )
569  {
570  return false;
571  }
572  QgsVectorDataProvider* dp = layer->dataProvider();
573  if ( !dp )
574  {
575  return false;
576  }
577  bool useField = false;
578  if ( uniqueIdField == -1 )
579  {
580  uniqueIdField = 0;
581  }
582  else
583  {
584  useField = true;
585  }
586 
587  QgsWkbTypes::Type outputType = dp->wkbType();
588  QgsCoordinateReferenceSystem crs = layer->crs();
589 
590  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
591  QgsFeature currentFeature;
592  QMultiMap<QString, QgsFeatureId> map;
593 
594  if ( onlySelectedFeatures )
595  {
596  //use QgsVectorLayer::featureAtId
597  const QgsFeatureIds selection = layer->selectedFeatureIds();
598  QgsFeatureIds::const_iterator it = selection.constBegin();
599  for ( ; it != selection.constEnd(); ++it )
600  {
601  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
602  {
603  continue;
604  }
605  map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
606  }
607  }
608  else
609  {
610  QgsFeatureIterator fit = layer->getFeatures();
611  while ( fit.nextFeature( currentFeature ) )
612  {
613  map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
614  }
615  }
616 
617  QgsGeometry dissolveGeometry; //dissolve geometry
618  QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin();
619  QgsFeature outputFeature;
620  while ( jt != map.constEnd() )
621  {
622  QString currentKey = jt.key();
623  int processedFeatures = 0;
624  bool first = true;
625  //take only selection
626  if ( onlySelectedFeatures )
627  {
628  //use QgsVectorLayer::featureAtId
629  const QgsFeatureIds selection = layer->selectedFeatureIds();
630  if ( p )
631  {
632  p->setMaximum( selection.size() );
633  }
634  while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
635  {
636  if ( p && p->wasCanceled() )
637  {
638  break;
639  }
640  if ( selection.contains( jt.value() ) )
641  {
642  if ( p )
643  {
644  p->setValue( processedFeatures );
645  }
646  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
647  {
648  continue;
649  }
650  if ( first )
651  {
652  outputFeature.setAttributes( currentFeature.attributes() );
653  first = false;
654  }
655  dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry );
656  ++processedFeatures;
657  }
658  ++jt;
659  }
660  }
661  //take all features
662  else
663  {
664  int featureCount = layer->featureCount();
665  if ( p )
666  {
667  p->setMaximum( featureCount );
668  }
669  while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
670  {
671  if ( p )
672  {
673  p->setValue( processedFeatures );
674  }
675 
676  if ( p && p->wasCanceled() )
677  {
678  break;
679  }
680  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
681  {
682  continue;
683  }
684  {
685  outputFeature.setAttributes( currentFeature.attributes() );
686  first = false;
687  }
688  dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry );
689  ++processedFeatures;
690  ++jt;
691  }
692  }
693  outputFeature.setGeometry( dissolveGeometry );
694  vWriter.addFeature( outputFeature );
695  }
696  return true;
697 }
698 
699 QgsGeometry QgsGeometryAnalyzer::dissolveFeature( const QgsFeature& f, const QgsGeometry& dissolveInto )
700 {
701  if ( !f.hasGeometry() )
702  {
703  return dissolveInto;
704  }
705 
706  QgsGeometry featureGeometry = f.geometry();
707 
708  if ( dissolveInto.isEmpty() )
709  {
710  return featureGeometry;
711  }
712  else
713  {
714  return dissolveInto.combine( featureGeometry );
715  }
716 }
717 
718 bool QgsGeometryAnalyzer::buffer( QgsVectorLayer* layer, const QString& shapefileName, double bufferDistance,
719  bool onlySelectedFeatures, bool dissolve, int bufferDistanceField, QProgressDialog* p )
720 {
721  if ( !layer )
722  {
723  return false;
724  }
725 
726  QgsVectorDataProvider* dp = layer->dataProvider();
727  if ( !dp )
728  {
729  return false;
730  }
731 
733  if ( dissolve )
734  {
735  outputType = QgsWkbTypes::MultiPolygon;
736  }
737  QgsCoordinateReferenceSystem crs = layer->crs();
738 
739  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
740  QgsFeature currentFeature;
741  QgsGeometry dissolveGeometry; //dissolve geometry (if dissolve enabled)
742 
743  //take only selection
744  if ( onlySelectedFeatures )
745  {
746  //use QgsVectorLayer::featureAtId
747  const QgsFeatureIds selection = layer->selectedFeatureIds();
748  if ( p )
749  {
750  p->setMaximum( selection.size() );
751  }
752 
753  int processedFeatures = 0;
754  QgsFeatureIds::const_iterator it = selection.constBegin();
755  for ( ; it != selection.constEnd(); ++it )
756  {
757  if ( p )
758  {
759  p->setValue( processedFeatures );
760  }
761 
762  if ( p && p->wasCanceled() )
763  {
764  break;
765  }
766  if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
767  {
768  continue;
769  }
770  bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField );
771  ++processedFeatures;
772  }
773 
774  if ( p )
775  {
776  p->setValue( selection.size() );
777  }
778  }
779  //take all features
780  else
781  {
782  QgsFeatureIterator fit = layer->getFeatures();
783 
784  int featureCount = layer->featureCount();
785  if ( p )
786  {
787  p->setMaximum( featureCount );
788  }
789  int processedFeatures = 0;
790 
791  while ( fit.nextFeature( currentFeature ) )
792  {
793  if ( p )
794  {
795  p->setValue( processedFeatures );
796  }
797  if ( p && p->wasCanceled() )
798  {
799  break;
800  }
801  bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField );
802  ++processedFeatures;
803  }
804  if ( p )
805  {
806  p->setValue( featureCount );
807  }
808  }
809 
810  if ( dissolve )
811  {
812  QgsFeature dissolveFeature;
813  if ( dissolveGeometry.isEmpty() )
814  {
815  QgsDebugMsg( "no dissolved geometry - should not happen" );
816  return false;
817  }
818  dissolveFeature.setGeometry( dissolveGeometry );
819  vWriter.addFeature( dissolveFeature );
820  }
821  return true;
822 }
823 
824 void QgsGeometryAnalyzer::bufferFeature( QgsFeature& f, int nProcessedFeatures, QgsVectorFileWriter* vfw, bool dissolve,
825  QgsGeometry& dissolveGeometry, double bufferDistance, int bufferDistanceField )
826 {
827  if ( !f.hasGeometry() )
828  {
829  return;
830  }
831 
832  double currentBufferDistance;
833  QgsGeometry featureGeometry = f.geometry();
834  QgsGeometry bufferGeometry;
835 
836  //create buffer
837  if ( bufferDistanceField == -1 )
838  {
839  currentBufferDistance = bufferDistance;
840  }
841  else
842  {
843  currentBufferDistance = f.attribute( bufferDistanceField ).toDouble();
844  }
845  bufferGeometry = featureGeometry.buffer( currentBufferDistance, 5 );
846 
847  if ( dissolve )
848  {
849  if ( nProcessedFeatures == 0 )
850  {
851  dissolveGeometry = bufferGeometry;
852  }
853  else
854  {
855  dissolveGeometry = dissolveGeometry.combine( bufferGeometry );
856  }
857  }
858  else //dissolve
859  {
860  QgsFeature newFeature;
861  newFeature.setGeometry( bufferGeometry );
862  newFeature.setAttributes( f.attributes() );
863 
864  //add it to vector file writer
865  if ( vfw )
866  {
867  vfw->addFeature( newFeature );
868  }
869  }
870 }
871 
872 bool QgsGeometryAnalyzer::eventLayer( QgsVectorLayer* lineLayer, QgsVectorLayer* eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString& outputLayer,
873  const QString& outputFormat, int locationField1, int locationField2, int offsetField, double offsetScale,
874  bool forceSingleGeometry, QgsVectorDataProvider* memoryProvider, QProgressDialog* p )
875 {
876  if ( !lineLayer || !eventLayer || !lineLayer->isValid() || !eventLayer->isValid() )
877  {
878  return false;
879  }
880 
881  //create line field / id map for line layer
882  QMultiHash< QString, QgsFeature > lineLayerIdMap; //1:n possible (e.g. several linear reference geometries for one feature in the event layer)
883  QgsFeatureIterator fit = lineLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() << lineField ) );
884  QgsFeature fet;
885  while ( fit.nextFeature( fet ) )
886  {
887  lineLayerIdMap.insert( fet.attribute( lineField ).toString(), fet );
888  }
889 
890  //create output datasource or attributes in memory provider
891  QgsVectorFileWriter* fileWriter = nullptr;
892  QgsFeatureList memoryProviderFeatures;
893  if ( !memoryProvider )
894  {
895  QgsWkbTypes::Type memoryProviderType = QgsWkbTypes::MultiLineString;
896  if ( locationField2 == -1 )
897  {
898  memoryProviderType = forceSingleGeometry ? QgsWkbTypes::Point : QgsWkbTypes::MultiPoint;
899  }
900  else
901  {
902  memoryProviderType = forceSingleGeometry ? QgsWkbTypes::LineString : QgsWkbTypes::MultiLineString;
903  }
904  fileWriter = new QgsVectorFileWriter( outputLayer,
905  eventLayer->dataProvider()->encoding(),
906  eventLayer->fields(),
907  memoryProviderType,
908  lineLayer->crs(),
909  outputFormat );
910  }
911  else
912  {
913  memoryProvider->addAttributes( eventLayer->fields().toList() );
914  }
915 
916  //iterate over eventLayer and write new features to output file or layer
917  fit = eventLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) );
918  QgsGeometry lrsGeom;
919  double measure1, measure2 = 0.0;
920 
921  int nEventFeatures = eventLayer->featureCount();
922  int featureCounter = 0;
923  int nOutputFeatures = 0; //number of output features for the current event feature
924  if ( p )
925  {
926  p->setWindowModality( Qt::WindowModal );
927  p->setMinimum( 0 );
928  p->setMaximum( nEventFeatures );
929  p->show();
930  }
931 
932  while ( fit.nextFeature( fet ) )
933  {
934  nOutputFeatures = 0;
935 
936  //update progress dialog
937  if ( p )
938  {
939  if ( p->wasCanceled() )
940  {
941  break;
942  }
943  p->setValue( featureCounter );
944  ++featureCounter;
945  }
946 
947  measure1 = fet.attribute( locationField1 ).toDouble();
948  if ( locationField2 != -1 )
949  {
950  measure2 = fet.attribute( locationField2 ).toDouble();
951  if ( qgsDoubleNear(( measure2 - measure1 ), 0.0 ) )
952  {
953  continue;
954  }
955  }
956 
957  QList<QgsFeature> featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() );
958  QList<QgsFeature>::iterator featureIdIt = featureIdList.begin();
959  for ( ; featureIdIt != featureIdList.end(); ++featureIdIt )
960  {
961  if ( locationField2 == -1 )
962  {
963  lrsGeom = locateAlongMeasure( measure1, featureIdIt->geometry() );
964  }
965  else
966  {
967  lrsGeom = locateBetweenMeasures( measure1, measure2, featureIdIt->geometry() );
968  }
969 
970  if ( !lrsGeom.isEmpty() )
971  {
972  ++nOutputFeatures;
973  addEventLayerFeature( fet, lrsGeom, featureIdIt->geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry );
974  }
975  }
976  if ( nOutputFeatures < 1 )
977  {
978  unlocatedFeatureIds.insert( fet.id() );
979  }
980  }
981 
982  if ( p )
983  {
984  p->setValue( nEventFeatures );
985  }
986 
987  if ( memoryProvider )
988  {
989  memoryProvider->addFeatures( memoryProviderFeatures );
990  }
991  delete fileWriter;
992  return true;
993 }
994 
995 void QgsGeometryAnalyzer::addEventLayerFeature( QgsFeature& feature, const QgsGeometry& geom, const QgsGeometry& lineGeom, QgsVectorFileWriter* fileWriter, QgsFeatureList& memoryFeatures,
996  int offsetField, double offsetScale, bool forceSingleType )
997 {
998  if ( geom.isEmpty() )
999  {
1000  return;
1001  }
1002 
1003  QList<QgsGeometry> geomList;
1004  if ( forceSingleType )
1005  {
1006  geomList = geom.asGeometryCollection();
1007  }
1008  else
1009  {
1010  geomList.push_back( geom );
1011  }
1012 
1013  QList<QgsGeometry>::iterator geomIt = geomList.begin();
1014  for ( ; geomIt != geomList.end(); ++geomIt )
1015  {
1016  //consider offset
1017  QgsGeometry newGeom = *geomIt;
1018  if ( offsetField >= 0 )
1019  {
1020  double offsetVal = feature.attribute( offsetField ).toDouble();
1021  offsetVal *= offsetScale;
1022  newGeom = createOffsetGeometry( *geomIt, lineGeom, offsetVal );
1023  if ( newGeom.isEmpty() )
1024  {
1025  continue;
1026  }
1027  }
1028 
1029  feature.setGeometry( newGeom );
1030  if ( fileWriter )
1031  {
1032  fileWriter->addFeature( feature );
1033  }
1034  else
1035  {
1036  memoryFeatures << feature;
1037  }
1038  }
1039 }
1040 
1041 QgsGeometry QgsGeometryAnalyzer::createOffsetGeometry( const QgsGeometry& geom, const QgsGeometry& lineGeom, double offset )
1042 {
1043  if ( !geom || lineGeom.isEmpty() )
1044  {
1045  return QgsGeometry();
1046  }
1047 
1048  QList<QgsGeometry> inputGeomList;
1049 
1050  if ( geom.isMultipart() )
1051  {
1052  inputGeomList = geom.asGeometryCollection();
1053  }
1054  else
1055  {
1056  inputGeomList.push_back( geom );
1057  }
1058 
1059  QList<GEOSGeometry*> outputGeomList;
1060  QList<QgsGeometry>::const_iterator inputGeomIt = inputGeomList.constBegin();
1061  GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler();
1062  for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt )
1063  {
1064  if ( geom.type() == QgsWkbTypes::LineGeometry )
1065  {
1066  GEOSGeometry* inputGeomItGeos = inputGeomIt->exportToGeos();
1067  GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( geosctxt, inputGeomItGeos, -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ );
1068  GEOSGeom_destroy_r( geosctxt, inputGeomItGeos );
1069  if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) )
1070  {
1071  return QgsGeometry();
1072  }
1073  if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 )
1074  {
1075  GEOSGeom_destroy_r( geosctxt, offsetGeom );
1076  return QgsGeometry();
1077  }
1078  outputGeomList.push_back( offsetGeom );
1079  }
1080  else if ( geom.type() == QgsWkbTypes::PointGeometry )
1081  {
1082  QgsPoint p = ( *inputGeomIt ).asPoint();
1083  p = createPointOffset( p.x(), p.y(), offset, lineGeom );
1084  GEOSCoordSequence* ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
1085  GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() );
1086  GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() );
1087  GEOSGeometry* geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq );
1088  outputGeomList.push_back( geosPt );
1089  }
1090  }
1091 
1092  QgsGeometry outGeometry;
1093  if ( !geom.isMultipart() )
1094  {
1095  GEOSGeometry* outputGeom = outputGeomList.at( 0 );
1096  if ( outputGeom )
1097  {
1098  outGeometry.fromGeos( outputGeom );
1099  }
1100  }
1101  else
1102  {
1103  GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()];
1104  for ( int i = 0; i < outputGeomList.size(); ++i )
1105  {
1106  geomArray[i] = outputGeomList.at( i );
1107  }
1108  GEOSGeometry* collection = nullptr;
1109  if ( geom.type() == QgsWkbTypes::PointGeometry )
1110  {
1111  collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() );
1112  }
1113  else if ( geom.type() == QgsWkbTypes::LineGeometry )
1114  {
1115  collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() );
1116  }
1117  outGeometry.fromGeos( collection );
1118  delete[] geomArray;
1119  }
1120  return outGeometry;
1121 }
1122 
1123 QgsPoint QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, const QgsGeometry& lineGeom ) const
1124 {
1125  QgsPoint p( x, y );
1126  QgsPoint minDistPoint;
1127  int afterVertexNr;
1128  lineGeom.closestSegmentWithContext( p, minDistPoint, afterVertexNr );
1129 
1130  int beforeVertexNr = afterVertexNr - 1;
1131  QgsPoint beforeVertex = lineGeom.vertexAt( beforeVertexNr );
1132  QgsPoint afterVertex = lineGeom.vertexAt( afterVertexNr );
1133 
1134  //get normal vector
1135  double dx = afterVertex.x() - beforeVertex.x();
1136  double dy = afterVertex.y() - beforeVertex.y();
1137  double normalX = -dy;
1138  double normalY = dx;
1139  double normalLength = sqrt( normalX * normalX + normalY * normalY );
1140  normalX *= ( dist / normalLength );
1141  normalY *= ( dist / normalLength );
1142 
1143  double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control
1144  Q_UNUSED( debugLength );
1145  return QgsPoint( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side
1146 }
1147 
1148 QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry& lineGeom )
1149 {
1150  if ( lineGeom.isEmpty() )
1151  {
1152  return QgsGeometry();
1153  }
1154 
1155  QgsMultiPolyline resultGeom;
1156 
1157  //need to go with WKB and z coordinate until QgsGeometry supports M values
1158  QByteArray wkb( lineGeom.exportToWkb() );
1159  QgsConstWkbPtr wkbPtr( wkb );
1160  wkbPtr.readHeader();
1161 
1162  QgsWkbTypes::Type wkbType = lineGeom.wkbType();
1163  if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D )
1164  {
1165  return QgsGeometry();
1166  }
1167 
1168  if ( wkbType == QgsWkbTypes::LineString25D )
1169  {
1170  locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
1171  }
1172  else if ( wkbType == QgsWkbTypes::MultiLineString25D )
1173  {
1174  int nLines;
1175  wkbPtr >> nLines;
1176  for ( int i = 0; i < nLines; ++i )
1177  {
1178  wkbPtr.readHeader();
1179  wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
1180  }
1181  }
1182 
1183  if ( resultGeom.size() < 1 )
1184  {
1185  return QgsGeometry();
1186  }
1187  return QgsGeometry::fromMultiPolyline( resultGeom );
1188 }
1189 
1191 {
1192  if ( lineGeom.isEmpty() )
1193  {
1194  return QgsGeometry();
1195  }
1196 
1197  QgsMultiPoint resultGeom;
1198 
1199  //need to go with WKB and z coordinate until QgsGeometry supports M values
1200  QByteArray wkb( lineGeom.exportToWkb() );
1201  QgsConstWkbPtr wkbPtr( wkb );
1202  QgsWkbTypes::Type wkbType = lineGeom.wkbType();
1203 
1204  if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D )
1205  {
1206  return QgsGeometry();
1207  }
1208 
1209  if ( wkbType == QgsWkbTypes::LineString25D )
1210  {
1211  locateAlongWkbString( wkbPtr, resultGeom, measure );
1212  }
1213  else if ( wkbType == QgsWkbTypes::MultiLineString25D )
1214  {
1215  int nLines;
1216  wkbPtr >> nLines;
1217  for ( int i = 0; i < nLines; ++i )
1218  {
1219  wkbPtr.readHeader();
1220  wkbPtr = locateAlongWkbString( wkbPtr, resultGeom, measure );
1221  }
1222  }
1223 
1224  if ( resultGeom.size() < 1 )
1225  {
1226  return QgsGeometry();
1227  }
1228 
1229  return QgsGeometry::fromMultiPoint( resultGeom );
1230 }
1231 
1232 QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPolyline& result, double fromMeasure, double toMeasure )
1233 {
1234  int nPoints;
1235  wkbPtr >> nPoints;
1236 
1237  QgsPolyline currentLine;
1238  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1239  for ( int i = 0; i < nPoints; ++i )
1240  {
1241  double x, y, z;
1242  wkbPtr >> x >> y >> z;
1243 
1244  if ( i > 0 )
1245  {
1246  QgsPoint pt1, pt2;
1247  bool secondPointClipped; //true if second point is != segment endpoint
1248  bool measureInSegment = clipSegmentByRange( prevx, prevy, prevz, x, y, z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
1249  if ( measureInSegment )
1250  {
1251  if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line
1252  {
1253  currentLine.append( pt1 );
1254  }
1255 
1256  if ( pt1 != pt2 ) //avoid duplicated entry if measure value equals m-value of vertex
1257  {
1258  currentLine.append( pt2 );
1259  }
1260 
1261  if ( secondPointClipped || i == nPoints - 1 ) //close current segment
1262  {
1263  if ( currentLine.size() > 1 )
1264  {
1265  result.append( currentLine );
1266  }
1267  currentLine.clear();
1268  }
1269  }
1270  }
1271  prevx = x;
1272  prevy = y;
1273  prevz = z;
1274  }
1275 
1276  return wkbPtr;
1277 }
1278 
1279 QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPoint& result, double measure )
1280 {
1281  int nPoints;
1282  wkbPtr >> nPoints;
1283 
1284  double x, y, z;
1285  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1286  for ( int i = 0; i < nPoints; ++i )
1287  {
1288  wkbPtr >> x >> y >> z;
1289 
1290  if ( i > 0 )
1291  {
1292  QgsPoint pt1, pt2;
1293  bool pt1Ok, pt2Ok;
1294  locateAlongSegment( prevx, prevy, prevz, x, y, z, measure, pt1Ok, pt1, pt2Ok, pt2 );
1295  if ( pt1Ok )
1296  {
1297  result.append( pt1 );
1298  }
1299  if ( pt2Ok && i == nPoints - 1 )
1300  {
1301  result.append( pt2 );
1302  }
1303  }
1304  prevx = x;
1305  prevy = y;
1306  prevz = z;
1307  }
1308 
1309  return wkbPtr;
1310 }
1311 
1312 bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1,
1313  QgsPoint& pt2, bool& secondPointClipped )
1314 {
1315  bool reversed = m1 > m2;
1316  double tmp;
1317 
1318  //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2)
1319  if ( reversed )
1320  {
1321  tmp = m1;
1322  m1 = m2;
1323  m2 = tmp;
1324 
1325  tmp = x1;
1326  x1 = x2;
1327  x2 = tmp;
1328 
1329  tmp = y1;
1330  y1 = y2;
1331  y2 = tmp;
1332  }
1333 
1334  //reverse range1, range2 if necessary
1335  if ( range1 > range2 )
1336  {
1337  tmp = range1;
1338  range1 = range2;
1339  range2 = tmp;
1340  }
1341 
1342  //segment completely outside of range
1343  if ( m2 < range1 || m1 > range2 )
1344  {
1345  return false;
1346  }
1347 
1348  //segment completely inside of range
1349  if ( m2 <= range2 && m1 >= range1 )
1350  {
1351  if ( reversed )
1352  {
1353  pt1.setX( x2 );
1354  pt1.setY( y2 );
1355  pt2.setX( x1 );
1356  pt2.setY( y1 );
1357  }
1358  else
1359  {
1360  pt1.setX( x1 );
1361  pt1.setY( y1 );
1362  pt2.setX( x2 );
1363  pt2.setY( y2 );
1364  }
1365  secondPointClipped = false;
1366  return true;
1367  }
1368 
1369  //m1 inside and m2 not
1370  if ( m1 >= range1 && m1 <= range2 )
1371  {
1372  pt1.setX( x1 );
1373  pt1.setY( y1 );
1374  double dist = ( range2 - m1 ) / ( m2 - m1 );
1375  pt2.setX( x1 + ( x2 - x1 ) * dist );
1376  pt2.setY( y1 + ( y2 - y1 ) * dist );
1377  secondPointClipped = !reversed;
1378  }
1379 
1380  //m2 inside and m1 not
1381  if ( m2 >= range1 && m2 <= range2 )
1382  {
1383  pt2.setX( x2 );
1384  pt2.setY( y2 );
1385  double dist = ( m2 - range1 ) / ( m2 - m1 );
1386  pt1.setX( x2 - ( x2 - x1 ) * dist );
1387  pt1.setY( y2 - ( y2 - y1 ) * dist );
1388  secondPointClipped = reversed;
1389  }
1390 
1391  //range1 and range 2 both inside the segment
1392  if ( range1 >= m1 && range2 <= m2 )
1393  {
1394  double dist1 = ( range1 - m1 ) / ( m2 - m1 );
1395  double dist2 = ( range2 - m1 ) / ( m2 - m1 );
1396  pt1.setX( x1 + ( x2 - x1 ) * dist1 );
1397  pt1.setY( y1 + ( y2 - y1 ) * dist1 );
1398  pt2.setX( x1 + ( x2 - x1 ) * dist2 );
1399  pt2.setY( y1 + ( y2 - y1 ) * dist2 );
1400  secondPointClipped = true;
1401  }
1402 
1403  if ( reversed ) //switch p1 and p2
1404  {
1405  QgsPoint tmpPt = pt1;
1406  pt1 = pt2;
1407  pt2 = tmpPt;
1408  }
1409 
1410  return true;
1411 }
1412 
1413 void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 )
1414 {
1415  bool reversed = false;
1416  pt1Ok = false;
1417  pt2Ok = false;
1418  double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints
1419 
1420  if ( m1 > m2 )
1421  {
1422  double tmp = m1;
1423  m1 = m2;
1424  m2 = tmp;
1425  reversed = true;
1426  }
1427 
1428  //segment does not match
1429  if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance )
1430  {
1431  pt1Ok = false;
1432  pt2Ok = false;
1433  return;
1434  }
1435 
1436  //match with vertex1
1437  if ( qgsDoubleNear( m1, measure, tolerance ) )
1438  {
1439  if ( reversed )
1440  {
1441  pt2Ok = true;
1442  pt2.setX( x2 );
1443  pt2.setY( y2 );
1444  }
1445  else
1446  {
1447  pt1Ok = true;
1448  pt1.setX( x1 );
1449  pt1.setY( y1 );
1450  }
1451  }
1452 
1453  //match with vertex2
1454  if ( qgsDoubleNear( m2, measure, tolerance ) )
1455  {
1456  if ( reversed )
1457  {
1458  pt1Ok = true;
1459  pt1.setX( x1 );
1460  pt1.setY( y1 );
1461  }
1462  else
1463  {
1464  pt2Ok = true;
1465  pt2.setX( x2 );
1466  pt2.setY( y2 );
1467  }
1468  }
1469 
1470 
1471  if ( pt1Ok || pt2Ok )
1472  {
1473  return;
1474  }
1475 
1476  //match between the vertices
1477  if ( qgsDoubleNear( m1, m2 ) )
1478  {
1479  pt1.setX( x1 );
1480  pt1.setY( y1 );
1481  pt1Ok = true;
1482  return;
1483  }
1484  double dist = ( measure - m1 ) / ( m2 - m1 );
1485  if ( reversed )
1486  {
1487  dist = 1 - dist;
1488  }
1489 
1490  pt1.setX( x1 + dist * ( x2 - x1 ) );
1491  pt1.setY( y1 + dist * ( y2 - y1 ) );
1492  pt1Ok = true;
1493 }
bool eventLayer(QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString &outputLayer, const QString &outputFormat, int locationField1, int locationField2=-1, int offsetField=-1, double offsetScale=1.0, bool forceSingleGeometry=false, QgsVectorDataProvider *memoryProvider=nullptr, QProgressDialog *p=nullptr)
Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event tabl...
QgsFeatureId id
Definition: qgsfeature.h:139
QString encoding() const
Get encoding which is used for accessing data.
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double y
Definition: qgspoint.h:147
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
bool simplify(QgsVectorLayer *layer, const QString &shapefileName, double tolerance, bool onlySelectedFeatures=false, QProgressDialog *p=nullptr)
Simplify vector layer using (a modified) Douglas-Peucker algorithm and write it to a new shape file...
bool addFeature(QgsFeature &feature, QgsFeatureRenderer *renderer=nullptr, QgsUnitTypes::DistanceUnit outputUnit=QgsUnitTypes::DistanceMeters)
Add feature to the currently opened data source.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:360
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QVector< QgsPoint > QgsPolyline
Polyline is represented as a vector of points.
Definition: qgsgeometry.h:46
bool extent(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, QProgressDialog *p=0)
Create a polygon based on the extent of all (selected) features and write it to a new shape file...
Container of fields for a vector layer.
Definition: qgsfields.h:36
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:78
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:153
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
QgsGeometry centroid() const
Returns the center of mass of a geometry.
bool centroids(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, QProgressDialog *p=nullptr)
Calculate the true centroids, or &#39;center of mass&#39; for a vector layer and write it to a new shape file...
A convenience class for writing vector files to disk.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
bool isValid() const
Return the status of the layer.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:214
virtual bool addFeatures(QgsFeatureList &flist)
Adds a list of features.
QgsGeometry locateAlongMeasure(double measure, const QgsGeometry &lineGeom)
Returns linear reference geometry.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:196
virtual QgsWkbTypes::Type wkbType() const =0
Returns the geometry type which is returned by this layer.
QgsFields fields() const
Returns the list of fields of this layer.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned.
const QgsFeatureIds & selectedFeatureIds() const
Return reference to identifiers of selected features.
QgsRectangle extent() const override
Return the extent of the layer.
QByteArray exportToWkb() const
Export the geometry to WKB.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
QList< QgsGeometry > asGeometryCollection() const
Return contents of the geometry as a list of geometries.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
QVector< QgsPoint > QgsMultiPoint
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:55
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:61
QgsGeometry locateBetweenMeasures(double fromMeasure, double toMeasure, const QgsGeometry &lineGeom)
Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:47
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
A class to represent a point.
Definition: qgspoint.h:142
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
void setX(double x)
Sets the x value of the point.
Definition: qgspoint.h:192
void setY(double y)
Sets the y value of the point.
Definition: qgspoint.h:200
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
QVector< QgsPolyline > QgsMultiPolyline
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:58
General purpose distance and area calculator.
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
double closestSegmentWithContext(const QgsPoint &point, QgsPoint &minDistPoint, int &afterVertex, double *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
static QgsGeometry fromMultiPoint(const QgsMultiPoint &multipoint)
Creates a new geometry from a QgsMultiPoint object.
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
bool buffer(QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, bool onlySelectedFeatures=false, bool dissolve=false, int bufferDistanceField=-1, QProgressDialog *p=nullptr)
Create buffers for a vector layer and write it to a new shape file.
This class represents a coordinate reference system (CRS).
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:186
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:162
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:196
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsfeature.h:55
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:277
QgsAbstractGeometry * geometry() const
Returns the underlying geometry store.
QgsAttributes attributes
Definition: qgsfeature.h:140
bool dissolve(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, int uniqueIdField=-1, QProgressDialog *p=nullptr)
Dissolve a vector layer and write it to a new shape file.
static QgsGeometry fromMultiPolyline(const QgsMultiPolyline &multiline)
Creates a new geometry from a QgsMultiPolyline object.
bool convexHull(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, int uniqueIdField=-1, QProgressDialog *p=nullptr)
Create convex hull(s) of a vector layer and write it to a new shape file.
double x
Definition: qgspoint.h:146