# -*- coding: utf-8 -*- """地区编码:把 region 字符串映射成「大洲码 + 国家/地区码 + 方位码」, 用于生成编目号(如 AFETNE = 非洲 / 埃塞俄比亚 / 东北部)。 """ import json import math # region -> (大洲码, 国家/地区码, 现代国名[用于查标注点], 固定方位或 None) # 大洲码:AF 非洲 AS 亚洲 EU 欧洲 NA 北美 SA 南美 OC 大洋洲 AN 南极 GL 全球/海域 REGION_CC = { # —— 非洲 —— "东非 · 肯尼亚": ("AF", "KE", "肯尼亚", None), "东非 · 埃塞俄比亚": ("AF", "ET", "埃塞俄比亚", None), "东非 · 坦桑尼亚": ("AF", "TZ", "坦桑尼亚", None), "北非 · 摩洛哥": ("AF", "MA", "摩洛哥", None), "古埃及 · 孟菲斯": ("AF", "EG", "埃及", None), "古埃及 · 阿拜多斯": ("AF", "EG", "埃及", None), "古埃及 · 吉萨": ("AF", "EG", "埃及", None), "古埃及 · 阿玛纳": ("AF", "EG", "埃及", None), "古埃及 · 亚历山大港": ("AF", "EG", "埃及", None), "北非 · 迦太基": ("AF", "TN", "突尼斯", None), "葡萄牙 · 休达": ("AF", "MA", "摩洛哥", None), "埃及 · 苏伊士": ("AF", "EG", "埃及", None), "南非 · 开普敦": ("AF", "ZA", "南非", None), "南非 · 比勒陀利亚": ("AF", "ZA", "南非", None), # —— 亚洲 —— "东亚 · 中国周口店": ("AS", "CN", "中国", None), "西亚 · 以色列": ("AS", "IL", "以色列", None), "西亚 · 伊拉克": ("AS", "IQ", "伊拉克", None), "日本 · 本州": ("AS", "JP", "日本", None), "西亚 · 两河流域": ("AS", "IQ", "伊拉克", None), "南亚 · 印度河谷": ("AS", "PK", "巴基斯坦", None), "美索不达米亚 · 两河流域": ("AS", "IQ", "伊拉克", None), "美索不达米亚 · 乌尔": ("AS", "IQ", "伊拉克", None), "美索不达米亚 · 巴比伦": ("AS", "IQ", "伊拉克", None), "中国 · 河南安阳": ("AS", "CN", "中国", None), "古印度 · 恒河流域": ("AS", "IN", "印度", None), "西亚 · 安纳托利亚": ("AS", "TR", "土耳其", None), "地中海 · 东岸": ("AS", "LB", "黎巴嫩", None), "中国 · 咸阳": ("AS", "CN", "中国", None), "古印度 · 蓝毗尼": ("AS", "NP", "尼泊尔", None), "中国 · 鲁国曲阜": ("AS", "CN", "中国", None), "古印度 · 华氏城": ("AS", "IN", "印度", None), "中国 · 北方边塞": ("AS", "CN", "中国", None), "中国 · 陕西西安": ("AS", "CN", "中国", None), "中国 · 陕西汉中": ("AS", "CN", "中国", None), "中国 · 四川": ("AS", "CN", "中国", None), "犹太 · 伯利恒": ("AS", "PS", "巴勒斯坦", None), "中国 · 东汉洛阳": ("AS", "CN", "中国", None), "拜占庭 · 君士坦丁堡": ("AS", "TR", "土耳其", None), "阿拉伯半岛 · 麦加": ("AS", "SA", "沙特阿拉伯", None), "中国 · 建康": ("AS", "CN", "中国", None), "阿拉伯半岛 · 麦地那": ("AS", "SA", "沙特阿拉伯", None), "波斯 · 萨珊": ("AS", "IR", "伊朗", None), "朝鲜半岛 · 百济": ("AS", "KR", "韩国", None), "中亚 · 怛罗斯": ("AS", "KZ", "哈萨克斯坦", None), "日本 · 京都": ("AS", "JP", "日本", None), "中国 · 敦煌": ("AS", "CN", "中国", None), "中国 · 开封": ("AS", "CN", "中国", None), "中国 · 北宋": ("AS", "CN", "中国", None), "柬埔寨 · 吴哥": ("AS", "KH", "柬埔寨", None), "蒙古高原": ("AS", "MN", "蒙古", None), "中国 · 大都": ("AS", "CN", "中国", None), "印度 · 卡利卡特": ("AS", "IN", "印度", None), "印度 · 帕尼帕特": ("AS", "IN", "印度", None), "日本 · 江户": ("AS", "JP", "日本", None), "中国 · 广东虎门": ("AS", "CN", "中国", None), "中国 · 武昌": ("AS", "CN", "中国", None), "中国 · 沈阳": ("AS", "CN", "中国", None), "中国 · 江西": ("AS", "CN", "中国", None), "日本 · 广岛": ("AS", "JP", "日本", None), "印度 · 新德里": ("AS", "IN", "印度", None), "以色列 · 特拉维夫": ("AS", "IL", "以色列", None), "朝鲜半岛": ("AS", "KP", "朝鲜", None), "尼泊尔 · 珠峰": ("AS", "NP", "尼泊尔", None), "印度尼西亚 · 万隆": ("AS", "ID", "印度尼西亚", None), "苏联 · 拜科努尔": ("AS", "KZ", "哈萨克斯坦", None), "中国 · 罗布泊": ("AS", "CN", "中国", None), "美国 · 越南": ("AS", "VN", "越南", None), "中东 · 埃及叙利亚": ("AS", "EG", "埃及", None), "伊朗 · 德黑兰": ("AS", "IR", "伊朗", None), "中国 · 香港": ("AS", "CN", "中国", None), "中国 · 澳门": ("AS", "CN", "中国", None), "伊拉克 · 巴格达": ("AS", "IQ", "伊拉克", None), "中国 · 酒泉": ("AS", "CN", "中国", None), "中国 · 文昌": ("AS", "CN", "中国", None), # —— 欧洲 —— "欧洲 · 德国": ("EU", "DE", "德国", None), "欧洲 · 奥地利": ("EU", "AT", "奥地利", None), "欧洲 · 法国": ("EU", "FR", "法国", None), "不列颠 · 威尔特郡": ("EU", "GB", "英国", None), "爱琴海 · 克里特岛": ("EU", "GR", "希腊", None), "古希腊 · 奥林匹亚": ("EU", "GR", "希腊", None), "罗马帝国 · 罗马": ("EU", "IT", "意大利", None), "古希腊 · 爱奥尼亚": ("EU", "GR", "希腊", None), "古希腊 · 雅典": ("EU", "GR", "希腊", None), "古希腊 · 马拉松": ("EU", "GR", "希腊", None), "古希腊 · 温泉关": ("EU", "GR", "希腊", None), "古希腊 · 斯塔基拉": ("EU", "GR", "希腊", None), "马其顿 · 希腊半岛": ("EU", "GR", "希腊", None), "古希腊 · 叙拉古": ("EU", "IT", "意大利", None), "古罗马 · 卡普阿": ("EU", "IT", "意大利", None), "古罗马 · 庞贝": ("EU", "IT", "意大利", None), "古罗马 · 米兰": ("EU", "IT", "意大利", None), "罗马帝国 · 塞萨洛尼基": ("EU", "GR", "希腊", None), "西罗马 · 拉文纳": ("EU", "IT", "意大利", None), "伊比利亚 · 直布罗陀": ("EU", "GB", "英国", None), "法兰克 · 图尔": ("EU", "FR", "法国", None), "法兰克 · 亚琛": ("EU", "DE", "德国", None), "法兰克 · 凡尔登": ("EU", "FR", "法国", None), "英格兰 · 黑斯廷斯": ("EU", "GB", "英国", None), "意大利 · 博洛尼亚": ("EU", "IT", "意大利", None), "西欧 · 克莱蒙": ("EU", "FR", "法国", None), "法国 · 巴黎": ("EU", "FR", "法国", None), "英格兰 · 兰尼米德": ("EU", "GB", "英国", None), "意大利 · 佛罗伦萨": ("EU", "IT", "意大利", None), "欧洲 · 英法": ("EU", "FR", "法国", None), "欧洲 · 意大利": ("EU", "IT", "意大利", None), "法国 · 鲁昂": ("EU", "FR", "法国", None), "德意志 · 美因茨": ("EU", "DE", "德国", None), "西班牙 · 格拉纳达": ("EU", "ES", "西班牙", None), "德意志 · 维滕贝格": ("EU", "DE", "德国", None), "波兰 · 弗龙堡": ("EU", "PL", "波兰", None), "德意志 · 奥格斯堡": ("EU", "DE", "德国", None), "英吉利海峡": ("EU", "GB", None, "CH"), "英国 · 伦敦": ("EU", "GB", "英国", None), "西班牙 · 马德里": ("EU", "ES", "西班牙", None), "意大利 · 帕多瓦": ("EU", "IT", "意大利", None), "欧洲 · 威斯特伐利亚": ("EU", "DE", "德国", None), "英国 · 剑桥": ("EU", "GB", "英国", None), "法国 · 凡尔赛": ("EU", "FR", "法国", None), "瑞典 · 乌普萨拉": ("EU", "SE", "瑞典", None), "欧洲 · 英格兰": ("EU", "GB", "英国", None), "英国 · 格拉斯哥": ("EU", "GB", "英国", None), "英格兰 · 伯克利": ("EU", "GB", "英国", None), "俄国 · 莫斯科": ("EU", "RU", "俄罗斯", None), "比利时 · 滑铁卢": ("EU", "BE", "比利时", None), "英格兰 · 斯托克顿": ("EU", "GB", "英国", None), "克里米亚 · 塞瓦斯托波尔": ("EU", "UA", "乌克兰", None), "意大利 · 都灵": ("EU", "IT", "意大利", None), "瑞典 · 斯德哥尔摩": ("EU", "SE", "瑞典", None), "俄国 · 圣彼得堡": ("EU", "RU", "俄罗斯", None), "德国 · 柏林": ("EU", "DE", "德国", None), "德国 · 曼海姆": ("EU", "DE", "德国", None), "德国 · 维尔茨堡": ("EU", "DE", "德国", None), "瑞士 · 伯尔尼": ("EU", "CH", "瑞士", None), "欧洲 · 萨拉热窝": ("EU", "BA", "波斯尼亚", None), "欧洲 · 康边": ("EU", "FR", "法国", None), "瑞士 · 日内瓦": ("EU", "CH", "瑞士", None), "欧洲 · 波兰": ("EU", "PL", "波兰", None), "苏联 · 斯大林格勒": ("EU", "RU", "俄罗斯", None), "法国 · 诺曼底": ("EU", "FR", "法国", None), "欧洲 · 布鲁塞尔": ("EU", "BE", "比利时", None), "苏联 · 切尔诺贝利": ("EU", "UA", "乌克兰", None), "欧洲 · 马斯特里赫特": ("EU", "NL", "荷兰", None), "苏格兰 · 爱丁堡": ("EU", "GB", "英国", None), "欧洲 · 法兰克福": ("EU", "DE", "德国", None), # —— 北美 —— "中南美 · 墨西哥湾": ("NA", "MX", "墨西哥", None), "北美 · 普利茅斯": ("NA", "US", "美国", None), "北美 · 费城": ("NA", "US", "美国", None), "世界 · 纽约": ("NA", "US", "美国", None), "海地 · 太子港": ("NA", "HT", "海地", None), "美国 · 萨姆特堡": ("NA", "US", "美国", None), "美国 · 葛底斯堡": ("NA", "US", "美国", None), "美国 · 华盛顿": ("NA", "US", "美国", None), "美国 · 波士顿": ("NA", "US", "美国", None), "美国 · 门洛帕克": ("NA", "US", "美国", None), "美国 · 基蒂霍克": ("NA", "US", "美国", None), "美国 · 纽约": ("NA", "US", "美国", None), "美国 · 珍珠港": ("NA", "US", "美国", None), "美国 · 芝加哥": ("NA", "US", "美国", None), "美国 · 新墨西哥": ("NA", "US", "美国", None), "古巴 · 哈瓦那": ("NA", "CU", "古巴", None), "古巴 · 加勒比": ("NA", "CU", "古巴", None), "美国 · 洛杉矶": ("NA", "US", "美国", None), "美国 · 西雅图": ("NA", "US", "美国", None), "美国 · 库比蒂诺": ("NA", "US", "美国", None), "美国 · 加利福尼亚": ("NA", "US", "美国", None), "美国 · 旧金山": ("NA", "US", "美国", None), "美国 · 卡纳维拉尔角": ("NA", "US", "美国", None), # —— 南美 —— "南美 · 秘鲁": ("SA", "PE", "秘鲁", None), "拉丁美洲 · 委内瑞拉": ("SA", "VE", "委内瑞拉", None), # —— 大洋洲 —— "澳大利亚 · 植物学湾": ("OC", "AU", "澳大利亚", None), # —— 跨区域 / 海域 / 极地 —— "北欧 · 格陵兰": ("NA", "GL", "格陵兰", None), "西班牙 → 美洲": ("NA", "ES", None, "AM"), "大西洋 · 托德西利亚斯": ("GL", "PT", None, "TR"), "欧洲 → 环球": ("GL", "GL", None, "GB"), "大西洋": ("GL", "AT", None, "OC"), "挪威 · 南极": ("AN", "AQ", None, "SP"), } # 从 Natural Earth 国家数据读取标注点(按 ISO_A2 编码,用于计算条目在国家内的方位) COUNTRY_LABEL = {} try: with open("public/world-countries.geojson", encoding="utf-8") as _f: _gj = json.load(_f) for _ft in _gj.get("features", []): _p = _ft.get("properties", {}) _iso = _p.get("ISO_A2") if _iso and _iso != "-99" and _p.get("LABEL_X") is not None and _p.get("LABEL_Y") is not None: COUNTRY_LABEL[_iso.upper()] = (_p["LABEL_X"], _p["LABEL_Y"]) except Exception as _e: print(f"警告:读取国家标注点失败,方位将回退为 XX:{_e}") def _dir(lat, lng, cx, cy): dlat = lat - cy dlng = lng - cx ns = "N" if dlat > 0.5 else ("S" if dlat < -0.5 else "") ew = "E" if dlng > 0.5 else ("W" if dlng < -0.5 else "") if not ns and not ew: return "CE" if not ns: return "EA" if ew == "E" else "WE" if not ew: return "NO" if ns == "N" else "SO" return ns + ew # 条目类型枚举:E 事件/战役 P 人物/政党 T 学说/技术 I 文物/艺术品 B 建筑/奇观 TYPE_OVERRIDE = { # 化石标本(人 → 文物) "露西 · 南方古猿": "I", "杰贝尔依罗智人化石": "I", # 建筑/奇观(物 → B) "哥贝克力石阵": "B", "加泰土丘聚落": "B", "胡夫金字塔": "B", "巨石阵": "B", "乌尔金字形神塔": "B", "米诺斯宫殿": "B", "罗马斗兽场": "B", "雅典卫城 · 帕特农神庙": "B", "万里长城": "B", "吴哥窟": "B", "巴黎圣母院": "B", "亚历山大图书馆": "B", "博洛尼亚大学": "B", "苏伊士运河通航": "B", # 学说/技术(物 → T) "赫梯铁器": "T", "造纸术萌芽": "T", "毕昇活字印刷": "T", "古腾堡印刷术": "T", "伽利略天文望远镜": "T", "哥白尼日心说": "T", "林奈分类法": "T", "门捷列夫元素周期表": "T", "瓦特改良蒸汽机": "T", "第一条铁路": "T", "诺贝尔炸药": "T", "电话发明": "T", "爱迪生白炽灯": "T", "本茨汽车": "T", "莱特兄弟首飞": "T", "福特T型车": "T", "晶体管发明": "T", "斯普特尼克1号": "T", "iPhone发布": "T", # 学说/技术(事 → T) "蔡伦造纸": "T", "达尔文《物种起源》": "T", "牛顿《自然哲学的数学原理》": "T", "爱因斯坦狭义相对论": "T", "互联网诞生": "T", "科赫发现结核杆菌": "T", "伦琴发现X射线": "T", "琴纳牛痘接种": "T", "首例心脏移植": "T", "克隆羊多利": "T", } def classify(name, category): if name in TYPE_OVERRIDE: return TYPE_OVERRIDE[name] if category == "人": return "P" if category == "事": return "E" return "I" # 物(默认文物/艺术品) def _time_seg(tn): age = abs(tn) if age < 10000: if tn < 0: return "BC" + f"{math.ceil(age / 100):02d}" return "AD" + f"{(tn - 1) // 100 + 1:02d}" if age < 100000: return "BCE1" if age < 1000000: return "BCE2" if age < 10000000: return "BCE3" return "BCE4" def make_code(tn, region, lat, lng, idx, name, category): """生成编目号,如 E3-AFETNE-I0001。""" t = _time_seg(tn) # 地区段:大洲 + 国家/地区 + 方位 cont, iso, zh, fixed = REGION_CC.get(region, ("GL", "XX", None, "XX")) if fixed: sub = fixed elif iso.upper() in COUNTRY_LABEL: cx, cy = COUNTRY_LABEL[iso.upper()] sub = _dir(lat, lng, cx, cy) else: sub = "XX" prefix = classify(name, category) return f"{t}-{cont}{iso}{sub}-{prefix}{idx:04d}"