"""Геометрические хелперы scraper_kit — чистая математика, без `app.*` / БД. Strangler-копия (#2133) bbox-констант/предикатов из `app.services.geocoder`, используемых скрапперами как ingest-guard (валидация координат detail-страниц перед записью). Здесь — только чистые функции; продуктовый geocoder (Nominatim / Yandex запросы, БД) НЕ копируется. """ from __future__ import annotations # ЕКБ bbox = (lat_min, lat_max, lon_min, lon_max). # TIGHT — центр агломерации; WIDE — с приграничьем, но всё ещё отсекает # Питер/Тюмень/Уфу (#1871). WIDE строго содержит TIGHT. EKB_BBOX_TIGHT = (56.65, 56.95, 60.40, 60.85) EKB_BBOX_WIDE = (56.6, 57.1, 60.3, 60.9) def is_within_ekb_bbox( lat: float, lon: float, bbox: tuple[float, float, float, float] = EKB_BBOX_TIGHT ) -> bool: """True если (lat, lon) внутри bbox (inclusive). bbox = (lat_min, lat_max, lon_min, lon_max).""" lat_min, lat_max, lon_min, lon_max = bbox return lat_min <= lat <= lat_max and lon_min <= lon <= lon_max def is_within_ekb_bbox_wide(lat: float, lon: float) -> bool: """Ingest-guard: True если координаты в широком ЕКБ-bbox (#1871). Используется для валидации координат из avito detail-страниц перед записью в БД. Шире geocoder-tight, поэтому не режет легитимное приграничье, но отсекает не-ЕКБ (Питер/Тюмень/Уфа). """ return is_within_ekb_bbox(lat, lon, EKB_BBOX_WIDE)