{html.escape(item["file"])} — {html.escape(item["title"])}
{details}
원문 / 이용조건"""Build a local reference index and GeoJSON from the downloaded OSM extract."""
import csv
import hashlib
import html
import json
from pathlib import Path
import xml.etree.ElementTree as ET
from PIL import Image, ImageDraw
root = Path(__file__).resolve().parents[1] / 'data/references/summit'
osm = ET.parse(root / 'maps/summit.osm').getroot()
nodes = {n.attrib['id']: [float(n.attrib['lon']), float(n.attrib['lat'])] for n in osm.findall('node')}
features = []
for element in osm:
tags = {t.attrib['k']: t.attrib['v'] for t in element.findall('tag')}
if not tags or element.tag not in ('node', 'way'):
continue
if element.tag == 'node':
lon,lat = nodes[element.attrib['id']]
if not (126.950 <= lon <= 126.975 and 37.430 <= lat <= 37.453):
continue
geometry = {'type': 'Point', 'coordinates': nodes[element.attrib['id']]}
else:
coordinates = [nodes[n.attrib['ref']] for n in element.findall('nd') if n.attrib['ref'] in nodes]
if len(coordinates) != len(element.findall('nd')) or len(coordinates) < 2:
continue
area = coordinates[0] == coordinates[-1] and (tags.get('area') == 'yes' or 'building' in tags or 'landuse' in tags)
geometry = {'type': 'Polygon' if area else 'LineString', 'coordinates': [coordinates] if area else coordinates}
features.append({'type': 'Feature', 'id': element.tag + '/' + element.attrib['id'], 'properties': tags, 'geometry': geometry})
(root / 'maps/summit.geojson').write_text(json.dumps({'type': 'FeatureCollection', 'features': features}, ensure_ascii=False), encoding='utf-8')
structures = [f for f in features if any(k in f['properties'] for k in ('building', 'man_made', 'barrier')) or f['properties'].get('tourism') == 'viewpoint']
with (root / 'maps/structure-inventory.csv').open('w', encoding='utf-8-sig', newline='') as out:
writer = csv.writer(out)
writer.writerow(['osm_id', 'name', 'tags', 'geometry'])
for f in structures:
writer.writerow([f['id'], f['properties'].get('name', ''), json.dumps(f['properties'], ensure_ascii=False), json.dumps(f['geometry'])])
def xy(c):
return ((c[0]-126.950)/.025*850, (37.453-c[1])/.023*985)
svg = ['')
(root/'maps/overview.svg').write_text(''.join(svg), encoding='utf-8')
downloads = json.loads((root/'photos/downloads.json').read_text(encoding='utf-8'))
recent_path = root/'photos/recent-downloads.json'
if recent_path.exists():
downloads += json.loads(recent_path.read_text(encoding='utf-8'))
cards=[]
valid=[]
for item in downloads:
if item['status'] != 'downloaded':
continue
if item['file'] in {f'photo-{i:02d}.jpg' for i in range(2,9)} | {'recent-01.jpg','recent-03.jpg','recent-06.jpg'}:
item['relevance'] = '주요 구조물 참고사진에서 제외: 인물, 원경, 계곡 또는 음식'
continue
path=root/'photos'/item['file']
with Image.open(path) as im:
im.verify()
item['sha256']=hashlib.sha256(path.read_bytes()).hexdigest()
valid.append(item)
meta=item['metadata']
details=' {details}
'.join(html.escape(k)+': '+meta.get(k,{}).get('value','미상') for k in ['Artist','DateTimeOriginal','LicenseShortName','LicenseUrl'])
cards.append(f'{html.escape(item["file"])} — {html.escape(item["title"])}
수집일 2026-10-29. OSM은 국가 수치지도 대체 참고자료이며 측량도면이 아닙니다. 사진은 촬영 시점의 모습으로 현재 형태와 차이가 있을 수 있습니다. 치수 미확정.
자료 범위와 한계 · GeoJSON · 구조물 목록 · OSM 출처·ODbL