QGIS API Documentation  2.3.0-Master
 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 : 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 
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 
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 
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 
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 ];
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 ] );
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  {
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, QList<int>& 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  QgsFeature lineFeature;
958  double measure1, measure2 = 0.0;
959 
960  int nEventFeatures = eventLayer->pendingFeatureCount();
961  int featureCounter = 0;
962  int nOutputFeatures = 0; //number of output features for the current event feature
963  if ( p )
964  {
965  p->setWindowModality( Qt::WindowModal );
966  p->setMinimum( 0 );
967  p->setMaximum( nEventFeatures );
968  p->show();
969  }
970 
971  while ( fit.nextFeature( fet ) )
972  {
973  nOutputFeatures = 0;
974 
975  //update progress dialog
976  if ( p )
977  {
978  if ( p->wasCanceled() )
979  {
980  break;
981  }
982  p->setValue( featureCounter );
983  ++featureCounter;
984  }
985 
986  measure1 = fet.attribute( locationField1 ).toDouble();
987  if ( locationField2 != -1 )
988  {
989  measure2 = fet.attribute( locationField2 ).toDouble();
990  }
991 
992  QList<QgsFeature> featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() );
993  QList<QgsFeature>::const_iterator featureIdIt = featureIdList.constBegin();
994  for ( ; featureIdIt != featureIdList.constEnd(); ++featureIdIt )
995  {
996  if ( locationField2 == -1 )
997  {
998  lrsGeom = locateAlongMeasure( measure1, featureIdIt->geometry() );
999  }
1000  else
1001  {
1002  lrsGeom = locateBetweenMeasures( measure1, measure2, featureIdIt->geometry() );
1003  }
1004 
1005  if ( lrsGeom )
1006  {
1007  ++nOutputFeatures;
1008  addEventLayerFeature( fet, lrsGeom, lineFeature.geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry );
1009  }
1010  }
1011  if ( nOutputFeatures < 1 )
1012  {
1013  unlocatedFeatureIds.push_back( fet.id() );
1014  }
1015  }
1016 
1017  if ( p )
1018  {
1019  p->setValue( nEventFeatures );
1020  }
1021 
1022  if ( memoryProvider )
1023  {
1024  memoryProvider->addFeatures( memoryProviderFeatures );
1025  }
1026  delete fileWriter;
1027  return true;
1028 }
1029 
1031  int offsetField, double offsetScale, bool forceSingleType )
1032 {
1033  if ( !geom )
1034  {
1035  return;
1036  }
1037 
1038  QList<QgsGeometry*> geomList;
1039  if ( forceSingleType )
1040  {
1041  geomList = geom->asGeometryCollection();
1042  }
1043  else
1044  {
1045  geomList.push_back( geom );
1046  }
1047 
1048  QList<QgsGeometry*>::iterator geomIt = geomList.begin();
1049  for ( ; geomIt != geomList.end(); ++geomIt )
1050  {
1051  //consider offset
1052  if ( offsetField >= 0 )
1053  {
1054  double offsetVal = feature.attribute( offsetField ).toDouble();
1055  offsetVal *= offsetScale;
1056  createOffsetGeometry( *geomIt, lineGeom, offsetVal );
1057  }
1058 
1059  feature.setGeometry( *geomIt );
1060  if ( fileWriter )
1061  {
1062  fileWriter->addFeature( feature );
1063  }
1064  else
1065  {
1066  memoryFeatures << feature;
1067  }
1068  }
1069 
1070  if ( forceSingleType )
1071  {
1072  delete geom;
1073  }
1074 }
1075 
1077 {
1078  if ( !geom || !lineGeom )
1079  {
1080  return;
1081  }
1082 
1083  QList<QgsGeometry*> inputGeomList;
1084 
1085  if ( geom->isMultipart() )
1086  {
1087  inputGeomList = geom->asGeometryCollection();
1088  }
1089  else
1090  {
1091  inputGeomList.push_back( geom );
1092  }
1093 
1094  QList<GEOSGeometry*> outputGeomList;
1095  QList<QgsGeometry*>::const_iterator inputGeomIt = inputGeomList.constBegin();
1096  for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt )
1097  {
1098  if ( geom->type() == QGis::Line )
1099  {
1100  //geos 3.3 needed for line offsets
1101 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
1102  ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3)))
1103  outputGeomList.push_back( GEOSOffsetCurve(( *inputGeomIt )->asGeos(), -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ ) );
1104 #else
1105  outputGeomList.push_back( GEOSGeom_clone(( *inputGeomIt )->asGeos() ) );
1106 #endif
1107  }
1108  else if ( geom->type() == QGis::Point )
1109  {
1110  QgsPoint p = ( *inputGeomIt )->asPoint();
1111  p = createPointOffset( p.x(), p.y(), offset, lineGeom );
1112  GEOSCoordSequence* ptSeq = GEOSCoordSeq_create( 1, 2 );
1113  GEOSCoordSeq_setX( ptSeq, 0, p.x() );
1114  GEOSCoordSeq_setY( ptSeq, 0, p.y() );
1115  GEOSGeometry* geosPt = GEOSGeom_createPoint( ptSeq );
1116  outputGeomList.push_back( geosPt );
1117  }
1118  }
1119 
1120  if ( !geom->isMultipart() )
1121  {
1122  GEOSGeometry* outputGeom = outputGeomList.at( 0 );
1123  if ( outputGeom )
1124  {
1125  geom->fromGeos( outputGeom );
1126  }
1127  }
1128  else
1129  {
1130  GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()];
1131  for ( int i = 0; i < outputGeomList.size(); ++i )
1132  {
1133  geomArray[i] = outputGeomList.at( i );
1134  }
1135  GEOSGeometry* collection = 0;
1136  if ( geom->type() == QGis::Point )
1137  {
1138  collection = GEOSGeom_createCollection( GEOS_MULTIPOINT, geomArray, outputGeomList.size() );
1139  }
1140  else if ( geom->type() == QGis::Line )
1141  {
1142  collection = GEOSGeom_createCollection( GEOS_MULTILINESTRING, geomArray, outputGeomList.size() );
1143  }
1144  geom->fromGeos( collection );
1145  delete[] geomArray;
1146  }
1147 }
1148 
1149 QgsPoint QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, QgsGeometry* lineGeom ) const
1150 {
1151  QgsPoint p( x, y );
1152  QgsPoint minDistPoint;
1153  int afterVertexNr;
1154  lineGeom->closestSegmentWithContext( p, minDistPoint, afterVertexNr );
1155 
1156  int beforeVertexNr = afterVertexNr - 1;
1157  QgsPoint beforeVertex = lineGeom->vertexAt( beforeVertexNr );
1158  QgsPoint afterVertex = lineGeom->vertexAt( afterVertexNr );
1159 
1160  //get normal vector
1161  double dx = afterVertex.x() - beforeVertex.x();
1162  double dy = afterVertex.y() - beforeVertex.y();
1163  double normalX = -dy;
1164  double normalY = dx;
1165  double normalLength = sqrt( normalX * normalX + normalY * normalY );
1166  normalX *= ( dist / normalLength );
1167  normalY *= ( dist / normalLength );
1168 
1169  double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control
1170  Q_UNUSED( debugLength );
1171  return QgsPoint( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side
1172 }
1173 
1174 QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, QgsGeometry* lineGeom )
1175 {
1176  if ( !lineGeom )
1177  {
1178  return 0;
1179  }
1180 
1181  QgsMultiPolyline resultGeom;
1182 
1183  //need to go with WKB and z coordinate until QgsGeometry supports M values
1184  const unsigned char* lineWkb = lineGeom->asWkb();
1185 
1186  const unsigned char* ptr = lineWkb + 1;
1187  QGis::WkbType wkbType;
1188  memcpy( &wkbType, ptr, sizeof( wkbType ) );
1189  ptr += sizeof( wkbType );
1190 
1191  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
1192  {
1193  return 0;
1194  }
1195 
1196  if ( wkbType == QGis::WKBLineString25D )
1197  {
1198  locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1199  }
1200  else if ( wkbType == QGis::WKBMultiLineString25D )
1201  {
1202  int* nLines = ( int* )ptr;
1203  ptr += sizeof( int );
1204  for ( int i = 0; i < *nLines; ++i )
1205  {
1206  ptr += ( 1 + sizeof( wkbType ) );
1207  ptr = locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1208  }
1209  }
1210 
1211  if ( resultGeom.size() < 1 )
1212  {
1213  return 0;
1214  }
1215  return QgsGeometry::fromMultiPolyline( resultGeom );
1216 }
1217 
1219 {
1220  if ( !lineGeom )
1221  {
1222  return 0;
1223  }
1224 
1225  QgsMultiPoint resultGeom;
1226 
1227  //need to go with WKB and z coordinate until QgsGeometry supports M values
1228  const unsigned char* lineWkb = lineGeom->asWkb();
1229 
1230  const unsigned char* ptr = lineWkb + 1;
1231  QGis::WkbType wkbType;
1232  memcpy( &wkbType, ptr, sizeof( wkbType ) );
1233  ptr += sizeof( wkbType );
1234 
1235  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
1236  {
1237  return 0;
1238  }
1239 
1240  if ( wkbType == QGis::WKBLineString25D )
1241  {
1242  locateAlongWkbString( ptr, resultGeom, measure );
1243  }
1244  else if ( wkbType == QGis::WKBMultiLineString25D )
1245  {
1246  int* nLines = ( int* )ptr;
1247  ptr += sizeof( int );
1248  for ( int i = 0; i < *nLines; ++i )
1249  {
1250  ptr += ( 1 + sizeof( wkbType ) );
1251  ptr = locateAlongWkbString( ptr, resultGeom, measure );
1252  }
1253  }
1254 
1255  if ( resultGeom.size() < 1 )
1256  {
1257  return 0;
1258  }
1259  return QgsGeometry::fromMultiPoint( resultGeom );
1260 }
1261 
1262 const unsigned char* QgsGeometryAnalyzer::locateBetweenWkbString( const unsigned char* ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure )
1263 {
1264  int* nPoints = ( int* ) ptr;
1265  ptr += sizeof( int );
1266  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1267  double *x, *y, *z;
1268  QgsPolyline currentLine;
1269 
1270  QgsPoint pt1, pt2;
1271  bool measureInSegment; //true if measure is contained in the segment
1272  bool secondPointClipped; //true if second point is != segment endpoint
1273 
1274 
1275  for ( int i = 0; i < *nPoints; ++i )
1276  {
1277  x = ( double* )ptr;
1278  ptr += sizeof( double );
1279  y = ( double* )ptr;
1280  ptr += sizeof( double );
1281  z = ( double* ) ptr;
1282  ptr += sizeof( double );
1283 
1284  if ( i > 0 )
1285  {
1286  measureInSegment = clipSegmentByRange( prevx, prevy, prevz, *x, *y, *z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
1287  if ( measureInSegment )
1288  {
1289  if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line
1290  {
1291  currentLine.append( pt1 );
1292  }
1293 
1294  if ( pt1 != pt2 ) //avoid duplicated entry if measure value equals m-value of vertex
1295  {
1296  currentLine.append( pt2 );
1297  }
1298 
1299  if ( secondPointClipped || i == *nPoints - 1 ) //close current segment
1300  {
1301  if ( currentLine.size() > 1 )
1302  {
1303  result.append( currentLine );
1304  }
1305  currentLine.clear();
1306  }
1307  }
1308  }
1309  prevx = *x; prevy = *y; prevz = *z;
1310  }
1311  return ptr;
1312 }
1313 
1314 const unsigned char* QgsGeometryAnalyzer::locateAlongWkbString( const unsigned char* ptr, QgsMultiPoint& result, double measure )
1315 {
1316  int* nPoints = ( int* ) ptr;
1317  ptr += sizeof( int );
1318  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1319  double *x, *y, *z;
1320 
1321  QgsPoint pt1, pt2;
1322  bool pt1Ok, pt2Ok;
1323 
1324  for ( int i = 0; i < *nPoints; ++i )
1325  {
1326  x = ( double* )ptr;
1327  ptr += sizeof( double );
1328  y = ( double* )ptr;
1329  ptr += sizeof( double );
1330  z = ( double* ) ptr;
1331  ptr += sizeof( double );
1332 
1333  if ( i > 0 )
1334  {
1335  locateAlongSegment( prevx, prevy, prevz, *x, *y, *z, measure, pt1Ok, pt1, pt2Ok, pt2 );
1336  if ( pt1Ok )
1337  {
1338  result.append( pt1 );
1339  }
1340  if ( pt2Ok && ( i == ( *nPoints - 1 ) ) )
1341  {
1342  result.append( pt2 );
1343  }
1344  }
1345  prevx = *x; prevy = *y; prevz = *z;
1346  }
1347  return ptr;
1348 }
1349 
1350 bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1,
1351  QgsPoint& pt2, bool& secondPointClipped )
1352 {
1353  bool reversed = m1 > m2;
1354  double tmp;
1355 
1356  //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2)
1357  if ( reversed )
1358  {
1359  tmp = m1;
1360  m1 = m2;
1361  m2 = tmp;
1362 
1363  tmp = x1;
1364  x1 = x2;
1365  x2 = tmp;
1366 
1367  tmp = y1;
1368  y1 = y2;
1369  y2 = tmp;
1370  }
1371 
1372  //reverse range1, range2 if necessary
1373  if ( range1 > range2 )
1374  {
1375  tmp = range1;
1376  range1 = range2;
1377  range2 = tmp;
1378  }
1379 
1380  //segment completely outside of range
1381  if ( m2 < range1 || m1 > range2 )
1382  {
1383  return false;
1384  }
1385 
1386  //segment completely inside of range
1387  if ( m2 <= range2 && m1 >= range1 )
1388  {
1389  if ( reversed )
1390  {
1391  pt1.setX( x2 ); pt1.setY( y2 );
1392  pt2.setX( x1 ); pt2.setY( y1 );
1393  }
1394  else
1395  {
1396  pt1.setX( x1 ); pt1.setY( y1 );
1397  pt2.setX( x2 ); pt2.setY( y2 );
1398  }
1399  secondPointClipped = false;
1400  return true;
1401  }
1402 
1403  //m1 inside and m2 not
1404  if ( m1 >= range1 && m1 <= range2 )
1405  {
1406  pt1.setX( x1 ); pt1.setY( y1 );
1407  double dist = ( range2 - m1 ) / ( m2 - m1 );
1408  pt2.setX( x1 + ( x2 - x1 ) * dist );
1409  pt2.setY( y1 + ( y2 - y1 ) * dist );
1410  secondPointClipped = !reversed;
1411  }
1412 
1413  //m2 inside and m1 not
1414  if ( m2 >= range1 && m2 <= range2 )
1415  {
1416  pt2.setX( x2 ); pt2.setY( y2 );
1417  double dist = ( m2 - range1 ) / ( m2 - m1 );
1418  pt1.setX( x2 - ( x2 - x1 ) * dist );
1419  pt1.setY( y2 - ( y2 - y1 ) * dist );
1420  secondPointClipped = reversed;
1421  }
1422 
1423  //range1 and range 2 both inside the segment
1424  if ( range1 >= m1 && range2 <= m2 )
1425  {
1426  double dist1 = ( range1 - m1 ) / ( m2 - m1 );
1427  double dist2 = ( range2 - m1 ) / ( m2 - m1 );
1428  pt1.setX( x1 + ( x2 - x1 ) * dist1 );
1429  pt1.setY( y1 + ( y2 - y1 ) * dist1 );
1430  pt2.setX( x1 + ( x2 - x1 ) * dist2 );
1431  pt2.setY( y1 + ( y2 - y1 ) * dist2 );
1432  secondPointClipped = true;
1433  }
1434 
1435  if ( reversed ) //switch p1 and p2
1436  {
1437  QgsPoint tmpPt = pt1;
1438  pt1 = pt2;
1439  pt2 = tmpPt;
1440  }
1441 
1442  return true;
1443 }
1444 
1445 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 )
1446 {
1447  bool reversed = false;
1448  pt1Ok = false;
1449  pt2Ok = false;
1450  double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints
1451 
1452  if ( m1 > m2 )
1453  {
1454  double tmp = m1;
1455  m1 = m2;
1456  m2 = tmp;
1457  reversed = true;
1458  }
1459 
1460  //segment does not match
1461  if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance )
1462  {
1463  pt1Ok = false;
1464  pt2Ok = false;
1465  return;
1466  }
1467 
1468  //match with vertex1
1469  if ( qgsDoubleNear( m1, measure, tolerance ) )
1470  {
1471  if ( reversed )
1472  {
1473  pt2Ok = true;
1474  pt2.setX( x2 ); pt2.setY( y2 );
1475  }
1476  else
1477  {
1478  pt1Ok = true;
1479  pt1.setX( x1 ); pt1.setY( y1 );
1480  }
1481  }
1482 
1483  //match with vertex2
1484  if ( qgsDoubleNear( m2, measure, tolerance ) )
1485  {
1486  if ( reversed )
1487  {
1488  pt1Ok = true;
1489  pt1.setX( x1 ); pt1.setY( y1 );
1490  }
1491  else
1492  {
1493  pt2Ok = true;
1494  pt2.setX( x2 ); pt2.setY( y2 );
1495  }
1496  }
1497 
1498 
1499  if ( pt1Ok || pt2Ok )
1500  {
1501  return;
1502  }
1503 
1504  //match between the vertices
1505  if ( qgsDoubleNear( m1, m2 ) )
1506  {
1507  pt1.setX( x1 );
1508  pt1.setY( y1 );
1509  pt1Ok = true;
1510  return;
1511  }
1512  double dist = ( measure - m1 ) / ( m2 - m1 );
1513  if ( reversed )
1514  {
1515  dist = 1 - dist;
1516  }
1517 
1518  pt1.setX( x1 + dist * ( x2 - x1 ) );
1519  pt1.setY( y1 + dist * ( y2 - y1 ) );
1520  pt1Ok = true;
1521 }
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:164
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.
void addEventLayerFeature(QgsFeature &feature, QgsGeometry *geom, QgsGeometry *lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures, int offsetField=-1, double offsetScale=1.0, bool forceSingleType=false)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
static bool clipSegmentByRange(double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint &pt1, QgsPoint &pt2, bool &secondPointClipped)
static void locateAlongSegment(double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool &pt1Ok, QgsPoint &pt1, bool &pt2Ok, QgsPoint &pt2)
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:36
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:326
bool isMultipart()
Returns true if wkb of the geometry is of WKBMulti* type.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:331
QList< double > simpleMeasure(QgsGeometry *geometry)
const unsigned char * locateAlongWkbString(const unsigned char *ptr, QgsMultiPoint &result, double measure)
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:38
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:164
void setAttributes(const QgsAttributes &attrs)
Definition: qgsfeature.h:145
WkbType
Used for symbology operations.
Definition: qgis.h:53
A convenience class for writing vector files to disk.
void bufferFeature(QgsFeature &f, int nProcessedFeatures, QgsVectorFileWriter *vfw, bool dissolve, QgsGeometry **dissolveGeometry, double bufferDistance, int bufferDistanceField)
Helper function to buffer an individual feature.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:114
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:324
double x() const
Definition: qgspoint.h:110
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
void createOffsetGeometry(QgsGeometry *geom, QgsGeometry *lineGeom, double offset)
Create geometry offset relative to line geometry.
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.
QgsPoint createPointOffset(double x, double y, double dist, QgsGeometry *lineGeom) const
void centroidFeature(QgsFeature &f, QgsVectorFileWriter *vfw)
Helper function to get the cetroid of an individual feature.
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:53
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:47
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
const QgsAttributes & attributes() const
Definition: qgsfeature.h:143
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:137
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:31
QVector< QgsPolyline > QgsPolygon
polygon: first item of the list is outer ring, inner rings (if any) start from second item ...
Definition: qgsgeometry.h:44
void convexFeature(QgsFeature &f, int nProcessedFeatures, QgsGeometry **dissolveGeometry)
Helper function to get the convex hull of feature(s)
virtual QGis::WkbType geometryType() const =0
Get feature type.
bool isValid()
A class to represent a point geometry.
Definition: qgspoint.h:63
void dissolveFeature(QgsFeature &f, int nProcessedFeatures, QgsGeometry **dissolveGeometry)
Helper function to dissolve feature(s)
void setX(double x)
Definition: qgspoint.h:87
bool eventLayer(QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QList< int > &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...
const unsigned char * locateBetweenWkbString(const unsigned char *ptr, QgsMultiPolyline &result, double fromMeasure, double toMeasure)
void setY(double y)
Definition: qgspoint.h:95
QVector< QgsPolyline > QgsMultiPolyline
a collection of QgsPolylines that share a common collection of attributes
Definition: qgsgeometry.h:50
void simplifyFeature(QgsFeature &f, QgsVectorFileWriter *vfw, double tolerance)
Helper function to simplify an individual feature.
static QgsGeometry * fromMultiPolyline(const QgsMultiPolyline &multiline)
construct geometry from a multipolyline
General purpose distance and area calculator.
double perimeterMeasure(QgsGeometry *geometry, QgsDistanceArea &measure)
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
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:118
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:184
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.