feat(nspd): get_feature_info FEATURE_COUNT=10 — multi-feature per point (#1080)
get_feature_info() шлёт WMS FEATURE_COUNT=10 (новый параметр feature_count, default 10). NSPD по умолчанию отдаёт 1 фичу/точку → перекрывающиеся зоны одного слоя теряются (37581 «иные ЗОУИТ» на ЕКБ = 2 фичи). Tile-геометрия не тронута. +2 теста (multi-feature parse, override), существующий обновлён. Refs #1067. Co-authored-by: lekss361 <lekss361@gendsgn.local> Co-committed-by: lekss361 <lekss361@gendsgn.local>
This commit is contained in:
parent
22fffb9878
commit
c2e0428803
2 changed files with 49 additions and 1 deletions
|
|
@ -370,13 +370,21 @@ class NSPDClient:
|
|||
lon: float,
|
||||
lat: float,
|
||||
buffer_m: int = 100,
|
||||
feature_count: int = 10,
|
||||
) -> list[NSPDFeature]:
|
||||
"""WMS GetFeatureInfo на точке — какие feature'ы layer'а покрывают (lon, lat).
|
||||
|
||||
Использует микро-bbox вокруг точки в EPSG:3857 (WMS требует bbox + I/J
|
||||
пиксель). Tile 256x256, I=128, J=128 — центр.
|
||||
|
||||
Returns features (может быть 0+).
|
||||
Args:
|
||||
feature_count: макс. число фич в ответе (WMS FEATURE_COUNT). Default 10
|
||||
(паритет с порталом nspd.gov.ru). Без него NSPD по умолчанию отдаёт
|
||||
ТОЛЬКО 1 фичу на точку — а на ЕКБ в одной точке часто пересекаются
|
||||
несколько зон одного слоя (напр. 37581 «иные ЗОУИТ» вернул 2). Для
|
||||
overlay-ингеста (#1067) нужно >1.
|
||||
|
||||
Returns features (может быть 0+, до feature_count).
|
||||
|
||||
Use cases:
|
||||
- ВРИ конкретного участка (layer_id=875838 territorial_zones)
|
||||
|
|
@ -393,6 +401,9 @@ class NSPDClient:
|
|||
"QUERY_LAYERS": str(layer_id),
|
||||
"LAYERS": str(layer_id),
|
||||
"INFO_FORMAT": "application/json",
|
||||
# FEATURE_COUNT: NSPD по умолчанию отдаёт 1 фичу/точку → теряем
|
||||
# перекрывающиеся зоны. Портал шлёт 10. Без этого overlay-ингест неполон.
|
||||
"FEATURE_COUNT": str(feature_count),
|
||||
# STYLES обязателен (пустой), иначе INFO_FORMAT игнорируется per NSPD WAF
|
||||
"STYLES": "",
|
||||
"I": "128",
|
||||
|
|
|
|||
|
|
@ -232,10 +232,47 @@ def test_get_feature_info_parses_response(monkeypatch: pytest.MonkeyPatch) -> No
|
|||
assert "INFO_FORMAT=application%2Fjson" in url
|
||||
assert "STYLES=" in url # required per NSPD WAF
|
||||
assert "CRS=EPSG%3A3857" in url
|
||||
assert "FEATURE_COUNT=10" in url # default >1 — иначе NSPD отдаёт 1 фичу/точку
|
||||
# bbox should reflect 100m buffer (200m side)
|
||||
assert "BBOX=" in url
|
||||
|
||||
|
||||
def test_get_feature_info_returns_multiple_overlapping_features(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""FEATURE_COUNT>1 → несколько перекрывающихся зон в одной точке (как 37581 на ЕКБ)."""
|
||||
captured_urls: list[str] = []
|
||||
|
||||
def fake_http(url: str, **kwargs: Any) -> dict[str, Any]:
|
||||
captured_urls.append(url)
|
||||
return {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{"id": "z1", "properties": {"reg_numb_border": "66:41-6.4125"}},
|
||||
{"id": "z2", "properties": {"reg_numb_border": "66:41-6.914"}},
|
||||
],
|
||||
}
|
||||
|
||||
monkeypatch.setattr("app.services.scrapers.nspd_client._http_get_json", fake_http)
|
||||
feats = NSPDClient().get_feature_info(37581, lon=60.576, lat=56.839, feature_count=10)
|
||||
assert len(feats) == 2
|
||||
assert {f.properties["reg_numb_border"] for f in feats} == {"66:41-6.4125", "66:41-6.914"}
|
||||
assert "FEATURE_COUNT=10" in captured_urls[0]
|
||||
|
||||
|
||||
def test_get_feature_info_custom_feature_count(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""feature_count прокидывается в URL (override default)."""
|
||||
captured_urls: list[str] = []
|
||||
|
||||
def fake_http(url: str, **kwargs: Any) -> dict[str, Any]:
|
||||
captured_urls.append(url)
|
||||
return {"features": []}
|
||||
|
||||
monkeypatch.setattr("app.services.scrapers.nspd_client._http_get_json", fake_http)
|
||||
NSPDClient().get_feature_info(875838, lon=60.605, lat=56.838, feature_count=25)
|
||||
assert "FEATURE_COUNT=25" in captured_urls[0]
|
||||
|
||||
|
||||
def test_get_features_in_bbox_url_builds_correctly(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""get_features_in_bbox использует переданный bbox без преобразования."""
|
||||
captured_urls: list[str] = []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue