| import pandas as pd |
| import numpy as np |
| import os |
| import ezdxf |
| from pathlib import Path |
|
|
| def process_mesh(input_csv_path: str, dxf_dir_path: str, max_faces=500, precision=2) -> str: |
| """ |
| V66 Geometry Engine: Optimized for Low-Disk usage on Hugging Face. |
| Processes coordinate lines directly from dynamic session paths. |
| """ |
| print(f" -> Processing Optimized Mesh from: {dxf_dir_path}") |
| |
| dxf_dir = Path(dxf_dir_path) |
| if not dxf_dir.exists(): |
| raise FileNotFoundError(f"DXF directory not found at {dxf_dir}") |
|
|
| all_points = [] |
| dxf_files = sorted(list(dxf_dir.glob("*.dxf"))) |
|
|
| |
| if len(dxf_files) > 60: |
| print(f" -> High frame count ({len(dxf_files)}). Downsampling for performance.") |
| dxf_files = dxf_files[::2] |
|
|
| for dxf_file in dxf_files: |
| try: |
| |
| frame_id = int(''.join(filter(str.isdigit, dxf_file.stem)) or 0) |
| doc = ezdxf.readfile(dxf_file) |
| msp = doc.modelspace() |
| |
| |
| entities = msp.query('LINE') |
| sampling_rate = 2 if len(entities) > 500 else 1 |
| |
| for i, entity in enumerate(entities): |
| if i % sampling_rate != 0: |
| continue |
| all_points.append({'t': frame_id, 'x': entity.dxf.start.x, 'y': entity.dxf.start.y, 'z': entity.dxf.start.z}) |
| all_points.append({'t': frame_id, 'x': entity.dxf.end.x, 'y': entity.dxf.end.y, 'z': entity.dxf.end.z}) |
| except Exception: |
| continue |
|
|
| if not all_points: |
| raise ValueError("No valid point geometry vectors could be parsed from DXF tracking layers.") |
|
|
| df_vertices = pd.DataFrame(all_points) |
| final_results = [] |
| center_x, center_y = df_vertices['x'].mean(), df_vertices['y'].mean() |
|
|
| for frame_id, group in df_vertices.groupby('t'): |
| if len(group) < 2: continue |
| |
| group = group.drop_duplicates(subset=['x', 'y']).copy() |
| group['dist'] = np.sqrt((group['x'] - center_x)**2 + (group['y'] - center_y)**2) |
| group = group.sort_values('dist') |
| |
| |
| window_size = 2 |
| rolling = group.rolling(window=window_size) |
| |
| for i, window in enumerate(rolling): |
| if len(window) < window_size or i > max_faces: |
| continue |
|
|
| pts = window[['x', 'y', 'z']].values |
| cp_x, cp_y = np.mean(pts[:, 0]), np.mean(pts[:, 1]) |
| |
| avg_dist = np.mean(window['dist']) |
| d_min, d_max = group['dist'].min(), group['dist'].max() |
| span = (d_max - d_min) if d_max != d_min else 1 |
| norm = (avg_dist - d_min) / span |
| |
| r, g, b = int(255 * norm), int(255 * (1 - norm)), int(255 * (0.5 + 0.5 * np.sin(norm * np.pi))) |
| dynamic_z = float(frame_id + 1.0) * (r + g + b) |
|
|
| v1 = pts[1] - pts[0] |
| v2 = np.array([0, 0, dynamic_z]) |
| normal = np.cross(v1, v2) |
| norm_val = np.linalg.norm(normal) |
| normal_unit = normal / norm_val if norm_val > 1e-9 else np.array([0, 0, 1]) |
|
|
| |
| row = (f"{frame_id}," |
| f"{cp_x:.{precision}f}," |
| f"{cp_y:.{precision}f}," |
| f"{dynamic_z:.1f}," |
| f"{r},{g},{b}," |
| f"{normal_unit[0]:.2f},{normal_unit[1]:.2f},{normal_unit[2]:.2f}," |
| f"{np.linalg.norm(v1):.2f}," |
| f"{np.arccos(np.clip(np.dot([0,0,1], normal_unit), -1.0, 1.0)):.2f}") |
| final_results.append(row) |
|
|
| |
| output_path = os.path.dirname(input_csv_path) + "/final_12d_features.csv" |
| with open(output_path, 'w') as f: |
| f.write("t,x,y,z,R,G,B,N_x,N_y,N_z,d,th\n") |
| f.write("\n".join(final_results)) |
|
|
| return output_path |