Skip to content

Commit 3978284

Browse files
committed
feat(timeline): 校准 profile 绑定
- Timeline model 加 calibration_profile 字段 - 打轴保存时写入当前校准文件名 - 凹图运行时校验 timeline 记录的 profile 与当前是否一致, 不一致警告(30f vs 31f 会导致帧级漂移)
1 parent 0e9a794 commit 3978284

4 files changed

Lines changed: 25 additions & 1 deletion

File tree

aao/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ def _on_profile_saved(self, filename: str) -> None:
241241
try:
242242
self._calibration_data = calibration.load(filename)
243243
self._profile_name = filename
244+
self.editor_page.set_profile(filename)
244245
except (OSError, ValueError):
245246
logger.exception("校准 %s 加载失败", filename)
246247
if self._controller is not None:
@@ -282,6 +283,7 @@ def _build_ui(self) -> None:
282283
self.farm_page.busy_changed.connect(self._set_busy)
283284

284285
self.editor_page = EditorWindow() # 打轴编辑器(已接入 canvas + 地图选点)
286+
self.editor_page.set_profile(self._profile_name)
285287
self._editor = self.editor_page # 供热键 mark_action
286288
self.calib_page = CalibrationPage()
287289
self.settings_page = SettingsPage()

aao/timeline/editor_window.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(self):
5959
self._current_frame = 0 # 实时帧(由外部更新)
6060
self._align_mode = False # False=打轴(游标不跟随),True=对轴(游标跟实时帧)
6161
self._candidates: list[str] = [] # 候选干员/装置列表
62+
self._profile_name = "" # 当前校准 profile 文件名(由 MainWindow 注入)
6263

6364
self.canvas = TimelineCanvas()
6465
self.canvas.node_clicked.connect(self._on_canvas_node_clicked)
@@ -430,11 +431,16 @@ def _on_open(self):
430431
self._refresh_table()
431432
self.lbl_status.setText(f"已加载 {len(self.timeline.actions)} 个动作")
432433

434+
def set_profile(self, profile_name: str) -> None:
435+
"""注入当前校准 profile 文件名(打轴帧数依赖此 profile,保存时写入 timeline)。"""
436+
self._profile_name = profile_name
437+
433438
def _on_save(self):
434439
path, _ = QFileDialog.getSaveFileName(self, "保存时间轴", "", "JSON (*.json)")
435440
if not path:
436441
return
437442
self.timeline.map_code = self.edit_map.text().strip()
443+
self.timeline.calibration_profile = self._profile_name
438444
self._collect_candidates()
439445
save_timeline(self.timeline, path)
440446
self.lbl_status.setText(f"已保存到 {path}")

aao/timeline/model.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,19 @@ class Timeline:
8989
actions: list[TimelineAction] = field(default_factory=list)
9090
name: str = "" # 用户可读名称
9191
candidates: list[str] = field(default_factory=list) # 候选干员/装置名
92+
calibration_profile: str = "" # 打轴时用的校准 profile 文件名
9293

9394
def to_dict(self) -> dict[str, Any]:
94-
return {
95+
d: dict[str, Any] = {
9596
"map_code": self.map_code,
9697
"coordinate": self.coordinate,
9798
"name": self.name,
9899
"candidates": self.candidates,
99100
"actions": [a.to_dict() for a in self.actions],
100101
}
102+
if self.calibration_profile:
103+
d["calibration_profile"] = self.calibration_profile
104+
return d
101105

102106
@classmethod
103107
def from_dict(cls, d: dict[str, Any]) -> Timeline:
@@ -106,6 +110,7 @@ def from_dict(cls, d: dict[str, Any]) -> Timeline:
106110
coordinate=d.get("coordinate", "frame"),
107111
name=d.get("name", ""),
108112
candidates=d.get("candidates", []),
113+
calibration_profile=d.get("calibration_profile", ""),
109114
actions=[TimelineAction.from_dict(a) for a in d.get("actions", [])],
110115
)
111116

custom/action/executor.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,29 @@ def _execute(self, context: Context, params: dict) -> CustomAction.RunResult:
9090

9191
# 优先 timeline_path(从文件加载,文件内含 map_code),兼容显式 timeline 数组
9292
timeline_path = params.get("timeline_path")
93+
tl_calib = ""
9394
if timeline_path:
9495
tl = self._load_timeline_file(timeline_path)
9596
if tl is None:
9697
return CustomAction.RunResult(success=False)
9798
raw_actions = tl.get("actions", [])
9899
map_code = params.get("map_code") or tl.get("map_code", "")
100+
tl_calib = tl.get("calibration_profile", "")
99101
else:
100102
raw_actions = params.get("timeline", [])
101103
map_code = params.get("map_code", "")
102104

103105
calib_file = params.get("calibration") or config.DEFAULT_CALIBRATION
104106

107+
# 校验:timeline 记录的校准 profile 与当前使用的是否一致(帧数偏差会导致漂移)
108+
if tl_calib and tl_calib != calib_file:
109+
logger.warning(
110+
"⚠ 校准 profile 不匹配:timeline 用的是 %s,当前运行用的是 %s。"
111+
"帧数可能不同(如 30f vs 31f),会导致时间轴漂移!",
112+
tl_calib,
113+
calib_file,
114+
)
115+
105116
if not raw_actions or not map_code:
106117
logger.error("缺少参数: 需要 timeline_path 或 (timeline + map_code)")
107118
return CustomAction.RunResult(success=False)

0 commit comments

Comments
 (0)