mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -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`
|
||||
|
||||
.. 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
|
||||
|
||||
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.
|
||||
|
||||
.. 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
|
||||
|
||||
void setFields( const QgsFields &fields );
|
||||
|
@ -45,6 +45,8 @@ QgsExpressionContextScope::QgsExpressionContextScope( const QgsExpressionContext
|
||||
, mVariables( other.mVariables )
|
||||
, mHasFeature( other.mHasFeature )
|
||||
, mFeature( other.mFeature )
|
||||
, mHasGeometry( other.mHasGeometry )
|
||||
, mGeometry( other.mGeometry )
|
||||
{
|
||||
QHash<QString, QgsScopedExpressionFunction * >::const_iterator it = other.mFunctions.constBegin();
|
||||
for ( ; it != other.mFunctions.constEnd(); ++it )
|
||||
@ -59,6 +61,8 @@ QgsExpressionContextScope &QgsExpressionContextScope::operator=( const QgsExpres
|
||||
mVariables = other.mVariables;
|
||||
mHasFeature = other.mHasFeature;
|
||||
mFeature = other.mFeature;
|
||||
mHasGeometry = other.mHasGeometry;
|
||||
mGeometry = other.mGeometry;
|
||||
|
||||
qDeleteAll( mFunctions );
|
||||
mFunctions.clear();
|
||||
@ -529,8 +533,7 @@ void QgsExpressionContext::setFeature( const QgsFeature &feature )
|
||||
|
||||
bool QgsExpressionContext::hasFeature() const
|
||||
{
|
||||
const auto constMStack = mStack;
|
||||
for ( const QgsExpressionContextScope *scope : constMStack )
|
||||
for ( const QgsExpressionContextScope *scope : mStack )
|
||||
{
|
||||
if ( scope->hasFeature() )
|
||||
return true;
|
||||
@ -551,6 +554,37 @@ QgsFeature QgsExpressionContext::feature() const
|
||||
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 )
|
||||
{
|
||||
if ( mStack.isEmpty() )
|
||||
|
@ -326,6 +326,39 @@ class CORE_EXPORT QgsExpressionContextScope
|
||||
*/
|
||||
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
|
||||
* fields set by the scope will be overwritten.
|
||||
@ -353,6 +386,8 @@ class CORE_EXPORT QgsExpressionContextScope
|
||||
QHash<QString, QgsScopedExpressionFunction * > mFunctions;
|
||||
bool mHasFeature = false;
|
||||
QgsFeature mFeature;
|
||||
bool mHasGeometry = false;
|
||||
QgsGeometry mGeometry;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -650,6 +685,30 @@ class CORE_EXPORT QgsExpressionContext
|
||||
*/
|
||||
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
|
||||
* 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 evaluate();
|
||||
void setFeature();
|
||||
void setGeometry();
|
||||
void setFields();
|
||||
void takeScopes();
|
||||
void highlighted();
|
||||
@ -486,6 +487,35 @@ void TestQgsExpressionContext::setFeature()
|
||||
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()
|
||||
{
|
||||
QgsFields fields;
|
||||
|
Loading…
x
Reference in New Issue
Block a user