BLOCK7 원본 구조선과 표고 재분석 및 불일치 기록

This commit is contained in:
김지영 committed 2026-10-20 10:51:46 +09:00
1 parent 100480b5e7
commit 39231d52c1
8 files changed
+149 -61

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
import json,pathlib,collections,math
ROOT=pathlib.Path(__file__).resolve().parents[1]
raw=(ROOT/'public/drawings/광터지하차도_일반도(BLOCK7).dxf').read_text(encoding='utf8',errors='replace').splitlines()
pairs=[(int(raw[i].strip()),raw[i+1].strip()) for i in range(0,len(raw)-1,2)]
entities=[]; current=None; section=''; block=None; blocks={}
for code,value in pairs:
if code==0:
if current:
if section=='ENTITIES': entities.append(current)
elif section=='BLOCKS' and block and current['type'] not in ('BLOCK','ENDBLK'): blocks.setdefault(block,[]).append(current)
current={'type':value,'data':[]}
if value=='ENDBLK': block=None
elif current:
current['data'].append((code,value))
if current['type']=='SECTION' and code==2: section=value
if current['type']=='BLOCK' and code==2: block=value
def get(e,c,d=None): return next((v for k,v in e['data'] if k==c),d)
def point(e,c=10): return [float(get(e,c,0)),float(get(e,c+10,0))]
def layer(e): return get(e,8,'')
out=ROOT/'docs/extracted';out.mkdir(exist_ok=True)
texts=[{'text':get(e,1,''),'p':point(e),'layer':layer(e)} for e in entities if e['type'] in ('TEXT','MTEXT')]
lines=[{'a':point(e),'b':point(e,11),'layer':layer(e),'handle':get(e,5)} for e in entities if e['type']=='LINE']
for name,data in [('texts',texts),('lines',lines),('blocks',blocks),('inserts',[{'name':get(e,2),'p':point(e),'sx':get(e,41,'1'),'sy':get(e,42,'1'),'rotation':get(e,50,'0'),'layer':layer(e)} for e in entities if e['type']=='INSERT'])]:
(out/(name+'.json')).write_text(json.dumps(data,ensure_ascii=False,indent=2),encoding='utf8')
print('Entities',collections.Counter(e['type'] for e in entities))
for t in texts:
if any(s in t['text'] for s in ('BLOCK7','106.675','107.307','101.636','101.069','102.436','101.869','299.010','318.990','선형','측구','20.100')): print(t)
for name,top in [('A',-74271),('B',-91211)]:
selected=[l for l in lines if l['layer'] in ('CS-CONC-MAJR','CS-CONC-MINR') and all(1118000<p[0]<1139000 and top-7500<p[1]<top+100 for p in (l['a'],l['b']))]
print(name,len(selected),collections.Counter(l['layer'] for l in selected))
(out/f'section-{name}.json').write_text(json.dumps(selected,ensure_ascii=False,indent=2),encoding='utf8')
# 도면 근거를 보존하는 모델 데이터와 원도면 검토 SVG 생성
sections=[]
for name,top,el,sta in [('A',-74271.37855593952,106.675,299.000),('B',-91211.37855593952,107.307,319.000)]:
selected=[l for l in lines if l['layer'] in ('CS-CONC-MAJR','CS-CONC-MINR') and all(1118000<p[0]<1139000 and top-7500<p[1]<top+100 for p in (l['a'],l['b']))]
sections.append({'name':name,'topCad':top,'topEL':el,'station':sta,'lines':selected})
def group(i):
if i<5 or i==100: return '底版'
if 5<=i<=15: return '좌측 측구·포장 경계'
if 16<=i<=26: return '우측 측구·포장 경계'
if 27<=i<=86: return '포장 반복선·내부선'
if 87<=i<=89: return '중앙 분리부'
if 90<=i<=94: return '좌측 벽체'
if 95<=i<=99: return '우측 벽체'
if 101<=i<=107: return '하부·외측 보조 윤곽'
return '바닥판 상면·세부선'
def norm(p,s): return [round((p[0]-1128486.218066491)/1000,7),round(s['topEL']+(p[1]-s['topCad'])/1000,7)]
parts=[]
for i,(a,b) in enumerate(zip(sections[0]['lines'],sections[1]['lines'])):
assert a['layer']==b['layer']
assert all(abs(a[k][0]-b[k][0])<0.01 for k in ['a','b'])
parts.append({'id':'line-'+a['handle'],'name':group(i).replace('底版','바닥판 하단')+' · '+str(i+1),'group':group(i).replace('底版','바닥판 하단'),'layer':a['layer'],'handles':[a['handle'],b['handle']],'a':[norm(a['a'],sections[0]),norm(a['b'],sections[0])],'b':[norm(b['a'],sections[1]),norm(b['b'],sections[1])],'repeat':27<=i<=86,'kind':'line','source':'일반도 14 / 단면 A-A·B-B / '+a['layer']})
# 삽입 블록의 반전과 실제 LINE/ARC 윤곽을 보존한다. 원호는 5도 간격으로 표시한다.
ductName='A$C2017021411375356'
for side,x,sx in [('좌측',1119736.218066468,1),('우측',1137236.218066513,-1)]:
for j,e in enumerate(blocks[ductName]):
if e['type']=='LINE': pts=[point(e),point(e,11)]
elif e['type']=='ARC':
center=point(e); r=float(get(e,40)); start=float(get(e,50)); end=float(get(e,51))
if end<=start:end+=360
pts=[[center[0]+r*math.cos(math.radians(t)),center[1]+r*math.sin(math.radians(t))] for t in [start+(end-start)*k/36 for k in range(37)]]
else: continue
profiles=[]
for s,y in zip(sections,[-77447.89255584464,-95669.3155558447]):profiles.append([norm([x+sx*p[0],y+p[1]],s) for p in pts])
parts.append({'id':f'duct-{side}-{j}','name':f'{side} 공동구·상부 상세 · {j+1}','group':f'{side} 공동구·상부 상세','layer':layer(e),'handles':[get(e,5)],'a':profiles[0],'b':profiles[1],'repeat':False,'kind':e['type'].lower(),'source':'일반도 14 / '+ductName+' / 원본 삽입 블록'})
model={'source':'광터지하차도_일반도(BLOCK7).dxf','units':'m','length':19.98,'sectionStations':[299,319],'longitudinalStations':[299.01,318.99],'sectionTops':[106.675,107.307],'sectionBottoms':[101.636,101.069],'centerEL':[None,None],'alignment':None,'status':'확인 필요','parts':parts}
modelDir=ROOT/'src/model';modelDir.mkdir(exist_ok=True)
(modelDir/'block7.json').write_text(json.dumps(model,ensure_ascii=False,indent=2),encoding='utf8')
import html
previewDir=ROOT/'public/analysis';previewDir.mkdir(exist_ok=True)
views=[('단면A',1113000,-84300,1142000,-69500),('단면B',1113000,-102300,1142000,-85500),('평면검토',1020000,-96000,1105000,-64000),('종단검토',1040000,-113000,1085000,-95000),('측구상세',1165000,-85000,1185000,-77000)]
for title,x0,y0,x1,y1 in views:
content=[]
for l in lines:
if all(x0<p[0]<x1 and y0<p[1]<y1 for p in (l['a'],l['b'])):
color='#326c5d' if l['layer'] in ('CS-CONC-MAJR','CS-CONC-MINR') else '#8d969e'
content.append(f'<line x1="{l["a"][0]}" y1="{-l["a"][1]}" x2="{l["b"][0]}" y2="{-l["b"][1]}" stroke="{color}" stroke-width="15"><title>{l["handle"]} / {l["layer"]}</title></line>')
for t in texts:
x,y=t['p']
if x0<x<x1 and y0<y<y1:content.append(f'<text x="{x}" y="{-y}" font-size="200" fill="#28334b">{html.escape(t["text"])}</text>')
# 공동구 삽입 블록의 실제 선 포함
for e in entities:
if e['type']=='INSERT' and get(e,2)==ductName:
x,y=point(e);sx=float(get(e,41,1));sy=float(get(e,42,1))
if x0<x<x1 and y0<y<y1:
for q in blocks[ductName]:
if q['type']=='LINE':
a,b=point(q),point(q,11);content.append(f'<line x1="{x+sx*a[0]}" y1="{-y-sy*a[1]}" x2="{x+sx*b[0]}" y2="{-y-sy*b[1]}" stroke="#a97635" stroke-width="15"/>')
svg=f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{x0} {-y1} {x1-x0} {y1-y0}"><rect x="{x0}" y="{-y1}" width="{x1-x0}" height="{y1-y0}" fill="#fff"/>'+''.join(content)+'</svg>'
(previewDir/(title+'.svg')).write_text(svg,encoding='utf8')
print('모델 추출:',len(parts),'객체. 단면 원본 선 114쌍, 공동구 20쌍 × 좌우.')