"""
param_store
パラメータプリセットの保存・読み込みを管理するモジュール
画像処理・PD 制御・Theil-Sen PD 制御パラメータを独立して管理する
"""
from dataclasses import asdict, dataclass
from common.json_utils import PARAMS_DIR, read_json, write_json
from pc.steering.pd_control import PdParams
from pc.steering.ts_pd_control import TsPdParams
from pc.vision.line_detector import ImageParams
_PD_FILE = PARAMS_DIR / "presets_pd.json"
_TS_PD_FILE = PARAMS_DIR / "presets_ts_pd.json"
_IMAGE_FILE = PARAMS_DIR / "presets_image.json"
# ── PD 制御プリセット ─────────────────────────
@dataclass
class PdPreset:
"""PD 制御パラメータのプリセット
Attributes:
title: プリセットのタイトル
memo: メモ
params: PD 制御パラメータ
"""
title: str
memo: str
params: PdParams
def load_pd_presets() -> list[PdPreset]:
"""PD 制御プリセット一覧を読み込む"""
return _load_presets(
_PD_FILE, PdPreset, "params", PdParams,
)
def add_pd_preset(preset: PdPreset) -> None:
"""PD 制御プリセットを追加する"""
presets = load_pd_presets()
presets.append(preset)
_save_presets(
_PD_FILE, presets, "params",
)
def delete_pd_preset(index: int) -> None:
"""PD 制御プリセットを削除する"""
presets = load_pd_presets()
if 0 <= index < len(presets):
presets.pop(index)
_save_presets(
_PD_FILE, presets, "params",
)
# ── Theil-Sen PD 制御プリセット ────────────────
@dataclass
class TsPdPreset:
"""Theil-Sen PD 制御パラメータのプリセット
Attributes:
title: プリセットのタイトル
memo: メモ
params: Theil-Sen PD 制御パラメータ
"""
title: str
memo: str
params: TsPdParams
def load_ts_pd_presets() -> list[TsPdPreset]:
"""Theil-Sen PD 制御プリセット一覧を読み込む"""
return _load_presets(
_TS_PD_FILE, TsPdPreset,
"params", TsPdParams,
)
def add_ts_pd_preset(preset: TsPdPreset) -> None:
"""Theil-Sen PD 制御プリセットを追加する"""
presets = load_ts_pd_presets()
presets.append(preset)
_save_presets(
_TS_PD_FILE, presets, "params",
)
def delete_ts_pd_preset(index: int) -> None:
"""Theil-Sen PD 制御プリセットを削除する"""
presets = load_ts_pd_presets()
if 0 <= index < len(presets):
presets.pop(index)
_save_presets(
_TS_PD_FILE, presets, "params",
)
# ── 画像処理プリセット ────────────────────────
@dataclass
class ImagePreset:
"""二値化パラメータのプリセット
Attributes:
title: プリセットのタイトル
memo: メモ
image_params: 二値化パラメータ
"""
title: str
memo: str
image_params: ImageParams
def load_image_presets() -> list[ImagePreset]:
"""画像処理プリセット一覧を読み込む"""
return _load_presets(
_IMAGE_FILE, ImagePreset,
"image_params", ImageParams,
)
def add_image_preset(preset: ImagePreset) -> None:
"""画像処理プリセットを追加する"""
presets = load_image_presets()
presets.append(preset)
_save_presets(
_IMAGE_FILE, presets, "image_params",
)
def delete_image_preset(index: int) -> None:
"""画像処理プリセットを削除する"""
presets = load_image_presets()
if 0 <= index < len(presets):
presets.pop(index)
_save_presets(
_IMAGE_FILE, presets, "image_params",
)
# ── 共通処理 ──────────────────────────────────
def _load_presets(path, preset_cls, params_key, params_cls):
"""プリセットファイルを読み込む"""
if not path.exists():
return []
data = read_json(path)
known = params_cls.__dataclass_fields__
presets = []
for item in data:
if params_key in item:
filtered = {
k: v
for k, v in item[params_key].items()
if k in known
}
params = params_cls(**filtered)
else:
params = params_cls()
presets.append(preset_cls(
title=item["title"],
memo=item["memo"],
**{params_key: params},
))
return presets
def _save_presets(path, presets, params_key):
"""プリセットファイルに保存する"""
data = []
for preset in presets:
data.append({
"title": preset.title,
"memo": preset.memo,
params_key: asdict(
getattr(preset, params_key),
),
})
write_json(path, data)