math-solver / solver /geometry_normalizer.py
Cuong2004
Deploy API from GitHub Actions
1993d5c
Raw History Blame Contribute Delete
2.17 kB
"""Geometry Normalizer: Normalizes coordinates, scales, frames, and removes degenerate geometries."""
from __future__ import annotations
import logging
import numpy as np
from typing import Dict, List, Tuple
logger = logging.getLogger(__name__)
class GeometryNormalizer:
"""Standardizes point naming, coordinate scaling, centering, and precision."""
def normalize_coordinates(
self,
coords: Dict[str, List[float]],
target_span: float = 8.0,
is_3d: bool = False,
) -> Dict[str, List[float]]:
if not coords:
return {}
cleaned: Dict[str, List[float]] = {}
for pid, pt in coords.items():
cleaned[pid] = [
0.0 if abs(val) < 1e-6 else float(np.round(val, 6))
for val in pt
]
# Calculate bounding box
all_pts = np.array(list(cleaned.values()))
if len(all_pts) == 0:
return cleaned
mins = np.min(all_pts, axis=0)
maxs = np.max(all_pts, axis=0)
spans = maxs - mins
max_span = float(np.max(spans))
# If geometry is valid and non-degenerate, scale into comfortable viewing range
if max_span > 1e-4:
scale = target_span / max_span
center = (mins + maxs) / 2.0
normalized: Dict[str, List[float]] = {}
for pid, pt in cleaned.items():
pt_arr = np.array(pt)
norm_pt = (pt_arr - center) * scale
if not is_3d:
# In 2D, pin z to 0 and center in 2D plane
normalized[pid] = [
float(np.round(norm_pt[0], 4)),
float(np.round(norm_pt[1], 4)),
0.0,
]
else:
# In 3D, keep z >= 0 ground orientation when appropriate
normalized[pid] = [
float(np.round(norm_pt[0], 4)),
float(np.round(norm_pt[1], 4)),
float(np.round(norm_pt[2], 4)),
]
return normalized
return cleaned