Source code for sec_interp.core.utils.geometry_utils.filtering

from __future__ import annotations

"""Geometry filtering utilities."""

from qgis.core import (
    QgsCoordinateReferenceSystem,
    QgsCoordinateTransform,
    QgsFeature,
    QgsFeatureRequest,
    QgsGeometry,
    QgsProject,
    QgsVectorLayer,
)

from sec_interp.logger_config import get_logger

logger = get_logger(__name__)


[docs] def filter_features_by_buffer( features_layer: QgsVectorLayer, buffer_geometry: QgsGeometry, buffer_crs: QgsCoordinateReferenceSystem | None = None, ) -> list[QgsFeature]: """Filter features that intersect with buffer using spatial index. Args: features_layer: Layer containing features to filter. buffer_geometry: Buffer geometry to use for spatial filter. buffer_crs: CRS of the buffer geometry (optional). Returns: List of QgsFeature objects that intersect the query buffer. """ if not features_layer or not features_layer.isValid(): raise ValueError("Invalid features layer") if not buffer_geometry or buffer_geometry.isNull(): raise ValueError("Invalid buffer geometry") # 1. Transform buffer geometry if needed query_geom = buffer_geometry if buffer_crs and features_layer.crs() != buffer_crs: transform = QgsCoordinateTransform(buffer_crs, features_layer.crs(), QgsProject.instance()) query_geom = QgsGeometry(buffer_geometry) query_geom.transform(transform) # 2. Get candidates using Bounding Box (Provider side filter) # This uses the provider's spatial index directly, avoiding O(N) index build request = QgsFeatureRequest().setFilterRect(query_geom.boundingBox()) # 3. Precise filtering filtered_features = [] for feature in features_layer.getFeatures(request): if feature.hasGeometry() and feature.geometry().intersects(query_geom): filtered_features.append(feature) logger.debug(f"Spatial Filter: confirmed {len(filtered_features)} features intersecting buffer") return filtered_features