Compare commits
No commits in common. "e075f01870b6e1ebcaa85cc67c10493b5dbe403f" and "f826a37345761a6b57ff996e5b4b612136eaf95a" have entirely different histories.
e075f01870
...
f826a37345
1 changed files with 10 additions and 59 deletions
|
|
@ -7,7 +7,6 @@ Pure function — no DB dependencies, consumes already-fetched data from analyze
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
|
||||||
from typing import Literal, TypedDict
|
from typing import Literal, TypedDict
|
||||||
|
|
||||||
from app.services.site_finder.network_obremenenie import (
|
from app.services.site_finder.network_obremenenie import (
|
||||||
|
|
@ -17,28 +16,11 @@ from app.services.site_finder.network_obremenenie import (
|
||||||
|
|
||||||
# ── Zone matching ─────────────────────────────────────────────────────────────
|
# ── Zone matching ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
# Regex для zone_code из PKK6 / pzz_zones_ekb: "Ж", "Ж-1", "Жс", "ЖС-2" и т.д.
|
# Residential zone codes — точные ПЗЗ Свердловска (Ж-1..Ж-5)
|
||||||
# Кейс-инсенситив для защиты от "ж-1" в нестандартных источниках.
|
RESIDENTIAL_ZONE_PREFIXES = ("Ж-", "Ж1", "Ж2", "Ж3", "Ж4", "Ж5")
|
||||||
# NSPD quarter-dump в zone_code кладёт кадастровый рег.номер (напр. "66:41-7.14") —
|
# Fallback по zone_name (lowercase substring)
|
||||||
# он никогда не начинается на "Ж", поэтому этот regex не даст false positive.
|
|
||||||
_RESIDENTIAL_CODE_RE = re.compile(r"^[Жж]", re.UNICODE)
|
|
||||||
|
|
||||||
# Fallback по zone_name (lowercase substring) — "жилая", "жилой", "жилая зона" и т.д.
|
|
||||||
RESIDENTIAL_KEYWORDS = ("жил",)
|
RESIDENTIAL_KEYWORDS = ("жил",)
|
||||||
|
|
||||||
# NSPD territorial zones layer 875838: subcategory (int) → тип зоны.
|
|
||||||
# Значения получены из реальных данных nspd_quarter_dumps (ЕКБ, 2026-02):
|
|
||||||
# subcategory=1 — 39 объектов — Жилые зоны малоэтажной застройки (ИЖС/таунхаусы)
|
|
||||||
# subcategory=2 — 221 объект — Жилые зоны (МКД разрешён, крупнейшая группа ЕКБ)
|
|
||||||
# subcategory=3 — 126 объектов — Зоны смешанного использования (МКД по ПЗЗ ЕКБ допустим)
|
|
||||||
# subcategory=4 — 77 объектов — Общественно-деловые
|
|
||||||
# subcategory=5 — 112 объектов — Производственные
|
|
||||||
# subcategory=6 — 92 объекта — Рекреационные
|
|
||||||
# subcategory=8 — 16 объектов — Специальные
|
|
||||||
# subcategory=10 — 113 объектов — Промышленные/транспортные
|
|
||||||
# subcategory=1 исключён намеренно: ИЖС-зона МКД не допускает.
|
|
||||||
NSPD_RESIDENTIAL_SUBCATEGORIES: frozenset[int] = frozenset({2, 3})
|
|
||||||
|
|
||||||
# ── ЗОУИТ taxonomy ────────────────────────────────────────────────────────────
|
# ── ЗОУИТ taxonomy ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
# Subcategory codes которые блокируют МКД (охранные зоны ЛЭП/газа/трубопровода).
|
# Subcategory codes которые блокируют МКД (охранные зоны ЛЭП/газа/трубопровода).
|
||||||
|
|
@ -89,46 +71,19 @@ class GateVerdict(TypedDict):
|
||||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
def is_residential_zone(
|
def is_residential_zone(zone_code: str | None, zone_name: str | None) -> bool:
|
||||||
zone_code: str | None,
|
|
||||||
zone_name: str | None,
|
|
||||||
raw_props: dict | None = None,
|
|
||||||
) -> bool:
|
|
||||||
"""Check if ПЗЗ zone permits residential (МКД) building.
|
"""Check if ПЗЗ zone permits residential (МКД) building.
|
||||||
|
|
||||||
Detection strategy (in priority order):
|
Checks zone_code prefix first (exact ПЗЗ codes), then zone_name lowercase
|
||||||
|
substring match as fallback for non-standard zone labels.
|
||||||
1. zone_code regex «^Ж» — ПЗЗ коды PKK6/pzz_zones_ekb: "Ж-1", "Жс", "ЖС-2" и т.д.
|
|
||||||
NSPD quarter-dump кладёт в zone_code кадастровый рег.номер ("66:41-7.14") —
|
|
||||||
он не начинается на «Ж», ложных срабатываний нет.
|
|
||||||
|
|
||||||
2. NSPD subcategory из raw_props — единственный надёжный тип-дискриминатор в
|
|
||||||
реальных данных nspd_quarter_dumps (layer 875838, ЕКБ 2026-02):
|
|
||||||
subcategory=2 ("Жилые зоны") и subcategory=3 ("Смешанное использование")
|
|
||||||
допускают МКД по ПЗЗ ЕКБ. subcategory=1 (ИЖС) — намеренно исключён.
|
|
||||||
|
|
||||||
3. zone_name substring «жил» — fallback для нестандартных источников.
|
|
||||||
"""
|
"""
|
||||||
# 1. PKK6-style zone_code: starts with Ж (case-insensitive)
|
if zone_code:
|
||||||
if zone_code and _RESIDENTIAL_CODE_RE.match(zone_code):
|
if any(zone_code.startswith(p) for p in RESIDENTIAL_ZONE_PREFIXES):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 2. NSPD subcategory from raw_props (primary discriminator for quarter-dump data)
|
|
||||||
if raw_props:
|
|
||||||
sub_raw = raw_props.get("subcategory")
|
|
||||||
if sub_raw is not None:
|
|
||||||
try:
|
|
||||||
if int(sub_raw) in NSPD_RESIDENTIAL_SUBCATEGORIES:
|
|
||||||
return True
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 3. zone_name substring fallback
|
|
||||||
if zone_name:
|
if zone_name:
|
||||||
zn_lower = zone_name.lower()
|
zn_lower = zone_name.lower()
|
||||||
if any(kw in zn_lower for kw in RESIDENTIAL_KEYWORDS):
|
if any(kw in zn_lower for kw in RESIDENTIAL_KEYWORDS):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -179,11 +134,7 @@ def compute_gate_verdict(
|
||||||
# Check 1 — ПЗЗ residential zone
|
# Check 1 — ПЗЗ residential zone
|
||||||
checks.append("ПЗЗ зональность")
|
checks.append("ПЗЗ зональность")
|
||||||
if nspd_zoning:
|
if nspd_zoning:
|
||||||
if not is_residential_zone(
|
if not is_residential_zone(nspd_zoning.get("zone_code"), nspd_zoning.get("zone_name")):
|
||||||
nspd_zoning.get("zone_code"),
|
|
||||||
nspd_zoning.get("zone_name"),
|
|
||||||
nspd_zoning.get("raw_props"),
|
|
||||||
):
|
|
||||||
zone_label = (
|
zone_label = (
|
||||||
nspd_zoning.get("zone_name") or nspd_zoning.get("zone_code") or "неизвестна"
|
nspd_zoning.get("zone_name") or nspd_zoning.get("zone_code") or "неизвестна"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue