一句话:不依赖任何 GIS 框架,用「OSM/高德数据 + Three.js 挤出」纯手搓校园 3D 地图。数据与渲染分离,任何"数据可视化 3D"都是同一套路。

核心认知:地图 API 从不给你 3D,只给坐标

地图类 API(高德/OSM/百度)返回的本质是带坐标的表格:

  • 楼 = 一圈经纬度点(墙脚轮廓)+ 属性(名字、层数)
  • 路 = 一串中心线点 + 等级(primary/service/footway...)
  • POI = 单个经纬度点 + 名字

3D 是自己算出来的:2D 轮廓 × 高度 = 3D 体块。楼高 = 层数标签 × 3.2m(缺失则按类型猜)。Three.js 的 ExtrudeGeometry 就是"压饼干":平面形状往上拉。

数据源对比(2026 实测,宁波高校场景)

来源轮廓名字楼层要 key备注
OSM✓ 全25/88 栋44/88 栋✗ 免费国内校园覆盖稀,欧洲城市极好
高德 REST✗ 无POI 点全✗✓ 免费只有"点",无楼块轮廓
高德 JS API✓(自渲染)✓✓✓数据取不出来,只给画布
天地图精度差✓✗✓不推荐校园场景

关键结论:

  • OSM + 高德 REST 互补合并 = 钱湖校区 88 栋楼全形 + 29 栋真名
  • 高德 JS API 楼块数据无法导出,想要数据只能:手工描卫星图 / CustomLayer 混合渲染(丑,不推荐)
  • 校内步行导航数据:所有家都没有,只能自建路径网

管线(Pipeline)

Overpass API (OSM)          高德 REST API
  │ way[building]              │ place/text (POI)
  ▼                            ▼
convert_overpass.py          enrich_campus.py
  经纬度→米(等距圆柱投影)      GCJ02→WGS84 反偏移
  按类型赋默认高度             点落在哪栋楼轮廓内→名字归谁
  ▼                            ▼
        campus.json (米制 GeoJSON)
                    ▼
          CampusCleanMap.vue (Three.js)
          Shape→Extrude / 路→ribbon面 / CSS2D标签

关键代码要点

  1. 经纬度转米(局部等距圆柱投影,校园尺度误差可忽略):

    x = (lon - CENTER_LON) * 111320 * cos(radians(CENTER_LAT))
    y = (lat - CENTER_LAT) * 110574
  2. GCJ02→WGS84 反偏移:标准近似逆算法,精度 1-2m。实测高德与 OSM 在该校区整体偏差仅 4m(用同名楼校准:POI 点换算后与 OSM 同名楼质心做中位数差)。
  3. POI 落楼:点在多边形内(point-in-polygon)直接配;45m 内配最近无名楼标"位置近似";校外丢弃。
  4. 路变面:中心线 + 等级宽度(primary 9m / footway 2.2m)→ 左右偏移 → ribbon 面。比画线真实得多。
  5. Three.js 侧:ShapeGeometry(底)+ ExtrudeGeometry(楼)+ CSS2DRenderer(标签)+ OrbitControls(拖拽)。One immediate render after setup 防黑屏。

踩坑记录

  • Overpass API 不稳:504/500 频发,kumi.systems 镜像也 502。重试 + sleep 15s 是唯一解。查询越简单越容易过。
  • OSM 校门节点缺失:两个校区 barrier/entrance 节点数为 0,没人标。需从「边界多边形 ∩ 道路延伸线」推断。
  • 地图 API 都不吐楼块数据:高德 JS API 的 3D 楼块是内部渲染,CustomLayer 只是让你往它的画布里挂自己的 Three.js 场景,不给数据。混合渲染视觉割裂,不如卫星图手描。
  • 三层楼高全是标签:hM 属性=米,building:levels×3.2,无标签按 btype 默认值(dormitory 6 层等),高度一半是估算。

复用套路

任何 3D 数据可视化(园区/城市/展馆/地铁)都是三段式:

REST API 拉 JSON → 经纬度转米/投影 → Three.js 挤出渲染

会校园,就会城市。

项目

  • 代码:Desktop/zwu-3dmap/zwu-map(Vue3 + Vite + Three.js,数据管线在 scripts/)
  • 相关:Plugins(Three.js 官方文档)、Overpass API 文档、高德开放平台

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web