Skip to content

Commit

Permalink
[FEATURE] Add snapping results to default value calculation
Browse files Browse the repository at this point in the history
... as @snapping_results variable
  • Loading branch information
m-kuhn committed Jul 7, 2017
1 parent a8cceff commit 9581fe0
Show file tree
Hide file tree
Showing 15 changed files with 120 additions and 13 deletions.
2 changes: 1 addition & 1 deletion python/core/geometry/qgscompoundcurve.sip
Expand Up @@ -77,7 +77,7 @@ class QgsCompoundCurve: QgsCurve

void addCurve( QgsCurve *c /Transfer/ );
%Docstring
Adds a curve to the geometr (takes ownership)
Adds a curve to the geometry (takes ownership)
%End

void removeCurve( int i );
Expand Down
9 changes: 9 additions & 0 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -809,6 +809,15 @@ class QgsExpressionContextUtils
:rtype: QgsExpressionContextScope
%End

static QgsExpressionContextScope *mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches ) /Factory/;
%Docstring
Sets the expression context variables which are available for expressions triggered by
a map tool capture like add feature.

.. versionadded:: 3.0
:rtype: QgsExpressionContextScope
%End

static QgsExpressionContextScope *updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope = 0 );
%Docstring
Updates a symbol scope related to a QgsSymbol to an expression context.
Expand Down
8 changes: 8 additions & 0 deletions python/gui/qgsmaptoolcapture.sip
Expand Up @@ -42,6 +42,14 @@ Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be
:rtype: QgsCompoundCurve
%End

QList<QgsPointLocator::Match> snappingMatches() const;
%Docstring
Return a list of matches for each point on the captureCurve.

.. versionadded:: 3.0
:rtype: list of QgsPointLocator.Match
%End

virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e );

virtual void keyPressEvent( QKeyEvent *e );
Expand Down
14 changes: 14 additions & 0 deletions src/app/qgsattributetypedialog.cpp
Expand Up @@ -71,6 +71,8 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx
isFieldEditableCheckBox->setEnabled( false );
}

mExpressionWidget->registerExpressionContextGenerator( this );

connect( mExpressionWidget, &QgsExpressionLineEdit::expressionChanged, this, &QgsAttributeTypeDialog::defaultExpressionChanged );
connect( mUniqueCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
Expand Down Expand Up @@ -293,6 +295,18 @@ void QgsAttributeTypeDialog::setDefaultValueExpression( const QString &expressio
mExpressionWidget->setExpression( expression );
}

QgsExpressionContext QgsAttributeTypeDialog::createExpressionContext() const
{
QgsExpressionContext context;
context
<< QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
<< QgsExpressionContextUtils::layerScope( mLayer )
<< QgsExpressionContextUtils::mapToolCaptureScope( QList<QgsPointLocator::Match>() );

return context;
}

QString QgsAttributeTypeDialog::constraintExpression() const
{
return constraintExpressionWidget->asExpression();
Expand Down
4 changes: 3 additions & 1 deletion src/app/qgsattributetypedialog.h
Expand Up @@ -26,7 +26,7 @@

class QDialog;

class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog
class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog, QgsExpressionContextGenerator
{
Q_OBJECT

Expand Down Expand Up @@ -163,6 +163,8 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
*/
void setDefaultValueExpression( const QString &expression );

QgsExpressionContext createExpressionContext() const override;

private slots:

/**
Expand Down
5 changes: 4 additions & 1 deletion src/app/qgsfeatureaction.cpp
Expand Up @@ -161,7 +161,7 @@ bool QgsFeatureAction::editFeature( bool showModal )
return true;
}

bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, bool showModal )
bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, bool showModal, QgsExpressionContextScope *scope SIP_TRANSFER )
{
if ( !mLayer || !mLayer->isEditable() )
return false;
Expand All @@ -188,6 +188,9 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, boo
// create new feature template - this will initialize the attributes to valid values, handling default
// values and field constraints
QgsExpressionContext context = mLayer->createExpressionContext();
if ( scope )
context.appendScope( scope );

QgsFeature newFeature = QgsVectorLayerUtils::createFeature( mLayer, mFeature->geometry(), initialAttributeValues,
&context );
*mFeature = newFeature;
Expand Down
3 changes: 2 additions & 1 deletion src/app/qgsfeatureaction.h
Expand Up @@ -29,6 +29,7 @@ class QgsIdentifyResultsDialog;
class QgsVectorLayer;
class QgsHighlight;
class QgsAttributeDialog;
class QgsExpressionContextScope;

class APP_EXPORT QgsFeatureAction : public QAction
{
Expand All @@ -51,7 +52,7 @@ class APP_EXPORT QgsFeatureAction : public QAction
*
* \returns true if feature was added if showModal is true. If showModal is false, returns true in every case
*/
bool addFeature( const QgsAttributeMap &defaultAttributes = QgsAttributeMap(), bool showModal = true );
bool addFeature( const QgsAttributeMap &defaultAttributes = QgsAttributeMap(), bool showModal = true, QgsExpressionContextScope *scope = nullptr );

private slots:
void onFeatureSaved( const QgsFeature &feature );
Expand Down
15 changes: 8 additions & 7 deletions src/app/qgsmaptooladdfeature.cpp
Expand Up @@ -48,8 +48,9 @@ QgsMapToolAddFeature::~QgsMapToolAddFeature()

bool QgsMapToolAddFeature::addFeature( QgsVectorLayer *vlayer, QgsFeature *f, bool showModal )
{
QgsExpressionContextScope *scope = QgsExpressionContextUtils::mapToolCaptureScope( snappingMatches() );
QgsFeatureAction *action = new QgsFeatureAction( tr( "add feature" ), *f, vlayer, QString(), -1, this );
bool res = action->addFeature( QgsAttributeMap(), showModal );
bool res = action->addFeature( QgsAttributeMap(), showModal, scope );
if ( showModal )
delete action;
return res;
Expand Down Expand Up @@ -250,6 +251,7 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
bool hasCurvedSegments = captureCurve()->hasCurvedSegments();
bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries;

QList<QgsPointLocator::Match> snappingMatchesList;
QgsCurve *curveToAdd = nullptr;
if ( hasCurvedSegments && providerSupportsCurvedSegments )
{
Expand All @@ -258,13 +260,13 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
else
{
curveToAdd = captureCurve()->curveToLine();
snappingMatchesList = snappingMatches();
}

if ( mode() == CaptureLine )
{
QgsGeometry *g = new QgsGeometry( curveToAdd );
f->setGeometry( *g );
delete g;
QgsGeometry g( curveToAdd );
f->setGeometry( g );
}
else
{
Expand All @@ -278,9 +280,8 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
poly = new QgsPolygonV2();
}
poly->setExteriorRing( curveToAdd );
QgsGeometry *g = new QgsGeometry( poly );
f->setGeometry( *g );
delete g;
QgsGeometry g( poly );
f->setGeometry( g );

QgsGeometry featGeom = f->geometry();
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
Expand Down
1 change: 0 additions & 1 deletion src/app/qgsmaptooladdfeature.h
Expand Up @@ -44,7 +44,6 @@ class APP_EXPORT QgsMapToolAddFeature : public QgsMapToolCapture
void setCheckGeometryType( bool checkGeometryType );

private:
QVariant snappingMatchesAsVariable() const;

/** Check if CaptureMode matches layer type. Default is true.
* \since QGIS 2.12 */
Expand Down
13 changes: 13 additions & 0 deletions src/core/expression/qgsexpression.cpp
Expand Up @@ -673,6 +673,19 @@ void QgsExpression::initVariableHelp()
sVariableHelpTexts.insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
sVariableHelpTexts.insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );

// map tool capture variables
sVariableHelpTexts.insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
"<p>An array with an item for each snapped point.</p>"
"<p>Each item is a map with the following keys:</p>"
"<dl>"
"<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
"<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
"<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
"<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
"<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
"</dl>" ) );


//symbol variables
sVariableHelpTexts.insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
sVariableHelpTexts.insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgscompoundcurve.h
Expand Up @@ -74,7 +74,7 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve
*/
const QgsCurve *curveAt( int i ) const;

/** Adds a curve to the geometr (takes ownership)
/** Adds a curve to the geometry (takes ownership)
*/
void addCurve( QgsCurve *c SIP_TRANSFER );

Expand Down
24 changes: 24 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -912,6 +912,30 @@ QgsExpressionContextScope *QgsExpressionContextUtils::mapSettingsScope( const Qg
return scope;
}

QgsExpressionContextScope *QgsExpressionContextUtils::mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches )
{
QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Map Tool Capture" ) );

QVariantList matchList;

for ( const QgsPointLocator::Match &match : matches )
{
QVariantMap matchMap;

matchMap.insert( QStringLiteral( "valid" ), match.isValid() );
matchMap.insert( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( match.layer() ) ) );
matchMap.insert( QStringLiteral( "feature_id" ), match.featureId() );
matchMap.insert( QStringLiteral( "vertex_index" ), match.vertexIndex() );
matchMap.insert( QStringLiteral( "distance" ), match.distance() );

matchList.append( matchMap );
}

scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "snapping_results" ), matchList ) );

return scope;
}

QgsExpressionContextScope *QgsExpressionContextUtils::updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope )
{
if ( !symbolScope )
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -26,6 +26,7 @@
#include "qgsfeature.h"
#include "qgsexpression.h"
#include "qgsexpressionfunction.h"
#include "qgspointlocator.h"

class QgsExpression;
class QgsExpressionNodeFunction;
Expand Down Expand Up @@ -743,6 +744,14 @@ class CORE_EXPORT QgsExpressionContextUtils
*/
static QgsExpressionContextScope *mapSettingsScope( const QgsMapSettings &mapSettings ) SIP_FACTORY;

/**
* Sets the expression context variables which are available for expressions triggered by
* a map tool capture like add feature.
*
* \since QGIS 3.0
*/
static QgsExpressionContextScope *mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches ) SIP_FACTORY;

/**
* Updates a symbol scope related to a QgsSymbol to an expression context.
* \param symbol symbol to extract properties from
Expand Down
15 changes: 15 additions & 0 deletions src/gui/qgsmaptoolcapture.cpp
Expand Up @@ -222,6 +222,7 @@ bool QgsMapToolCapture::tracingAddVertex( const QgsPointXY &point )

mRubberBand->addPoint( point );
mCaptureCurve.addVertex( layerPoint );
mSnappingMatches.append( QgsPointLocator::Match() );
}
return res;
}
Expand Down Expand Up @@ -251,6 +252,7 @@ bool QgsMapToolCapture::tracingAddVertex( const QgsPointXY &point )
continue; // avoid duplicate vertices if there are any
mRubberBand->addPoint( points[i], i == points.count() - 1 );
mCaptureCurve.addVertex( layerPoints[i - 1] );
mSnappingMatches.append( QgsPointLocator::Match() );
}

tracer->reportError( QgsTracer::ErrNone, true ); // clear messagebar if there was any error
Expand Down Expand Up @@ -433,6 +435,7 @@ int QgsMapToolCapture::addVertex( const QgsPointXY &point, const QgsPointLocator
// ordinary digitizing
mRubberBand->addPoint( point );
mCaptureCurve.addVertex( layerPoint );
mSnappingMatches.append( match );
}

if ( mCaptureMode == CaptureLine )
Expand Down Expand Up @@ -493,10 +496,17 @@ int QgsMapToolCapture::addCurve( QgsCurve *c )
c->transform( ct, QgsCoordinateTransform::ReverseTransform );
}
mCaptureCurve.addCurve( c );
for ( int i = 0; i < c->length(); ++i )
mSnappingMatches.append( QgsPointLocator::Match() );

return 0;
}

QList<QgsPointLocator::Match> QgsMapToolCapture::snappingMatches() const
{
return mSnappingMatches;
}


void QgsMapToolCapture::undo()
{
Expand Down Expand Up @@ -531,6 +541,7 @@ void QgsMapToolCapture::undo()
vertexToRemove.ring = 0;
vertexToRemove.vertex = size() - 1;
mCaptureCurve.deleteVertex( vertexToRemove );
mSnappingMatches.removeAt( vertexToRemove.vertex );

validateGeometry();
}
Expand Down Expand Up @@ -599,6 +610,7 @@ void QgsMapToolCapture::stopCapturing()

mCapturing = false;
mCaptureCurve.clear();
mSnappingMatches.clear();
if ( currentVectorLayer() )
currentVectorLayer()->triggerRepaint();
}
Expand Down Expand Up @@ -717,6 +729,9 @@ void QgsMapToolCapture::setPoints( const QList<QgsPointXY> &pointList )
QgsLineString *line = new QgsLineString( pointList );
mCaptureCurve.clear();
mCaptureCurve.addCurve( line );
mSnappingMatches.clear();
for ( int i = 0; i < line->length(); ++i )
mSnappingMatches.append( QgsPointLocator::Match() );
}

#ifdef Q_OS_WIN
Expand Down
9 changes: 9 additions & 0 deletions src/gui/qgsmaptoolcapture.h
Expand Up @@ -56,6 +56,13 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
*/
const QgsCompoundCurve *captureCurve() const { return &mCaptureCurve; }

/**
* Return a list of matches for each point on the captureCurve.
*
* \since QGIS 3.0
*/
QList<QgsPointLocator::Match> snappingMatches() const;

virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override;

/**
Expand Down Expand Up @@ -193,6 +200,8 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
//! List to store the points of digitized lines and polygons (in layer coordinates)
QgsCompoundCurve mCaptureCurve;

QList<QgsPointLocator::Match> mSnappingMatches;

void validateGeometry();
QStringList mValidationWarnings;
QgsGeometryValidator *mValidator = nullptr;
Expand Down

0 comments on commit 9581fe0

Please sign in to comment.