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