@@ -76,6 +76,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
76
76
addAlgorithm ( new QgsMinimumEnclosingCircleAlgorithm () );
77
77
addAlgorithm ( new QgsConvexHullAlgorithm () );
78
78
addAlgorithm ( new QgsPromoteToMultipartAlgorithm () );
79
+ addAlgorithm ( new QgsSelectByLocationAlgorithm () );
79
80
}
80
81
81
82
void QgsCentroidAlgorithm::initAlgorithm ( const QVariantMap & )
@@ -1337,8 +1338,184 @@ QgsCollectAlgorithm *QgsCollectAlgorithm::createInstance() const
1337
1338
return new QgsCollectAlgorithm ();
1338
1339
}
1339
1340
1340
- // /@endcond
1341
1341
1342
1342
1343
+ void QgsSelectByLocationAlgorithm::initAlgorithm ( const QVariantMap & )
1344
+ {
1345
+ QStringList predicates = QStringList () << QObject::tr ( " intersects" )
1346
+ << QObject::tr ( " contains" )
1347
+ << QObject::tr ( " is disjoint" )
1348
+ << QObject::tr ( " equals" )
1349
+ << QObject::tr ( " touches" )
1350
+ << QObject::tr ( " overlaps" )
1351
+ << QObject::tr ( " within" )
1352
+ << QObject::tr ( " crosses" );
1353
+
1354
+ QStringList methods = QStringList () << QObject::tr ( " creating new selection" )
1355
+ << QObject::tr ( " adding to current selection" )
1356
+ << QObject::tr ( " select within current selection" )
1357
+ << QObject::tr ( " removing from current selection" );
1358
+
1359
+ addParameter ( new QgsProcessingParameterVectorLayer ( QStringLiteral ( " INPUT" ), QObject::tr ( " Select features from" ),
1360
+ QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
1361
+
1362
+
1363
+ addParameter ( new QgsProcessingParameterEnum ( QStringLiteral ( " PREDICATE" ),
1364
+ QObject::tr ( " Where the features are (geometric predicate)" ),
1365
+ predicates, true , QVariant::fromValue ( QList< int >() << 0 ) ) );
1366
+
1367
+ addParameter ( new QgsProcessingParameterFeatureSource ( QStringLiteral ( " INTERSECT" ),
1368
+ QObject::tr ( " By comparing to the features from" ),
1369
+ QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
1370
+
1371
+ addParameter ( new QgsProcessingParameterEnum ( QStringLiteral ( " METHOD" ),
1372
+ QObject::tr ( " Modify current selection by" ),
1373
+ methods, false , 0 ) );
1374
+ }
1375
+
1376
+ QString QgsSelectByLocationAlgorithm::shortHelpString () const
1377
+ {
1378
+ return QObject::tr ( " This algorithm creates a selection in a vector layer. The criteria for selecting "
1379
+ " features is based on the spatial relationship between each feature and the features in an additional layer." );
1380
+ }
1381
+
1382
+ QgsSelectByLocationAlgorithm *QgsSelectByLocationAlgorithm::createInstance () const
1383
+ {
1384
+ return new QgsSelectByLocationAlgorithm ();
1385
+ }
1386
+
1387
+ QVariantMap QgsSelectByLocationAlgorithm::processAlgorithm ( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
1388
+ {
1389
+ QgsVectorLayer *selectLayer = parameterAsVectorLayer ( parameters, QStringLiteral ( " INPUT" ), context );
1390
+ QgsVectorLayer::SelectBehavior method = static_cast < QgsVectorLayer::SelectBehavior >( parameterAsEnum ( parameters, QStringLiteral ( " METHOD" ), context ) );
1391
+ QgsFeatureSource *intersectSource = parameterAsSource ( parameters, QStringLiteral ( " INTERSECT" ), context );
1392
+ const QList< int > selectedPredicates = parameterAsEnums ( parameters, QStringLiteral ( " PREDICATE" ), context );
1393
+
1394
+ // build a list of 'reversed' predicates, because in this function
1395
+ // we actually test the reverse of what the user wants (allowing us
1396
+ // to prepare geometries and optimise the algorithm)
1397
+ QList< Predicate > predicates;
1398
+ for ( int i : selectedPredicates )
1399
+ {
1400
+ predicates << reversePredicate ( static_cast < Predicate >( i ) );
1401
+ }
1402
+
1403
+ QgsFeatureIds disjointSet;
1404
+ if ( predicates.contains ( Disjoint ) )
1405
+ disjointSet = selectLayer->allFeatureIds ();
1406
+
1407
+ QgsFeatureIds selectedSet;
1408
+ QgsFeatureRequest request = QgsFeatureRequest ().setSubsetOfAttributes ( QgsAttributeList () ).setDestinationCrs ( selectLayer->crs () );
1409
+ QgsFeatureIterator fIt = intersectSource->getFeatures ( request );
1410
+ double step = intersectSource->featureCount () > 0 ? 100.0 / intersectSource->featureCount () : 1 ;
1411
+ int current = 0 ;
1412
+ QgsFeature f;
1413
+ while ( fIt .nextFeature ( f ) )
1414
+ {
1415
+ if ( feedback->isCanceled () )
1416
+ break ;
1417
+
1418
+ if ( !f.hasGeometry () )
1419
+ continue ;
1420
+
1421
+ std::unique_ptr< QgsGeometryEngine > engine ( QgsGeometry::createGeometryEngine ( f.geometry ().geometry () ) );
1422
+ engine->prepareGeometry ();
1423
+ QgsRectangle bbox = f.geometry ().boundingBox ();
1424
+
1425
+ request = QgsFeatureRequest ().setFlags ( QgsFeatureRequest::NoGeometry ).setFilterRect ( bbox ).setSubsetOfAttributes ( QgsAttributeList () );
1426
+ QgsFeatureIterator testFeatureIt = selectLayer->getFeatures ( request );
1427
+ QgsFeature testFeature;
1428
+ while ( testFeatureIt.nextFeature ( testFeature ) )
1429
+ {
1430
+ if ( feedback->isCanceled () )
1431
+ break ;
1432
+
1433
+ if ( selectedSet.contains ( testFeature.id () ) )
1434
+ {
1435
+ // already added this one, no need for further tests
1436
+ continue ;
1437
+ }
1438
+
1439
+ for ( Predicate predicate : qgsAsConst ( predicates ) )
1440
+ {
1441
+ bool isMatch = false ;
1442
+ switch ( predicate )
1443
+ {
1444
+ case Intersects:
1445
+ isMatch = engine->intersects ( testFeature.geometry ().geometry () );
1446
+ break ;
1447
+ case Contains:
1448
+ isMatch = engine->contains ( testFeature.geometry ().geometry () );
1449
+ break ;
1450
+ case Disjoint:
1451
+ if ( engine->intersects ( testFeature.geometry ().geometry () ) )
1452
+ {
1453
+ disjointSet.remove ( testFeature.id () );
1454
+ }
1455
+ break ;
1456
+ case IsEqual:
1457
+ isMatch = engine->isEqual ( testFeature.geometry ().geometry () );
1458
+ break ;
1459
+ case Touches:
1460
+ isMatch = engine->touches ( testFeature.geometry ().geometry () );
1461
+ break ;
1462
+ case Overlaps:
1463
+ isMatch = engine->overlaps ( testFeature.geometry ().geometry () );
1464
+ break ;
1465
+ case Within:
1466
+ isMatch = engine->within ( testFeature.geometry ().geometry () );
1467
+ break ;
1468
+ case Crosses:
1469
+ isMatch = engine->crosses ( testFeature.geometry ().geometry () );
1470
+ break ;
1471
+ }
1472
+ if ( isMatch )
1473
+ selectedSet.insert ( testFeature.id () );
1474
+ }
1475
+
1476
+ }
1477
+
1478
+ feedback->setProgress ( int ( current * step ) );
1479
+ }
1480
+
1481
+ if ( predicates.contains ( Disjoint ) )
1482
+ {
1483
+ selectedSet = selectedSet.unite ( disjointSet );
1484
+ }
1485
+
1486
+ selectLayer->selectByIds ( selectedSet, method );
1487
+ QVariantMap results;
1488
+ results.insert ( QStringLiteral ( " OUTPUT" ), parameters.value ( QStringLiteral ( " INPUT" ) ) );
1489
+ return results;
1490
+ }
1491
+
1492
+ QgsSelectByLocationAlgorithm::Predicate QgsSelectByLocationAlgorithm::reversePredicate ( QgsSelectByLocationAlgorithm::Predicate predicate ) const
1493
+ {
1494
+ switch ( predicate )
1495
+ {
1496
+ case Intersects:
1497
+ return Intersects;
1498
+ case Contains:
1499
+ return Within;
1500
+ case Disjoint:
1501
+ return Disjoint;
1502
+ case IsEqual:
1503
+ return IsEqual;
1504
+ case Touches:
1505
+ return Touches;
1506
+ case Overlaps:
1507
+ return Overlaps;
1508
+ case Within:
1509
+ return Contains;
1510
+ case Crosses:
1511
+ return Crosses;
1512
+ }
1513
+ // no warnings
1514
+ return Intersects;
1515
+ }
1516
+
1517
+
1518
+
1519
+ // /@endcond
1343
1520
1344
1521
0 commit comments