scene_service.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """场景位置:data/scene_positions.csv 的读写(含初始种子)。
  2. 坐标存“参考系”(Z 不含随模型变化的 dz),前端应用时再叠加 dz。
  3. """
  4. import csv
  5. import os
  6. from typing import Any
  7. from config import DATA_DIR, SCENE_CSV
  8. FIELDS = [
  9. "id", "name",
  10. "camera_x", "camera_y", "camera_z",
  11. "target_x", "target_y", "target_z",
  12. ]
  13. # 初始种子:俯视 / 角度A(参考系坐标,与前端 VIEW_PRESETS 一致)。
  14. SEED: list[tuple[int, str, list[float], list[float]]] = [
  15. (1, "俯视", [2.0, 22.0, -3.2], [2.0, 0.0, -22.0]),
  16. (2, "角度A", [5.4, 16.7, -6.3], [9.4, 0.0, -22.5]),
  17. ]
  18. def _ensure_file() -> None:
  19. if SCENE_CSV.exists():
  20. return
  21. DATA_DIR.mkdir(parents=True, exist_ok=True)
  22. with SCENE_CSV.open("w", encoding="utf-8", newline="") as handle:
  23. writer = csv.writer(handle)
  24. writer.writerow(FIELDS)
  25. for scene_id, name, camera, target in SEED:
  26. writer.writerow([scene_id, name, *camera, *target])
  27. def _to_scene(row: dict[str, str]) -> dict[str, Any]:
  28. return {
  29. "id": int(row["id"]),
  30. "name": row["name"],
  31. "camera": [float(row["camera_x"]), float(row["camera_y"]), float(row["camera_z"])],
  32. "target": [float(row["target_x"]), float(row["target_y"]), float(row["target_z"])],
  33. }
  34. def _read() -> list[dict[str, Any]]:
  35. _ensure_file()
  36. with SCENE_CSV.open("r", encoding="utf-8", newline="") as handle:
  37. return [_to_scene(row) for row in csv.DictReader(handle)]
  38. def _write(scenes: list[dict[str, Any]]) -> None:
  39. DATA_DIR.mkdir(parents=True, exist_ok=True)
  40. tmp = SCENE_CSV.parent / (SCENE_CSV.name + ".tmp")
  41. with tmp.open("w", encoding="utf-8", newline="") as handle:
  42. writer = csv.writer(handle)
  43. writer.writerow(FIELDS)
  44. for scene in scenes:
  45. writer.writerow([scene["id"], scene["name"], *scene["camera"], *scene["target"]])
  46. os.replace(tmp, SCENE_CSV)
  47. def list_scenes() -> list[dict[str, Any]]:
  48. return _read()
  49. def add_scene(name: str, camera: list[float], target: list[float]) -> dict[str, Any]:
  50. scenes = _read()
  51. scene = {
  52. "id": max((s["id"] for s in scenes), default=0) + 1,
  53. "name": name,
  54. "camera": [float(v) for v in camera],
  55. "target": [float(v) for v in target],
  56. }
  57. scenes.append(scene)
  58. _write(scenes)
  59. return scene
  60. def rename_scene(scene_id: int, name: str) -> dict[str, Any] | None:
  61. scenes = _read()
  62. for scene in scenes:
  63. if scene["id"] == scene_id:
  64. scene["name"] = name
  65. _write(scenes)
  66. return scene
  67. return None
  68. def delete_scene(scene_id: int) -> bool:
  69. scenes = _read()
  70. remaining = [scene for scene in scenes if scene["id"] != scene_id]
  71. if len(remaining) == len(scenes):
  72. return False
  73. _write(remaining)
  74. return True