QGIS API Documentation  2.99.0-Master (08ee180)
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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->selectedFeaturesIds();
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 }
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:186
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...
QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned.
QgsFeatureId id
Definition: qgsfeature.h:139
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:116
QList< QgsGeometry > asGeometryCollection() const
Return contents of the geometry as a list of geometries.
bool isValid() const
Return the status of the layer.
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
QgsFields fields() const
Returns the list of fields of this layer.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:360
QVector< QgsPoint > QgsPolyline
Polyline is represented as a vector of points.
Definition: qgsgeometry.h:46
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.
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
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
virtual bool addFeatures(QgsFeatureList &flist)
Adds a list of features.
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 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.
QByteArray exportToWkb() const
Export the geometry to WKB.
QString encoding() const
Get encoding which is used for accessing data.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
QgsRectangle extent() const override
Return the extent of the layer.
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.
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
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
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
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
A class to represent a point.
Definition: qgspoint.h:111
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
void setX(double x)
Sets the x value of the point.
Definition: qgspoint.h:161
void setY(double y)
Sets the y value of the point.
Definition: qgspoint.h:169
QVector< QgsPolyline > QgsMultiPolyline
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:58
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
General purpose distance and area calculator.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:277
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.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:162
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:214
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
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.
QgsAbstractGeometry * geometry() const
Returns the underlying geometry store.
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.
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
A vector of attributes.
Definition: qgsfeature.h:55
Represents a vector layer which manages a vector based data sets.
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:196
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
QgsAttributes attributes
Definition: qgsfeature.h:140
QgsGeometry centroid() const
Returns the center of mass of a geometry.
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:115