Skip to content
Permalink
Browse files

Calculate layer to map conversion on the fly

  • Loading branch information
m-kuhn committed Sep 11, 2018
1 parent 9d22389 commit 6d2ec207e12008fcb08a8350aa85158031b7de22
Showing with 165 additions and 105 deletions.
  1. +7 −3 src/analysis/vector/geometry_checker/qgsfeaturepool.cpp
  2. +7 −15 src/analysis/vector/geometry_checker/qgsfeaturepool.h
  3. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryanglecheck.cpp
  4. +6 −4 src/analysis/vector/geometry_checker/qgsgeometryareacheck.cpp
  5. +31 −4 src/analysis/vector/geometry_checker/qgsgeometrycheck.cpp
  6. +12 −5 src/analysis/vector/geometry_checker/qgsgeometrycheck.h
  7. +10 −0 src/analysis/vector/geometry_checker/qgsgeometrychecker.cpp
  8. +8 −2 src/analysis/vector/geometry_checker/qgsgeometrychecker.h
  9. +21 −11 src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.cpp
  10. +12 −4 src/analysis/vector/geometry_checker/qgsgeometrycheckerutils.h
  11. +4 −4 src/analysis/vector/geometry_checker/qgsgeometrycontainedcheck.cpp
  12. +2 −2 src/analysis/vector/geometry_checker/qgsgeometrydanglecheck.cpp
  13. +1 −1 src/analysis/vector/geometry_checker/qgsgeometrydegeneratepolygoncheck.cpp
  14. +4 −4 src/analysis/vector/geometry_checker/qgsgeometryduplicatecheck.cpp
  15. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryduplicatenodescheck.cpp
  16. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryfollowboundariescheck.cpp
  17. +4 −4 src/analysis/vector/geometry_checker/qgsgeometrygapcheck.cpp
  18. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryholecheck.cpp
  19. +2 −2 src/analysis/vector/geometry_checker/qgsgeometrylineintersectioncheck.cpp
  20. +2 −2 src/analysis/vector/geometry_checker/qgsgeometrylinelayerintersectioncheck.cpp
  21. +1 −1 src/analysis/vector/geometry_checker/qgsgeometrymultipartcheck.cpp
  22. +6 −6 src/analysis/vector/geometry_checker/qgsgeometryoverlapcheck.cpp
  23. +2 −2 src/analysis/vector/geometry_checker/qgsgeometrypointcoveredbylinecheck.cpp
  24. +2 −2 src/analysis/vector/geometry_checker/qgsgeometrypointinpolygoncheck.cpp
  25. +3 −3 src/analysis/vector/geometry_checker/qgsgeometrysegmentlengthcheck.cpp
  26. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryselfcontactcheck.cpp
  27. +1 −1 src/analysis/vector/geometry_checker/qgsgeometryselfintersectioncheck.cpp
  28. +1 −1 src/analysis/vector/geometry_checker/qgsgeometrytypecheck.cpp
  29. +2 −2 src/analysis/vector/geometry_checker/qgsvectordataproviderfeaturepool.cpp
  30. +1 −1 src/analysis/vector/geometry_checker/qgsvectordataproviderfeaturepool.h
  31. +3 −7 src/plugins/geometry_checker/qgsgeometrycheckersetuptab.cpp
  32. +5 −7 tests/src/geometry_checker/testqgsgeometrychecks.cpp
@@ -26,13 +26,12 @@
#include <QMutexLocker>


QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform )
QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer )
: mFeatureCache( CACHE_SIZE )
, mLayer( layer )
, mLayerToMapUnits( layerToMapUnits )
, mLayerToMapTransform( layerToMapTransform )
, mLayerId( layer->id() )
, mGeometryType( layer->geometryType() )
, mCrs( layer->crs() )
{

}
@@ -118,6 +117,11 @@ void QgsFeaturePool::setFeatureIds( const QgsFeatureIds &ids )
mFeatureIds = ids;
}

QgsCoordinateReferenceSystem QgsFeaturePool::crs() const
{
return mCrs;
}

QgsWkbTypes::GeometryType QgsFeaturePool::geometryType() const
{
return mGeometryType;
@@ -38,7 +38,7 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink
{

public:
QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform );
QgsFeaturePool( QgsVectorLayer *layer );
virtual ~QgsFeaturePool() = default;

/**
@@ -72,18 +72,6 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink
*/
QgsFeatureIds getIntersects( const QgsRectangle &rect ) const;

/**
* 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; }

/**
* Get a pointer to the underlying layer.
* May return a ``nullptr`` if the layer has been deleted.
@@ -101,6 +89,11 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink
*/
QgsWkbTypes::GeometryType geometryType() const;

/**
* The coordinate reference system of this layer.
*/
QgsCoordinateReferenceSystem crs() const;

protected:

/**
@@ -135,10 +128,9 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink
mutable QReadWriteLock mCacheLock;
QgsFeatureIds mFeatureIds;
QgsSpatialIndex mIndex;
double mLayerToMapUnits = 1.0;
QgsCoordinateTransform mLayerToMapTransform;
QString mLayerId;
QgsWkbTypes::GeometryType mGeometryType;
QgsCoordinateReferenceSystem mCrs;
};

#endif // QGS_FEATUREPOOL_H
@@ -20,7 +20,7 @@
void QgsGeometryAngleCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter );
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, context() );
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
{
const QgsAbstractGeometry *geom = layerFeature.geometry();
@@ -21,11 +21,11 @@
void QgsGeometryAreaCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter );
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, mContext );
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
{
double layerToMapUnits = layerFeature.layerToMapUnits();
const QgsAbstractGeometry *geom = layerFeature.geometry();
double layerToMapUnits = mContext->layerScaleFactor( layerFeature.layer() );
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
{
double value;
@@ -47,11 +47,13 @@ void QgsGeometryAreaCheck::fixError( QgsGeometryCheckError *error, int method, c
error->setObsolete();
return;
}
double layerToMapUnits = featurePool->getLayerToMapUnits();
QgsGeometry g = feature.geometry();

const QgsGeometry g = feature.geometry();
const QgsAbstractGeometry *geom = g.constGet();
QgsVertexId vidx = error->vidx();

double layerToMapUnits = mContext->layerScaleFactor( featurePool->layer() );

// Check if polygon still exists
if ( !vidx.isValid( geom ) )
{
@@ -19,13 +19,39 @@
#include "qgsfeaturepool.h"
#include "qgsvectorlayer.h"

QgsGeometryCheckerContext::QgsGeometryCheckerContext( int _precision, const QgsCoordinateReferenceSystem &_mapCrs, const QMap<QString, QgsFeaturePool *> &_featurePools )
QgsGeometryCheckerContext::QgsGeometryCheckerContext( int _precision, const QgsCoordinateReferenceSystem &_mapCrs, const QMap<QString, QgsFeaturePool *> &_featurePools, const QgsCoordinateTransformContext &transformContext )
: tolerance( std::pow( 10, -_precision ) )
, reducedTolerance( std::pow( 10, -_precision / 2 ) )
, mapCrs( _mapCrs )
, featurePools( _featurePools )
, transformContext( transformContext )
{
}

const QgsCoordinateTransform &QgsGeometryCheckerContext::layerTransform( QgsVectorLayer *layer )
{
Q_ASSERT( QThread::currentThread() == qApp->thread() );

if ( !mTransformCache.contains( layer ) )
{
QgsCoordinateTransform transform = QgsCoordinateTransform( layer->crs(), mapCrs, transformContext );
mTransformCache[layer] = transform;
}

return mTransformCache[layer];
}

double QgsGeometryCheckerContext::layerScaleFactor( QgsVectorLayer *layer )
{
Q_ASSERT( QThread::currentThread() == qApp->thread() );

if ( !mScaleFactorCache.contains( layer ) )
{
double scaleFactor = layerTransform( layer ).scaleFactor( layer->extent() );
mScaleFactorCache[layer] = scaleFactor;
}

return mScaleFactorCache.value( layer );
}

QgsGeometryCheckError::QgsGeometryCheckError( const QgsGeometryCheck *check, const QString &layerId,
@@ -66,10 +92,11 @@ QgsGeometryCheckError::QgsGeometryCheckError( const QgsGeometryCheck *check,
{
mGeometry.reset( layerFeature.geometry()->clone() );
}
if ( layerFeature.geometryCrs() != layerFeature.layerToMapTransform().destinationCrs().authid() )
if ( !layerFeature.useMapCrs() )
{
mGeometry->transform( layerFeature.layerToMapTransform() );
mErrorLocation = layerFeature.layerToMapTransform().transform( mErrorLocation );
const QgsCoordinateTransform &transform = check->context()->layerTransform( layerFeature.layer() );
mGeometry->transform( transform );
mErrorLocation = transform.transform( mErrorLocation );
}
}

@@ -33,11 +33,18 @@ class QgsFeaturePool;

struct ANALYSIS_EXPORT QgsGeometryCheckerContext
{
QgsGeometryCheckerContext( int _precision, const QgsCoordinateReferenceSystem &_mapCrs, const QMap<QString, QgsFeaturePool *> &_featurePools );
const double tolerance;
const double reducedTolerance;
const QgsCoordinateReferenceSystem mapCrs;
const QMap<QString, QgsFeaturePool *> featurePools;
QgsGeometryCheckerContext( int _precision, const QgsCoordinateReferenceSystem &_mapCrs, const QMap<QString, QgsFeaturePool *> &_featurePools, const QgsCoordinateTransformContext &transformContext );
const double tolerance;
const double reducedTolerance;
const QgsCoordinateReferenceSystem mapCrs;
const QMap<QString, QgsFeaturePool *> featurePools;
const QgsCoordinateTransformContext transformContext;
const QgsCoordinateTransform &layerTransform( QgsVectorLayer *layer );
double layerScaleFactor( QgsVectorLayer *layer );

private:
QMap<QgsVectorLayer *, QgsCoordinateTransform> mTransformCache;
QMap<QgsVectorLayer *, double> mScaleFactorCache;
};

class ANALYSIS_EXPORT QgsGeometryCheck
@@ -291,3 +291,13 @@ void QgsGeometryChecker::runCheck( const QgsGeometryCheck *check )
emit errorAdded( error );
}
}

QgsGeometryChecker::RunCheckWrapper::RunCheckWrapper( QgsGeometryChecker *instance )
: mInstance( instance )
{
}

void QgsGeometryChecker::RunCheckWrapper::operator()( const QgsGeometryCheck *check )
{
mInstance->runCheck( check );
}
@@ -23,6 +23,8 @@
#include <QList>
#include <QMutex>
#include <QStringList>
#include <memory>

#include "qgis_analysis.h"
#include "qgsfeatureid.h"

@@ -55,8 +57,12 @@ class ANALYSIS_EXPORT QgsGeometryChecker : public QObject
class RunCheckWrapper
{
public:
explicit RunCheckWrapper( QgsGeometryChecker *instance ) : mInstance( instance ) {}
void operator()( const QgsGeometryCheck *check ) { mInstance->runCheck( check ); }

/**
* The caller needs to make sure that the context is not deleted before this thread ends.
*/
explicit RunCheckWrapper( QgsGeometryChecker *instance );
void operator()( const QgsGeometryCheck *check );
private:
QgsGeometryChecker *mInstance = nullptr;
};
@@ -23,22 +23,25 @@
#include "qgsgeometrycollection.h"
#include "qgssurface.h"
#include "qgsvectorlayer.h"
#include "qgsgeometrycheck.h"

#include <qmath.h>

namespace QgsGeometryCheckerUtils
{
LayerFeature::LayerFeature( const QgsFeaturePool *pool, const QgsFeature &feature, bool useMapCrs )
LayerFeature::LayerFeature( const QgsFeaturePool *pool, const QgsFeature &feature, QgsGeometryCheckerContext *context, bool useMapCrs )
: mFeaturePool( pool )
, mFeature( feature )
, mMapCrs( useMapCrs )
{
mGeometry = feature.geometry().constGet()->clone();
if ( useMapCrs && !mFeaturePool->getLayerToMapTransform().isShortCircuited() )
const QgsCoordinateTransform &transform = context->layerTransform( mFeaturePool->layer() );
if ( useMapCrs && context->mapCrs.isValid() && !transform.isShortCircuited() )
{
mGeometry->transform( mFeaturePool->getLayerToMapTransform() );
mGeometry->transform( transform );
}
}

LayerFeature::~LayerFeature()
{
delete mGeometry;
@@ -49,9 +52,6 @@ namespace QgsGeometryCheckerUtils
return mFeaturePool->layer();
}

double LayerFeature::layerToMapUnits() const { return mFeaturePool->getLayerToMapUnits(); }
const QgsCoordinateTransform &LayerFeature::layerToMapTransform() const { return mFeaturePool->getLayerToMapTransform(); }

QString LayerFeature::id() const
{
return QString( "%1:%2" ).arg( layer()->name() ).arg( mFeature.id() );
@@ -76,6 +76,11 @@ namespace QgsGeometryCheckerUtils
{
nextLayerFeature( true );
}

bool LayerFeature::useMapCrs() const
{
return mMapCrs;
}
LayerFeatures::iterator::~iterator()
{
delete mCurrentFeature;
@@ -149,7 +154,7 @@ namespace QgsGeometryCheckerUtils
if ( featurePool->getFeature( *mFeatureIt, feature ) && feature.geometry() && feature.geometry().constGet() )
{
delete mCurrentFeature;
mCurrentFeature = new LayerFeature( mParent->mFeaturePools[*mLayerIt], feature, mParent->mUseMapCrs );
mCurrentFeature = new LayerFeature( mParent->mFeaturePools[*mLayerIt], feature, mParent->mContext, mParent->mUseMapCrs );
return true;
}
++mFeatureIt;
@@ -162,30 +167,35 @@ namespace QgsGeometryCheckerUtils
LayerFeatures::LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
const QMap<QString, QgsFeatureIds> &featureIds,
const QList<QgsWkbTypes::GeometryType> &geometryTypes,
QAtomicInt *progressCounter, bool useMapCrs )
QAtomicInt *progressCounter,
QgsGeometryCheckerContext *context,
bool useMapCrs )
: mFeaturePools( featurePools )
, mFeatureIds( featureIds )
, mLayerIds( featurePools.keys() )
, mGeometryTypes( geometryTypes )
, mProgressCounter( progressCounter )
, mContext( context )
, mUseMapCrs( useMapCrs )
{}

LayerFeatures::LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
const QList<QString> &layerIds, const QgsRectangle &extent,
const QList<QgsWkbTypes::GeometryType> &geometryTypes )
const QList<QgsWkbTypes::GeometryType> &geometryTypes,
QgsGeometryCheckerContext *context )
: mFeaturePools( featurePools )
, mLayerIds( layerIds )
, mExtent( extent )
, mGeometryTypes( geometryTypes )
, mContext( context )
, mUseMapCrs( true )
{
for ( const QString &layerId : layerIds )
{
const QgsFeaturePool *featurePool = featurePools[layerId];
if ( geometryTypes.contains( featurePool->layer()->geometryType() ) )
if ( geometryTypes.contains( featurePool->geometryType() ) )
{
mFeatureIds.insert( layerId, featurePool->getIntersects( featurePool->getLayerToMapTransform().transform( extent, QgsCoordinateTransform::ReverseTransform ) ) );
mFeatureIds.insert( layerId, featurePool->getIntersects( context->layerTransform( featurePool->layer() ).transform( extent, QgsCoordinateTransform::ReverseTransform ) ) );
}
else
{
@@ -26,13 +26,14 @@

class QgsGeometryEngine;
class QgsFeaturePool;
struct QgsGeometryCheckerContext;

namespace QgsGeometryCheckerUtils
{
class LayerFeature
{
public:
LayerFeature( const QgsFeaturePool *pool, const QgsFeature &feature, bool useMapCrs );
LayerFeature( const QgsFeaturePool *pool, const QgsFeature &feature, QgsGeometryCheckerContext *context, bool useMapCrs );
~LayerFeature();
const QgsFeature &feature() const { return mFeature; }
QgsVectorLayer *layer() const;
@@ -44,6 +45,8 @@ namespace QgsGeometryCheckerUtils
bool operator==( const LayerFeature &other ) const;
bool operator!=( const LayerFeature &other ) const;

bool useMapCrs() const;

private:
const QgsFeaturePool *mFeaturePool;
QgsFeature mFeature;
@@ -57,10 +60,14 @@ namespace QgsGeometryCheckerUtils
LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
const QMap<QString, QgsFeatureIds> &featureIds,
const QList<QgsWkbTypes::GeometryType> &geometryTypes,
QAtomicInt *progressCounter, bool useMapCrs = false );
QAtomicInt *progressCounter,
QgsGeometryCheckerContext *context,
bool useMapCrs = false );

LayerFeatures( const QMap<QString, QgsFeaturePool *> &featurePools,
const QList<QString> &layerIds, const QgsRectangle &extent,
const QList<QgsWkbTypes::GeometryType> &geometryTypes );
const QList<QgsWkbTypes::GeometryType> &geometryTypes,
QgsGeometryCheckerContext *context );

class iterator
{
@@ -91,7 +98,8 @@ namespace QgsGeometryCheckerUtils
QgsRectangle mExtent;
QList<QgsWkbTypes::GeometryType> mGeometryTypes;
QAtomicInt *mProgressCounter = nullptr;
bool mUseMapCrs;
QgsGeometryCheckerContext *mContext = nullptr;
bool mUseMapCrs = true;
};

std::unique_ptr<QgsGeometryEngine> createGeomEngine( const QgsAbstractGeometry *geometry, double tolerance );

0 comments on commit 6d2ec20

Please sign in to comment.
You can’t perform that action at this time.