- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환 - Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용 - pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관) - worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md) - D:\Rhino-MCP 경로 참조를 새 위치로 치환 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
68 lines
3.3 KiB
Python
68 lines
3.3 KiB
Python
import sys, json, re, io, collections, math
|
||
sys.path.insert(0,'pylib')
|
||
import rhino3dm
|
||
tab=json.load(open('ok2_table.json',encoding='utf-8'))
|
||
det=[e for e in json.load(open('ok2_shapes.json',encoding='utf-8')) if 'L' in e]
|
||
Mo=json.load(open('ok_model_dims.json',encoding='utf-8'))
|
||
UW={'H35':7.51,'H32':6.23,'H29':5.04,'H25':3.98,'H22':3.04,'H19':2.25,'H16':1.56,'H13':0.995}
|
||
# 모델 곡선 실제 길이
|
||
m3=rhino3dm.File3dm.Read(r"D:\★Pier 자료\심수석님 검토 파일\검토_옥성교P1\옥성교P1_G5.3dm")
|
||
geo=collections.defaultdict(list)
|
||
for o in m3.Objects:
|
||
g=o.Geometry; nm=o.Attributes.Name or ''
|
||
if nm.startswith('P1-RC-') and hasattr(g,'GetLength'):
|
||
us=dict(o.Attributes.GetUserStrings()); mk=us.get('mark') or nm.split('-')[2]
|
||
geo[mk].append(g.GetLength())
|
||
def mm(s):
|
||
out=[]
|
||
for p in s.split('~'):
|
||
p=re.sub(r'[^\d.]','',p)
|
||
if not p: continue
|
||
v=float(p); out.append(v*1000 if '.' in p and v<100 else v)
|
||
return out
|
||
D=collections.defaultdict(list)
|
||
for e in det: D[e['mark']].append(e)
|
||
o=io.open('ok_rerun2.txt','w',encoding='utf-8')
|
||
res={}
|
||
for t in tab:
|
||
mk=t['mark']; r={'mark':mk,'issues':[]}
|
||
# 표 산술
|
||
if abs(t['L']*t['n']/1000.0-t['tot'])>0.0015*max(1,t['n']): r['issues'].append(u'표 산술 L×N≠총길이 (%.3f×%d=%.3f ↔ %.3f)'%(t['L']/1000,t['n'],t['L']*t['n']/1e6,t['tot']))
|
||
m=Mo.get(mk)
|
||
if not m:
|
||
r['issues'].append(u'모델에 없음'); res[mk]=r; o.write(u'%s 표 n=%d L=%.0f → 모델 없음\n'%(mk,t['n'],t['L'])); continue
|
||
half=2 if mk in('P3','P4') else 1
|
||
n=m['n']//half
|
||
if n!=t['n']: r['issues'].append(u'본수 표%d/모델%d'%(t['n'],n))
|
||
dl=[v*half for v in m['dl']]; mean=sum(dl)/len(dl); tot=sum(dl)/1000.0/half*half
|
||
tot_m=sum(m['dl'])/1000.0
|
||
r['L']=(t['L'],mean,min(dl),max(dl)); r['tot']=(t['tot'],tot_m)
|
||
# 길이 판정
|
||
dev=mean-t['L']
|
||
if abs(dev)>3 or max(dl)-min(dl)>3: r['issues'].append(u'길이 표%.0f 모델평균%.0f (%.0f~%.0f) %+.0f'%(t['L'],mean,min(dl),max(dl),dev))
|
||
# 실제 곡선 길이 vs 설계길이
|
||
gl=geo.get(mk,[])
|
||
if gl:
|
||
gm=sum(gl)/len(gl)*(half)
|
||
r['geo']=gm
|
||
if gm<mean*0.97: r['issues'].append(u'형상 실길이 %.0f < 설계길이 %.0f (j 등 미작도 %.0f)'%(gm,mean,mean-gm))
|
||
# 철근상세 치수
|
||
miss=[]
|
||
dd=D.get(mk,[])
|
||
for e in dd[:1]:
|
||
for s in e['dims']:
|
||
k,_,v=s.partition('='); k=k.strip()
|
||
if k.startswith('j') or k.startswith('x'): continue
|
||
for val in mm(v):
|
||
if not any(abs(val-q)<=3 for q in m['values']): miss.append('%s=%s'%(k,v))
|
||
if miss: r['issues'].append(u'상세 치수 모델에 없음 %s'%miss)
|
||
r['dia']=(t['dia'],m['dia']);
|
||
if t['dia']!=m['dia']: r['issues'].append(u'직경 표%s/모델%s'%(t['dia'],m['dia']))
|
||
res[mk]=r
|
||
o.write(u'%s %s n표%d/모 %d | L표 %.0f 모델 %.0f(%.0f~%.0f) 실길이 %s | 총 %.3f/%.3f | 도면 %s | %s\n'%(mk,t['dia'],t['n'],n,t['L'],mean,min(dl),max(dl),('%.0f'%r['geo']) if 'geo' in r else '-',t['tot'],tot_m,(' '.join(dd[0]['dims']) if dd else '-'),' ; '.join(r['issues']) if r['issues'] else '일치'))
|
||
json.dump(res,open('ok_rerun2.json','w',encoding='utf-8'),ensure_ascii=False)
|
||
bad=[k for k,v in res.items() if v['issues']]
|
||
o.write(u'\n문제 있는 마크 %d / %d: %s\n'%(len(bad),len(res),bad))
|
||
o.close()
|
||
print(len(bad),len(res))
|