File size: 4,118 Bytes
76fa046
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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")))

    # --- STRATEGY 1: FRAME SAMPLING ---
    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:
            # Safely isolate frame index numerical components
            frame_id = int(''.join(filter(str.isdigit, dxf_file.stem)) or 0)
            doc = ezdxf.readfile(dxf_file)
            msp = doc.modelspace()
            
            # --- STRATEGY 2: VERTEX DECIMATION ---
            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')
        
        # --- STRATEGY 3: FACE LIMITING ---
        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])

            # --- STRATEGY 4: STRING FORMATTING & ROUNDING ---
            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)

    # Save output to the exact same temporary folder directory as the input CSV path
    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