mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-09 00:08:52 -04:00
Allow geometries to be set separate to features in expression contexts
Refs #46455 -- we need a way to separate these too, as we don't always want $geometry to refer to a feature's geometry
This commit is contained in:
parent
a8eaf46995
commit
11a8d40a86
@ -333,6 +333,49 @@ Removes any feature associated with the scope.
|
|||||||
.. seealso:: :py:func:`hasFeature`
|
.. seealso:: :py:func:`hasFeature`
|
||||||
|
|
||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool hasGeometry() const;
|
||||||
|
%Docstring
|
||||||
|
Returns ``True`` if the scope has a geometry associated with it.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`geometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsGeometry geometry() const;
|
||||||
|
%Docstring
|
||||||
|
Sets the geometry associated with the scope.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setGeometry`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`hasGeometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setGeometry( const QgsGeometry &geometry );
|
||||||
|
%Docstring
|
||||||
|
Convenience function for setting a ``geometry`` for the scope. Any existing
|
||||||
|
geometry set by the scope will be overwritten.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`removeGeometry`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`geometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
%End
|
||||||
|
|
||||||
|
void removeGeometry();
|
||||||
|
%Docstring
|
||||||
|
Removes any geometry associated with the scope.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setGeometry`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`hasGeometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
%End
|
%End
|
||||||
|
|
||||||
void setFields( const QgsFields &fields );
|
void setFields( const QgsFields &fields );
|
||||||
@ -692,6 +735,35 @@ Returns ``True`` if the context has a feature associated with it.
|
|||||||
Convenience function for retrieving the feature for the context, if set.
|
Convenience function for retrieving the feature for the context, if set.
|
||||||
|
|
||||||
.. seealso:: :py:func:`setFeature`
|
.. seealso:: :py:func:`setFeature`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setGeometry( const QgsGeometry &geometry );
|
||||||
|
%Docstring
|
||||||
|
Convenience function for setting a ``geometry`` for the context. The geometry
|
||||||
|
will be set within the last scope of the context, so will override any
|
||||||
|
existing geometries within the context.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`geometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool hasGeometry() const;
|
||||||
|
%Docstring
|
||||||
|
Returns ``True`` if the context has a geometry associated with it.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`geometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsGeometry geometry() const;
|
||||||
|
%Docstring
|
||||||
|
Convenience function for retrieving the geometry for the context, if set.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setGeometry`
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
%End
|
%End
|
||||||
|
|
||||||
void setFields( const QgsFields &fields );
|
void setFields( const QgsFields &fields );
|
||||||
|
@ -45,6 +45,8 @@ QgsExpressionContextScope::QgsExpressionContextScope( const QgsExpressionContext
|
|||||||
, mVariables( other.mVariables )
|
, mVariables( other.mVariables )
|
||||||
, mHasFeature( other.mHasFeature )
|
, mHasFeature( other.mHasFeature )
|
||||||
, mFeature( other.mFeature )
|
, mFeature( other.mFeature )
|
||||||
|
, mHasGeometry( other.mHasGeometry )
|
||||||
|
, mGeometry( other.mGeometry )
|
||||||
{
|
{
|
||||||
QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
|
QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
|
||||||
for ( ; it != other.mFunctions.constEnd(); ++it )
|
for ( ; it != other.mFunctions.constEnd(); ++it )
|
||||||
@ -59,6 +61,8 @@ QgsExpressionContextScope &QgsExpressionContextScope::operator=( const QgsExpres
|
|||||||
mVariables = other.mVariables;
|
mVariables = other.mVariables;
|
||||||
mHasFeature = other.mHasFeature;
|
mHasFeature = other.mHasFeature;
|
||||||
mFeature = other.mFeature;
|
mFeature = other.mFeature;
|
||||||
|
mHasGeometry = other.mHasGeometry;
|
||||||
|
mGeometry = other.mGeometry;
|
||||||
|
|
||||||
qDeleteAll( mFunctions );
|
qDeleteAll( mFunctions );
|
||||||
mFunctions.clear();
|
mFunctions.clear();
|
||||||
@ -529,8 +533,7 @@ void QgsExpressionContext::setFeature( const QgsFeature &feature )
|
|||||||
|
|
||||||
bool QgsExpressionContext::hasFeature() const
|
bool QgsExpressionContext::hasFeature() const
|
||||||
{
|
{
|
||||||
const auto constMStack = mStack;
|
for ( const QgsExpressionContextScope *scope : mStack )
|
||||||
for ( const QgsExpressionContextScope *scope : constMStack )
|
|
||||||
{
|
{
|
||||||
if ( scope->hasFeature() )
|
if ( scope->hasFeature() )
|
||||||
return true;
|
return true;
|
||||||
@ -551,6 +554,37 @@ QgsFeature QgsExpressionContext::feature() const
|
|||||||
return QgsFeature();
|
return QgsFeature();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsExpressionContext::setGeometry( const QgsGeometry &geometry )
|
||||||
|
{
|
||||||
|
if ( mStack.isEmpty() )
|
||||||
|
mStack.append( new QgsExpressionContextScope() );
|
||||||
|
|
||||||
|
mStack.last()->setGeometry( geometry );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsExpressionContext::hasGeometry() const
|
||||||
|
{
|
||||||
|
for ( const QgsExpressionContextScope *scope : mStack )
|
||||||
|
{
|
||||||
|
if ( scope->hasGeometry() )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsGeometry QgsExpressionContext::geometry() const
|
||||||
|
{
|
||||||
|
//iterate through stack backwards, so that higher priority variables take precedence
|
||||||
|
QList< QgsExpressionContextScope * >::const_iterator it = mStack.constEnd();
|
||||||
|
while ( it != mStack.constBegin() )
|
||||||
|
{
|
||||||
|
--it;
|
||||||
|
if ( ( *it )->hasGeometry() )
|
||||||
|
return ( *it )->geometry();
|
||||||
|
}
|
||||||
|
return QgsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
void QgsExpressionContext::setFields( const QgsFields &fields )
|
void QgsExpressionContext::setFields( const QgsFields &fields )
|
||||||
{
|
{
|
||||||
if ( mStack.isEmpty() )
|
if ( mStack.isEmpty() )
|
||||||
|
@ -326,6 +326,39 @@ class CORE_EXPORT QgsExpressionContextScope
|
|||||||
*/
|
*/
|
||||||
void removeFeature() { mHasFeature = false; mFeature = QgsFeature(); }
|
void removeFeature() { mHasFeature = false; mFeature = QgsFeature(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the scope has a geometry associated with it.
|
||||||
|
* \see geometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
bool hasGeometry() const { return mHasGeometry; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the geometry associated with the scope.
|
||||||
|
* \see setGeometry()
|
||||||
|
* \see hasGeometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
QgsGeometry geometry() const { return mGeometry; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for setting a \a geometry for the scope. Any existing
|
||||||
|
* geometry set by the scope will be overwritten.
|
||||||
|
|
||||||
|
* \see removeGeometry()
|
||||||
|
* \see geometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
void setGeometry( const QgsGeometry &geometry ) { mHasGeometry = true; mGeometry = geometry; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any geometry associated with the scope.
|
||||||
|
* \see setGeometry()
|
||||||
|
* \see hasGeometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
void removeGeometry() { mHasGeometry = false; mGeometry = QgsGeometry(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function for setting a fields for the scope. Any existing
|
* Convenience function for setting a fields for the scope. Any existing
|
||||||
* fields set by the scope will be overwritten.
|
* fields set by the scope will be overwritten.
|
||||||
@ -353,6 +386,8 @@ class CORE_EXPORT QgsExpressionContextScope
|
|||||||
QHash<QString, QgsScopedExpressionFunction * > mFunctions;
|
QHash<QString, QgsScopedExpressionFunction * > mFunctions;
|
||||||
bool mHasFeature = false;
|
bool mHasFeature = false;
|
||||||
QgsFeature mFeature;
|
QgsFeature mFeature;
|
||||||
|
bool mHasGeometry = false;
|
||||||
|
QgsGeometry mGeometry;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -650,6 +685,30 @@ class CORE_EXPORT QgsExpressionContext
|
|||||||
*/
|
*/
|
||||||
QgsFeature feature() const;
|
QgsFeature feature() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for setting a \a geometry for the context. The geometry
|
||||||
|
* will be set within the last scope of the context, so will override any
|
||||||
|
* existing geometries within the context.
|
||||||
|
|
||||||
|
* \see geometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
void setGeometry( const QgsGeometry &geometry );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the context has a geometry associated with it.
|
||||||
|
* \see geometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
bool hasGeometry() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for retrieving the geometry for the context, if set.
|
||||||
|
* \see setGeometry()
|
||||||
|
* \since QGIS 3.24
|
||||||
|
*/
|
||||||
|
QgsGeometry geometry() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function for setting a fields for the context. The fields
|
* Convenience function for setting a fields for the context. The fields
|
||||||
* will be set within the last scope of the context, so will override any
|
* will be set within the last scope of the context, so will override any
|
||||||
|
@ -44,6 +44,7 @@ class TestQgsExpressionContext : public QObject
|
|||||||
void contextStackFunctions();
|
void contextStackFunctions();
|
||||||
void evaluate();
|
void evaluate();
|
||||||
void setFeature();
|
void setFeature();
|
||||||
|
void setGeometry();
|
||||||
void setFields();
|
void setFields();
|
||||||
void takeScopes();
|
void takeScopes();
|
||||||
void highlighted();
|
void highlighted();
|
||||||
@ -486,6 +487,35 @@ void TestQgsExpressionContext::setFeature()
|
|||||||
QCOMPARE( contextWithScope.feature().id(), 50LL );
|
QCOMPARE( contextWithScope.feature().id(), 50LL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsExpressionContext::setGeometry()
|
||||||
|
{
|
||||||
|
QgsGeometry g( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ) );
|
||||||
|
QgsExpressionContextScope scope;
|
||||||
|
scope.setGeometry( g );
|
||||||
|
QVERIFY( scope.hasGeometry() );
|
||||||
|
QCOMPARE( scope.geometry().asWkt(), QStringLiteral( "Point (1 2)" ) );
|
||||||
|
scope.removeGeometry();
|
||||||
|
QVERIFY( !scope.hasGeometry() );
|
||||||
|
QVERIFY( scope.geometry().isNull() );
|
||||||
|
|
||||||
|
//test setting a geometry in a context with no scopes
|
||||||
|
QgsExpressionContext emptyContext;
|
||||||
|
QVERIFY( !emptyContext.hasGeometry() );
|
||||||
|
QVERIFY( emptyContext.geometry().isNull() );
|
||||||
|
emptyContext.setGeometry( g );
|
||||||
|
//setGeometry should have created a scope
|
||||||
|
QCOMPARE( emptyContext.scopeCount(), 1 );
|
||||||
|
QVERIFY( emptyContext.hasGeometry() );
|
||||||
|
QCOMPARE( emptyContext.geometry().asWkt(), QStringLiteral( "Point (1 2)" ) );
|
||||||
|
|
||||||
|
QgsExpressionContext contextWithScope;
|
||||||
|
contextWithScope << new QgsExpressionContextScope();
|
||||||
|
contextWithScope.setGeometry( g );
|
||||||
|
QCOMPARE( contextWithScope.scopeCount(), 1 );
|
||||||
|
QVERIFY( contextWithScope.hasGeometry() );
|
||||||
|
QCOMPARE( contextWithScope.geometry().asWkt(), QStringLiteral( "Point (1 2)" ) );
|
||||||
|
}
|
||||||
|
|
||||||
void TestQgsExpressionContext::setFields()
|
void TestQgsExpressionContext::setFields()
|
||||||
{
|
{
|
||||||
QgsFields fields;
|
QgsFields fields;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user