mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #7805 from m-kuhn/vectordataproviderfeaturepool
Refactor QgsFeaturePool
This commit is contained in:
commit
273e99877b
69
python/core/auto_generated/qgsreadwritelocker.sip.in
Normal file
69
python/core/auto_generated/qgsreadwritelocker.sip.in
Normal file
@ -0,0 +1,69 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsreadwritelocker.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsReadWriteLocker
|
||||
{
|
||||
%Docstring
|
||||
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteLocks.
|
||||
|
||||
Locking and unlocking a QReadWriteLocks in complex functions and statements or in exception handling code
|
||||
is error-prone and difficult to debug.
|
||||
QgsReadWriteLocker can be used in such situations to ensure that the state of the lock is always well-defined.
|
||||
|
||||
QgsReadWriteLocker should be created within a function where a QReadWriteLock needs to be locked.
|
||||
The lock may be locked when QgsReadWriteLocker is created or when changeMode is called.
|
||||
You can unlock and relock the lock with unlock() and changeMode().
|
||||
If locked, the lock will be unlocked when the QgsReadWriteLocker is destroyed.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsreadwritelocker.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum Mode
|
||||
{
|
||||
Read,
|
||||
Write,
|
||||
Unlocked
|
||||
};
|
||||
|
||||
QgsReadWriteLocker( QReadWriteLock &lock, Mode mode );
|
||||
%Docstring
|
||||
Create a new QgsReadWriteLocker for ``lock`` and initialize in ``mode``.
|
||||
%End
|
||||
|
||||
void changeMode( Mode mode );
|
||||
%Docstring
|
||||
Change the mode of the lock to ``mode``.
|
||||
The lock will be unlocked and relocked as required.
|
||||
%End
|
||||
|
||||
void unlock();
|
||||
%Docstring
|
||||
Unlocks the lock.
|
||||
Equivalent to doing ``changeMode( QgsReadWriteLocker.Unlock );``
|
||||
%End
|
||||
|
||||
~QgsReadWriteLocker();
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsreadwritelocker.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -107,6 +107,7 @@
|
||||
%Include auto_generated/qgspythonrunner.sip
|
||||
%Include auto_generated/qgsrange.sip
|
||||
%Include auto_generated/qgsreadwritecontext.sip
|
||||
%Include auto_generated/qgsreadwritelocker.sip
|
||||
%Include auto_generated/qgsrenderchecker.sip
|
||||
%Include auto_generated/qgsrendercontext.sip
|
||||
%Include auto_generated/qgsrulebasedlabeling.sip
|
||||
|
@ -132,6 +132,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
network/qgsgraphanalyzer.cpp
|
||||
|
||||
vector/geometry_checker/qgsfeaturepool.cpp
|
||||
vector/geometry_checker/qgsvectordataproviderfeaturepool.cpp
|
||||
vector/geometry_checker/qgsgeometrychecker.cpp
|
||||
vector/geometry_checker/qgsgeometryanglecheck.cpp
|
||||
vector/geometry_checker/qgsgeometryareacheck.cpp
|
||||
@ -232,6 +233,7 @@ SET(QGIS_ANALYSIS_HDRS
|
||||
vector/qgszonalstatistics.h
|
||||
vector/geometry_checker/qgsgeometrycheckerutils.h
|
||||
vector/geometry_checker/qgsfeaturepool.h
|
||||
vector/geometry_checker/qgsvectordataproviderfeaturepool.h
|
||||
|
||||
interpolation/qgsinterpolator.h
|
||||
interpolation/qgsgridfilewriter.h
|
||||
|
@ -20,44 +20,26 @@
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsreadwritelocker.h"
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform, bool selectedOnly )
|
||||
|
||||
QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform )
|
||||
: mFeatureCache( CACHE_SIZE )
|
||||
, mLayer( layer )
|
||||
, mLayerToMapUnits( layerToMapUnits )
|
||||
, mLayerToMapTransform( layerToMapTransform )
|
||||
, mSelectedOnly( selectedOnly )
|
||||
, mLayerId( layer->id() )
|
||||
, mGeometryType( layer->geometryType() )
|
||||
{
|
||||
// Build spatial index
|
||||
QgsFeature feature;
|
||||
QgsFeatureRequest req;
|
||||
req.setSubsetOfAttributes( QgsAttributeList() );
|
||||
if ( selectedOnly )
|
||||
{
|
||||
mFeatureIds = layer->selectedFeatureIds();
|
||||
req.setFilterFids( mFeatureIds );
|
||||
}
|
||||
|
||||
QgsFeatureIterator it = layer->getFeatures( req );
|
||||
while ( it.nextFeature( feature ) )
|
||||
{
|
||||
if ( feature.geometry() )
|
||||
{
|
||||
mIndex.insertFeature( feature );
|
||||
mFeatureIds.insert( feature.id() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFeatureIds.remove( feature.id() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsFeaturePool::get( QgsFeatureId id, QgsFeature &feature )
|
||||
{
|
||||
QMutexLocker lock( &mLayerMutex );
|
||||
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
|
||||
QgsFeature *cachedFeature = mFeatureCache.object( id );
|
||||
if ( cachedFeature )
|
||||
{
|
||||
@ -66,78 +48,82 @@ bool QgsFeaturePool::get( QgsFeatureId id, QgsFeature &feature )
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<QgsVectorLayerFeatureSource> source = QgsVectorLayerUtils::getFeatureSource( mLayer );
|
||||
|
||||
// Feature not in cache, retrieve from layer
|
||||
// TODO: avoid always querying all attributes (attribute values are needed when merging by attribute)
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
|
||||
if ( !source->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
locker.changeMode( QgsReadWriteLocker::Write );
|
||||
mFeatureCache.insert( id, new QgsFeature( feature ) );
|
||||
mIndex.insertFeature( feature );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsFeaturePool::addFeature( QgsFeature &feature )
|
||||
QgsFeatureIds QgsFeaturePool::getFeatureIds() const
|
||||
{
|
||||
QgsFeatureList features;
|
||||
features.append( feature );
|
||||
mLayerMutex.lock();
|
||||
mLayer->dataProvider()->addFeatures( features );
|
||||
feature.setId( features.front().id() );
|
||||
if ( mSelectedOnly )
|
||||
{
|
||||
QgsFeatureIds selectedFeatureIds = mLayer->selectedFeatureIds();
|
||||
selectedFeatureIds.insert( feature.id() );
|
||||
mLayer->selectByIds( selectedFeatureIds );
|
||||
}
|
||||
mLayerMutex.unlock();
|
||||
mIndexMutex.lock();
|
||||
mIndex.insertFeature( feature );
|
||||
mIndexMutex.unlock();
|
||||
}
|
||||
|
||||
void QgsFeaturePool::updateFeature( QgsFeature &feature )
|
||||
{
|
||||
QgsFeature origFeature;
|
||||
get( feature.id(), origFeature );
|
||||
|
||||
QgsGeometryMap geometryMap;
|
||||
geometryMap.insert( feature.id(), feature.geometry() );
|
||||
QgsChangedAttributesMap changedAttributesMap;
|
||||
QgsAttributeMap attribMap;
|
||||
for ( int i = 0, n = feature.attributes().size(); i < n; ++i )
|
||||
{
|
||||
attribMap.insert( i, feature.attributes().at( i ) );
|
||||
}
|
||||
changedAttributesMap.insert( feature.id(), attribMap );
|
||||
mLayerMutex.lock();
|
||||
mFeatureCache.remove( feature.id() ); // Remove to force reload on next get()
|
||||
mLayer->dataProvider()->changeGeometryValues( geometryMap );
|
||||
mLayer->dataProvider()->changeAttributeValues( changedAttributesMap );
|
||||
mLayerMutex.unlock();
|
||||
mIndexMutex.lock();
|
||||
mIndex.deleteFeature( origFeature );
|
||||
mIndex.insertFeature( feature );
|
||||
mIndexMutex.unlock();
|
||||
}
|
||||
|
||||
void QgsFeaturePool::deleteFeature( QgsFeatureId fid )
|
||||
{
|
||||
QgsFeature origFeature;
|
||||
if ( get( fid, origFeature ) )
|
||||
{
|
||||
mIndexMutex.lock();
|
||||
mIndex.deleteFeature( origFeature );
|
||||
mIndexMutex.unlock();
|
||||
}
|
||||
mLayerMutex.lock();
|
||||
mFeatureCache.remove( origFeature.id() );
|
||||
mLayer->dataProvider()->deleteFeatures( QgsFeatureIds() << fid );
|
||||
mLayerMutex.unlock();
|
||||
return mFeatureIds;
|
||||
}
|
||||
|
||||
QgsFeatureIds QgsFeaturePool::getIntersects( const QgsRectangle &rect ) const
|
||||
{
|
||||
QMutexLocker lock( &mIndexMutex );
|
||||
return QgsFeatureIds::fromList( mIndex.intersects( rect ) );
|
||||
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
|
||||
QgsFeatureIds ids = QgsFeatureIds::fromList( mIndex.intersects( rect ) );
|
||||
return ids;
|
||||
}
|
||||
|
||||
QgsVectorLayer *QgsFeaturePool::layer() const
|
||||
{
|
||||
Q_ASSERT( QThread::currentThread() == qApp->thread() );
|
||||
|
||||
return mLayer.data();
|
||||
}
|
||||
|
||||
void QgsFeaturePool::insertFeature( const QgsFeature &feature )
|
||||
{
|
||||
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
|
||||
mFeatureCache.insert( feature.id(), new QgsFeature( feature ) );
|
||||
mIndex.insertFeature( feature );
|
||||
}
|
||||
|
||||
void QgsFeaturePool::refreshCache( const QgsFeature &feature )
|
||||
{
|
||||
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
|
||||
mFeatureCache.remove( feature.id() );
|
||||
mIndex.deleteFeature( feature );
|
||||
locker.unlock();
|
||||
|
||||
QgsFeature tempFeature;
|
||||
get( feature.id(), tempFeature );
|
||||
}
|
||||
|
||||
void QgsFeaturePool::removeFeature( const QgsFeatureId featureId )
|
||||
{
|
||||
QgsFeature origFeature;
|
||||
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
|
||||
if ( get( featureId, origFeature ) )
|
||||
{
|
||||
locker.changeMode( QgsReadWriteLocker::Write );
|
||||
mIndex.deleteFeature( origFeature );
|
||||
}
|
||||
locker.changeMode( QgsReadWriteLocker::Write );
|
||||
mFeatureCache.remove( origFeature.id() );
|
||||
}
|
||||
|
||||
void QgsFeaturePool::setFeatureIds( const QgsFeatureIds &ids )
|
||||
{
|
||||
mFeatureIds = ids;
|
||||
}
|
||||
|
||||
QgsWkbTypes::GeometryType QgsFeaturePool::geometryType() const
|
||||
{
|
||||
return mGeometryType;
|
||||
}
|
||||
|
||||
QString QgsFeaturePool::layerId() const
|
||||
{
|
||||
return mLayerId;
|
||||
}
|
||||
|
@ -21,42 +21,124 @@
|
||||
|
||||
#include <QCache>
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
|
||||
#include "qgis_analysis.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsspatialindex.h"
|
||||
#include "qgsfeaturesink.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
|
||||
class ANALYSIS_EXPORT QgsFeaturePool
|
||||
/**
|
||||
* \ingroup analysis
|
||||
* A feature pool is based on a vector layer and caches features.
|
||||
*/
|
||||
class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink
|
||||
{
|
||||
|
||||
public:
|
||||
QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform, bool selectedOnly = false );
|
||||
QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform );
|
||||
virtual ~QgsFeaturePool() = default;
|
||||
|
||||
/**
|
||||
* Retrieve the feature with the specified \a id into \a feature.
|
||||
* It will be retrieved from the cache or from the underlying layer if unavailable.
|
||||
* If the feature is neither available from the cache nor from the layer it will return false.
|
||||
*/
|
||||
bool get( QgsFeatureId id, QgsFeature &feature );
|
||||
void addFeature( QgsFeature &feature );
|
||||
void updateFeature( QgsFeature &feature );
|
||||
void deleteFeature( QgsFeatureId fid );
|
||||
|
||||
/**
|
||||
* Updates a feature in this pool.
|
||||
* Implementations will update the feature on the layer or on the data provider.
|
||||
*/
|
||||
virtual void updateFeature( QgsFeature &feature ) = 0;
|
||||
|
||||
/**
|
||||
* Removes a feature from this pool.
|
||||
* Implementations will remove the feature from the layer or from the data provider.
|
||||
*/
|
||||
virtual void deleteFeature( QgsFeatureId fid ) = 0;
|
||||
|
||||
/**
|
||||
* Returns the complete set of feature ids in this pool.
|
||||
* Note that this concerns the features governed by this pool, which are not necessarily all cached.
|
||||
*/
|
||||
QgsFeatureIds getFeatureIds() const;
|
||||
|
||||
/**
|
||||
* Get all feature ids in the bounding box \a rect. It will use a spatial index to
|
||||
* determine the ids.
|
||||
*/
|
||||
QgsFeatureIds getIntersects( const QgsRectangle &rect ) const;
|
||||
QgsVectorLayer *getLayer() const { return mLayer; }
|
||||
const QgsFeatureIds &getFeatureIds() const { return mFeatureIds; }
|
||||
|
||||
/**
|
||||
* The factor of layer units to map units.
|
||||
* TODO: should this be removed and determined on runtime by checks that need it?
|
||||
*/
|
||||
double getLayerToMapUnits() const { return mLayerToMapUnits; }
|
||||
|
||||
/**
|
||||
* A coordinate transform from layer to map CRS.
|
||||
* TODO: should this be removed and determined on runtime by checks that need it?
|
||||
*/
|
||||
const QgsCoordinateTransform &getLayerToMapTransform() const { return mLayerToMapTransform; }
|
||||
|
||||
void clearLayer() { mLayer = nullptr; }
|
||||
/**
|
||||
* Get a pointer to the underlying layer.
|
||||
* May return a ``nullptr`` if the layer has been deleted.
|
||||
* This must only be called from the main thread.
|
||||
*/
|
||||
QgsVectorLayer *layer() const;
|
||||
|
||||
/**
|
||||
* The layer id of the layer.
|
||||
*/
|
||||
QString layerId() const;
|
||||
|
||||
/**
|
||||
* The geometry type of this layer.
|
||||
*/
|
||||
QgsWkbTypes::GeometryType geometryType() const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Inserts a feature into the cache and the spatial index.
|
||||
* To be used by implementations of ``addFeature``.
|
||||
*/
|
||||
void insertFeature( const QgsFeature &feature );
|
||||
|
||||
/**
|
||||
* Changes a feature in the cache and the spatial index.
|
||||
* To be used by implementations of ``updateFeature``.
|
||||
*/
|
||||
void refreshCache( const QgsFeature &feature );
|
||||
|
||||
/**
|
||||
* Removes a feature from the cache and the spatial index.
|
||||
* To be used by implementations of ``deleteFeature``.
|
||||
*/
|
||||
void removeFeature( const QgsFeatureId featureId );
|
||||
|
||||
/**
|
||||
* Set all the feature ids governed by this feature pool.
|
||||
* Should be called by subclasses constructor and whenever
|
||||
* they insert a new feature.
|
||||
*/
|
||||
void setFeatureIds( const QgsFeatureIds &ids );
|
||||
|
||||
private:
|
||||
|
||||
static const int CACHE_SIZE = 1000;
|
||||
|
||||
QCache<QgsFeatureId, QgsFeature> mFeatureCache;
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
QPointer<QgsVectorLayer> mLayer;
|
||||
mutable QReadWriteLock mCacheLock;
|
||||
QgsFeatureIds mFeatureIds;
|
||||
QMutex mLayerMutex;
|
||||
mutable QMutex mIndexMutex;
|
||||
QgsSpatialIndex mIndex;
|
||||
double mLayerToMapUnits = 1.0;
|
||||
QgsCoordinateTransform mLayerToMapTransform;
|
||||
bool mSelectedOnly = false;
|
||||
QString mLayerId;
|
||||
QgsWkbTypes::GeometryType mGeometryType;
|
||||
};
|
||||
|
||||
#endif // QGS_FEATUREPOOL_H
|
||||
|
@ -149,7 +149,7 @@ QMap<QString, QgsFeatureIds> QgsGeometryCheck::allLayerFeatureIds() const
|
||||
QMap<QString, QgsFeatureIds> featureIds;
|
||||
for ( QgsFeaturePool *pool : mContext->featurePools )
|
||||
{
|
||||
featureIds.insert( pool->getLayer()->id(), pool->getFeatureIds() );
|
||||
featureIds.insert( pool->layerId(), pool->getFeatureIds() );
|
||||
}
|
||||
return featureIds;
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ QgsGeometryChecker::QgsGeometryChecker( const QList<QgsGeometryCheck *> &checks,
|
||||
{
|
||||
for ( auto it = mContext->featurePools.constBegin(); it != mContext->featurePools.constEnd(); ++it )
|
||||
{
|
||||
if ( it.value()->getLayer() )
|
||||
if ( it.value()->layer() )
|
||||
{
|
||||
it.value()->getLayer()->setReadOnly( true );
|
||||
it.value()->layer()->setReadOnly( true );
|
||||
// Enter update mode to defer ogr dataset repacking until the checker has finished
|
||||
it.value()->getLayer()->dataProvider()->enterUpdateMode();
|
||||
it.value()->layer()->dataProvider()->enterUpdateMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,10 +47,10 @@ QgsGeometryChecker::~QgsGeometryChecker()
|
||||
qDeleteAll( mChecks );
|
||||
for ( auto it = mContext->featurePools.constBegin(); it != mContext->featurePools.constEnd(); ++it )
|
||||
{
|
||||
if ( it.value()->getLayer() )
|
||||
if ( it.value()->layer() )
|
||||
{
|
||||
it.value()->getLayer()->dataProvider()->leaveUpdateMode();
|
||||
it.value()->getLayer()->setReadOnly( false );
|
||||
it.value()->layer()->dataProvider()->leaveUpdateMode();
|
||||
it.value()->layer()->setReadOnly( false );
|
||||
}
|
||||
delete it.value();
|
||||
}
|
||||
@ -68,7 +68,7 @@ QFuture<void> QgsGeometryChecker::execute( int *totalSteps )
|
||||
{
|
||||
if ( check->checkType() <= QgsGeometryCheck::FeatureCheck )
|
||||
{
|
||||
*totalSteps += check->isCompatible( it.value()->getLayer()->geometryType() ) ? it.value()->getFeatureIds().size() : 0;
|
||||
*totalSteps += check->isCompatible( it.value()->layer()->geometryType() ) ? it.value()->getFeatureIds().size() : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -145,7 +145,7 @@ bool QgsGeometryChecker::fixError( QgsGeometryCheckError *error, int method, boo
|
||||
{
|
||||
const QMap<QgsFeatureId, QList<QgsGeometryCheck::Change>> &layerChanges = it.value();
|
||||
QgsFeaturePool *featurePool = mContext->featurePools[it.key()];
|
||||
QgsCoordinateTransform t( featurePool->getLayer()->crs(), mContext->mapCrs, QgsProject::instance() );
|
||||
QgsCoordinateTransform t( featurePool->layer()->crs(), mContext->mapCrs, QgsProject::instance() );
|
||||
for ( auto layerChangeIt = layerChanges.constBegin(); layerChangeIt != layerChanges.constEnd(); ++layerChangeIt )
|
||||
{
|
||||
bool removed = false;
|
||||
@ -184,7 +184,7 @@ bool QgsGeometryChecker::fixError( QgsGeometryCheckError *error, int method, boo
|
||||
for ( const QString &layerId : mContext->featurePools.keys() )
|
||||
{
|
||||
QgsFeaturePool *featurePool = mContext->featurePools[layerId];
|
||||
QgsCoordinateTransform t( mContext->mapCrs, featurePool->getLayer()->crs(), QgsProject::instance() );
|
||||
QgsCoordinateTransform t( mContext->mapCrs, featurePool->layer()->crs(), QgsProject::instance() );
|
||||
recheckAreaFeatures[layerId] = featurePool->getIntersects( t.transform( recheckArea ) );
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ bool QgsGeometryChecker::fixError( QgsGeometryCheckError *error, int method, boo
|
||||
{
|
||||
for ( const QString &layerId : changes.keys() )
|
||||
{
|
||||
mContext->featurePools[layerId]->getLayer()->triggerRepaint();
|
||||
mContext->featurePools[layerId]->layer()->triggerRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace QgsGeometryCheckerUtils
|
||||
{
|
||||
delete mGeometry;
|
||||
}
|
||||
const QgsVectorLayer &LayerFeature::layer() const { return *mFeaturePool->getLayer(); }
|
||||
const QgsVectorLayer &LayerFeature::layer() const { return *mFeaturePool->layer(); }
|
||||
double LayerFeature::layerToMapUnits() const { return mFeaturePool->getLayerToMapUnits(); }
|
||||
const QgsCoordinateTransform &LayerFeature::layerToMapTransform() const { return mFeaturePool->getLayerToMapTransform(); }
|
||||
|
||||
@ -114,7 +114,7 @@ namespace QgsGeometryCheckerUtils
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( mParent->mGeometryTypes.contains( mParent->mFeaturePools[*mLayerIt]->getLayer()->geometryType() ) )
|
||||
if ( mParent->mGeometryTypes.contains( mParent->mFeaturePools[*mLayerIt]->geometryType() ) )
|
||||
{
|
||||
mFeatureIt = mParent->mFeatureIds[*mLayerIt].constBegin();
|
||||
return true;
|
||||
@ -178,7 +178,7 @@ namespace QgsGeometryCheckerUtils
|
||||
for ( const QString &layerId : layerIds )
|
||||
{
|
||||
const QgsFeaturePool *featurePool = featurePools[layerId];
|
||||
if ( geometryTypes.contains( featurePool->getLayer()->geometryType() ) )
|
||||
if ( geometryTypes.contains( featurePool->layer()->geometryType() ) )
|
||||
{
|
||||
mFeatureIds.insert( layerId, featurePool->getIntersects( featurePool->getLayerToMapTransform().transform( extent, QgsCoordinateTransform::ReverseTransform ) ) );
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ QString QgsGeometryDuplicateCheckError::duplicatesString( const QMap<QString, Qg
|
||||
QStringList str;
|
||||
for ( auto it = duplicates.constBegin(); it != duplicates.constEnd(); ++it )
|
||||
{
|
||||
str.append( featurePools[it.key()]->getLayer()->name() + ":" );
|
||||
str.append( featurePools[it.key()]->layer()->name() + ":" );
|
||||
QStringList ids;
|
||||
for ( QgsFeatureId id : it.value() )
|
||||
{
|
||||
|
@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
qgsvectordataproviderfeaturepool.h
|
||||
--------------------------------------
|
||||
Date : 3.9.2018
|
||||
Copyright : (C) 2018 by Matthias Kuhn
|
||||
email : matthias@opengis.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 "qgsvectordataproviderfeaturepool.h"
|
||||
|
||||
#include "qgsfeaturerequest.h"
|
||||
|
||||
template <typename Func>
|
||||
void runOnMainThread( const Func &func )
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
|
||||
// Make sure we only deal with the vector layer on the main thread where it lives.
|
||||
// Anything else risks a crash.
|
||||
if ( QThread::currentThread() == qApp->thread() )
|
||||
func();
|
||||
else
|
||||
QMetaObject::invokeMethod( qApp, func, Qt::BlockingQueuedConnection );
|
||||
#else
|
||||
func();
|
||||
#endif
|
||||
}
|
||||
|
||||
QgsVectorDataProviderFeaturePool::QgsVectorDataProviderFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform, bool selectedOnly )
|
||||
: QgsFeaturePool( layer, layerToMapUnits, layerToMapTransform )
|
||||
, mSelectedOnly( selectedOnly )
|
||||
{
|
||||
// Build spatial index
|
||||
QgsFeature feature;
|
||||
QgsFeatureRequest req;
|
||||
QgsFeatureIds featureIds;
|
||||
if ( selectedOnly )
|
||||
{
|
||||
featureIds = layer->selectedFeatureIds();
|
||||
req.setFilterFids( featureIds );
|
||||
}
|
||||
|
||||
QgsFeatureIterator it = layer->getFeatures( req );
|
||||
while ( it.nextFeature( feature ) )
|
||||
{
|
||||
if ( feature.geometry() )
|
||||
{
|
||||
insertFeature( feature );
|
||||
featureIds.insert( feature.id() );
|
||||
}
|
||||
else
|
||||
{
|
||||
featureIds.remove( feature.id() );
|
||||
}
|
||||
}
|
||||
setFeatureIds( featureIds );
|
||||
}
|
||||
|
||||
bool QgsVectorDataProviderFeaturePool::addFeature( QgsFeature &feature, Flags flags )
|
||||
{
|
||||
Q_UNUSED( flags );
|
||||
QgsFeatureList features;
|
||||
features.append( feature );
|
||||
|
||||
bool res = false;
|
||||
|
||||
auto addFeatureSynchronized = [ this, &features, &res ]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
res = lyr->dataProvider()->addFeatures( features );
|
||||
};
|
||||
|
||||
runOnMainThread( addFeatureSynchronized );
|
||||
|
||||
if ( !res )
|
||||
return false;
|
||||
|
||||
feature.setId( features.front().id() );
|
||||
if ( mSelectedOnly )
|
||||
{
|
||||
runOnMainThread( [ this, feature ]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
{
|
||||
QgsFeatureIds selectedFeatureIds = lyr->selectedFeatureIds();
|
||||
selectedFeatureIds.insert( feature.id() );
|
||||
lyr->selectByIds( selectedFeatureIds );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
insertFeature( feature );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QgsVectorDataProviderFeaturePool::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
|
||||
{
|
||||
Q_UNUSED( flags );
|
||||
|
||||
bool res = false;
|
||||
|
||||
auto addFeatureSynchronized = [ this, &features, &res ]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
res = lyr->dataProvider()->addFeatures( features );
|
||||
};
|
||||
|
||||
runOnMainThread( addFeatureSynchronized );
|
||||
|
||||
if ( !res )
|
||||
return false;
|
||||
|
||||
if ( mSelectedOnly )
|
||||
{
|
||||
runOnMainThread( [ this, features ]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
{
|
||||
QgsFeatureIds selectedFeatureIds = lyr->selectedFeatureIds();
|
||||
for ( const QgsFeature &feature : qgis::as_const( features ) )
|
||||
selectedFeatureIds.insert( feature.id() );
|
||||
lyr->selectByIds( selectedFeatureIds );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
for ( const QgsFeature &feature : qgis::as_const( features ) )
|
||||
insertFeature( feature );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void QgsVectorDataProviderFeaturePool::updateFeature( QgsFeature &feature )
|
||||
{
|
||||
QgsFeature origFeature;
|
||||
get( feature.id(), origFeature );
|
||||
|
||||
QgsGeometryMap geometryMap;
|
||||
geometryMap.insert( feature.id(), feature.geometry() );
|
||||
QgsChangedAttributesMap changedAttributesMap;
|
||||
QgsAttributeMap attribMap;
|
||||
for ( int i = 0, n = feature.attributes().size(); i < n; ++i )
|
||||
{
|
||||
attribMap.insert( i, feature.attributes().at( i ) );
|
||||
}
|
||||
changedAttributesMap.insert( feature.id(), attribMap );
|
||||
|
||||
runOnMainThread( [this, geometryMap, changedAttributesMap]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
{
|
||||
lyr->dataProvider()->changeGeometryValues( geometryMap );
|
||||
lyr->dataProvider()->changeAttributeValues( changedAttributesMap );
|
||||
}
|
||||
} );
|
||||
|
||||
refreshCache( feature );
|
||||
}
|
||||
|
||||
void QgsVectorDataProviderFeaturePool::deleteFeature( QgsFeatureId fid )
|
||||
{
|
||||
removeFeature( fid );
|
||||
runOnMainThread( [this, fid]()
|
||||
{
|
||||
QgsVectorLayer *lyr = layer();
|
||||
if ( lyr )
|
||||
{
|
||||
lyr->dataProvider()->deleteFeatures( QgsFeatureIds() << fid );
|
||||
}
|
||||
} );
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/***************************************************************************
|
||||
qgsvectordataproviderfeaturepool.h
|
||||
--------------------------------------
|
||||
Date : 3.9.2018
|
||||
Copyright : (C) 2018 by Matthias Kuhn
|
||||
email : matthias@opengis.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 QGSVECTORDATAPROVIDERFEATUREPOOL_H
|
||||
#define QGSVECTORDATAPROVIDERFEATUREPOOL_H
|
||||
|
||||
#include "qgsfeaturepool.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
/**
|
||||
* \ingroup analysis
|
||||
* A feature pool based on a vector data provider.
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class ANALYSIS_EXPORT QgsVectorDataProviderFeaturePool : public QgsFeaturePool
|
||||
{
|
||||
public:
|
||||
QgsVectorDataProviderFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform, bool selectedOnly = false );
|
||||
|
||||
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = nullptr ) override;
|
||||
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = nullptr ) override;
|
||||
void updateFeature( QgsFeature &feature ) override;
|
||||
void deleteFeature( QgsFeatureId fid ) override;
|
||||
|
||||
private:
|
||||
bool mSelectedOnly = false;
|
||||
};
|
||||
|
||||
#endif // QGSVECTORDATAPROVIDERFEATUREPOOL_H
|
@ -281,6 +281,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsproxyprogresstask.cpp
|
||||
qgspythonrunner.cpp
|
||||
qgsreadwritecontext.cpp
|
||||
qgsreadwritelocker.cpp
|
||||
qgsrelation.cpp
|
||||
qgsrelationmanager.cpp
|
||||
qgsrenderchecker.cpp
|
||||
@ -921,6 +922,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgspythonrunner.h
|
||||
qgsrange.h
|
||||
qgsreadwritecontext.h
|
||||
qgsreadwritelocker.h
|
||||
qgsrenderchecker.h
|
||||
qgsrendercontext.h
|
||||
qgsrulebasedlabeling.h
|
||||
|
54
src/core/qgsreadwritelocker.cpp
Normal file
54
src/core/qgsreadwritelocker.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/***************************************************************************
|
||||
qgsreadwritelocker.cpp
|
||||
-------------------------
|
||||
begin : September 2018
|
||||
copyright : (C) 2018 by Matthias Kuhn
|
||||
email : matthias@opengis.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 "qgsreadwritelocker.h"
|
||||
|
||||
QgsReadWriteLocker::QgsReadWriteLocker( QReadWriteLock &lock, QgsReadWriteLocker::Mode mode )
|
||||
: mLock( lock )
|
||||
, mMode( mode )
|
||||
{
|
||||
if ( mode == Read )
|
||||
mLock.lockForRead();
|
||||
else if ( mode == Write )
|
||||
mLock.lockForWrite();
|
||||
}
|
||||
|
||||
void QgsReadWriteLocker::changeMode( QgsReadWriteLocker::Mode mode )
|
||||
{
|
||||
if ( mode == mMode )
|
||||
return;
|
||||
|
||||
unlock();
|
||||
|
||||
if ( mMode == Read )
|
||||
mLock.lockForRead();
|
||||
else if ( mMode == Write )
|
||||
mLock.lockForWrite();
|
||||
}
|
||||
|
||||
void QgsReadWriteLocker::unlock()
|
||||
{
|
||||
if ( mMode != Unlocked )
|
||||
mLock.unlock();
|
||||
|
||||
mMode = Unlocked;
|
||||
}
|
||||
|
||||
QgsReadWriteLocker::~QgsReadWriteLocker()
|
||||
{
|
||||
unlock();
|
||||
}
|
78
src/core/qgsreadwritelocker.h
Normal file
78
src/core/qgsreadwritelocker.h
Normal file
@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
qgsreadwritelocker.cpp
|
||||
-------------------------
|
||||
begin : September 2018
|
||||
copyright : (C) 2018 by Matthias Kuhn
|
||||
email : matthias@opengis.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 QGSREADWRITELOCKER_H
|
||||
#define QGSREADWRITELOCKER_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteLocks.
|
||||
*
|
||||
* Locking and unlocking a QReadWriteLocks in complex functions and statements or in exception handling code
|
||||
* is error-prone and difficult to debug.
|
||||
* QgsReadWriteLocker can be used in such situations to ensure that the state of the lock is always well-defined.
|
||||
*
|
||||
* QgsReadWriteLocker should be created within a function where a QReadWriteLock needs to be locked.
|
||||
* The lock may be locked when QgsReadWriteLocker is created or when changeMode is called.
|
||||
* You can unlock and relock the lock with unlock() and changeMode().
|
||||
* If locked, the lock will be unlocked when the QgsReadWriteLocker is destroyed.
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class CORE_EXPORT QgsReadWriteLocker
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* A QReadWriteLock can be in 3 different modes, read, write or unlocked.
|
||||
*/
|
||||
enum Mode
|
||||
{
|
||||
Read, //!< Lock for read
|
||||
Write, //!< Lock for write
|
||||
Unlocked //!< Unlocked
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new QgsReadWriteLocker for \a lock and initialize in \a mode.
|
||||
*/
|
||||
QgsReadWriteLocker( QReadWriteLock &lock, Mode mode );
|
||||
|
||||
/**
|
||||
* Change the mode of the lock to \a mode.
|
||||
* The lock will be unlocked and relocked as required.
|
||||
*/
|
||||
void changeMode( Mode mode );
|
||||
|
||||
/**
|
||||
* Unlocks the lock.
|
||||
* Equivalent to doing ``changeMode( QgsReadWriteLocker::Unlock );``
|
||||
*/
|
||||
void unlock();
|
||||
|
||||
~QgsReadWriteLocker();
|
||||
|
||||
private:
|
||||
QReadWriteLock &mLock;
|
||||
Mode mMode = Unlocked;
|
||||
};
|
||||
|
||||
#endif // QGSREADWRITELOCKER_H
|
@ -75,7 +75,7 @@ void QgsGeometryCheckerFixSummaryDialog::addError( QTableWidget *table, QgsGeome
|
||||
|
||||
int row = table->rowCount();
|
||||
table->insertRow( row );
|
||||
table->setItem( row, 0, new QTableWidgetItem( !error->layerId().isEmpty() ? mChecker->getContext()->featurePools[error->layerId()]->getLayer()->name() : "" ) );
|
||||
table->setItem( row, 0, new QTableWidgetItem( !error->layerId().isEmpty() ? mChecker->getContext()->featurePools[error->layerId()]->layer()->name() : "" ) );
|
||||
QTableWidgetItem *idItem = new QTableWidgetItem();
|
||||
idItem->setData( Qt::EditRole, error->featureId() != FEATUREID_NULL ? QVariant( error->featureId() ) : QVariant() );
|
||||
table->setItem( row, 1, idItem );
|
||||
|
@ -57,7 +57,7 @@ QgsGeometryCheckerResultTab::QgsGeometryCheckerResultTab( QgisInterface *iface,
|
||||
|
||||
for ( const QString &layerId : mChecker->getContext()->featurePools.keys() )
|
||||
{
|
||||
QgsVectorLayer *layer = mChecker->getContext()->featurePools[layerId]->getLayer();
|
||||
QgsVectorLayer *layer = mChecker->getContext()->featurePools[layerId]->layer();
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem( ui.treeWidgetMergeAttribute, QStringList() << layer->name() << "" );
|
||||
QComboBox *attribCombo = new QComboBox();
|
||||
for ( int i = 0, n = layer->fields().count(); i < n; ++i )
|
||||
@ -85,7 +85,7 @@ QgsGeometryCheckerResultTab::QgsGeometryCheckerResultTab( QgisInterface *iface,
|
||||
bool allLayersEditable = true;
|
||||
for ( const QgsFeaturePool *featurePool : mChecker->getContext()->featurePools.values() )
|
||||
{
|
||||
if ( ( featurePool->getLayer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeGeometries ) == 0 )
|
||||
if ( ( featurePool->layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeGeometries ) == 0 )
|
||||
{
|
||||
allLayersEditable = false;
|
||||
break;
|
||||
@ -148,7 +148,7 @@ void QgsGeometryCheckerResultTab::addError( QgsGeometryCheckError *error )
|
||||
ui.tableWidgetErrors->insertRow( row );
|
||||
QTableWidgetItem *idItem = new QTableWidgetItem();
|
||||
idItem->setData( Qt::EditRole, error->featureId() != FEATUREID_NULL ? QVariant( error->featureId() ) : QVariant() );
|
||||
ui.tableWidgetErrors->setItem( row, 0, new QTableWidgetItem( !error->layerId().isEmpty() ? mChecker->getContext()->featurePools[error->layerId()]->getLayer()->name() : "" ) );
|
||||
ui.tableWidgetErrors->setItem( row, 0, new QTableWidgetItem( !error->layerId().isEmpty() ? mChecker->getContext()->featurePools[error->layerId()]->layer()->name() : "" ) );
|
||||
ui.tableWidgetErrors->setItem( row, 1, idItem );
|
||||
ui.tableWidgetErrors->setItem( row, 2, new QTableWidgetItem( error->description() ) );
|
||||
ui.tableWidgetErrors->setItem( row, 3, new QTableWidgetItem( posStr ) );
|
||||
@ -221,7 +221,7 @@ void QgsGeometryCheckerResultTab::updateError( QgsGeometryCheckError *error, boo
|
||||
void QgsGeometryCheckerResultTab::exportErrors()
|
||||
{
|
||||
QString initialdir;
|
||||
QDir dir = QFileInfo( mChecker->getContext()->featurePools.first()->getLayer()->dataProvider()->dataSourceUri() ).dir();
|
||||
QDir dir = QFileInfo( mChecker->getContext()->featurePools.first()->layer()->dataProvider()->dataSourceUri() ).dir();
|
||||
if ( dir.exists() )
|
||||
{
|
||||
initialdir = dir.absolutePath();
|
||||
@ -280,7 +280,7 @@ bool QgsGeometryCheckerResultTab::exportErrorsDo( const QString &file )
|
||||
for ( int row = 0, nRows = ui.tableWidgetErrors->rowCount(); row < nRows; ++row )
|
||||
{
|
||||
QgsGeometryCheckError *error = ui.tableWidgetErrors->item( row, 0 )->data( Qt::UserRole ).value<QgsGeometryCheckError *>();
|
||||
QgsVectorLayer *srcLayer = mChecker->getContext()->featurePools[error->layerId()]->getLayer();
|
||||
QgsVectorLayer *srcLayer = mChecker->getContext()->featurePools[error->layerId()]->layer();
|
||||
QgsFeature f( layer->fields() );
|
||||
f.setAttribute( fieldLayer, srcLayer->name() );
|
||||
f.setAttribute( fieldFeatureId, error->featureId() );
|
||||
@ -454,7 +454,7 @@ void QgsGeometryCheckerResultTab::openAttributeTable()
|
||||
{
|
||||
mAttribTableDialogs[layerId]->close();
|
||||
}
|
||||
mAttribTableDialogs[layerId] = mIface->showAttributeTable( mChecker->getContext()->featurePools[layerId]->getLayer(), expr.join( QStringLiteral( " or " ) ) );
|
||||
mAttribTableDialogs[layerId] = mIface->showAttributeTable( mChecker->getContext()->featurePools[layerId]->layer(), expr.join( QStringLiteral( " or " ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,7 +528,7 @@ void QgsGeometryCheckerResultTab::fixErrors( bool prompt )
|
||||
}
|
||||
for ( const QString &layerId : mChecker->getContext()->featurePools.keys() )
|
||||
{
|
||||
mChecker->getContext()->featurePools[layerId]->getLayer()->triggerRepaint();
|
||||
mChecker->getContext()->featurePools[layerId]->layer()->triggerRepaint();
|
||||
}
|
||||
|
||||
if ( mStatistics.itemCount() > 0 )
|
||||
@ -618,7 +618,6 @@ void QgsGeometryCheckerResultTab::checkRemovedLayer( const QStringList &ids )
|
||||
{
|
||||
if ( ids.contains( layerId ) )
|
||||
{
|
||||
mChecker->getContext()->featurePools[layerId]->clearLayer();
|
||||
if ( isEnabled() )
|
||||
requiredLayersRemoved = true;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "qgsgeometrycheckfactory.h"
|
||||
#include "qgsgeometrycheck.h"
|
||||
#include "qgsfeaturepool.h"
|
||||
#include "qgsvectordataproviderfeaturepool.h"
|
||||
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgisinterface.h"
|
||||
@ -236,7 +237,7 @@ void QgsGeometryCheckerSetupTab::selectOutputDirectory()
|
||||
void QgsGeometryCheckerSetupTab::runChecks()
|
||||
{
|
||||
// Get selected layer
|
||||
QList<QgsVectorLayer *> layers = getSelectedLayers();
|
||||
const QList<QgsVectorLayer *> layers = getSelectedLayers();
|
||||
if ( layers.isEmpty() )
|
||||
return;
|
||||
|
||||
@ -416,7 +417,7 @@ void QgsGeometryCheckerSetupTab::runChecks()
|
||||
{
|
||||
double layerToMapUntis = mIface->mapCanvas()->mapSettings().layerToMapUnits( layer );
|
||||
QgsCoordinateTransform layerToMapTransform( layer->crs(), QgsProject::instance()->crs(), QgsProject::instance() );
|
||||
featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
|
||||
featurePools.insert( layer->id(), new QgsVectorDataProviderFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
|
||||
}
|
||||
// LineLayerIntersection check is enabled, make sure there is also a feature pool for that layer
|
||||
if ( ui.checkLineLayerIntersection->isChecked() && !featurePools.keys().contains( ui.comboLineLayerIntersection->currentData().toString() ) )
|
||||
@ -425,7 +426,7 @@ void QgsGeometryCheckerSetupTab::runChecks()
|
||||
Q_ASSERT( layer );
|
||||
double layerToMapUntis = mIface->mapCanvas()->mapSettings().layerToMapUnits( layer );
|
||||
QgsCoordinateTransform layerToMapTransform( layer->crs(), QgsProject::instance()->crs(), QgsProject::instance() );
|
||||
featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
|
||||
featurePools.insert( layer->id(), new QgsVectorDataProviderFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
|
||||
}
|
||||
|
||||
QgsGeometryCheckerContext *context = new QgsGeometryCheckerContext( ui.spinBoxTolerance->value(), QgsProject::instance()->crs(), featurePools );
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qgsgeometryselfcontactcheck.h"
|
||||
#include "qgsgeometryselfintersectioncheck.h"
|
||||
#include "qgsgeometrysliverpolygoncheck.h"
|
||||
#include "qgsvectordataproviderfeaturepool.h"
|
||||
#include "qgsproject.h"
|
||||
|
||||
#include "qgsgeometrytypecheck.h"
|
||||
@ -478,7 +479,7 @@ void TestQgsGeometryChecks::testFollowBoundariesCheck()
|
||||
QList<QgsGeometryCheckError *> checkErrors;
|
||||
QStringList messages;
|
||||
|
||||
QgsGeometryFollowBoundariesCheck( context, context->featurePools[layers["follow_ref.shp"]]->getLayer() ).collectErrors( checkErrors, messages );
|
||||
QgsGeometryFollowBoundariesCheck( context, context->featurePools[layers["follow_ref.shp"]]->layer() ).collectErrors( checkErrors, messages );
|
||||
listErrors( checkErrors, messages );
|
||||
|
||||
QCOMPARE( checkErrors.size(), 2 );
|
||||
@ -640,9 +641,9 @@ void TestQgsGeometryChecks::testMultipartCheck()
|
||||
|
||||
QVERIFY( searchCheckErrors( checkErrors, layers["point_layer.shp"] ).isEmpty() );
|
||||
// Easier to ensure that multipart features don't appear as errors than verifying each single-part multi-type feature
|
||||
QVERIFY( QgsWkbTypes::isSingleType( context->featurePools[layers["point_layer.shp"]]->getLayer()->wkbType() ) );
|
||||
QVERIFY( QgsWkbTypes::isMultiType( context->featurePools[layers["line_layer.shp"]]->getLayer()->wkbType() ) );
|
||||
QVERIFY( QgsWkbTypes::isMultiType( context->featurePools[layers["polygon_layer.shp"]]->getLayer()->wkbType() ) );
|
||||
QVERIFY( QgsWkbTypes::isSingleType( context->featurePools[layers["point_layer.shp"]]->layer()->wkbType() ) );
|
||||
QVERIFY( QgsWkbTypes::isMultiType( context->featurePools[layers["line_layer.shp"]]->layer()->wkbType() ) );
|
||||
QVERIFY( QgsWkbTypes::isMultiType( context->featurePools[layers["polygon_layer.shp"]]->layer()->wkbType() ) );
|
||||
QVERIFY( searchCheckErrors( checkErrors, layers["line_layer.shp"] ).size() > 0 );
|
||||
QVERIFY( searchCheckErrors( checkErrors, layers["polygon_layer.shp"] ).size() > 0 );
|
||||
QVERIFY( searchCheckErrors( checkErrors, layers["line_layer.shp"], 0 ).isEmpty() );
|
||||
@ -858,7 +859,7 @@ void TestQgsGeometryChecks::testSelfIntersectionCheck()
|
||||
// Test fixes
|
||||
QgsFeature f;
|
||||
|
||||
int nextId = context->featurePools[errs1[0]->layerId()]->getLayer()->featureCount();
|
||||
int nextId = context->featurePools[errs1[0]->layerId()]->layer()->featureCount();
|
||||
QVERIFY( fixCheckError( errs1[0],
|
||||
QgsGeometrySelfIntersectionCheck::ToSingleObjects, QgsGeometryCheckError::StatusFixed,
|
||||
{
|
||||
@ -885,7 +886,7 @@ void TestQgsGeometryChecks::testSelfIntersectionCheck()
|
||||
QCOMPARE( f.geometry().constGet()->vertexCount( 0 ), 4 );
|
||||
QCOMPARE( f.geometry().constGet()->vertexCount( 1 ), 5 );
|
||||
|
||||
nextId = context->featurePools[errs3[0]->layerId()]->getLayer()->featureCount();
|
||||
nextId = context->featurePools[errs3[0]->layerId()]->layer()->featureCount();
|
||||
QVERIFY( fixCheckError( errs3[0],
|
||||
QgsGeometrySelfIntersectionCheck::ToSingleObjects, QgsGeometryCheckError::StatusFixed,
|
||||
{
|
||||
@ -975,7 +976,7 @@ QgsFeaturePool *TestQgsGeometryChecks::createFeaturePool( QgsVectorLayer *layer,
|
||||
{
|
||||
double layerToMapUntis = layerToMapUnits( layer, mapCrs );
|
||||
QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransform( layer->crs(), mapCrs, QgsProject::instance() );
|
||||
return new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly );
|
||||
return new QgsVectorDataProviderFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly );
|
||||
}
|
||||
|
||||
QgsGeometryCheckerContext *TestQgsGeometryChecks::createTestContext( QTemporaryDir &tempDir, QMap<QString, QString> &layers, const QgsCoordinateReferenceSystem &mapCrs, double prec ) const
|
||||
@ -1008,8 +1009,8 @@ void TestQgsGeometryChecks::cleanupTestContext( QgsGeometryCheckerContext *ctx )
|
||||
{
|
||||
for ( const QgsFeaturePool *pool : ctx->featurePools )
|
||||
{
|
||||
pool->getLayer()->dataProvider()->leaveUpdateMode();
|
||||
delete pool->getLayer();
|
||||
pool->layer()->dataProvider()->leaveUpdateMode();
|
||||
delete pool->layer();
|
||||
}
|
||||
qDeleteAll( ctx->featurePools );
|
||||
delete ctx;
|
||||
|
Loading…
x
Reference in New Issue
Block a user