Metadata-Version: 2.4
Name: tftree-manager
Version: 0.1.10
Summary: TF 树梳理与变换管理 core：YAML/JSON 外参加载、图路径与环检测、direct relation 更新、局部求逆、compute/projection 变换计算
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.20.0
Requires-Dist: PyYAML>=5.4.0
Requires-Dist: mdrive4-json>=0.0.7
Requires-Dist: minieye-runtime-config>=0.0.6
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# tftree-manager

**当前版本：0.1.10**

`tftree-manager` 是 D03 的 TF/外参 core 包，负责加载、查询、拓扑诊断、compute/projection 变换计算、YAML/JSON I/O 和外参更新原语。它不再承载可视化、GUI、服务端或端到端业务工作流。

## 安装

```bash
pip install tftree-manager
```

## V0.1.10 mdrive4 JSON 公共字段

D03 的 mdrive4 JSON 写回不再本地逐文件维护 `vehicle_id`。`persist_vehicle_id`
会映射为 D11 `normalize_vehicle_context(..., common_vehicle_fields={"vehicle_id": ...})`，
由 D11 统一处理目录公共字段继承、冲突阻断和缺失记录创建。

## V0.1.9 mdrive4 JSON 缺失记录创建

D03 导出 mdrive4 JSON 遇到缺失 camera/sensor 时，委托 D11
`mdrive4_json.create_record(...)` 创建 native 记录。缺少完整内参或外参时写入
`is_valid=false`，不在 D03 内拼装伪造内参字段。

## V0.1.7 mdrive4 JSON prj_model 合同

D03 写出 mdrive4 JSON 相机内参时遵循当前 mdrive4-json 合同：

- `model_type="FISHEYE"` 写 `prj_model=1`。
- `model_type="PINHOLE"` 写 `prj_model=3`。

## V0.1.6 路径分类 API

D03 新增轻量路径形状分类 API，用于在调用具体 loader 前区分输入来源：

```python
from tftree_manager import classify_calibration_source_path, validate_calibration_source_path

result = classify_calibration_source_path("/path/to/mdrive_conf/car/vehicle_config.pb.txt")
assert result.family == "mdrive-pb"

validated = validate_calibration_source_path(
    "/path/to/vehicle_cfg/car/calib",
    expected_family="mdrive4-json",
)
```

该 API 只识别路径形状，不解析 PB/JSON/YAML 内容。PB/JSON 语义正确性仍由 `pb_calibration`、`mdrive4_json` 或具体 loader 负责。

识别范围：

- `mdrive-pb`：`vehicle_config.pb.txt` 或 `*.pb.txt` 文件路径。
- `mdrive4-json`：名为 `calib/` 且非空的目录。
- `yaml-workspace`：包含 `.yaml` / `.yml` 文件的目录。
- `unknown` / `invalid`：缺失路径、PB/JSON 混合路径、`vehicle_cfg` 下缺少 `calib/`、空 JSON `calib/` 目录、无法识别的文件后缀。

## V0.1.5 瘦身边界

D03 V0.1.5 只保留 TF core 能力：

- workspace 加载/保存：`TFTreeWorkspace.load_yaml()`、`load_mdrive4_json()`、`save_yaml()`。
- transform 查询：`TransformQueryService.get_transform()`、`compute_all_from_root()`、`convert_transform_mode()`。
- 路径和拓扑诊断：`TopologyService` 的路径、环检测、边查询，以及 directed/bidirectional 拓扑评估。
- 外参操作：`TransformOperationService` 的 direct relation、标定链路替换、相邻边求逆和 direct transform upsert。
- 格式边界：YAML、mdrive4 JSON、PB 派生 YAML、JSON camera compute/projection 轴系转换。
- 非 UI facade：`TransformLookup`、`PathLookup`、`JsonRootEdgeUpdater`。

以下能力已从 D03 移除，且不保留旧兼容入口：

- 3D sensor orientation plot、车辆外形叠加和 `plot-orientation` CLI。
- 2D graph visualization 数据模型、布局、画布和 graph editor。
- Qt/PySide canvas/editor/prune UI。
- Flask app、`tftree-manager-server` 和 server 兼容模块。
- `ui` / `plot` extras 及其 PySide6、matplotlib、Flask、minieye-runtime-config 依赖。

可视化相关能力迁移到 D14/D15，由 D14/D15 依赖 D03 core API 构建展示、交互和报告，不再反向塞回 D03。

## 推荐入口

```python
from tftree_manager import (
    TFTreeWorkspace,
    TransformOperationService,
    TransformQueryService,
    TopologyService,
)

workspace = TFTreeWorkspace.load_yaml("/path/to/yaml_dir")
query = TransformQueryService(workspace)
topology = TopologyService(workspace)
ops = TransformOperationService(workspace)

frames = workspace.frames()
cycles = topology.detect_cycles()

# 默认 compute，用于标定文件、尺寸链、保存和 JSON/PB/YAML 写回。
T_compute = query.get_transform("lidar", "camera")

# projection 用于 lidar2cam 显示、PnP 和图像投影。
T_projection = query.get_transform("lidar", "camera", output_mode="projection")

# 如果外部输入矩阵来自投影链路，D03 在 API 边界归一为 compute 后存储。
ops.upsert_direct_transform(
    "lidar",
    "camera",
    T_projection,
    input_mode="projection",
    save=False,
)
```

## CLI

D03 CLI 只保留 core 操作：

```bash
tftree-manager <yaml_dir>
tftree-manager load-json <json_dir> --output-dir <yaml_dir> [--root-frame ego]
tftree-manager invert-edge <yaml_dir> <A> <B> [--output-dir <dir>] [--no-save]
tftree-manager rewrite-direct <yaml_dir> <update_yaml> [--output-dir <dir>] [--prune-frame <frame> ...]
tftree-manager upsert-direct <yaml_dir> --update-yaml <path> [--replace-frame <frame> ...]
```

## compute / projection 合同

- `compute` 是默认模式，用于标定文件、尺寸链、direct/manual link 存储、PB/YAML/JSON 写回。
- `projection` 用于 lidar2cam 显示、PnP 和图像投影。
- graph 内部只保存 `compute`；`projection` 只在 `get_transform(..., output_mode="projection")`、`convert_transform_mode(...)` 或 `input_mode="projection"` 的 D03 API 边界派生/归一。
- mdrive4 JSON camera 的 `compute` 轴系为 FLU，`projection` 轴系为 OpenCV/RDF。
- PB/YAML 无 `order_manifest.yaml.frame_axes` metadata 时，D03 不推测相机轴系，`compute` 与 `projection` 返回一致。
- JSON 写回必须走 D03 的 compute -> JSON FLU 序列化，业务侧不要自行拼 camera JSON RPY/translation。

## 兼容层

`TFTreeManager` 仅作为 deprecated compat wrapper 保留，用于旧项目平滑运行；新接入应以 `TFTreeWorkspace + services` 为主入口。该兼容层不包含任何可视化入口。

## facade

重复的矩阵查询、路径查询和 JSON root edge 更新可优先使用稳定 facade：

```python
from tftree_manager import JsonRootEdgeUpdater, PathLookup, TransformLookup

matrix = TransformLookup.from_yaml("/path/to/yaml_dir").matrix("lidar", "camera")
path_edges = PathLookup.from_yaml("/path/to/yaml_dir").edge_keys("lidar", "camera")

updater = JsonRootEdgeUpdater.from_yaml("/path/to/yaml_dir", root_frame="vrf_ground")
updater.update_root_edge("lidar", "camera", matrix, save=False)
```

## 更多文档

- `doc/README.md`：V0.1.6 core 能力边界和迁移口径。
- `doc/API_USAGE.md`：V0.1.6 core API 接入示例。
- `doc/UPDATE.md`：版本更新说明与迁移方向。
- `plan/`：V0.1.5 当前边界说明；旧 GUI/可视化计划已归档移除，不再作为 D03 目标。
