﻿"""
도진웍스 LiDAR 3D 뷰어 - open3d 네이티브 창
드래그=회전 / 휠=줌 / 우클릭=이동 / Q=종료
"""
import open3d as o3d
import trimesh
import numpy as np
from pathlib import Path

MERGED = Path("E:/도진팩토리/3D스캔및티칭시스템/output/merged.glb")
PLY_BASE = Path("E:/도진팩토리/3D스캔및티칭시스템")

def load_mesh():
    if MERGED.exists():
        print(f"merged.glb 로드 중...")
        m = trimesh.load(str(MERGED), force='mesh')
        mesh = o3d.geometry.TriangleMesh()
        mesh.vertices  = o3d.utility.Vector3dVector(m.vertices.astype(float))
        mesh.triangles = o3d.utility.Vector3iVector(m.faces)
        mesh.compute_vertex_normals()
        print(f"버텍스 {len(mesh.vertices):,} / 페이스 {len(mesh.triangles):,}")
        return mesh

    # fallback: PLY 시퀀스 전체 포인트클라우드
    seq_dirs = sorted(PLY_BASE.rglob("PLY_meshes"),
                      key=lambda p: p.parent.parent.stat().st_mtime, reverse=True)
    if not seq_dirs:
        print("스캔 파일 없음"); return None

    import struct
    plys = sorted(seq_dirs[0].rglob("*.ply"))
    step = max(1, len(plys)//300)   # 최대 300프레임 샘플링
    all_pts = []
    for ply in plys[::step]:
        with open(ply,'rb') as f:
            n_v = 0
            while True:
                line = f.readline().decode('utf-8','ignore').strip()
                if line.startswith('element vertex'): n_v = int(line.split()[-1])
                elif line == 'end_header': break
            data = struct.unpack_from(f'<{n_v*5}f', f.read(n_v*20))
            for i in range(n_v):
                all_pts.append([data[i*5], data[i*5+1], data[i*5+2]])

    pts = np.array(all_pts, dtype=np.float32)
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(pts)
    print(f"포인트클라우드: {len(pts):,}점")
    return pcd

geom = load_mesh()
if geom is None:
    print("로드 실패"); exit(1)

print("\n조작: 마우스 드래그=회전 / 휠=줌 / 우클릭드래그=이동 / Q=종료")
o3d.visualization.draw_geometries(
    [geom],
    window_name="도진웍스 LiDAR 3D 뷰어",
    width=1280, height=800,
    point_show_normal=False
)
