QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsgeometryanalyzer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometryanalyzer.cpp - QGIS Tools for vector geometry analysis
3  -------------------
4  begin : 19 March 2009
5  copyright : (C) Carson Farmer
6  email : [email protected]
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsgeometryanalyzer.h"
19 
20 #include "qgsapplication.h"
21 #include "qgsfield.h"
22 #include "qgsfeature.h"
23 #include "qgslogger.h"
25 #include "qgsvectorfilewriter.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgsdistancearea.h"
28 #include <QProgressDialog>
29 
31  const QString& shapefileName,
32  double tolerance,
33  bool onlySelectedFeatures,
34  QProgressDialog *p )
35 {
36  if ( !layer )
37  {
38  return false;
39  }
40 
41  QgsVectorDataProvider* dp = layer->dataProvider();
42  if ( !dp )
43  {
44  return false;
45  }
46 
47  QGis::WkbType outputType = dp->geometryType();
48  const QgsCoordinateReferenceSystem crs = layer->crs();
49 
50  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->pendingFields(), outputType, &crs );
51  QgsFeature currentFeature;
52 
53  //take only selection
54  if ( onlySelectedFeatures )
55  {
56  //use QgsVectorLayer::featureAtId
57  const QgsFeatureIds selection = layer->selectedFeaturesIds();
58  if ( p )
59  {
60  p->setMaximum( selection.size() );
61  }
62 
63  int processedFeatures = 0;
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, 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 
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 
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  for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt )
1104  {
1105  if ( geom->type() == QGis::Line )
1106  {
1107  //geos 3.3 needed for line offsets
1108 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
1109  ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3)))
1110  GEOSGeometry* offsetGeom = GEOSOffsetCurve(( *inputGeomIt )->asGeos(), -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ );
1111  if ( !offsetGeom || !GEOSisValid( offsetGeom ) )
1112  {
1113  return false;
1114  }
1115  if ( !GEOSisValid( offsetGeom ) || GEOSGeomTypeId( offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints( offsetGeom ) < 1 )
1116  {
1117  GEOSGeom_destroy( offsetGeom );
1118  return false;
1119  }
1120  outputGeomList.push_back( offsetGeom );
1121 #else
1122  outputGeomList.push_back( GEOSGeom_clone(( *inputGeomIt )->asGeos() ) );
1123 #endif
1124  }
1125  else if ( geom->type() == QGis::Point )
1126  {
1127  QgsPoint p = ( *inputGeomIt )->asPoint();
1128  p = createPointOffset( p.x(), p.y(), offset, lineGeom );
1129  GEOSCoordSequence* ptSeq = GEOSCoordSeq_create( 1, 2 );
1130  GEOSCoordSeq_setX( ptSeq, 0, p.x() );
1131  GEOSCoordSeq_setY( ptSeq, 0, p.y() );
1132  GEOSGeometry* geosPt = GEOSGeom_createPoint( ptSeq );
1133  outputGeomList.push_back( geosPt );
1134  }
1135  }
1136 
1137  if ( !geom->isMultipart() )
1138  {
1139  GEOSGeometry* outputGeom = outputGeomList.at( 0 );
1140  if ( outputGeom )
1141  {
1142  geom->fromGeos( outputGeom );
1143  }
1144  }
1145  else
1146  {
1147  GEOSGeometry** geomArray = new GEOSGeometry*[outputGeomList.size()];
1148  for ( int i = 0; i < outputGeomList.size(); ++i )
1149  {
1150  geomArray[i] = outputGeomList.at( i );
1151  }
1152  GEOSGeometry* collection = 0;
1153  if ( geom->type() == QGis::Point )
1154  {
1155  collection = GEOSGeom_createCollection( GEOS_MULTIPOINT, geomArray, outputGeomList.size() );
1156  }
1157  else if ( geom->type() == QGis::Line )
1158  {
1159  collection = GEOSGeom_createCollection( GEOS_MULTILINESTRING, geomArray, outputGeomList.size() );
1160  }
1161  geom->fromGeos( collection );
1162  delete[] geomArray;
1163  }
1164  return true;
1165 }
1166 
1167 QgsPoint QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, QgsGeometry* lineGeom ) const
1168 {
1169  QgsPoint p( x, y );
1170  QgsPoint minDistPoint;
1171  int afterVertexNr;
1172  lineGeom->closestSegmentWithContext( p, minDistPoint, afterVertexNr );
1173 
1174  int beforeVertexNr = afterVertexNr - 1;
1175  QgsPoint beforeVertex = lineGeom->vertexAt( beforeVertexNr );
1176  QgsPoint afterVertex = lineGeom->vertexAt( afterVertexNr );
1177 
1178  //get normal vector
1179  double dx = afterVertex.x() - beforeVertex.x();
1180  double dy = afterVertex.y() - beforeVertex.y();
1181  double normalX = -dy;
1182  double normalY = dx;
1183  double normalLength = sqrt( normalX * normalX + normalY * normalY );
1184  normalX *= ( dist / normalLength );
1185  normalY *= ( dist / normalLength );
1186 
1187  double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control
1188  Q_UNUSED( debugLength );
1189  return QgsPoint( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side
1190 }
1191 
1192 QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, QgsGeometry* lineGeom )
1193 {
1194  if ( !lineGeom )
1195  {
1196  return 0;
1197  }
1198 
1199  QgsMultiPolyline resultGeom;
1200 
1201  //need to go with WKB and z coordinate until QgsGeometry supports M values
1202  const unsigned char* lineWkb = lineGeom->asWkb();
1203 
1204  const unsigned char* ptr = lineWkb + 1;
1205  QGis::WkbType wkbType;
1206  memcpy( &wkbType, ptr, sizeof( wkbType ) );
1207  ptr += sizeof( wkbType );
1208 
1209  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
1210  {
1211  return 0;
1212  }
1213 
1214  if ( wkbType == QGis::WKBLineString25D )
1215  {
1216  locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1217  }
1218  else if ( wkbType == QGis::WKBMultiLineString25D )
1219  {
1220  int* nLines = ( int* )ptr;
1221  ptr += sizeof( int );
1222  for ( int i = 0; i < *nLines; ++i )
1223  {
1224  ptr += ( 1 + sizeof( wkbType ) );
1225  ptr = locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1226  }
1227  }
1228 
1229  if ( resultGeom.size() < 1 )
1230  {
1231  return 0;
1232  }
1233  return QgsGeometry::fromMultiPolyline( resultGeom );
1234 }
1235 
1237 {
1238  if ( !lineGeom )
1239  {
1240  return 0;
1241  }
1242 
1243  QgsMultiPoint resultGeom;
1244 
1245  //need to go with WKB and z coordinate until QgsGeometry supports M values
1246  const unsigned char* lineWkb = lineGeom->asWkb();
1247 
1248  const unsigned char* ptr = lineWkb + 1;
1249  QGis::WkbType wkbType;
1250  memcpy( &wkbType, ptr, sizeof( wkbType ) );
1251  ptr += sizeof( wkbType );
1252 
1253  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
1254  {
1255  return 0;
1256  }
1257 
1258  if ( wkbType == QGis::WKBLineString25D )
1259  {
1260  locateAlongWkbString( ptr, resultGeom, measure );
1261  }
1262  else if ( wkbType == QGis::WKBMultiLineString25D )
1263  {
1264  int* nLines = ( int* )ptr;
1265  ptr += sizeof( int );
1266  for ( int i = 0; i < *nLines; ++i )
1267  {
1268  ptr += ( 1 + sizeof( wkbType ) );
1269  ptr = locateAlongWkbString( ptr, resultGeom, measure );
1270  }
1271  }
1272 
1273  if ( resultGeom.size() < 1 )
1274  {
1275  return 0;
1276  }
1277  return QgsGeometry::fromMultiPoint( resultGeom );
1278 }
1279 
1280 const unsigned char* QgsGeometryAnalyzer::locateBetweenWkbString( const unsigned char* ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure )
1281 {
1282  int* nPoints = ( int* ) ptr;
1283  ptr += sizeof( int );
1284  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1285  double *x, *y, *z;
1286  QgsPolyline currentLine;
1287 
1288  QgsPoint pt1, pt2;
1289  bool measureInSegment; //true if measure is contained in the segment
1290  bool secondPointClipped; //true if second point is != segment endpoint
1291 
1292 
1293  for ( int i = 0; i < *nPoints; ++i )
1294  {
1295  x = ( double* )ptr;
1296  ptr += sizeof( double );
1297  y = ( double* )ptr;
1298  ptr += sizeof( double );
1299  z = ( double* ) ptr;
1300  ptr += sizeof( double );
1301 
1302  if ( i > 0 )
1303  {
1304  measureInSegment = clipSegmentByRange( prevx, prevy, prevz, *x, *y, *z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
1305  if ( measureInSegment )
1306  {
1307  if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line
1308  {
1309  currentLine.append( pt1 );
1310  }
1311 
1312  if ( pt1 != pt2 ) //avoid duplicated entry if measure value equals m-value of vertex
1313  {
1314  currentLine.append( pt2 );
1315  }
1316 
1317  if ( secondPointClipped || i == *nPoints - 1 ) //close current segment
1318  {
1319  if ( currentLine.size() > 1 )
1320  {
1321  result.append( currentLine );
1322  }
1323  currentLine.clear();
1324  }
1325  }
1326  }
1327  prevx = *x; prevy = *y; prevz = *z;
1328  }
1329  return ptr;
1330 }
1331 
1332 const unsigned char* QgsGeometryAnalyzer::locateAlongWkbString( const unsigned char* ptr, QgsMultiPoint& result, double measure )
1333 {
1334  int* nPoints = ( int* ) ptr;
1335  ptr += sizeof( int );
1336  double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1337  double *x, *y, *z;
1338 
1339  QgsPoint pt1, pt2;
1340  bool pt1Ok, pt2Ok;
1341 
1342  for ( int i = 0; i < *nPoints; ++i )
1343  {
1344  x = ( double* )ptr;
1345  ptr += sizeof( double );
1346  y = ( double* )ptr;
1347  ptr += sizeof( double );
1348  z = ( double* ) ptr;
1349  ptr += sizeof( double );
1350 
1351  if ( i > 0 )
1352  {
1353  locateAlongSegment( prevx, prevy, prevz, *x, *y, *z, measure, pt1Ok, pt1, pt2Ok, pt2 );
1354  if ( pt1Ok )
1355  {
1356  result.append( pt1 );
1357  }
1358  if ( pt2Ok && ( i == ( *nPoints - 1 ) ) )
1359  {
1360  result.append( pt2 );
1361  }
1362  }
1363  prevx = *x; prevy = *y; prevz = *z;
1364  }
1365  return ptr;
1366 }
1367 
1368 bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1,
1369  QgsPoint& pt2, bool& secondPointClipped )
1370 {
1371  bool reversed = m1 > m2;
1372  double tmp;
1373 
1374  //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2)
1375  if ( reversed )
1376  {
1377  tmp = m1;
1378  m1 = m2;
1379  m2 = tmp;
1380 
1381  tmp = x1;
1382  x1 = x2;
1383  x2 = tmp;
1384 
1385  tmp = y1;
1386  y1 = y2;
1387  y2 = tmp;
1388  }
1389 
1390  //reverse range1, range2 if necessary
1391  if ( range1 > range2 )
1392  {
1393  tmp = range1;
1394  range1 = range2;
1395  range2 = tmp;
1396  }
1397 
1398  //segment completely outside of range
1399  if ( m2 < range1 || m1 > range2 )
1400  {
1401  return false;
1402  }
1403 
1404  //segment completely inside of range
1405  if ( m2 <= range2 && m1 >= range1 )
1406  {
1407  if ( reversed )
1408  {
1409  pt1.setX( x2 ); pt1.setY( y2 );
1410  pt2.setX( x1 ); pt2.setY( y1 );
1411  }
1412  else
1413  {
1414  pt1.setX( x1 ); pt1.setY( y1 );
1415  pt2.setX( x2 ); pt2.setY( y2 );
1416  }
1417  secondPointClipped = false;
1418  return true;
1419  }
1420 
1421  //m1 inside and m2 not
1422  if ( m1 >= range1 && m1 <= range2 )
1423  {
1424  pt1.setX( x1 ); pt1.setY( y1 );
1425  double dist = ( range2 - m1 ) / ( m2 - m1 );
1426  pt2.setX( x1 + ( x2 - x1 ) * dist );
1427  pt2.setY( y1 + ( y2 - y1 ) * dist );
1428  secondPointClipped = !reversed;
1429  }
1430 
1431  //m2 inside and m1 not
1432  if ( m2 >= range1 && m2 <= range2 )
1433  {
1434  pt2.setX( x2 ); pt2.setY( y2 );
1435  double dist = ( m2 - range1 ) / ( m2 - m1 );
1436  pt1.setX( x2 - ( x2 - x1 ) * dist );
1437  pt1.setY( y2 - ( y2 - y1 ) * dist );
1438  secondPointClipped = reversed;
1439  }
1440 
1441  //range1 and range 2 both inside the segment
1442  if ( range1 >= m1 && range2 <= m2 )
1443  {
1444  double dist1 = ( range1 - m1 ) / ( m2 - m1 );
1445  double dist2 = ( range2 - m1 ) / ( m2 - m1 );
1446  pt1.setX( x1 + ( x2 - x1 ) * dist1 );
1447  pt1.setY( y1 + ( y2 - y1 ) * dist1 );
1448  pt2.setX( x1 + ( x2 - x1 ) * dist2 );
1449  pt2.setY( y1 + ( y2 - y1 ) * dist2 );
1450  secondPointClipped = true;
1451  }
1452 
1453  if ( reversed ) //switch p1 and p2
1454  {
1455  QgsPoint tmpPt = pt1;
1456  pt1 = pt2;
1457  pt2 = tmpPt;
1458  }
1459 
1460  return true;
1461 }
1462 
1463 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 )
1464 {
1465  bool reversed = false;
1466  pt1Ok = false;
1467  pt2Ok = false;
1468  double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints
1469 
1470  if ( m1 > m2 )
1471  {
1472  double tmp = m1;
1473  m1 = m2;
1474  m2 = tmp;
1475  reversed = true;
1476  }
1477 
1478  //segment does not match
1479  if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance )
1480  {
1481  pt1Ok = false;
1482  pt2Ok = false;
1483  return;
1484  }
1485 
1486  //match with vertex1
1487  if ( qgsDoubleNear( m1, measure, tolerance ) )
1488  {
1489  if ( reversed )
1490  {
1491  pt2Ok = true;
1492  pt2.setX( x2 ); pt2.setY( y2 );
1493  }
1494  else
1495  {
1496  pt1Ok = true;
1497  pt1.setX( x1 ); pt1.setY( y1 );
1498  }
1499  }
1500 
1501  //match with vertex2
1502  if ( qgsDoubleNear( m2, measure, tolerance ) )
1503  {
1504  if ( reversed )
1505  {
1506  pt1Ok = true;
1507  pt1.setX( x1 ); pt1.setY( y1 );
1508  }
1509  else
1510  {
1511  pt2Ok = true;
1512  pt2.setX( x2 ); pt2.setY( y2 );
1513  }
1514  }
1515 
1516 
1517  if ( pt1Ok || pt2Ok )
1518  {
1519  return;
1520  }
1521 
1522  //match between the vertices
1523  if ( qgsDoubleNear( m1, m2 ) )
1524  {
1525  pt1.setX( x1 );
1526  pt1.setY( y1 );
1527  pt1Ok = true;
1528  return;
1529  }
1530  double dist = ( measure - m1 ) / ( m2 - m1 );
1531  if ( reversed )
1532  {
1533  dist = 1 - dist;
1534  }
1535 
1536  pt1.setX( x1 + dist * ( x2 - x1 ) );
1537  pt1.setY( y1 + dist * ( y2 - y1 ) );
1538  pt1Ok = true;
1539 }
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:167
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)
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.
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:325
bool isMultipart()
Returns true if wkb of the geometry is of WKBMulti* type.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:330
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:161
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.
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: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: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
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: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:140
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
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
bool createOffsetGeometry(QgsGeometry *geom, QgsGeometry *lineGeom, double offset)
Create geometry offset relative to line geometry.
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:189
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.