diff --git a/docs/figures/geo-q2-guaranteed-reception-disk.png b/docs/figures/geo-q2-guaranteed-reception-disk.png index 9fb885f..6de6f06 100644 Binary files a/docs/figures/geo-q2-guaranteed-reception-disk.png and b/docs/figures/geo-q2-guaranteed-reception-disk.png differ diff --git a/scripts/make_figures.py b/scripts/make_figures.py index dba1c9b..57e7ec4 100644 --- a/scripts/make_figures.py +++ b/scripts/make_figures.py @@ -23,7 +23,7 @@ import math import os import sys from pathlib import Path -from typing import Any, Callable, Iterable, Sequence +from typing import Any, Callable, Sequence ROOT = Path(__file__).resolve().parents[1] FONT_DIR = ROOT / "docs" / "paper" / "fonts" @@ -130,7 +130,7 @@ def new_axes(width_mm: float, height_mm: float, *, ncols: int = 1, def axes_for_panels(panel_mm: float, aspects: Sequence[float], *, scale: float = 1.0, width_ratios: Sequence[float] | None = None, - extra_mm: float = 30.0, **kw: Any) -> tuple[Any, Any]: + **kw: Any) -> tuple[Any, Any]: """按"每个面板高 panel_mm、宽 = 高 × 宽高比"手工排版。 等比例坐标轴(``set_aspect('equal')``)在自动布局(constrained/tight)下会被 @@ -310,7 +310,8 @@ def decompose(run: dict[str, Any]) -> dict[str, Any]: y=req.get("position", {}).get("y"))) wall = [r for r in run["actions"] if r.get("wall_ts_ms")] real_s = (wall[-1]["wall_ts_ms"] - wall[0]["wall_ts_ms"]) / 1000.0 if len(wall) > 1 else 0.0 - return dict(rows=rows, virtual_s=float(run["actions"][-1]["response"].get("virtual_time_s") or 0), + last = run["actions"][-1]["response"] + return dict(rows=rows, virtual_s=float(last.get("virtual_time_s") or 0.0), real_s=real_s, move_s=sum(r["move_s"] for r in rows), switch_s=sum(r["switch_s"] for r in rows), @@ -386,12 +387,12 @@ def clip_wedge(region: np.ndarray, station: Sequence[float], bearing: float, region = candidates[0] continue region = min(candidates, key=lambda cand: _direction_error(cand, station, - bearing, half_deg)) + bearing)) return region -def _direction_error(poly: np.ndarray, station: Sequence[float], bearing: float, - half_deg: float) -> float: +def _direction_error(poly: np.ndarray, station: Sequence[float], + bearing: float) -> float: """多边形中心方向与示向度的偏差;用于挑正确的半平面一侧。""" centre = poly.mean(axis=0) dx, dy = centre[0] - station[0], centre[1] - station[1] @@ -691,7 +692,6 @@ def fig_q1_meetup(font: dict[str, Any]) -> Any: stations = data["stations"] xs = [s[0] for s in stations] ys = [s[1] for s in stations] - cx, cy = (min(xs) + max(xs)) / 2, (min(ys) + max(ys)) / 2 half = max(max(xs) - min(xs), max(ys) - min(ys)) / 2 * 1.35 + 60 reach = 2.4 * half mec_c = data["mec"]["center"] @@ -703,7 +703,7 @@ def fig_q1_meetup(font: dict[str, Any]) -> Any: span = float(np.abs(verts - np.array(zoom_c)).max()) zoom = max(1.8 * span, 0.8 * mec_r + span, 12.0) - fig, axes = axes_for_panels(62.0, [1.0, 1.0], width_ratios=[1.0, 1.0]) + fig, axes = axes_for_panels(62.0, [1.0, 1.0]) ax, axz = axes polar_axes(ax, half, grid=half / 2) for sx, sy, bearing, hd in stations: @@ -846,13 +846,13 @@ def fig_q2_safe_disk(font: dict[str, Any]) -> Any: edgecolor=C["success"], lw=1.2)) ax.annotate("", xy=c, xytext=(0, 0), arrowprops=dict(arrowstyle="-|>", color=C["violet"], lw=1.0)) - ax.annotate(f"a = {a:.1f} m", ((c[0] + 0) / 2, (c[1] + 0) / 2), - textcoords="offset points", xytext=(-6, 26), ha="right", - fontproperties=font["song"], fontsize=7.6, color=C["violet"], + ax.annotate(f"a = {a:.1f} m", (c[0] / 2, c[1] / 2), textcoords="offset points", + xytext=(-10, 30), ha="center", fontproperties=font["song"], + fontsize=7.6, color=C["violet"], arrowprops=dict(arrowstyle="-", color=C["violet"], lw=0.8)) - ax.annotate(f"安全盘半径 {safe:.1f} m", (c[0], c[1] - safe * 0.7), - textcoords="offset points", xytext=(14, -20), ha="left", - fontproperties=font["song"], fontsize=7.6, color=C["success"], + ax.annotate(f"安全盘半径 {safe:.1f} m", (c[0], c[1]), textcoords="offset points", + xytext=(30, -34), ha="left", fontproperties=font["song"], + fontsize=7.6, color=C["success"], arrowprops=dict(arrowstyle="-", color=C["success"], lw=0.8)) ax.text(0, OMEGA_R * 0.98, "Ω:R = 1800 m", fontproperties=font["song"], fontsize=7.6, color=C["primary"], ha="center", va="top") @@ -860,7 +860,7 @@ def fig_q2_safe_disk(font: dict[str, Any]) -> Any: ax.set_ylabel("y / m", fontproperties=font["song"]) # 右:安全性依据(两半径相加 = 1000 m) - axz.set_aspect("auto") + axz.set_aspect("equal", adjustable="box") axz.axis("off") axz.set_xlim(-1.15, 1.25) axz.set_ylim(-0.35, 1.05) @@ -945,7 +945,6 @@ def fig_q3_seven_coverage(font: dict[str, Any]) -> Any: def fig_q4_mincover(font: dict[str, Any]) -> Any: plan = load_plan("q4_mincover_v2") pts = np.array(plan["points"], dtype=float) - cert = plan["certificate"] fig, axes = axes_for_panels(64.0, [1.0, 1.0], width_ratios=[1.0, 1.0]) ax, axr = axes