"""Decode the original DahojI PDF's outlined digits without OCR or AI. Digit signatures are from visually checked vector glyphs of this exact PDF. No rounding/borrowing of Excel ground elevations is used as source data. """ from pathlib import Path import collections,json,math,re import numpy as np from build_sample_grounds import OUTPUT,save folder=OUTPUT/'03_대호지교';raw=json.loads((folder/'original_profile_vectors.json').read_text(encoding='utf-8')) groups=json.loads((folder/'glyph_groups.json').read_text(encoding='utf-8')) mapping={0:'0',1:'.',2:'1',4:'2',5:'3',6:'9',7:'4',8:'5',9:'8',10:'7',11:'6'} signature_map={groups[k]['signature']:v for k,v in mapping.items()} angles=[] for index in groups[2]['indices']: path=raw['curves'][index]['path'];delta=np.array(path[2][1])-path[1][1] u=np.array([-delta[1],delta[0]]) if u[0]<0:u=-u angles.append(math.atan2(u[1],u[0])) hist,edges=np.histogram(angles,bins=90,range=(-math.pi/2,math.pi/2));mode=int(hist.argmax()) angle=float(np.median([v for v in angles if edges[mode]<=v<=edges[mode+1]])) u=np.array([math.cos(angle),math.sin(angle)]);v=np.array([-u[1],u[0]]) transform=np.column_stack([u,v]);glyphs=[];previous=[] for index,c in enumerate(raw['curves']): color=c['non_stroking_color'] if not(c['fill'] and isinstance(color,list) and len(color)==3 and abs(color[0]-.54902)<.01 and 20=p['x0']-.001 and c['x1']<=p['x1']+.001 and c['top']>=p['top']-.001 and c['bottom']<=p['bottom']+.001 for j,p in previous[-3:]) previous.append((index,c)) if inside or signature not in signature_map:continue character=signature_map[signature] points=np.array([pt for cmd in c['path'] for pt in cmd[1:] if isinstance(pt,list)]) rotated=points@transform;lo=rotated.min(0);hi=rotated.max(0) if character=='.': sides=np.linalg.norm(np.diff(points[:4],axis=0),axis=1) if sides.min()>0 and sides.max()/sides.min()>2:character='-' glyphs.append(dict(index=index,character=character,lo=lo.tolist(),hi=hi.tolist(), bbox=[c['x0'],c['top'],c['x1'],c['bottom']])) height=float(np.median([g['hi'][1]-g['lo'][1] for g in glyphs if g['character'].isdigit()])) tokens=[];token=[] def flush(): if not token:return text=''.join(g['character'] for g in token) if re.fullmatch(r'-?\d+\.\d{1,3}',text): bounds=np.array([g['bbox'] for g in token]);xy=(bounds[:,:2].min(0)+bounds[:,2:].max(0))/2 tokens.append(dict(text=text,elevation_m=float(text),pdf_center=xy.tolist(),glyph_indices=[g['index'] for g in token], bbox=[*bounds[:,:2].min(0),*bounds[:,2:].max(0)])) token.clear() for g in glyphs: if token: last=token[-1];normal=[x for x in token if x['character']!='-'] baseline=np.median([x['hi'][1] for x in normal]) if normal else g['hi'][1] adjacent=(-.08*height