from __future__ import annotations from copy import deepcopy from pathlib import Path from typing import Any import yaml DEFAULT_CONFIG: dict[str, Any] = { "paths": { "cad": "CAD/11.step", "mesh": "Mesh/11.stl", "pointcloud": "PointCloud/11.ply", "noisy_pointcloud": "Noise_PointCloud/11_noisy.ply", "output_mesh": "Mesh/11.stl", "curvature_output": None, }, "cad": { "precision": 1.0, "enabled": False, }, "noise": { "enabled": True, "std": 4.0, "seed": None, }, "filters": { "enabled": True, "methods": ["SOR"], "sor_neighbors": 20, "sor_std_ratio": 2.0, "ror_points": 5, "ror_radius": 20.0, "voxel_size": 0.05, "pass_axis": "z", "pass_min": None, "pass_max": None, "bf_sigma_s": 0.01, "bf_sigma_r": 0.1, }, "registration": { "voxel_size": 10.0, "roll": 10.0, "pitch": 10.0, "yaw": 10.0, "trans_range": 0.0, "random_seed": None, }, "evaluation": { "chunk_size": 2048, "triangle_chunk_size": 4096, "cad_mesh_deflection": 0.1, }, "curvature": { "radius": 2.0, "max_nn": 30, "color_scale": 3.0, }, "plane": { "size_mm": 1000.0, "noise_std_mm": 0.5, "num_points": 10000, "threshold_mm": 0.5, "max_iterations": 2000, }, "visualization": { "enabled": True, }, } def deep_update(base: dict[str, Any], updates: dict[str, Any]) -> dict[str, Any]: result = deepcopy(base) for key, value in updates.items(): if isinstance(value, dict) and isinstance(result.get(key), dict): result[key] = deep_update(result[key], value) else: result[key] = value return result class ConfigLoader: """Load YAML config and merge it with project defaults.""" def __init__(self, default_config: dict[str, Any] | None = None) -> None: self.default_config = default_config or DEFAULT_CONFIG def load(self, config_path: str | None = None) -> dict[str, Any]: config = deepcopy(self.default_config) if not config_path: return config path = Path(config_path) if not path.exists(): raise FileNotFoundError(f"Config file not found: {path}") with path.open("r", encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} if not isinstance(user_config, dict): raise ValueError("Config file must contain a YAML mapping at the top level.") return deep_update(config, user_config)