83 lines
3.6 KiB
Bash
Executable File
83 lines
3.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# --------------------------------------------------------------------------
|
|
# verify-oneway.sh — يتحقق أن محرك التوجيه يحترم اتجاهات السير
|
|
#
|
|
# يختار طرقاً موسومة oneway=yes من البيانات نفسها، ويطلب مساراً على كل منها
|
|
# في الاتجاهين. على طريق أحادي سليم يجب أن تختلف المسافتان (العودة تحتاج
|
|
# التفافاً). التطابق التام = المحرك يتجاهل oneway.
|
|
#
|
|
# السبب المعتاد للفشل: سقوط قاعدة "!car_access → 0" من custom_model.
|
|
# التفاصيل الكاملة: docs/ROUTING_ONEWAY_AR.md
|
|
#
|
|
# bash infrastructure/scripts/verify-oneway.sh
|
|
#
|
|
# متغيّرات: GH_URL (افتراضي http://localhost:8989)، BBOX، SAMPLES
|
|
# --------------------------------------------------------------------------
|
|
set -uo pipefail
|
|
|
|
APP_DIR="${APP_DIR:-/home/hamzadoctor/app}"
|
|
GH_URL="${GH_URL:-http://localhost:8989}"
|
|
PBF="${PBF:-${APP_DIR}/infrastructure/osm-data/master_map.osm.pbf}"
|
|
BBOX="${BBOX:-36.055,32.100,36.072,32.116}" # lon1,lat1,lon2,lat2
|
|
SAMPLES="${SAMPLES:-8}"
|
|
|
|
command -v osmium >/dev/null || { echo "❌ osmium غير مثبّت: apt-get install -y osmium-tool"; exit 2; }
|
|
[ -f "$PBF" ] || { echo "❌ الملف غير موجود: $PBF"; exit 2; }
|
|
curl -fsS "$GH_URL/health" >/dev/null || { echo "❌ المحرك لا يستجيب على $GH_URL"; exit 2; }
|
|
|
|
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
|
|
|
|
osmium extract -b "$BBOX" "$PBF" -o "$TMP/area.pbf" --overwrite >/dev/null 2>&1
|
|
osmium tags-filter "$TMP/area.pbf" w/oneway=yes -o "$TMP/ow.pbf" --overwrite >/dev/null 2>&1
|
|
osmium export -f geojson "$TMP/ow.pbf" -o "$TMP/ow.geojson" --overwrite >/dev/null 2>&1
|
|
|
|
GH_URL="$GH_URL" SAMPLES="$SAMPLES" python3 - "$TMP/ow.geojson" <<'PY'
|
|
import json, os, sys, urllib.request
|
|
|
|
gh = os.environ["GH_URL"]
|
|
want = int(os.environ["SAMPLES"])
|
|
|
|
def route(a, b):
|
|
u = f"{gh}/route?point={a}&point={b}&profile=car"
|
|
try:
|
|
return round(json.load(urllib.request.urlopen(u, timeout=20))["paths"][0]["distance"])
|
|
except Exception:
|
|
return None
|
|
|
|
feats = json.load(open(sys.argv[1]))["features"]
|
|
print("═" * 60)
|
|
print(" فحص احترام اتجاهات السير — " + gh)
|
|
print("═" * 60)
|
|
|
|
tested = identical = 0
|
|
for f in feats:
|
|
if tested >= want:
|
|
break
|
|
g = f["geometry"]
|
|
if g["type"] != "LineString" or len(g["coordinates"]) < 2:
|
|
continue
|
|
c = g["coordinates"]
|
|
a = f"{c[0][1]:.7f},{c[0][0]:.7f}"
|
|
b = f"{c[-1][1]:.7f},{c[-1][0]:.7f}"
|
|
fwd, rev = route(a, b), route(b, a)
|
|
if fwd is None or rev is None or fwd == 0:
|
|
continue
|
|
tested += 1
|
|
name = (f["properties"].get("name") or "بلا اسم")[:24]
|
|
# المعيار هو الاختلاف لا نسبته: الالتفاف قد يكون صغيراً نسبياً على مقطع طويل
|
|
ok = fwd != rev
|
|
identical += (not ok)
|
|
print(f" {name:24} ذهاب:{fwd:6d}م عودة:{rev:6d}م {'✅' if ok else '❌ متطابق'}")
|
|
|
|
print()
|
|
if tested == 0:
|
|
print("⚠️ لم يُعثر على طرق أحادية صالحة للاختبار — راجع BBOX أو البيانات.")
|
|
sys.exit(2)
|
|
if identical:
|
|
print(f"❌ فشل: {identical} من {tested} طريقاً أحادياً يُخترق — المحرك يتجاهل oneway.")
|
|
print(" الأرجح: سقوط قاعدة '!car_access → 0' من custom_model في config.yml")
|
|
print(" اقرأ: docs/ROUTING_ONEWAY_AR.md")
|
|
sys.exit(1)
|
|
print(f"✅ نجح: {tested} طريقاً أحادياً، كلها محترمة الاتجاه.")
|
|
PY
|