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