diff --git a/doc/api_break.dox b/doc/api_break.dox index 000f40309da..17e5773d269 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 <QProgressDialog> - -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<double> QgsGeometryAnalyzer::simpleMeasure( QgsGeometry &mpGeometry ) -{ - QList<double> 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<QString, QgsFeatureId> 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<QString, QgsFeatureId>::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<double> 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<double> 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<QString, QgsFeatureId> 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<QString, QgsFeatureId>::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<QgsFeature> featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() ); - QList<QgsFeature>::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<QgsGeometry> geomList; - if ( forceSingleType ) - { - geomList = geom.asGeometryCollection(); - } - else - { - geomList.push_back( geom ); - } - - QList<QgsGeometry>::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<QgsGeometry> inputGeomList; - - if ( geom.isMultipart() ) - { - inputGeomList = geom.asGeometryCollection(); - } - else - { - inputGeomList.push_back( geom ); - } - - QList<GEOSGeometry *> outputGeomList; - QList<QgsGeometry>::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<double> 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 <QProgressDialog> - -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<QgsFeatureId> 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<QString> 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 <QFile> -#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<QgsFeatureId> 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 <QString> -#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 <qgsgeometryanalyzer.h> -#include <qgsapplication.h> -#include <qgsproviderregistry.h> -#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"