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