double QgsMapTool::searchRadiusMU( QgsMapCanvas * canvas ) { if ( !canvas ) { return 0; } QgsMapSettings mapSettings = canvas->mapSettings(); QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings ); return searchRadiusMU( context ); }
bool QgsMapToolIdentify::identifyVectorLayer( QList<IdentifyResult> *results, QgsVectorLayer *layer, const QgsPoint& point ) { if ( !layer || !layer->hasGeometryType() ) return false; if ( layer->hasScaleBasedVisibility() && ( layer->minimumScale() > mCanvas->mapSettings().scale() || layer->maximumScale() <= mCanvas->mapSettings().scale() ) ) { QgsDebugMsg( "Out of scale limits" ); return false; } QApplication::setOverrideCursor( Qt::WaitCursor ); QMap< QString, QString > commonDerivedAttributes; commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() ); int featureCount = 0; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } QgsFeatureList::iterator f_it = featureList.begin(); bool filter = false; QgsRenderContext context( QgsRenderContext::fromMapSettings( mCanvas->mapSettings() ) ); context.expressionContext() << QgsExpressionContextUtils::layerScope( layer ); QgsFeatureRendererV2* renderer = layer->rendererV2(); if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent ) { // setup scale for scale dependent visibility (rule based) renderer->startRender( context, layer->fields() ); filter = renderer->capabilities() & QgsFeatureRendererV2::Filter; } for ( ; f_it != featureList.end(); ++f_it ) { QMap< QString, QString > derivedAttributes = commonDerivedAttributes; QgsFeatureId fid = f_it->id(); context.expressionContext().setFeature( *f_it ); if ( filter && !renderer->willRenderFeature( *f_it, context ) ) continue; featureCount++; derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) ); derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) ); results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) ); } if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent ) { renderer->stopRender( context ); } QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) ); QApplication::restoreOverrideCursor(); return featureCount > 0; }
bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y ) { if ( !layer ) return false; QgsPoint point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); QgsFeatureList featList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featList << QgsFeature( f ); } catch ( QgsCsException & cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } if ( featList.size() == 0 ) return false; Q_FOREACH ( const QgsFeature& feat, featList ) { if ( layer->actions()->defaultAction() >= 0 ) { // define custom substitutions: layer id and clicked coords QMap<QString, QVariant> substitutionMap; substitutionMap.insert( "$layerid", layer->id() ); point = toLayerCoordinates( layer, point ); substitutionMap.insert( "$clickx", point.x() ); substitutionMap.insert( "$clicky", point.y() ); int actionIdx = layer->actions()->defaultAction(); layer->actions()->doAction( actionIdx, feat, &substitutionMap ); } else { QgsMapLayerAction* mapLayerAction = QgsMapLayerActionRegistry::instance()->defaultActionForLayer( layer ); if ( mapLayerAction ) { mapLayerAction->triggerForFeature( layer, &feat ); } } } return true; }
bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y ) { if ( !layer ) return false; QgsPointXY point = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y ); QgsRectangle r; // create the search rectangle double searchRadius = searchRadiusMU( mCanvas ); r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { r = toLayerCoordinates( layer, r ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and proceed with no features found QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) ); } QgsAction defaultAction = layer->actions()->defaultAction( QStringLiteral( "Canvas" ) ); QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature feat; while ( fit.nextFeature( feat ) ) { if ( defaultAction.isValid() ) { // define custom substitutions: layer id and clicked coords QgsExpressionContext context; context << QgsExpressionContextUtils::globalScope() << QgsExpressionContextUtils::projectScope( QgsProject::instance() ) << QgsExpressionContextUtils::mapSettingsScope( mCanvas->mapSettings() ); QgsExpressionContextScope *actionScope = new QgsExpressionContextScope(); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "click_x" ), point.x(), true ) ); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "click_y" ), point.y(), true ) ); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), QStringLiteral( "Canvas" ), true ) ); context << actionScope; defaultAction.run( layer, feat, context ); } else { QgsMapLayerAction *mapLayerAction = QgsGui::mapLayerActionRegistry()->defaultActionForLayer( layer ); if ( mapLayerAction ) { mapLayerAction->triggerForFeature( layer, &feat ); } } } return true; }
double QgsQuickIdentifyKit::searchRadiusMU() const { QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings->mapSettings() ); return searchRadiusMU( context ); }
QgsFeatureList QgsQuickIdentifyKit::identifyVectorLayer( QgsVectorLayer *layer, const QgsPointXY &point ) const { QgsFeatureList results; if ( !layer || !layer->isSpatial() ) return results; if ( !layer->isInScaleRange( mMapSettings->mapSettings().scale() ) ) return results; QgsFeatureList featureList; // toLayerCoordinates will throw an exception for an 'invalid' point. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. try { // create the search rectangle double searchRadius = searchRadiusMU(); QgsRectangle r; r.setXMinimum( point.x() - searchRadius ); r.setXMaximum( point.x() + searchRadius ); r.setYMinimum( point.y() - searchRadius ); r.setYMaximum( point.y() + searchRadius ); r = toLayerCoordinates( layer, r ); QgsFeatureRequest req; req.setFilterRect( r ); req.setLimit( mFeaturesLimit ); req.setFlags( QgsFeatureRequest::ExactIntersect ); QgsFeatureIterator fit = layer->getFeatures( req ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } catch ( QgsCsException &cse ) { QgsDebugMsg( QStringLiteral( "Invalid point, proceed without a found features." ) ); Q_UNUSED( cse ); } bool filter = false; QgsRenderContext context( QgsRenderContext::fromMapSettings( mMapSettings->mapSettings() ) ); context.expressionContext() << QgsExpressionContextUtils::layerScope( layer ); QgsFeatureRenderer *renderer = layer->renderer(); if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { // setup scale for scale dependent visibility (rule based) renderer->startRender( context, layer->fields() ); filter = renderer->capabilities() & QgsFeatureRenderer::Filter; } for ( const QgsFeature &feature : featureList ) { context.expressionContext().setFeature( feature ); if ( filter && !renderer->willRenderFeature( const_cast<QgsFeature &>( feature ), context ) ) continue; results.append( feature ); } if ( renderer && renderer->capabilities() & QgsFeatureRenderer::ScaleDependent ) { renderer->stopRender( context ); } return results; }