From 0227bdc3762258a1ac5bcf4ff2a5b76dfd7705bb Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 7 Aug 2017 06:35:01 +1000 Subject: [PATCH] Remove QgsGeometryAnalyzer, QgsOverlayAnalyzer, QgsPointSample These classes are unused in the master QGIS code, and are unmaintained and with no unit tests or other QA, and have inflexible API (e.g. always requiring writing outputs to shapefiles) They all have equivalent algorithms available via Processing (where the algorithms are unit tested and maintained). We should be pushing all QGIS api users to use the Processing algorithms instead. --- doc/api_break.dox | 2 + python/analysis/analysis_auto.sip | 3 - .../analysis/vector/qgsgeometryanalyzer.sip | 143 -- python/analysis/vector/qgsoverlayanalyzer.sip | 46 - python/analysis/vector/qgspointsample.sip | 38 - src/analysis/CMakeLists.txt | 6 - src/analysis/vector/qgsgeometryanalyzer.cpp | 1493 ----------------- src/analysis/vector/qgsgeometryanalyzer.h | 161 -- src/analysis/vector/qgsoverlayanalyzer.cpp | 195 --- src/analysis/vector/qgsoverlayanalyzer.h | 54 - src/analysis/vector/qgspointsample.cpp | 170 -- src/analysis/vector/qgspointsample.h | 57 - tests/src/analysis/CMakeLists.txt | 1 - tests/src/analysis/testqgsvectoranalyzer.cpp | 145 -- 14 files changed, 2 insertions(+), 2512 deletions(-) delete mode 100644 python/analysis/vector/qgsgeometryanalyzer.sip delete mode 100644 python/analysis/vector/qgsoverlayanalyzer.sip delete mode 100644 python/analysis/vector/qgspointsample.sip delete mode 100644 src/analysis/vector/qgsgeometryanalyzer.cpp delete mode 100644 src/analysis/vector/qgsgeometryanalyzer.h delete mode 100644 src/analysis/vector/qgsoverlayanalyzer.cpp delete mode 100644 src/analysis/vector/qgsoverlayanalyzer.h delete mode 100644 src/analysis/vector/qgspointsample.cpp delete mode 100644 src/analysis/vector/qgspointsample.h delete mode 100644 tests/src/analysis/testqgsvectoranalyzer.cpp diff --git a/doc/api_break.dox b/doc/api_break.dox index 1ff0c69d92e..4f3a969fddc 100644 --- a/doc/api_break.dox +++ b/doc/api_break.dox @@ -269,6 +269,7 @@ should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinat - QgsFileNameWidgetWrapper was removed. Use QgsExternalResourceWidgetWrapper instead. - QgsFileDropEdit was removed. Use QgsFileWidget instead. - QgsFormAnnotationItem. Use QgsFormAnnotation instead. +- QgsGeometryAnalyzer. Use the equivalent Processing algorithms instead. - QgsHtmlAnnotationItem. Use QgsHtmlAnnotation instead. - QgsHttpTransaction. This class was outdated and code should be ported to native Qt or Python implementations. - QgsGenericProjectionSelector. Use QgsProjectionSelectionTreeWidget instead. @@ -287,6 +288,7 @@ should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinat - QgsMapRenderer. It has been replaced by QgsMapRendererJob with subclasses and QgsMapSettings. - QgsMapToolTouch. The touch navigation functionality is now built into the standard QgsMapToolPan tool. - QgsPhotoWidgetWrapper was removed. Use QgsExternalResourceWidgetWrapper instead. +- QgsPointSample. Use the Processing "Random Points in Polygon" algorithm instead. - QgsPseudoColorShader. This shader has been broken for some time and was replaced by QgsSingleBandPseudoColorRenderer. - QgsProjectBadLayerGuiHandler was removed. It was unused in QGIS code and barely useful. Implement your own QgsProjectBadLayerHandler subclass if needed. - QgsRendererV2DataDefinedMenus was removed. Use QgsPropertyOverrideButton instead. diff --git a/python/analysis/analysis_auto.sip b/python/analysis/analysis_auto.sip index 898598b2041..4966059b096 100644 --- a/python/analysis/analysis_auto.sip +++ b/python/analysis/analysis_auto.sip @@ -12,9 +12,6 @@ %Include raster/qgsrastermatrix.sip %Include raster/qgsrastercalcnode.sip %Include raster/qgstotalcurvaturefilter.sip -%Include vector/qgsgeometryanalyzer.sip -%Include vector/qgsoverlayanalyzer.sip -%Include vector/qgspointsample.sip %Include vector/qgstransectsample.sip %Include vector/qgszonalstatistics.sip %Include interpolation/qgsinterpolator.sip diff --git a/python/analysis/vector/qgsgeometryanalyzer.sip b/python/analysis/vector/qgsgeometryanalyzer.sip deleted file mode 100644 index 47f4a4a493e..00000000000 --- a/python/analysis/vector/qgsgeometryanalyzer.sip +++ /dev/null @@ -1,143 +0,0 @@ -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgsgeometryanalyzer.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ - - - - - - -class QgsGeometryAnalyzer -{ -%Docstring - The QGis class provides vector geometry analysis functions -%End - -%TypeHeaderCode -#include "qgsgeometryanalyzer.h" -%End - public: - - bool simplify( QgsVectorLayer *layer, const QString &shapefileName, double tolerance, - bool onlySelectedFeatures = false, QProgressDialog *p = 0 ); -%Docstring - Simplify vector layer using (a modified) Douglas-Peucker algorithm - and write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param tolerance (level of simplification) - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool centroids( QgsVectorLayer *layer, const QString &shapefileName, - bool onlySelectedFeatures = false, QProgressDialog *p = 0 ); -%Docstring - Calculate the true centroids, or 'center of mass' for a vector layer and - write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool extent( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, QProgressDialog *p = 0 ); -%Docstring - Create a polygon based on the extent of all (selected) features and write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, - bool onlySelectedFeatures = false, bool dissolve = false, int bufferDistanceField = -1, QProgressDialog *p = 0 ); -%Docstring - Create buffers for a vector layer and write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param bufferDistance distance for buffering (if no buffer field is specified) - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param dissolve if true, merge all the buffers to a big multipolygon - \param bufferDistanceField index of the attribute field that contains the buffer distance (or -1 if all features have the same buffer distance) - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool convexHull( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, - int uniqueIdField = -1, QProgressDialog *p = 0 ); -%Docstring - Create convex hull(s) of a vector layer and write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param uniqueIdField index of the attribute field that contains the unique convex hull id (or -1 if - all features have the same buffer distance) - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool dissolve( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, - int uniqueIdField = -1, QProgressDialog *p = 0 ); -%Docstring - Dissolve a vector layer and write it to a new shape file - \param layer input vector layer - \param shapefileName path to the output shp - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param uniqueIdField index of the attribute field that contains the unique id to dissolve on (or -1 if - all features should be dissolved together) - \param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - - bool eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds /Out/, 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 ); -%Docstring - Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event table along the features of a line layer. - Note that currently (until QgsGeometry supports m-values) the z-coordinate of the line layer is used for linear referencing - \param lineLayer layer with the line geometry - \param eventLayer layer with features and location field - \param lineField join index in line layer - \param eventField join index in event layer - \param outputLayer name of output file (can be empty if a memory layer is used) - \param outputFormat name of output format (can be empty if a memory provider is used to store the results) - \param unlocatedFeatureIds out: ids of event features where linear referencing was not successful - \param locationField1 attribute index of location field in event layer - \param locationField2 attribute index of location end field (or -1 for point layer) - \param offsetField attribute index for offset field. Negative offset value = offset to left side, positive value = offset to right side - \param offsetScale factor to scale offset - \param forceSingleGeometry force layer to single point/line type. Feature attributes are copied in case of multiple matches - \param memoryProvider memory provider to write output to (can be 0 if output is written to a file) - \param p progress dialog or 0 if no progress dialog should be shown - :rtype: bool -%End - - QgsGeometry locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom ); -%Docstring -Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS) - :rtype: QgsGeometry -%End - - QgsGeometry locateAlongMeasure( double measure, const QgsGeometry &lineGeom ); -%Docstring - Returns linear reference geometry. Unlike the PostGIS function, this method always returns multipoint or 0 if no match (not geometry collection). - Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS) - :rtype: QgsGeometry -%End - -}; -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgsgeometryanalyzer.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ diff --git a/python/analysis/vector/qgsoverlayanalyzer.sip b/python/analysis/vector/qgsoverlayanalyzer.sip deleted file mode 100644 index fd550e1bca7..00000000000 --- a/python/analysis/vector/qgsoverlayanalyzer.sip +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgsoverlayanalyzer.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ - - - - - - -class QgsOverlayAnalyzer -{ -%Docstring - The QGis class provides vector overlay analysis functions -%End - -%TypeHeaderCode -#include "qgsoverlayanalyzer.h" -%End - public: - - bool intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB, - const QString &shapefileName, bool onlySelectedFeatures = false, - QProgressDialog *p = 0 ); -%Docstring - Perform an intersection on two input vector layers and write output to a new shape file -\param layerA input vector layer -\param layerB input vector layer -\param shapefileName path to the output shp -\param onlySelectedFeatures if true, only selected features are considered, else all the features -\param p progress dialog (or 0 if no progress dialog is to be shown) - :rtype: bool -%End - -}; - -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgsoverlayanalyzer.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ diff --git a/python/analysis/vector/qgspointsample.sip b/python/analysis/vector/qgspointsample.sip deleted file mode 100644 index f685510b82b..00000000000 --- a/python/analysis/vector/qgspointsample.sip +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgspointsample.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ - - - -class QgsPointSample -{ -%Docstring - Creates random points in polygons / multipolygons* -%End - -%TypeHeaderCode -#include "qgspointsample.h" -%End - public: - QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute = QString() ); - - int createRandomPoints( QProgressDialog *pd ); -%Docstring - Starts calculation of random points -:return: 0 in case of success* - :rtype: int -%End - -}; - -/************************************************************************ - * This file has been generated automatically from * - * * - * src/analysis/vector/qgspointsample.h * - * * - * Do not edit manually ! Edit header and run scripts/sipify.pl again * - ************************************************************************/ diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index 6aa593fbae8..072f6f3dd3c 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -35,12 +35,9 @@ SET(QGIS_ANALYSIS_SRCS raster/qgsrastercalculator.cpp raster/qgsrastermatrix.cpp vector/mersenne-twister.cpp - vector/qgsgeometryanalyzer.cpp vector/qgsgeometrysnapper.cpp - vector/qgspointsample.cpp vector/qgstransectsample.cpp vector/qgszonalstatistics.cpp - vector/qgsoverlayanalyzer.cpp openstreetmap/qgsosmbase.cpp openstreetmap/qgsosmdatabase.cpp @@ -116,9 +113,6 @@ SET(QGIS_ANALYSIS_HDRS raster/qgsrastercalcnode.h raster/qgstotalcurvaturefilter.h - vector/qgsgeometryanalyzer.h - vector/qgsoverlayanalyzer.h - vector/qgspointsample.h vector/qgstransectsample.h vector/qgszonalstatistics.h diff --git a/src/analysis/vector/qgsgeometryanalyzer.cpp b/src/analysis/vector/qgsgeometryanalyzer.cpp deleted file mode 100644 index ddfcb087ef9..00000000000 --- a/src/analysis/vector/qgsgeometryanalyzer.cpp +++ /dev/null @@ -1,1493 +0,0 @@ -/*************************************************************************** - qgsgeometryanalyzer.cpp - QGIS Tools for vector geometry analysis - ------------------- - begin : 19 March 2009 - copyright : (C) Carson Farmer - email : carson.farmer@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "qgsgeometryanalyzer.h" - -#include "qgsapplication.h" -#include "qgsfields.h" -#include "qgsfeature.h" -#include "qgsfeatureiterator.h" -#include "qgslogger.h" -#include "qgscoordinatereferencesystem.h" -#include "qgsvectorfilewriter.h" -#include "qgsvectordataprovider.h" -#include "qgsdistancearea.h" -#include "qgis.h" -#include "qgsvectorlayer.h" - -#include - -bool QgsGeometryAnalyzer::simplify( QgsVectorLayer *layer, - const QString &shapefileName, - double tolerance, - bool onlySelectedFeatures, - QProgressDialog *p ) -{ - if ( !layer ) - { - return false; - } - - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - return false; - } - - QgsWkbTypes::Type outputType = dp->wkbType(); - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); - QgsFeature currentFeature; - - //take only selection - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selection.size() ); - } - - int processedFeatures = 0; - QgsFeatureIds::const_iterator it = selection.constBegin(); - for ( ; it != selection.constEnd(); ++it ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) - { - continue; - } - simplifyFeature( currentFeature, &vWriter, tolerance ); - ++processedFeatures; - } - - if ( p ) - { - p->setValue( selection.size() ); - } - } - //take all features - else - { - QgsFeatureIterator fit = layer->getFeatures(); - - int featureCount = layer->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - int processedFeatures = 0; - - while ( fit.nextFeature( currentFeature ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - break; - } - simplifyFeature( currentFeature, &vWriter, tolerance ); - ++processedFeatures; - } - if ( p ) - { - p->setValue( featureCount ); - } - } - - return true; -} - -void QgsGeometryAnalyzer::simplifyFeature( QgsFeature &f, QgsVectorFileWriter *vfw, double tolerance ) -{ - if ( !f.hasGeometry() ) - { - return; - } - - QgsGeometry featureGeometry = f.geometry(); - - // simplify feature - QgsGeometry tmpGeometry = featureGeometry.simplify( tolerance ); - - QgsFeature newFeature; - newFeature.setGeometry( tmpGeometry ); - newFeature.setAttributes( f.attributes() ); - - //add it to vector file writer - if ( vfw ) - { - vfw->addFeature( newFeature ); - } -} - -bool QgsGeometryAnalyzer::centroids( QgsVectorLayer *layer, const QString &shapefileName, - bool onlySelectedFeatures, QProgressDialog *p ) -{ - if ( !layer ) - { - QgsDebugMsg( "No layer passed to centroids" ); - return false; - } - - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - QgsDebugMsg( "No data provider for layer passed to centroids" ); - return false; - } - - QgsWkbTypes::Type outputType = QgsWkbTypes::Point; - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); - QgsFeature currentFeature; - - //take only selection - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selection.size() ); - } - - int processedFeatures = 0; - QgsFeatureIds::const_iterator it = selection.constBegin(); - for ( ; it != selection.constEnd(); ++it ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) - { - continue; - } - centroidFeature( currentFeature, &vWriter ); - ++processedFeatures; - } - - if ( p ) - { - p->setValue( selection.size() ); - } - } - //take all features - else - { - QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ); - - int featureCount = layer->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - int processedFeatures = 0; - - while ( fit.nextFeature( currentFeature ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - break; - } - centroidFeature( currentFeature, &vWriter ); - ++processedFeatures; - } - if ( p ) - { - p->setValue( featureCount ); - } - } - - return true; -} - - -void QgsGeometryAnalyzer::centroidFeature( QgsFeature &f, QgsVectorFileWriter *vfw ) -{ - if ( !f.hasGeometry() ) - { - return; - } - - QgsGeometry featureGeometry = f.geometry(); - QgsFeature newFeature; - newFeature.setGeometry( featureGeometry.centroid() ); - newFeature.setAttributes( f.attributes() ); - - //add it to vector file writer - if ( vfw ) - { - vfw->addFeature( newFeature ); - } -} - -bool QgsGeometryAnalyzer::extent( QgsVectorLayer *layer, - const QString &shapefileName, - bool onlySelectedFeatures, - QProgressDialog * ) -{ - if ( !layer ) - { - return false; - } - - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - return false; - } - - QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsFields fields; - fields.append( QgsField( QStringLiteral( "MINX" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "MINY" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "MAXX" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "MAXY" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "CNTX" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "CNTY" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "HEIGHT" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "WIDTH" ), QVariant::Double ) ); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs ); - - QgsRectangle rect; - if ( onlySelectedFeatures ) // take only selection - { - rect = layer->boundingBoxOfSelected(); - } - else - { - rect = layer->extent(); - } - - double minx = rect.xMinimum(); - double miny = rect.yMinimum(); - double maxx = rect.xMaximum(); - double maxy = rect.yMaximum(); - double height = rect.height(); - double width = rect.width(); - double cntx = minx + ( width / 2.0 ); - double cnty = miny + ( height / 2.0 ); - double area = width * height; - double perim = ( 2 * width ) + ( 2 * height ); - - QgsFeature feat; - QgsAttributes attrs( 10 ); - attrs[0] = QVariant( minx ); - attrs[1] = QVariant( miny ); - attrs[2] = QVariant( maxx ); - attrs[3] = QVariant( maxy ); - attrs[4] = QVariant( cntx ); - attrs[5] = QVariant( cnty ); - attrs[6] = QVariant( area ); - attrs[7] = QVariant( perim ); - attrs[8] = QVariant( height ); - attrs[9] = QVariant( width ); - feat.setAttributes( attrs ); - feat.setGeometry( QgsGeometry::fromRect( rect ) ); - vWriter.addFeature( feat ); - return true; -} - -QList QgsGeometryAnalyzer::simpleMeasure( QgsGeometry &mpGeometry ) -{ - QList list; - double perim; - if ( mpGeometry.wkbType() == QgsWkbTypes::Point ) - { - QgsPointXY pt = mpGeometry.asPoint(); - list.append( pt.x() ); - list.append( pt.y() ); - } - else - { - QgsDistanceArea measure; - list.append( measure.measureArea( mpGeometry ) ); - if ( mpGeometry.type() == QgsWkbTypes::PolygonGeometry ) - { - perim = perimeterMeasure( mpGeometry, measure ); - list.append( perim ); - } - } - return list; -} - -double QgsGeometryAnalyzer::perimeterMeasure( const QgsGeometry &geometry, QgsDistanceArea &measure ) -{ - return measure.measurePerimeter( geometry ); -} - -bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer *layer, const QString &shapefileName, - bool onlySelectedFeatures, int uniqueIdField, QProgressDialog *p ) -{ - if ( !layer ) - { - return false; - } - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - return false; - } - bool useField = false; - if ( uniqueIdField == -1 ) - { - uniqueIdField = 0; - } - else - { - useField = true; - } - QgsFields fields; - fields.append( QgsField( QStringLiteral( "UID" ), QVariant::String ) ); - fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) ); - fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) ); - - QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs ); - QgsFeature currentFeature; - QgsGeometry dissolveGeometry; //dissolve geometry - QMultiMap map; - - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - QgsFeatureIds::const_iterator it = selection.constBegin(); - for ( ; it != selection.constEnd(); ++it ) - { -#if 0 - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - // break; // it may be better to do something else here? - return false; - } -#endif - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) - { - continue; - } - map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); - } - } - else - { - QgsFeatureIterator fit = layer->getFeatures(); - while ( fit.nextFeature( currentFeature ) ) - { -#if 0 - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - // break; // it may be better to do something else here? - return false; - } -#endif - map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); - } - } - - QMultiMap::const_iterator jt = map.constBegin(); - while ( jt != map.constEnd() ) - { - QString currentKey = jt.key(); - int processedFeatures = 0; - //take only selection - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selection.size() ); - } - processedFeatures = 0; - while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) - { - if ( p && p->wasCanceled() ) - { - break; - } - if ( selection.contains( jt.value() ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) - { - continue; - } - convexFeature( currentFeature, processedFeatures, dissolveGeometry ); - ++processedFeatures; - } - ++jt; - } - QList values; - if ( dissolveGeometry.isNull() ) - { - QgsDebugMsg( "no dissolved geometry - should not happen" ); - return false; - } - dissolveGeometry = dissolveGeometry.convexHull(); - values = simpleMeasure( dissolveGeometry ); - QgsAttributes attributes( 3 ); - attributes[0] = QVariant( currentKey ); - attributes[1] = values.at( 0 ); - attributes[2] = values.at( 1 ); - QgsFeature dissolveFeature; - dissolveFeature.setAttributes( attributes ); - dissolveFeature.setGeometry( dissolveGeometry ); - vWriter.addFeature( dissolveFeature ); - } - //take all features - else - { - int featureCount = layer->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - processedFeatures = 0; - while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) - { - continue; - } - convexFeature( currentFeature, processedFeatures, dissolveGeometry ); - ++processedFeatures; - ++jt; - } - QList values; - if ( dissolveGeometry.isNull() ) - { - QgsDebugMsg( "no dissolved geometry - should not happen" ); - return false; - } - dissolveGeometry = dissolveGeometry.convexHull(); - // values = simpleMeasure( tmpGeometry ); - values = simpleMeasure( dissolveGeometry ); - QgsAttributes attributes; - attributes[0] = QVariant( currentKey ); - attributes[1] = QVariant( values[ 0 ] ); - attributes[2] = QVariant( values[ 1 ] ); - QgsFeature dissolveFeature; - dissolveFeature.setAttributes( attributes ); - dissolveFeature.setGeometry( dissolveGeometry ); - vWriter.addFeature( dissolveFeature ); - } - } - return true; -} - - -void QgsGeometryAnalyzer::convexFeature( QgsFeature &f, int nProcessedFeatures, QgsGeometry &dissolveGeometry ) -{ - if ( !f.hasGeometry() ) - { - return; - } - - QgsGeometry featureGeometry = f.geometry(); - QgsGeometry convexGeometry = featureGeometry.convexHull(); - - if ( nProcessedFeatures == 0 ) - { - dissolveGeometry = convexGeometry; - } - else - { - dissolveGeometry = dissolveGeometry.combine( convexGeometry ); - } -} - -bool QgsGeometryAnalyzer::dissolve( QgsVectorLayer *layer, const QString &shapefileName, - bool onlySelectedFeatures, int uniqueIdField, QProgressDialog *p ) -{ - if ( !layer ) - { - return false; - } - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - return false; - } - bool useField = false; - if ( uniqueIdField == -1 ) - { - uniqueIdField = 0; - } - else - { - useField = true; - } - - QgsWkbTypes::Type outputType = dp->wkbType(); - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); - QgsFeature currentFeature; - QMultiMap map; - - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - QgsFeatureIds::const_iterator it = selection.constBegin(); - for ( ; it != selection.constEnd(); ++it ) - { - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) - { - continue; - } - map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); - } - } - else - { - QgsFeatureIterator fit = layer->getFeatures(); - while ( fit.nextFeature( currentFeature ) ) - { - map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); - } - } - - QgsGeometry dissolveGeometry; //dissolve geometry - QMultiMap::const_iterator jt = map.constBegin(); - QgsFeature outputFeature; - while ( jt != map.constEnd() ) - { - QString currentKey = jt.key(); - int processedFeatures = 0; - bool first = true; - //take only selection - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selection.size() ); - } - while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) - { - if ( p && p->wasCanceled() ) - { - break; - } - if ( selection.contains( jt.value() ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) - { - continue; - } - if ( first ) - { - outputFeature.setAttributes( currentFeature.attributes() ); - first = false; - } - dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry ); - ++processedFeatures; - } - ++jt; - } - } - //take all features - else - { - int featureCount = layer->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) - { - continue; - } - { - outputFeature.setAttributes( currentFeature.attributes() ); - first = false; - } - dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry ); - ++processedFeatures; - ++jt; - } - } - outputFeature.setGeometry( dissolveGeometry ); - vWriter.addFeature( outputFeature ); - } - return true; -} - -QgsGeometry QgsGeometryAnalyzer::dissolveFeature( const QgsFeature &f, const QgsGeometry &dissolveInto ) -{ - if ( !f.hasGeometry() ) - { - return dissolveInto; - } - - QgsGeometry featureGeometry = f.geometry(); - - if ( dissolveInto.isNull() ) - { - return featureGeometry; - } - else - { - return dissolveInto.combine( featureGeometry ); - } -} - -bool QgsGeometryAnalyzer::buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, - bool onlySelectedFeatures, bool dissolve, int bufferDistanceField, QProgressDialog *p ) -{ - if ( !layer ) - { - return false; - } - - QgsVectorDataProvider *dp = layer->dataProvider(); - if ( !dp ) - { - return false; - } - - QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; - if ( dissolve ) - { - outputType = QgsWkbTypes::MultiPolygon; - } - QgsCoordinateReferenceSystem crs = layer->crs(); - - QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); - QgsFeature currentFeature; - QgsGeometry dissolveGeometry; //dissolve geometry (if dissolve enabled) - - //take only selection - if ( onlySelectedFeatures ) - { - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selection = layer->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selection.size() ); - } - - int processedFeatures = 0; - QgsFeatureIds::const_iterator it = selection.constBegin(); - for ( ; it != selection.constEnd(); ++it ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) - { - continue; - } - bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField ); - ++processedFeatures; - } - - if ( p ) - { - p->setValue( selection.size() ); - } - } - //take all features - else - { - QgsFeatureIterator fit = layer->getFeatures(); - - int featureCount = layer->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - int processedFeatures = 0; - - while ( fit.nextFeature( currentFeature ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - break; - } - bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField ); - ++processedFeatures; - } - if ( p ) - { - p->setValue( featureCount ); - } - } - - if ( dissolve ) - { - QgsFeature dissolveFeature; - if ( dissolveGeometry.isNull() ) - { - QgsDebugMsg( "no dissolved geometry - should not happen" ); - return false; - } - dissolveFeature.setGeometry( dissolveGeometry ); - vWriter.addFeature( dissolveFeature ); - } - return true; -} - -void QgsGeometryAnalyzer::bufferFeature( QgsFeature &f, int nProcessedFeatures, QgsVectorFileWriter *vfw, bool dissolve, - QgsGeometry &dissolveGeometry, double bufferDistance, int bufferDistanceField ) -{ - if ( !f.hasGeometry() ) - { - return; - } - - double currentBufferDistance; - QgsGeometry featureGeometry = f.geometry(); - QgsGeometry bufferGeometry; - - //create buffer - if ( bufferDistanceField == -1 ) - { - currentBufferDistance = bufferDistance; - } - else - { - currentBufferDistance = f.attribute( bufferDistanceField ).toDouble(); - } - bufferGeometry = featureGeometry.buffer( currentBufferDistance, 5 ); - - if ( dissolve ) - { - if ( nProcessedFeatures == 0 ) - { - dissolveGeometry = bufferGeometry; - } - else - { - dissolveGeometry = dissolveGeometry.combine( bufferGeometry ); - } - } - else //dissolve - { - QgsFeature newFeature; - newFeature.setGeometry( bufferGeometry ); - newFeature.setAttributes( f.attributes() ); - - //add it to vector file writer - if ( vfw ) - { - vfw->addFeature( newFeature ); - } - } -} - -bool QgsGeometryAnalyzer::eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString &outputLayer, - const QString &outputFormat, int locationField1, int locationField2, int offsetField, double offsetScale, - bool forceSingleGeometry, QgsVectorDataProvider *memoryProvider, QProgressDialog *p ) -{ - if ( !lineLayer || !eventLayer || !lineLayer->isValid() || !eventLayer->isValid() ) - { - return false; - } - - //create line field / id map for line layer - QMultiHash< QString, QgsFeature > lineLayerIdMap; //1:n possible (e.g. several linear reference geometries for one feature in the event layer) - QgsFeatureIterator fit = lineLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() << lineField ) ); - QgsFeature fet; - while ( fit.nextFeature( fet ) ) - { - lineLayerIdMap.insert( fet.attribute( lineField ).toString(), fet ); - } - - //create output datasource or attributes in memory provider - QgsVectorFileWriter *fileWriter = nullptr; - QgsFeatureList memoryProviderFeatures; - if ( !memoryProvider ) - { - QgsWkbTypes::Type memoryProviderType = QgsWkbTypes::MultiLineString; - if ( locationField2 == -1 ) - { - memoryProviderType = forceSingleGeometry ? QgsWkbTypes::Point : QgsWkbTypes::MultiPoint; - } - else - { - memoryProviderType = forceSingleGeometry ? QgsWkbTypes::LineString : QgsWkbTypes::MultiLineString; - } - fileWriter = new QgsVectorFileWriter( outputLayer, - eventLayer->dataProvider()->encoding(), - eventLayer->fields(), - memoryProviderType, - lineLayer->crs(), - outputFormat ); - } - else - { - memoryProvider->addAttributes( eventLayer->fields().toList() ); - } - - //iterate over eventLayer and write new features to output file or layer - fit = eventLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ); - QgsGeometry lrsGeom; - double measure1, measure2 = 0.0; - - int nEventFeatures = eventLayer->featureCount(); - int featureCounter = 0; - int nOutputFeatures = 0; //number of output features for the current event feature - if ( p ) - { - p->setWindowModality( Qt::WindowModal ); - p->setMinimum( 0 ); - p->setMaximum( nEventFeatures ); - p->show(); - } - - while ( fit.nextFeature( fet ) ) - { - nOutputFeatures = 0; - - //update progress dialog - if ( p ) - { - if ( p->wasCanceled() ) - { - break; - } - p->setValue( featureCounter ); - ++featureCounter; - } - - measure1 = fet.attribute( locationField1 ).toDouble(); - if ( locationField2 != -1 ) - { - measure2 = fet.attribute( locationField2 ).toDouble(); - if ( qgsDoubleNear( ( measure2 - measure1 ), 0.0 ) ) - { - continue; - } - } - - QList featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() ); - QList::iterator featureIdIt = featureIdList.begin(); - for ( ; featureIdIt != featureIdList.end(); ++featureIdIt ) - { - if ( locationField2 == -1 ) - { - lrsGeom = locateAlongMeasure( measure1, featureIdIt->geometry() ); - } - else - { - lrsGeom = locateBetweenMeasures( measure1, measure2, featureIdIt->geometry() ); - } - - if ( !lrsGeom.isNull() ) - { - ++nOutputFeatures; - addEventLayerFeature( fet, lrsGeom, featureIdIt->geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry ); - } - } - if ( nOutputFeatures < 1 ) - { - unlocatedFeatureIds.insert( fet.id() ); - } - } - - if ( p ) - { - p->setValue( nEventFeatures ); - } - - if ( memoryProvider ) - { - memoryProvider->addFeatures( memoryProviderFeatures ); - } - delete fileWriter; - return true; -} - -void QgsGeometryAnalyzer::addEventLayerFeature( QgsFeature &feature, const QgsGeometry &geom, const QgsGeometry &lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures, - int offsetField, double offsetScale, bool forceSingleType ) -{ - if ( geom.isNull() ) - { - return; - } - - QList geomList; - if ( forceSingleType ) - { - geomList = geom.asGeometryCollection(); - } - else - { - geomList.push_back( geom ); - } - - QList::iterator geomIt = geomList.begin(); - for ( ; geomIt != geomList.end(); ++geomIt ) - { - //consider offset - QgsGeometry newGeom = *geomIt; - if ( offsetField >= 0 ) - { - double offsetVal = feature.attribute( offsetField ).toDouble(); - offsetVal *= offsetScale; - newGeom = createOffsetGeometry( *geomIt, lineGeom, offsetVal ); - if ( newGeom.isNull() ) - { - continue; - } - } - - feature.setGeometry( newGeom ); - if ( fileWriter ) - { - fileWriter->addFeature( feature ); - } - else - { - memoryFeatures << feature; - } - } -} - -QgsGeometry QgsGeometryAnalyzer::createOffsetGeometry( const QgsGeometry &geom, const QgsGeometry &lineGeom, double offset ) -{ - if ( !geom || lineGeom.isNull() ) - { - return QgsGeometry(); - } - - QList inputGeomList; - - if ( geom.isMultipart() ) - { - inputGeomList = geom.asGeometryCollection(); - } - else - { - inputGeomList.push_back( geom ); - } - - QList outputGeomList; - QList::const_iterator inputGeomIt = inputGeomList.constBegin(); - GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler(); - for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt ) - { - if ( geom.type() == QgsWkbTypes::LineGeometry ) - { - GEOSGeometry *inputGeomItGeos = inputGeomIt->exportToGeos(); - GEOSGeometry *offsetGeom = GEOSOffsetCurve_r( geosctxt, inputGeomItGeos, -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*miterLimit*/ ); - GEOSGeom_destroy_r( geosctxt, inputGeomItGeos ); - if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) ) - { - return QgsGeometry(); - } - if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 ) - { - GEOSGeom_destroy_r( geosctxt, offsetGeom ); - return QgsGeometry(); - } - outputGeomList.push_back( offsetGeom ); - } - else if ( geom.type() == QgsWkbTypes::PointGeometry ) - { - QgsPointXY p = ( *inputGeomIt ).asPoint(); - p = createPointOffset( p.x(), p.y(), offset, lineGeom ); - GEOSCoordSequence *ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 ); - GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() ); - GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() ); - GEOSGeometry *geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq ); - outputGeomList.push_back( geosPt ); - } - } - - QgsGeometry outGeometry; - if ( !geom.isMultipart() ) - { - GEOSGeometry *outputGeom = outputGeomList.at( 0 ); - if ( outputGeom ) - { - outGeometry.fromGeos( outputGeom ); - } - } - else - { - GEOSGeometry **geomArray = new GEOSGeometry*[outputGeomList.size()]; - for ( int i = 0; i < outputGeomList.size(); ++i ) - { - geomArray[i] = outputGeomList.at( i ); - } - GEOSGeometry *collection = nullptr; - if ( geom.type() == QgsWkbTypes::PointGeometry ) - { - collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() ); - } - else if ( geom.type() == QgsWkbTypes::LineGeometry ) - { - collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() ); - } - outGeometry.fromGeos( collection ); - delete[] geomArray; - } - return outGeometry; -} - -QgsPointXY QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, const QgsGeometry &lineGeom ) const -{ - QgsPointXY p( x, y ); - QgsPointXY minDistPoint; - int afterVertexNr; - lineGeom.closestSegmentWithContext( p, minDistPoint, afterVertexNr ); - - int beforeVertexNr = afterVertexNr - 1; - QgsPointXY beforeVertex = lineGeom.vertexAt( beforeVertexNr ); - QgsPointXY afterVertex = lineGeom.vertexAt( afterVertexNr ); - - //get normal vector - double dx = afterVertex.x() - beforeVertex.x(); - double dy = afterVertex.y() - beforeVertex.y(); - double normalX = -dy; - double normalY = dx; //#spellok - double normalLength = sqrt( normalX * normalX + normalY * normalY ); //#spellok - normalX *= ( dist / normalLength ); - normalY *= ( dist / normalLength ); //#spellok - - double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control //#spellok - Q_UNUSED( debugLength ); - return QgsPointXY( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side //#spellok -} - -QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom ) -{ - if ( lineGeom.isNull() ) - { - return QgsGeometry(); - } - - QgsMultiPolyline resultGeom; - - //need to go with WKB and z coordinate until QgsGeometry supports M values - QByteArray wkb( lineGeom.exportToWkb() ); - QgsConstWkbPtr wkbPtr( wkb ); - wkbPtr.readHeader(); - - QgsWkbTypes::Type wkbType = lineGeom.wkbType(); - if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D ) - { - return QgsGeometry(); - } - - if ( wkbType == QgsWkbTypes::LineString25D ) - { - locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); - } - else if ( wkbType == QgsWkbTypes::MultiLineString25D ) - { - int nLines; - wkbPtr >> nLines; - for ( int i = 0; i < nLines; ++i ) - { - wkbPtr.readHeader(); - wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); - } - } - - if ( resultGeom.size() < 1 ) - { - return QgsGeometry(); - } - return QgsGeometry::fromMultiPolyline( resultGeom ); -} - -QgsGeometry QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsGeometry &lineGeom ) -{ - if ( lineGeom.isNull() ) - { - return QgsGeometry(); - } - - QgsMultiPoint resultGeom; - - //need to go with WKB and z coordinate until QgsGeometry supports M values - QByteArray wkb( lineGeom.exportToWkb() ); - QgsConstWkbPtr wkbPtr( wkb ); - QgsWkbTypes::Type wkbType = lineGeom.wkbType(); - - if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D ) - { - return QgsGeometry(); - } - - if ( wkbType == QgsWkbTypes::LineString25D ) - { - locateAlongWkbString( wkbPtr, resultGeom, measure ); - } - else if ( wkbType == QgsWkbTypes::MultiLineString25D ) - { - int nLines; - wkbPtr >> nLines; - for ( int i = 0; i < nLines; ++i ) - { - wkbPtr.readHeader(); - wkbPtr = locateAlongWkbString( wkbPtr, resultGeom, measure ); - } - } - - if ( resultGeom.size() < 1 ) - { - return QgsGeometry(); - } - - return QgsGeometry::fromMultiPoint( resultGeom ); -} - -QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPolyline &result, double fromMeasure, double toMeasure ) -{ - int nPoints; - wkbPtr >> nPoints; - - QgsPolyline currentLine; - double prevx = 0.0, prevy = 0.0, prevz = 0.0; - for ( int i = 0; i < nPoints; ++i ) - { - double x, y, z; - wkbPtr >> x >> y >> z; - - if ( i > 0 ) - { - QgsPointXY pt1, pt2; - bool secondPointClipped; //true if second point is != segment endpoint - bool measureInSegment = clipSegmentByRange( prevx, prevy, prevz, x, y, z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped ); - if ( measureInSegment ) - { - if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line - { - currentLine.append( pt1 ); - } - - if ( pt1 != pt2 ) //avoid duplicated entry if measure value equals m-value of vertex - { - currentLine.append( pt2 ); - } - - if ( secondPointClipped || i == nPoints - 1 ) //close current segment - { - if ( currentLine.size() > 1 ) - { - result.append( currentLine ); - } - currentLine.clear(); - } - } - } - prevx = x; - prevy = y; - prevz = z; - } - - return wkbPtr; -} - -QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPoint &result, double measure ) -{ - int nPoints; - wkbPtr >> nPoints; - - double x, y, z; - double prevx = 0.0, prevy = 0.0, prevz = 0.0; - for ( int i = 0; i < nPoints; ++i ) - { - wkbPtr >> x >> y >> z; - - if ( i > 0 ) - { - QgsPointXY pt1, pt2; - bool pt1Ok, pt2Ok; - locateAlongSegment( prevx, prevy, prevz, x, y, z, measure, pt1Ok, pt1, pt2Ok, pt2 ); - if ( pt1Ok ) - { - result.append( pt1 ); - } - if ( pt2Ok && i == nPoints - 1 ) - { - result.append( pt2 ); - } - } - prevx = x; - prevy = y; - prevz = z; - } - - return wkbPtr; -} - -bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPointXY &pt1, - QgsPointXY &pt2, bool &secondPointClipped ) -{ - bool reversed = m1 > m2; - double tmp; - - //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2) - if ( reversed ) - { - tmp = m1; - m1 = m2; - m2 = tmp; - - tmp = x1; - x1 = x2; - x2 = tmp; - - tmp = y1; - y1 = y2; - y2 = tmp; - } - - //reverse range1, range2 if necessary - if ( range1 > range2 ) - { - tmp = range1; - range1 = range2; - range2 = tmp; - } - - //segment completely outside of range - if ( m2 < range1 || m1 > range2 ) - { - return false; - } - - //segment completely inside of range - if ( m2 <= range2 && m1 >= range1 ) - { - if ( reversed ) - { - pt1.setX( x2 ); - pt1.setY( y2 ); - pt2.setX( x1 ); - pt2.setY( y1 ); - } - else - { - pt1.setX( x1 ); - pt1.setY( y1 ); - pt2.setX( x2 ); - pt2.setY( y2 ); - } - secondPointClipped = false; - return true; - } - - //m1 inside and m2 not - if ( m1 >= range1 && m1 <= range2 ) - { - pt1.setX( x1 ); - pt1.setY( y1 ); - double dist = ( range2 - m1 ) / ( m2 - m1 ); - pt2.setX( x1 + ( x2 - x1 ) * dist ); - pt2.setY( y1 + ( y2 - y1 ) * dist ); - secondPointClipped = !reversed; - } - - //m2 inside and m1 not - if ( m2 >= range1 && m2 <= range2 ) - { - pt2.setX( x2 ); - pt2.setY( y2 ); - double dist = ( m2 - range1 ) / ( m2 - m1 ); - pt1.setX( x2 - ( x2 - x1 ) * dist ); - pt1.setY( y2 - ( y2 - y1 ) * dist ); - secondPointClipped = reversed; - } - - //range1 and range 2 both inside the segment - if ( range1 >= m1 && range2 <= m2 ) - { - double dist1 = ( range1 - m1 ) / ( m2 - m1 ); - double dist2 = ( range2 - m1 ) / ( m2 - m1 ); - pt1.setX( x1 + ( x2 - x1 ) * dist1 ); - pt1.setY( y1 + ( y2 - y1 ) * dist1 ); - pt2.setX( x1 + ( x2 - x1 ) * dist2 ); - pt2.setY( y1 + ( y2 - y1 ) * dist2 ); - secondPointClipped = true; - } - - if ( reversed ) //switch p1 and p2 - { - QgsPointXY tmpPt = pt1; - pt1 = pt2; - pt2 = tmpPt; - } - - return true; -} - -void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool &pt1Ok, QgsPointXY &pt1, bool &pt2Ok, QgsPointXY &pt2 ) -{ - bool reversed = false; - pt1Ok = false; - pt2Ok = false; - double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints - - if ( m1 > m2 ) - { - double tmp = m1; - m1 = m2; - m2 = tmp; - reversed = true; - } - - //segment does not match - if ( ( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance ) - { - pt1Ok = false; - pt2Ok = false; - return; - } - - //match with vertex1 - if ( qgsDoubleNear( m1, measure, tolerance ) ) - { - if ( reversed ) - { - pt2Ok = true; - pt2.setX( x2 ); - pt2.setY( y2 ); - } - else - { - pt1Ok = true; - pt1.setX( x1 ); - pt1.setY( y1 ); - } - } - - //match with vertex2 - if ( qgsDoubleNear( m2, measure, tolerance ) ) - { - if ( reversed ) - { - pt1Ok = true; - pt1.setX( x1 ); - pt1.setY( y1 ); - } - else - { - pt2Ok = true; - pt2.setX( x2 ); - pt2.setY( y2 ); - } - } - - - if ( pt1Ok || pt2Ok ) - { - return; - } - - //match between the vertices - if ( qgsDoubleNear( m1, m2 ) ) - { - pt1.setX( x1 ); - pt1.setY( y1 ); - pt1Ok = true; - return; - } - double dist = ( measure - m1 ) / ( m2 - m1 ); - if ( reversed ) - { - dist = 1 - dist; - } - - pt1.setX( x1 + dist * ( x2 - x1 ) ); - pt1.setY( y1 + dist * ( y2 - y1 ) ); - pt1Ok = true; -} diff --git a/src/analysis/vector/qgsgeometryanalyzer.h b/src/analysis/vector/qgsgeometryanalyzer.h deleted file mode 100644 index c7111f53aa8..00000000000 --- a/src/analysis/vector/qgsgeometryanalyzer.h +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************** - qgsgeometryanalyzer.h - QGIS Tools for vector geometry analysis - ------------------- - begin : 19 March 2009 - copyright : (C) Carson Farmer - email : carson.farmer@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSGEOMETRYANALYZERH -#define QGSGEOMETRYANALYZERH - -#include "qgsfeature.h" -#include "qgsgeometry.h" -#include "qgis_analysis.h" - -class QgsVectorFileWriter; -class QProgressDialog; -class QgsVectorDataProvider; -class QgsDistanceArea; - -/** \ingroup analysis - * The QGis class provides vector geometry analysis functions - */ - -class ANALYSIS_EXPORT QgsGeometryAnalyzer -{ - public: - - /** Simplify vector layer using (a modified) Douglas-Peucker algorithm - * and write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param tolerance (level of simplification) - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool simplify( QgsVectorLayer *layer, const QString &shapefileName, double tolerance, - bool onlySelectedFeatures = false, QProgressDialog *p = nullptr ); - - /** Calculate the true centroids, or 'center of mass' for a vector layer and - * write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool centroids( QgsVectorLayer *layer, const QString &shapefileName, - bool onlySelectedFeatures = false, QProgressDialog *p = nullptr ); - - /** Create a polygon based on the extent of all (selected) features and write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool extent( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, QProgressDialog *p = 0 ); - - /** Create buffers for a vector layer and write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param bufferDistance distance for buffering (if no buffer field is specified) - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param dissolve if true, merge all the buffers to a big multipolygon - * \param bufferDistanceField index of the attribute field that contains the buffer distance (or -1 if all features have the same buffer distance) - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, - bool onlySelectedFeatures = false, bool dissolve = false, int bufferDistanceField = -1, QProgressDialog *p = nullptr ); - - /** Create convex hull(s) of a vector layer and write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param uniqueIdField index of the attribute field that contains the unique convex hull id (or -1 if - * all features have the same buffer distance) - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool convexHull( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, - int uniqueIdField = -1, QProgressDialog *p = nullptr ); - - /** Dissolve a vector layer and write it to a new shape file - * \param layer input vector layer - * \param shapefileName path to the output shp - * \param onlySelectedFeatures if true, only selected features are considered, else all the features - * \param uniqueIdField index of the attribute field that contains the unique id to dissolve on (or -1 if - * all features should be dissolved together) - * \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool dissolve( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, - int uniqueIdField = -1, QProgressDialog *p = nullptr ); - - /** Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event table along the features of a line layer. - * Note that currently (until QgsGeometry supports m-values) the z-coordinate of the line layer is used for linear referencing - * \param lineLayer layer with the line geometry - * \param eventLayer layer with features and location field - * \param lineField join index in line layer - * \param eventField join index in event layer - * \param outputLayer name of output file (can be empty if a memory layer is used) - * \param outputFormat name of output format (can be empty if a memory provider is used to store the results) - * \param unlocatedFeatureIds out: ids of event features where linear referencing was not successful - * \param locationField1 attribute index of location field in event layer - * \param locationField2 attribute index of location end field (or -1 for point layer) - * \param offsetField attribute index for offset field. Negative offset value = offset to left side, positive value = offset to right side - * \param offsetScale factor to scale offset - * \param forceSingleGeometry force layer to single point/line type. Feature attributes are copied in case of multiple matches - * \param memoryProvider memory provider to write output to (can be 0 if output is written to a file) - * \param p progress dialog or 0 if no progress dialog should be shown - */ - bool eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds SIP_OUT, const QString &outputLayer, - const QString &outputFormat, int locationField1, int locationField2 = -1, int offsetField = -1, double offsetScale = 1.0, - bool forceSingleGeometry = false, QgsVectorDataProvider *memoryProvider = nullptr, QProgressDialog *p = nullptr ); - - //! Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS) - QgsGeometry locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom ); - - /** Returns linear reference geometry. Unlike the PostGIS function, this method always returns multipoint or 0 if no match (not geometry collection). - * Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS) - */ - QgsGeometry locateAlongMeasure( double measure, const QgsGeometry &lineGeom ); - - private: - - QList simpleMeasure( QgsGeometry &geometry ); - double perimeterMeasure( const QgsGeometry &geometry, QgsDistanceArea &measure ); - //! Helper function to simplify an individual feature - void simplifyFeature( QgsFeature &f, QgsVectorFileWriter *vfw, double tolerance ); - //! Helper function to get the cetroid of an individual feature - void centroidFeature( QgsFeature &f, QgsVectorFileWriter *vfw ); - //! Helper function to buffer an individual feature - void bufferFeature( QgsFeature &f, int nProcessedFeatures, QgsVectorFileWriter *vfw, bool dissolve, QgsGeometry &dissolveGeometry, - double bufferDistance, int bufferDistanceField ); - //! Helper function to get the convex hull of feature(s) - void convexFeature( QgsFeature &f, int nProcessedFeatures, QgsGeometry &dissolveGeometry ); - //! Helper function to dissolve feature(s) - QgsGeometry dissolveFeature( const QgsFeature &f, const QgsGeometry &dissolveInto ); - - //helper functions for event layer - void addEventLayerFeature( QgsFeature &feature, const QgsGeometry &geom, const QgsGeometry &lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures, int offsetField = -1, double offsetScale = 1.0, - bool forceSingleType = false ); - - /** Create geometry offset relative to line geometry. - \param geom the geometry to modify - \param lineGeom the line geometry to which the feature is referenced - \param offset the offset value in layer unit. Negative values mean offset towards left, positive values offset to the right side*/ - QgsGeometry createOffsetGeometry( const QgsGeometry &geom, const QgsGeometry &lineGeom, double offset ); - QgsPointXY createPointOffset( double x, double y, double dist, const QgsGeometry &lineGeom ) const; - QgsConstWkbPtr locateBetweenWkbString( QgsConstWkbPtr ptr, QgsMultiPolyline &result, double fromMeasure, double toMeasure ); - QgsConstWkbPtr locateAlongWkbString( QgsConstWkbPtr ptr, QgsMultiPoint &result, double measure ); - static bool clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPointXY &pt1, QgsPointXY &pt2, bool &secondPointClipped ); - static void locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool &pt1Ok, QgsPointXY &pt1, bool &pt2Ok, QgsPointXY &pt2 ); -}; -#endif //QGSVECTORANALYZER diff --git a/src/analysis/vector/qgsoverlayanalyzer.cpp b/src/analysis/vector/qgsoverlayanalyzer.cpp deleted file mode 100644 index 39049e7176c..00000000000 --- a/src/analysis/vector/qgsoverlayanalyzer.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/*************************************************************************** - qgsoverlayanalyzer.cpp - QGIS Tools for vector geometry analysis - ------------------- - begin : 8 Nov 2009 - copyright : (C) Carson J. Q. Farmer - email : carson.farmer@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#include "qgsoverlayanalyzer.h" - -#include "qgsapplication.h" -#include "qgsfeatureiterator.h" -#include "qgsfields.h" -#include "qgsfeature.h" -#include "qgsgeometry.h" -#include "qgslogger.h" -#include "qgscoordinatereferencesystem.h" -#include "qgsspatialindex.h" -#include "qgsvectorfilewriter.h" -#include "qgsvectordataprovider.h" -#include "qgsdistancearea.h" -#include - -bool QgsOverlayAnalyzer::intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB, - const QString &shapefileName, bool onlySelectedFeatures, - QProgressDialog *p ) -{ - if ( !layerA || !layerB ) - { - return false; - } - - QgsVectorDataProvider *dpA = layerA->dataProvider(); - QgsVectorDataProvider *dpB = layerB->dataProvider(); - if ( !dpA || !dpB ) - { - return false; - } - - QgsWkbTypes::Type outputType = dpA->wkbType(); - QgsCoordinateReferenceSystem crs = layerA->crs(); - QgsFields fieldsA = layerA->fields(); - QgsFields fieldsB = layerB->fields(); - combineFieldLists( fieldsA, fieldsB ); - - QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, crs ); - QgsFeature currentFeature; - - //take only selection - if ( onlySelectedFeatures ) - { - QgsFeatureIds selectionB = layerB->selectedFeatureIds(); - QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( selectionB ).setSubsetOfAttributes( QgsAttributeList() ); - QgsSpatialIndex index = QgsSpatialIndex( layerB->getFeatures( req ) ); - - //use QgsVectorLayer::featureAtId - const QgsFeatureIds selectionA = layerA->selectedFeatureIds(); - if ( p ) - { - p->setMaximum( selectionA.size() ); - } - req = QgsFeatureRequest().setFilterFids( selectionA ); - QgsFeatureIterator selectionAIt = layerA->getFeatures( req ); - QgsFeature currentFeature; - int processedFeatures = 0; - while ( selectionAIt.nextFeature( currentFeature ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - - if ( p && p->wasCanceled() ) - { - break; - } - - intersectFeature( currentFeature, &vWriter, layerB, &index ); - ++processedFeatures; - } - - if ( p ) - { - p->setValue( selectionA.size() ); - } - } - //take all features - else - { - QgsFeatureRequest req = QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ); - QgsSpatialIndex index = QgsSpatialIndex( layerB->getFeatures( req ) ); - - int featureCount = layerA->featureCount(); - if ( p ) - { - p->setMaximum( featureCount ); - } - int processedFeatures = 0; - - QgsFeatureIterator fit = layerA->getFeatures(); - - QgsFeature currentFeature; - while ( fit.nextFeature( currentFeature ) ) - { - if ( p ) - { - p->setValue( processedFeatures ); - } - if ( p && p->wasCanceled() ) - { - break; - } - intersectFeature( currentFeature, &vWriter, layerB, &index ); - ++processedFeatures; - } - if ( p ) - { - p->setValue( featureCount ); - } - } - return true; -} - -void QgsOverlayAnalyzer::intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw, - QgsVectorLayer *vl, QgsSpatialIndex *index ) -{ - if ( !f.hasGeometry() ) - { - return; - } - - QgsGeometry featureGeometry = f.geometry(); - QgsGeometry intersectGeometry; - QgsFeature overlayFeature; - - QList intersects = index->intersects( featureGeometry.boundingBox() ); - QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( intersects.toSet() ); - QgsFeatureIterator intersectIt = vl->getFeatures( req ); - QgsFeature outFeature; - while ( intersectIt.nextFeature( overlayFeature ) ) - { - if ( featureGeometry.intersects( overlayFeature.geometry() ) ) - { - intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() ); - - outFeature.setGeometry( intersectGeometry ); - QgsAttributes attributesA = f.attributes(); - QgsAttributes attributesB = overlayFeature.attributes(); - combineAttributeMaps( attributesA, attributesB ); - outFeature.setAttributes( attributesA ); - - //add it to vector file writer - if ( vfw ) - { - vfw->addFeature( outFeature ); - } - } - } -} - -void QgsOverlayAnalyzer::combineFieldLists( QgsFields &fieldListA, const QgsFields &fieldListB ) -{ - QList names; - Q_FOREACH ( const QgsField &field, fieldListA ) - names.append( field.name() ); - - for ( int idx = 0; idx < fieldListB.count(); ++idx ) - { - QgsField field = fieldListB.at( idx ); - int count = 0; - while ( names.contains( field.name() ) ) - { - QString name = QStringLiteral( "%1_%2" ).arg( field.name() ).arg( count ); - field = QgsField( name, field.type() ); - ++count; - } - fieldListA.append( field ); - names.append( field.name() ); - } -} - -void QgsOverlayAnalyzer::combineAttributeMaps( QgsAttributes &attributesA, const QgsAttributes &attributesB ) -{ - attributesA += attributesB; -} - diff --git a/src/analysis/vector/qgsoverlayanalyzer.h b/src/analysis/vector/qgsoverlayanalyzer.h deleted file mode 100644 index 0fd9ada8a49..00000000000 --- a/src/analysis/vector/qgsoverlayanalyzer.h +++ /dev/null @@ -1,54 +0,0 @@ -/*************************************************************************** - qgsoverlayanalyzer.h - QGIS Tools for vector geometry analysis - ------------------- - begin : 19 March 2009 - copyright : (C) Carson Farmer - email : carson.farmer@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef QGSOVERLAYANALYZERH -#define QGSOVERLAYANALYZERH - -#include "qgsvectorlayer.h" -#include "qgis_analysis.h" - -class QgsVectorFileWriter; -class QProgressDialog; -class QgsSpatialIndex; - -/** \ingroup analysis - * The QGis class provides vector overlay analysis functions - */ - -class ANALYSIS_EXPORT QgsOverlayAnalyzer -{ - public: - - /** Perform an intersection on two input vector layers and write output to a new shape file - \param layerA input vector layer - \param layerB input vector layer - \param shapefileName path to the output shp - \param onlySelectedFeatures if true, only selected features are considered, else all the features - \param p progress dialog (or 0 if no progress dialog is to be shown) - */ - bool intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB, - const QString &shapefileName, bool onlySelectedFeatures = false, - QProgressDialog *p = nullptr ); - - private: - - void combineFieldLists( QgsFields &fieldListA, const QgsFields &fieldListB ); - void intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw, QgsVectorLayer *dp, QgsSpatialIndex *index ); - void combineAttributeMaps( QgsAttributes &attributesA, const QgsAttributes &attributesB ); -}; - -#endif //QGSVECTORANALYZER diff --git a/src/analysis/vector/qgspointsample.cpp b/src/analysis/vector/qgspointsample.cpp deleted file mode 100644 index 528ecbca227..00000000000 --- a/src/analysis/vector/qgspointsample.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************** - qgspointsample.cpp - --------------------- - begin : July 2013 - copyright : (C) 2013 by Marco Hugentobler - email : marco dot hugentobler at sourcepole dot ch - *************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#include "qgspointsample.h" -#include "qgsfeatureiterator.h" -#include "qgsgeometry.h" -#include "qgsspatialindex.h" -#include "qgsvectorfilewriter.h" -#include "qgsvectorlayer.h" -#include -#include "mersenne-twister.h" - - -QgsPointSample::QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute ): mInputLayer( inputLayer ), - mOutputLayer( outputLayer ), mNumberOfPointsAttribute( nPointsAttribute ), mMinDistanceAttribute( minDistAttribute ), mNCreatedPoints( 0 ) -{ -} - -QgsPointSample::QgsPointSample() - : mInputLayer( nullptr ) - , mNCreatedPoints( 0 ) -{ -} - -int QgsPointSample::createRandomPoints( QProgressDialog *pd ) -{ - Q_UNUSED( pd ); - - //create input layer from id (test if polygon, valid) - if ( !mInputLayer ) - { - return 1; - } - - if ( mInputLayer->geometryType() != QgsWkbTypes::PolygonGeometry ) - { - return 2; - } - - //delete output file if it already exists - if ( QFile::exists( mOutputLayer ) ) - { - QgsVectorFileWriter::deleteShapeFile( mOutputLayer ); - } - - //create vector file writer - QgsFields outputFields; - outputFields.append( QgsField( QStringLiteral( "id" ), QVariant::Int ) ); - outputFields.append( QgsField( QStringLiteral( "station_id" ), QVariant::Int ) ); - outputFields.append( QgsField( QStringLiteral( "stratum_id" ), QVariant::Int ) ); - QgsVectorFileWriter writer( mOutputLayer, QStringLiteral( "UTF-8" ), - outputFields, - QgsWkbTypes::Point, - mInputLayer->crs() ); - - //check if creation of output layer successful - if ( writer.hasError() != QgsVectorFileWriter::NoError ) - { - return 3; - } - - //init random number generator - mt_srand( QTime::currentTime().msec() ); - QgsFeature fet; - int nPoints = 0; - double minDistance = 0; - mNCreatedPoints = 0; - - QgsFeatureIterator fIt = mInputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( - QStringList() << mNumberOfPointsAttribute << mMinDistanceAttribute, mInputLayer->fields() ) ); - while ( fIt.nextFeature( fet ) ) - { - nPoints = fet.attribute( mNumberOfPointsAttribute ).toInt(); - if ( !mMinDistanceAttribute.isEmpty() ) - { - minDistance = fet.attribute( mMinDistanceAttribute ).toDouble(); - } - addSamplePoints( fet, writer, nPoints, minDistance ); - } - - return 0; -} - -void QgsPointSample::addSamplePoints( QgsFeature &inputFeature, QgsVectorFileWriter &writer, int nPoints, double minDistance ) -{ - if ( !inputFeature.hasGeometry() ) - return; - - QgsGeometry geom = inputFeature.geometry(); - QgsRectangle geomRect = geom.boundingBox(); - if ( geomRect.isEmpty() ) - { - return; - } - - QgsSpatialIndex sIndex; //to check minimum distance - QMap< QgsFeatureId, QgsPointXY > pointMapForFeature; - - int nIterations = 0; - int maxIterations = nPoints * 200; - int points = 0; - - double randX = 0; - double randY = 0; - - while ( nIterations < maxIterations && points < nPoints ) - { - randX = ( ( double )mt_rand() / MD_RAND_MAX ) * geomRect.width() + geomRect.xMinimum(); - randY = ( ( double )mt_rand() / MD_RAND_MAX ) * geomRect.height() + geomRect.yMinimum(); - QgsPointXY randPoint( randX, randY ); - QgsGeometry ptGeom = QgsGeometry::fromPoint( randPoint ); - if ( ptGeom.within( geom ) && checkMinDistance( randPoint, sIndex, minDistance, pointMapForFeature ) ) - { - //add feature to writer - QgsFeature f( mNCreatedPoints ); - f.setAttribute( QStringLiteral( "id" ), mNCreatedPoints + 1 ); - f.setAttribute( QStringLiteral( "station_id" ), points + 1 ); - f.setAttribute( QStringLiteral( "stratum_id" ), inputFeature.id() ); - f.setGeometry( ptGeom ); - writer.addFeature( f ); - sIndex.insertFeature( f ); - pointMapForFeature.insert( mNCreatedPoints, randPoint ); - ++points; - ++mNCreatedPoints; - } - ++nIterations; - } -} - -bool QgsPointSample::checkMinDistance( QgsPointXY &pt, QgsSpatialIndex &index, double minDistance, QMap< QgsFeatureId, QgsPointXY > &pointMap ) -{ - if ( minDistance <= 0 ) - { - return true; - } - - QList neighborList = index.nearestNeighbor( pt, 1 ); - if ( neighborList.isEmpty() ) - { - return true; - } - - QMap< QgsFeatureId, QgsPointXY >::const_iterator it = pointMap.find( neighborList[0] ); - if ( it == pointMap.constEnd() ) //should not happen - { - return true; - } - - QgsPointXY neighborPt = it.value(); - if ( neighborPt.sqrDist( pt ) < ( minDistance * minDistance ) ) - { - return false; - } - return true; -} - - - - diff --git a/src/analysis/vector/qgspointsample.h b/src/analysis/vector/qgspointsample.h deleted file mode 100644 index 098838c9f3e..00000000000 --- a/src/analysis/vector/qgspointsample.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - qgspointsample.h - --------------------- - begin : July 2013 - copyright : (C) 2013 by Marco Hugentobler - email : marco dot hugentobler at sourcepole dot ch - *************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#ifndef QGSPOINTSAMPLE_H -#define QGSPOINTSAMPLE_H - -#include "qgsfeature.h" -#include -#include "qgis_analysis.h" - -class QgsFeature; -class QgsPointXY; -class QgsSpatialIndex; -class QgsVectorFileWriter; -class QgsVectorLayer; -class QProgressDialog; - -/** \ingroup analysis - * Creates random points in polygons / multipolygons*/ -class ANALYSIS_EXPORT QgsPointSample -{ - public: - QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute = QString() ); - - /** Starts calculation of random points - \returns 0 in case of success*/ - int createRandomPoints( QProgressDialog *pd ); - - private: - - QgsPointSample(); //default constructor is forbidden - void addSamplePoints( QgsFeature &inputFeature, QgsVectorFileWriter &writer, int nPoints, double minDistance ); - bool checkMinDistance( QgsPointXY &pt, QgsSpatialIndex &index, double minDistance, QMap< QgsFeatureId, QgsPointXY > &pointMap ); - - //! Layer id of input polygon/multipolygon layer - QgsVectorLayer *mInputLayer = nullptr; - //! Output path of result layer - QString mOutputLayer; - //! Attribute containing number of points per feature - QString mNumberOfPointsAttribute; - //! Attribute containing minimum distance between sample points (or -1 if no min. distance constraint) - QString mMinDistanceAttribute; - QgsFeatureId mNCreatedPoints; //helper to find free ids -}; - -#endif // QGSPOINTSAMPLE_H diff --git a/tests/src/analysis/CMakeLists.txt b/tests/src/analysis/CMakeLists.txt index e79255854bd..21835c35c4f 100644 --- a/tests/src/analysis/CMakeLists.txt +++ b/tests/src/analysis/CMakeLists.txt @@ -63,7 +63,6 @@ ENDMACRO (ADD_QGIS_TEST) ############################################################# # Tests: SET(TESTS - testqgsvectoranalyzer.cpp testqgsgeometrysnapper.cpp testopenstreetmap.cpp testqgszonalstatistics.cpp diff --git a/tests/src/analysis/testqgsvectoranalyzer.cpp b/tests/src/analysis/testqgsvectoranalyzer.cpp deleted file mode 100644 index 057b210121b..00000000000 --- a/tests/src/analysis/testqgsvectoranalyzer.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************** - testqgsvectoranalyzer.cpp - -------------------------------------- -Date : Sun Sep 16 12:22:49 AKDT 2007 -Copyright : (C) 2007 by Gary E. Sherman -Email : sherman at mrcc dot com - *************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#include "qgstest.h" - -//header for class being tested -#include -#include -#include -#include "qgsvectorlayer.h" - -class TestQgsVectorAnalyzer : public QObject -{ - Q_OBJECT - - public: - TestQgsVectorAnalyzer() - : mpLineLayer( 0 ) - , mpPolyLayer( 0 ) - , mpPointLayer( 0 ) - {} - - private slots: - void initTestCase();// will be called before the first testfunction is executed. - void cleanupTestCase();// will be called after the last testfunction was executed. - void init() ;// will be called before each testfunction is executed. - void cleanup() ;// will be called after every testfunction. - //! Our tests proper begin here - void singleToMulti(); - void multiToSingle(); - void extractNodes(); - void polygonsToLines(); - void exportGeometryInfo(); - void simplifyGeometry(); - void polygonCentroids(); - void layerExtent(); - private: - QgsGeometryAnalyzer mAnalyzer; - QgsVectorLayer *mpLineLayer = nullptr; - QgsVectorLayer *mpPolyLayer = nullptr; - QgsVectorLayer *mpPointLayer = nullptr; - -}; - -void TestQgsVectorAnalyzer::initTestCase() -{ - // - // Runs once before any tests are run - // - // init QGIS's paths - true means that all path will be inited from prefix - QgsApplication::init(); - QgsApplication::initQgis(); - QgsApplication::showSettings(); - - //create some objects that will be used in all tests... - //create a map layer that will be used in all tests... - QString myBaseFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt - QString myEndName = QStringLiteral( "lines.shp" ); - QString myFileName = myBaseFileName + '/' + myEndName; - qDebug() << myFileName; - QFileInfo myLineInfo( myFileName ); - mpLineLayer = new QgsVectorLayer( myLineInfo.filePath(), - myLineInfo.completeBaseName(), QStringLiteral( "ogr" ) ); - - myEndName = QStringLiteral( "polys.shp" ); - myFileName = myBaseFileName + '/' + myEndName; - QFileInfo myPolyInfo( myFileName ); - mpPolyLayer = new QgsVectorLayer( myPolyInfo.filePath(), - myPolyInfo.completeBaseName(), QStringLiteral( "ogr" ) ); - - myEndName = QStringLiteral( "points.shp" ); - myFileName = myBaseFileName + '/' + myEndName; - QFileInfo myPointInfo( myFileName ); - mpPointLayer = new QgsVectorLayer( myPointInfo.filePath(), - myPointInfo.completeBaseName(), QStringLiteral( "ogr" ) ); -} -void TestQgsVectorAnalyzer::cleanupTestCase() -{ - delete mpLineLayer; - delete mpPolyLayer; - delete mpPointLayer; - QgsApplication::exitQgis(); -} -void TestQgsVectorAnalyzer::init() -{ - -} -void TestQgsVectorAnalyzer::cleanup() -{ - -} -void TestQgsVectorAnalyzer::singleToMulti() -{ - -} -void TestQgsVectorAnalyzer::multiToSingle() -{ - -} -void TestQgsVectorAnalyzer::extractNodes() -{ - -} -void TestQgsVectorAnalyzer::polygonsToLines() -{ - -} -void TestQgsVectorAnalyzer::exportGeometryInfo() -{ -} - -void TestQgsVectorAnalyzer::simplifyGeometry() -{ - QString myTmpDir = QDir::tempPath() + '/'; - QString myFileName = myTmpDir + "simplify_layer.shp"; - QVERIFY( mAnalyzer.simplify( mpLineLayer, myFileName, 1.0 ) ); -} - -void TestQgsVectorAnalyzer::polygonCentroids() -{ - QString myTmpDir = QDir::tempPath() + '/'; - QString myFileName = myTmpDir + "centroid_layer.shp"; - QVERIFY( mAnalyzer.centroids( mpPolyLayer, myFileName ) ); -} - -void TestQgsVectorAnalyzer::layerExtent() -{ - QString myTmpDir = QDir::tempPath() + '/'; - QString myFileName = myTmpDir + "extent_layer.shp"; - QVERIFY( mAnalyzer.extent( mpPointLayer, myFileName ) ); -} - -QGSTEST_MAIN( TestQgsVectorAnalyzer ) -#include "testqgsvectoranalyzer.moc"