Skip to content
Permalink
Browse files

Add test

Add onStyleChanged
Add if mRenderContext when necessary
Orderer renderer if and add enableInvisibleFeature
  • Loading branch information
lbartoletti committed Sep 25, 2018
1 parent 458fa17 commit 9bbabcfbf5e0e44f2a8fce1a21cea01d04c1f151
Showing with 117 additions and 5 deletions.
  1. +2 −0 python/core/auto_generated/qgstracer.sip.in
  2. +15 −5 src/core/qgstracer.cpp
  3. +2 −0 src/core/qgstracer.h
  4. +98 −0 tests/src/core/testqgstracer.cpp
@@ -58,6 +58,8 @@ Sets the ``crs`` and ``transformContext`` used for tracing.
void setRenderContext( const QgsRenderContext *renderContext );
%Docstring
Sets the ``renderContext`` used for tracing only on visible features.

.. versionadded:: 3.4
%End

QgsRectangle extent() const;
@@ -24,6 +24,7 @@
#include "qgsvectorlayer.h"
#include "qgsexception.h"
#include "qgsrenderer.h"
#include "qgssettings.h"

#include <queue>
#include <vector>
@@ -459,8 +460,7 @@ QgsTracer::QgsTracer() = default;
bool QgsTracer::initGraph()
{
if ( mGraph )
return true;
// already initialized
return true; // already initialized

mHasTopologyProblem = false;

@@ -475,15 +475,17 @@ bool QgsTracer::initGraph()

t1.start();
int featuresCounted = 0;
bool enableInvisibleFeature = QgsSettings().value( QStringLiteral( "/qgis/digitizing/snap_invisible_feature" ), false ).toBool();
for ( QgsVectorLayer *vl : qgis::as_const( mLayers ) )
{
QgsFeatureRequest request;

bool filter = false;
std::unique_ptr< QgsFeatureRenderer > renderer( vl->renderer() ? vl->renderer()->clone() : nullptr );
std::unique_ptr< QgsFeatureRenderer > renderer;
QgsRenderContext *ctx = nullptr;
if ( mRenderContext )
if ( !enableInvisibleFeature && mRenderContext )
{
renderer.reset( vl->renderer() ? vl->renderer()->clone() : nullptr );
mRenderContext->expressionContext() << QgsExpressionContextUtils::layerScope( vl );
ctx = mRenderContext.get();
if ( renderer )
@@ -602,6 +604,7 @@ void QgsTracer::setLayers( const QList<QgsVectorLayer *> &layers )
disconnect( layer, &QgsVectorLayer::geometryChanged, this, &QgsTracer::onGeometryChanged );
disconnect( layer, &QgsVectorLayer::attributeValueChanged, this, &QgsTracer::onAttributeValueChanged );
disconnect( layer, &QgsVectorLayer::dataChanged, this, &QgsTracer::onDataChanged );
disconnect( layer, &QgsVectorLayer::styleChanged, this, &QgsTracer::onStyleChanged );
disconnect( layer, &QObject::destroyed, this, &QgsTracer::onLayerDestroyed );
}

@@ -702,14 +705,21 @@ void QgsTracer::onAttributeValueChanged( QgsFeatureId fid, int idx, const QVaria
Q_UNUSED( fid );
Q_UNUSED( idx );
Q_UNUSED( value );
invalidateGraph();
if ( mRenderContext )
invalidateGraph();
}

void QgsTracer::onDataChanged( )
{
invalidateGraph();
}

void QgsTracer::onStyleChanged( )
{
if ( mRenderContext )
invalidateGraph();
}

void QgsTracer::onLayerDestroyed( QObject *obj )
{
// remove the layer before it is completely invalid (static_cast should be the safest cast)
@@ -70,6 +70,7 @@ class CORE_EXPORT QgsTracer : public QObject

/**
* Sets the \a renderContext used for tracing only on visible features.
* \since QGIS 3.4
*/
void setRenderContext( const QgsRenderContext *renderContext );

@@ -169,6 +170,7 @@ class CORE_EXPORT QgsTracer : public QObject
void onGeometryChanged( QgsFeatureId fid, const QgsGeometry &geom );
void onAttributeValueChanged( QgsFeatureId fid, int idx, const QVariant &value );
void onDataChanged( );
void onStyleChanged( );
void onLayerDestroyed( QObject *obj );

private:
@@ -20,6 +20,12 @@
#include <qgstracer.h>
#include <qgsvectorlayer.h>
#include "qgsproject.h"
#include "qgscategorizedsymbolrenderer.h"
#include "qgssettings.h"
#include "qgslayertree.h"
#include "qgslayertreemodel.h"
#include "qgsmapsettings.h"
#include "qgssnappingutils.h"

class TestQgsTracer : public QObject
{
@@ -36,6 +42,7 @@ class TestQgsTracer : public QObject
void testReprojection();
void testCurved();
void testOffset();
void testInvisible();

private:

@@ -156,6 +163,97 @@ void TestQgsTracer::testSimple()
delete vl;
}

void TestQgsTracer::testInvisible()
{
QgsVectorLayer *mVL = new QgsVectorLayer( QStringLiteral( "Linestring?field=fld:int" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
QgsFeature f1, f2, f3, f4;
int idx = mVL->fields().indexFromName( QStringLiteral( "fld" ) );
QVERIFY( idx != -1 );
f1.initAttributes( 1 );
f2.initAttributes( 1 );
f3.initAttributes( 1 );
f4.initAttributes( 1 );

/* This shape - nearly a square (one side is shifted to have exactly one shortest
* path between corners):
* 0,10 +----+ 20,10
* | /
* 0,0 +--+ 10,0
*/
QgsGeometry geom = QgsGeometry::fromWkt( "LINESTRING(0 0, 0 10)" );
f1.setGeometry( geom );
f1.setAttribute( idx, QVariant( 2 ) );
geom = QgsGeometry::fromWkt( "LINESTRING(0 0, 10 0)" );
f2.setGeometry( geom );
f2.setAttribute( idx, QVariant( 1 ) );
geom = QgsGeometry::fromWkt( "LINESTRING(0 10, 20 10)" );
f3.setGeometry( geom );
f3.setAttribute( idx, QVariant( 1 ) );
geom = QgsGeometry::fromWkt( "LINESTRING(10 0, 20 10)" );
f4.setGeometry( geom );
f4.setAttribute( idx, QVariant( 1 ) );
QgsFeatureList flist;
flist << f1 << f2 << f3 << f4;

mVL->dataProvider()->addFeatures( flist );

QgsProject::instance()->addMapLayer( mVL );

QgsCategorizedSymbolRenderer *renderer = new QgsCategorizedSymbolRenderer();
renderer->setClassAttribute( QStringLiteral( "fld" ) );
renderer->setSourceSymbol( QgsSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ) );
renderer->addCategory( QgsRendererCategory( "2", QgsSymbol::defaultSymbol( QgsWkbTypes::LineGeometry ), QStringLiteral( "2" ) ) );
mVL->setRenderer( renderer );

//create legend with symbology nodes for categorized renderer
QgsLayerTree *root = new QgsLayerTree();
QgsLayerTreeLayer *n = new QgsLayerTreeLayer( mVL );
root->addChildNode( n );
QgsLayerTreeModel *m = new QgsLayerTreeModel( root, nullptr );
m->refreshLayerLegend( n );

QList<QgsLayerTreeModelLegendNode *> nodes = m->layerLegendNodes( n );
QCOMPARE( nodes.length(), 1 );
//uncheck all and test that all nodes are unchecked
static_cast< QgsSymbolLegendNode * >( nodes.at( 0 ) )->uncheckAllItems();
Q_FOREACH ( QgsLayerTreeModelLegendNode *ln, nodes )
{
QVERIFY( ln->data( Qt::CheckStateRole ) == Qt::Unchecked );
}

QgsMapSettings mapSettings;
mapSettings.setOutputSize( QSize( 100, 100 ) );
mapSettings.setExtent( QgsRectangle( 0, 0, 1, 1 ) );
QVERIFY( mapSettings.hasValidSettings() );
mapSettings.setLayers( QList<QgsMapLayer *>() << mVL );

QgsSnappingUtils u;
u.setMapSettings( mapSettings );
u.setEnableSnappingForInvisibleFeature( false );
u.setCurrentLayer( mVL );

QgsSnappingConfig snappingConfig = u.config();
snappingConfig.setEnabled( true );
snappingConfig.setTolerance( 10 );
snappingConfig.setUnits( QgsTolerance::Pixels );
snappingConfig.setMode( QgsSnappingConfig::ActiveLayer );
u.setConfig( snappingConfig );
QgsTracer tracer;
tracer.setLayers( QList<QgsVectorLayer *>() << mVL );

QgsPolylineXY points1 = tracer.findShortestPath( QgsPointXY( 10, 0 ), QgsPointXY( 0, 10 ) );
QCOMPARE( points1.count(), 3 );
QCOMPARE( points1[0], QgsPointXY( 10, 0 ) );
QCOMPARE( points1[1], QgsPointXY( 0, 0 ) );
QCOMPARE( points1[2], QgsPointXY( 0, 10 ) );

QgsRenderContext renderContext = QgsRenderContext::fromMapSettings( mapSettings );
tracer.setRenderContext( &renderContext );
points1 = tracer.findShortestPath( QgsPointXY( 10, 0 ), QgsPointXY( 0, 10 ) );
QCOMPARE( points1.count(), 0 );

}

void TestQgsTracer::testPolygon()
{
// the same shape as in testSimple() but with just one polygon ring

0 comments on commit 9bbabcf

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