| from pathlib import Path |
| import trimesh |
| import numpy as np |
|
|
|
|
| def check_head_model(model_path: str | Path) -> dict: |
| """Validate a head model mesh.""" |
| model_path = Path(model_path) |
| if not model_path.exists(): |
| return {"status": "error", "message": f"Model not found: {model_path}"} |
|
|
| try: |
| scene = trimesh.load(str(model_path)) |
| except Exception as e: |
| return {"status": "error", "message": f"Failed to load model: {e}"} |
|
|
| results = [] |
| if isinstance(scene, trimesh.Scene): |
| for name, g in scene.geometry.items(): |
| if isinstance(g, trimesh.Trimesh): |
| centroid = g.vertices.mean(0) |
| y_min, y_max = g.vertices[:, 1].min(), g.vertices[:, 1].max() |
| results.append({ |
| "mesh": name, |
| "centroid": centroid.round(3).tolist(), |
| "y_range": [float(y_min), float(y_max)] |
| }) |
| else: |
| centroid = scene.vertices.mean(0) |
| y_min, y_max = scene.vertices[:, 1].min(), scene.vertices[:, 1].max() |
| results.append({ |
| "mesh": model_path.stem, |
| "centroid": centroid.round(3).tolist(), |
| "y_range": [float(y_min), float(y_max)] |
| }) |
|
|
| return {"status": "ok", "results": results} |
|
|
|
|
| def check_body_model(model_path: str | Path) -> dict: |
| """Validate a body model mesh with anatomical checks.""" |
| model_path = Path(model_path) |
| if not model_path.exists(): |
| return {"status": "error", "message": f"Model not found: {model_path}"} |
|
|
| try: |
| scene = trimesh.load(str(model_path)) |
| except Exception as e: |
| return {"status": "error", "message": f"Failed to load model: {e}"} |
|
|
| if isinstance(scene, trimesh.Scene): |
| body = trimesh.util.concatenate(list(scene.geometry.values())) |
| else: |
| body = scene |
|
|
| v = body.vertices |
| y_min, y_max = v[:, 1].min(), v[:, 1].max() |
|
|
| checks = [ |
| ('feet', 0.01), |
| ('hips', 0.50), |
| ('chest', 0.65), |
| ('neck', 0.75), |
| ('chin', 0.87), |
| ('crown', 0.99) |
| ] |
|
|
| results = [] |
| for name, frac in checks: |
| y = y_min + (y_max - y_min) * frac |
| pts = v[(v[:, 1] > y - 0.03) & (v[:, 1] < y + 0.03)] |
| if len(pts) < 3: |
| continue |
| results.append({ |
| "location": name, |
| "fraction": frac, |
| "x_mean": float(pts[:, 0].mean()), |
| "x_std": float(pts[:, 0].std()), |
| "z_mean": float(pts[:, 2].mean()), |
| "z_std": float(pts[:, 2].std()), |
| "points": int(len(pts)) |
| }) |
|
|
| return {"status": "ok", "y_range": [float(y_min), float(y_max)], "results": results} |
|
|
|
|
| def check_model(model_path: str | Path, model_type: str = "auto") -> dict: |
| """Check a model, auto-detecting type if needed.""" |
| model_path = Path(model_path) |
|
|
| if model_type == "auto": |
| if "head" in model_path.name.lower(): |
| model_type = "head" |
| elif "body" in model_path.name.lower(): |
| model_type = "body" |
| else: |
| return {"status": "error", "message": "Could not auto-detect model type. Use --model-type to specify (head/body)"} |
|
|
| if model_type == "head": |
| return check_head_model(model_path) |
| elif model_type == "body": |
| return check_body_model(model_path) |
| else: |
| return {"status": "error", "message": f"Unknown model type: {model_type}"} |
|
|