# -*- coding: utf-8 -*-
"""조립도 시트 전체에서 '두께 PL 만큼 떨어진 평행선 쌍 + 길이가 그 부재 치수와 일치'
   하는 곳을 찾는다. 근접(풍선) 추정이 아니라 치수 일치 실측이라 근거가 강하다."""
import json, math
import numpy as np

SCR = r'C:\Users\user\AppData\Local\Temp\claude\E-----Claude--20260728-claude-code-2-1-219\8defc145-8ae5-48d0-9058-355f3d9ae8ed\scratchpad'
X0, Y0, X1, Y1 = 326830, 3900, 331790, 8130

# 항번: (도번, 실측 외곽 a, b, 두께 t)   ← OBJ 실측 bbox
PARTS = {
    1:  ('2110DN-0031-001', 388.0, 250.0, 30.0),
    2:  ('2110DN-0031-002', 440.0, 250.0, 30.0),
    4:  ('2110DN-0031-005', 607.0, 196.0, 25.0),
    5:  ('2110DN-0031-010', 198.0, 83.0, 20.0),
    6:  ('2110DN-0031-006', 613.0, 197.0, 20.0),
    7:  ('2110DN-0031-008', 198.0, 83.0, 20.0),
    8:  ('2110DN-0031-004', 250.0, 344.46, 30.0),
    9:  ('2110DN-0031-011', 253.0, 150.0, 30.0),
    14: ('2110DN-0031-009', 150.0, 40.0, 12.0),
    15: ('2110DN-0031-012', 90.0, 90.0, 6.0),
}

VIEWS = {
    'LEFT':  (327200, 3950, 328250, 5700),
    'FRONT': (328400, 3950, 329400, 5700),
    'RIGHT': (329800, 3950, 330750, 5700),
    'SECC':  (330880, 3950, 331849, 5900),
    'SECA':  (327100, 5950, 328600, 7100),
    'MIDT':  (328600, 5950, 330000, 7100),
    'SECB':  (329900, 5950, 331100, 7100),
}


def view_of(x, y):
    for k, (a, b, c, d) in VIEWS.items():
        if a < x < c and b < y < d:
            return k
    return '?'


def main():
    d2 = json.load(open(SCR + r'\index2.json', encoding='utf-8'))
    L = np.array([l[:4] for l in d2['lines']], dtype=float)
    m = ((L[:, 0] > X0) & (L[:, 0] < X1) & (L[:, 1] > Y0) & (L[:, 1] < Y1))
    S = L[m]
    P0 = S[:, :2]
    P1 = S[:, 2:]
    V = P1 - P0
    N = np.hypot(V[:, 0], V[:, 1])
    keep = N > 12
    S, P0, P1, V, N = S[keep], P0[keep], P1[keep], V[keep], N[keep]
    U = V / N[:, None]
    print('segments', len(S))

    thks = sorted(set(p[3] for p in PARTS.values()))
    found = {}
    for i in range(len(S)):
        for j in range(i + 1, len(S)):
            if abs(abs(U[i] @ U[j]) - 1) > 0.02:
                continue
            nrm = np.array([-U[i][1], U[i][0]])
            gap = abs((P0[j] - P0[i]) @ nrm)
            if gap < 2:
                continue
            ts = [t for t in thks if abs(gap - t) < 0.6]
            if not ts:
                continue
            # 겹치는 길이(투영)
            t0 = np.array([P0[i] @ U[i], P1[i] @ U[i], P0[j] @ U[i], P1[j] @ U[i]])
            ov = min(t0[:2].max(), t0[2:].max()) - max(t0[:2].min(), t0[2:].min())
            span = max(N[i], N[j])
            if ov < 5:
                continue
            for it, (pn, a, b, t) in PARTS.items():
                if abs(gap - t) > 0.6:
                    continue
                for dim in (a, b):
                    if abs(span - dim) < 1.5:
                        mid = (P0[i] + P1[i] + P0[j] + P1[j]) / 4
                        key = (it, round(mid[0], 1), round(mid[1], 1))
                        found.setdefault(key, {
                            'item': it, 'pn': pn, 'dim': dim, 'gap': round(gap, 2),
                            'span': round(span, 1),
                            'ang': round(math.degrees(math.atan2(U[i][1], U[i][0])) % 180, 1),
                            'view': view_of(mid[0], mid[1]),
                            'lo': [round(float(min(P0[i][0], P1[i][0], P0[j][0], P1[j][0])), 2),
                                   round(float(min(P0[i][1], P1[i][1], P0[j][1], P1[j][1])), 2)],
                            'hi': [round(float(max(P0[i][0], P1[i][0], P0[j][0], P1[j][0])), 2),
                                   round(float(max(P0[i][1], P1[i][1], P0[j][1], P1[j][1])), 2)]})
    out = sorted(found.values(), key=lambda r: (r['item'], r['view']))
    json.dump(out, open(SCR + r'\asm31_scan.json', 'w'), indent=1)
    for r in out:
        print('%2d %-18s dim%-7g gap%-6g ang%-6g %-6s lo%s hi%s'
              % (r['item'], r['pn'], r['dim'], r['gap'], r['ang'], r['view'], r['lo'], r['hi']))


if __name__ == '__main__':
    main()
