"""
Edit C 검증: 렌더된 TCP 마커의 '실제 월드좌표'가 4자세 진실과 0.01mm 이내인가 (fk 아님, 실제 메시).
+ 토치 T회전 방향 캡처(홈 vs T+90) + 정반정합 캡처.
"""
import asyncio, json, sys, math
from playwright.async_api import async_playwright
URL='http://localhost:8090/DOZIKWORKS_OS_v5_locked.dc.html'
wp=json.loads(open(r'E:\도진팩토리\3D스캔및티칭시스템\weld_path.json',encoding='utf-8').read())
arc=[p for p in wp['poses'] if p.get('arc')==1]
segs=[pt for seg in wp['segs'] for pt in seg]
n=min(len(arc),len(segs)); idxs=[0,min(34,n-1),min(63,n-1),min(99,n-1)]
poses4=[{k:arc[i][k] for k in ['S','L','U','R','B','T']} for i in idxs]
truth4=[segs[i] for i in idxs]

async def main():
    async with async_playwright() as p:
        br=await p.chromium.launch(channel='msedge',headless=True)
        pg=await br.new_page(viewport={'width':1536,'height':864})
        errs=[]; pg.on('console',lambda m: errs.append(m.text) if m.type=='error' else None)
        await pg.goto(URL); await pg.wait_for_timeout(32000)
        # 각 자세에서 setJoints → 마커 메시 월드좌표 → _grp 로컬 mm
        res=await pg.evaluate("""async (poses)=>{
          const a=window.__dzw, T=a._T; const out=[];
          for(const j of poses){
            a.setJoints(j); await new Promise(r=>setTimeout(r,120));
            a._grp.updateMatrixWorld(true);
            const w=new T.Vector3(); a._tcpMarker.getWorldPosition(w);
            const loc=a._grp.worldToLocal(w.clone());   // _grp 로컬 = 진실 mm
            out.push([loc.x,loc.y,loc.z]);
          }
          return out;
        }""",poses4)
        print("=== 렌더된 TCP 마커 월드→진실mm vs weld_path 진실 ===")
        maxe=0
        for lbl,mk,tr in zip(['SEAM-01','SEAM-02','SEAM-03','SEAM-04'],res,truth4):
            e=math.sqrt(sum((a-b)**2 for a,b in zip(mk,tr))); maxe=max(maxe,e)
            print(f"  {lbl}: 마커={[round(x,2) for x in mk]} truth={[round(x,2) for x in tr]} 오차={e:.3f}mm")
        print(f"  ★ 마커 최대오차 {maxe:.3f}mm →", "통과 ✅" if maxe<0.01 else "실패 ❌")
        # 홈 자세 캡처
        await pg.evaluate("(()=>{const a=window.__dzw; a.setJoints({S:0,L:0,U:0,R:0,B:0,T:0}); if(a.orbit){a.orbit.phi=1.1;a.orbit.theta=0.6;a.orbit.r=3.2;a.updateCam();}})()")
        await pg.wait_for_timeout(1000); await pg.screenshot(path='shots/verify_C_home.png')
        # T축 회전 자세 (토치 방향 확인): T=0 vs T=+90
        await pg.evaluate("(()=>{const a=window.__dzw; a.setJoints({S:0,L:20,U:-20,R:0,B:-60,T:0}); if(a.orbit){a.orbit.phi=1.2;a.orbit.theta=0.3;a.orbit.r=1.6;a.updateCam();}})()")
        await pg.wait_for_timeout(800); await pg.screenshot(path='shots/verify_C_T0.png')
        await pg.evaluate("(()=>{const a=window.__dzw; a.setJoints({S:0,L:20,U:-20,R:0,B:-60,T:90});})()")
        await pg.wait_for_timeout(800); await pg.screenshot(path='shots/verify_C_T90.png')
        print("캡처: verify_C_home / verify_C_T0 / verify_C_T90  콘솔에러", len(errs))
        await br.close()
asyncio.run(main())
