本文档独立记录 MinBIMGIS 公开 API,与 MinBIM 主引擎文档分开维护、分开版本化。以下划线
_开头的属性和方法不属于稳定公开接口。
1 概述
独立于主引擎的 GIS 包,产物 dist/minbim-gis.min.js(UMD,挂 window.MinBIMGIS)/ dist/minbim-gis.module.min.js(ESM)。影像/地形瓦片、3DTiles(倾斜摄影/白模/点云)、GeoJSON 矢量统一以图层形式挂进场景,与 BIM 模型共享坐标系与渲染循环。
公开出口包括 VERSION、attach、detach、GISViewer、TileLayer、Tiles3DLayer、GeoJsonLayer、CoordWidget。通常通过 attach() 创建管理器,而不是直接实例化 GISViewer。
引入约定:UMD 必须在 minbim.min.js 之后加载(复用主包的 THREE,不重复打包);浏览器直接 import gis/ 源码调试时,页面需在 module script 之前配置 import map:{ "imports": { "three": "../libs/three/three.module.js" } }。
配套数据服务:影像/地形/3dtiles/geojson 数据由本地服务托管(tk 不下发前端):
node gis_server/gis-server.js # 配置见 gis_server/config.json(tk 必须为天地图「服务端」类型)
# 路由:/tianditu/{layer}/{z}/{x}/{y}.png /local/... /terrain/... /3dtiles/... /geojson/... /health
2 快速上手
const gis = MinBIMGIS.attach(viewer, { intro: true }); // 注入(幂等),返回 GISViewer
gis.setOrigin(117.12, 36.65); // 本地原点(必须先于一切图层)
const tileLayer = new MinBIMGIS.TileLayer({ // 影像 + 地形
terrain: { url: 'http://localhost:8080/terrain' },
imagery: [
{ index: 0, url: 'http://localhost:8080/tianditu/img_w', minZoom: 3, maxZoom: 18 },
{ index: 1, url: 'http://localhost:8080/tianditu/cia_w', minZoom: 3, maxZoom: 18 },
],
});
gis.addLayer(tileLayer);
gis.onFinished(() => { /* 过场结束,可加载 BIM/3dtiles 等 */ });
3 管理器(GISViewer)
const gis = MinBIMGIS.attach(viewer, options); // 注入 viewer.GISViewer(重复调用返回同一个)
MinBIMGIS.detach(viewer); // 解除注入并释放
attach options:
| 参数 | 默认 | 说明 |
|---|---|---|
| intro | true |
开场过场动画(地球推进 + 云遮罩),false 跳过 |
| introDuration | 1.5 |
过场地球推进时长(秒) |
| fog | true |
自适应雾(far=视线地平线距离);场景已有雾则不接管 |
| fogColor | 0xcfd9e5 |
自持雾颜色(宜与 scene.background 一致) |
方法与事件:
gis.setOrigin(lon, lat, alt = 0); // 本地 ENU 原点(CGCS2000≈WGS84),必须先于 addLayer,之后不可改
gis.setView(lon, lat, height = 2e4);// 初始视角:目标点上空 height 米、近垂直俯视(经纬度缺省用原点)
gis.flyTo(lon, lat, alt, options); // 相机平滑飞到经纬度高程点,返回 Promise<boolean>(false=被新 flyTo 打断)
// options: { height=保持当前高度, pitch=89°(垂直朝下), heading=0°(朝北), duration=2600 }
gis.addLayer(layer); // 添加图层,返回递增 id
gis.getTerrainLayer(); // 取地形图层(无或已关闭地形时返回 null)
gis.onViewReady(fn); // 初始机位就位(过场切机位瞬间;无过场则首个 tick)
gis.onFinished(fn); // 过场全部收尾(无过场与 viewReady 同帧);过时机立即回调
gis.paused = true; // 暂停全部图层更新
gis.dispose(); // 销毁
// 坐标换算(BIM 模型 GIS 落位)
const p = gis.lonLatToLocal(lon, lat, alt); // -> {x, y, z}(真实米,x东 y高 z=-北)
const g2 = gis.localToLonLat(x, y, z); // -> {lon, lat, alt}
// BIM 模型落到 GIS 坐标
loader.load('../model/rvm').then((model) => {
const p = gis.lonLatToLocal(117.115, 36.65, 122);
model.position.set(p.x, p.y, p.z);
});
// 飞到目标点上空 500m、30° 俯角朝南看(heading 180)
await gis.flyTo(117.043044, 36.64725, 102, { height: 500, pitch: 30, heading: 180 });
// 垂直俯瞰(默认 pitch 89°),height 缺省保持当前高度
await gis.flyTo(117.10, 36.76);
图层契约:任何实现 { enabled, hasTerrain, object3d, update(camera), dispose() } 的对象都可 addLayer。addLayer 会注入 layer.viewer/manager/id,并按 id × 0.1 累加 layer.elevation(错层防 z-fight)。
4 TileLayer — 影像/地形瓦片层
const tileLayer = new MinBIMGIS.TileLayer({
imagery: [
{ index: 0, url: 'http://localhost:8080/tianditu/img_w', minZoom: 3, maxZoom: 18 }, // index 0=底层不透明影像,定 LOD 范围
{ index: 1, url: 'http://localhost:8080/tianditu/cia_w', minZoom: 3, maxZoom: 18 }, // 叠加层(注记等)
],
terrain: { // 缺省 = 平地(不加载任何 DEM)
url: 'http://localhost:8080/terrain', // 支持 {z}/{x}/{y} 占位符,否则按前缀拼 /{z}/{x}/{y}.bin
metaUrl: '…/meta.json', // 缺省取 url 前缀 + meta.json
exaggeration: 1, // 高程夸张系数
grid: 65, // DEM 网格(以 meta.json 为准)
},
});
| options | 默认 | 说明 |
|---|---|---|
| imagery | 必填 | 通道数组;index 从 0 逐层递增(缺省按数组顺序),上限 4 通道 |
| terrain | 无 | DEM 配置,全场景唯一(第二个带 terrain 的图层 addLayer 抛错) |
| maxTiles | 320 |
视锥内在池瓦片预算 |
| viewDistance | 2 |
视野距离系数(足印兜底) |
| baseLayer | false |
常驻垫底层(防空挡,较耗资源,默认关) |
| baseZoomDelta | 4 |
垫底层级别 = 当前 zoom − 此值 |
| maxCacheEntries | 800 |
瓦片材质/DEM 缓存 LRU 上限 |
| showTileMesh | true |
是否渲染瓦片 mesh |
方法:
tileLayer.setChannelOpacity(ch, v); // 通道不透明度(ch=imagery[].index),瞬时生效
tileLayer.setTerrainEnabled(false); // 运行时关地形:瓦片压平 + 停发 DEM(缓存保留,重开秒恢复);
// GeoJsonLayer drape/高程采样自动退平地
tileLayer.terrainEnabled; // 地形开关状态
tileLayer.setExaggeration(2); // 高程夸张系数,已加载瓦片即时重写
tileLayer.renderHeightAt(lon, lat); // 渲染面高程(含夸张/级别抬升),无地形/DEM 未就绪返回 null
tileLayer.sampleHeight(lon, lat); // 原始高程(米),同上可返回 null
tileLayer.enabled = false; // 图层整体停更新(配合 object3d.visible 显隐)
5 Tiles3DLayer — 3DTiles 层(倾斜摄影/白模/Max/点云)
const layer = new MinBIMGIS.Tiles3DLayer({
url: 'http://localhost:8080/3dtiles/osgb/tileset.json',
lonLatAlt: [117.125591, 36.707154, 50], // 手动落位(优先于自动解析)
rotation: [0, 0, -53], // ENU 欧拉角(度):x 绕东轴、y 绕北轴、z 绕天轴/航向
scale: 1, // 源数据单位错误时压回(如毫米→米 = 0.001)
recenter: false, // 内容原点偏离场地时收到锚点(点云常用)
});
gis.addLayer(layer);
| options | 默认 | 说明 |
|---|---|---|
| url | 必填 | tileset.json 地址(asset 必须带 gltfUpAxis,否则朝向错误) |
| lonLatAlt | 自动 | [lon, lat, alt];缺省依次尝试 boundingVolume.region → 根 transform 平移列 |
| rotation | [0,0,0] |
度,Rz·Ry·Rx 序(与 Cesium 侧 rx/ry/rz 修正同语义) |
| scale | 1 |
均匀缩放 |
| recenter | false |
根包围盒中心水平移到锚点 |
| pointSize | — | 点云点大小(pnts 自动补圆点贴图) |
| errorTarget | 6 |
SSE 误差目标(越小越精细越耗) |
| cacheBytes | 库默认 ≈430MB | LRU 显存上限(点云/大模型建议 2GiB,触顶会静默丢瓦片) |
| fetchOptions | — | 透传给库的请求选项 |
layer.setErrorTarget(4); // 运行时调 LOD 精度(静止也生效)
layer.setCacheBytes(2 * 1024 ** 3); // 运行时调缓存上限
落位优先级:options.lonLatAlt > boundingVolume.region > 根 transform 平移列;无根 transform 且无 region 的数据集必须手动 lonLatAlt。
6 GeoJsonLayer — GeoJSON 矢量层
const layer = new MinBIMGIS.GeoJsonLayer({
url: 'http://localhost:8080/geojson/jinan.geojson', // 或 data: 已解析对象
style: (feature) => ({ // 也可直接给常量对象
fill: '#3f7fff', fillOpacity: 0.45,
lineColor: '#ffffff', lineOpacity: 0.8, // 面自动描边(缺省不描)
pointColor: '#ffdd55', pointSize: 6, // 像素
altitude: 0, lift: 0.5, extrudeHeight: 0,
}),
drape: true, // 贴地(有地形才生效,否则平地)
drapeResolution: 500, // 缺省自适应 clamp(数据对角线/250, 25, 1000) 米
});
gis.addLayer(layer);
- 支持 FeatureCollection / Feature / 裸 Geometry,坐标按 EPSG:4326;点(圆点精灵)/线(1px)/面(带洞三角化)全量一次建几何,同样式签名合批。
extrudeHeight > 0:面拉伸成体块(顶面+侧墙,侧墙色 ×0.75),与 drape 互斥。- drape 贴地:逐顶点按地形渲染高程采样,多边形三角化后按
drapeResolution保形细分(防内部"穿山");DEM 异步就绪/换级别/夸张变化自动原位更新高度,无需干预。 layer.setData(geojson)全量替换数据;layer.dispose()释放并从场景摘除。
7 CoordWidget — 经纬度/高程读数挂件
new MinBIMGIS.CoordWidget(viewer, gis, {
precision: 6, // 经纬度小数位
showHeight: true, // 是否显示高程
position: "bottom-left" // CSS 定位:bottom-left / bottom-right / top-left / top-right
});
8 Analysis — GIS 分析模块(gis.analysis)
attach 后自动注入 gis.analysis,无需额外创建。统一约定:
- 坐标/高程口径:输入坐标一律
[lon, lat](EPSG:4326),高程一律原始高程(米,不含夸张系数),内部自动换算渲染空间(水位/等高线/坑底随setExaggeration联动)。 - 依赖:除量测/等高线/实时太阳外,其余功能都需要带
terrain的 TileLayer(DEM 经 gis_server 主动拉取,与视野内已加载瓦片无关)。 - region 参数(flood/sunlight 等用到):
{ bounds: [minLon, minLat, maxLon, maxLat] }或{ center: [lon, lat], radius }(米),缺省 = 当前视野目标点附近。 - 栅格精度:栅格类功能还接受
{ zoom, cellSize, maxCells=1e6 },默认按 DEM 原生分辨率,超上限自动放粗cellSize。
const an = gis.analysis;
8.1 量测 — an.measure(type)
贴地交互量测:click 加点、mousemove 预览、右键(或 dblclick)结束、Esc 取消。距离为沿地形 3D 长度,面积为水平投影(附周长)。结果直接标注在场景内(线段/总长/面积标签)。
an.measure('distance'); // 或 'area';再次调用自动重开
an.measure(null); // 关闭并清除
8.2 剖面分析 — an.profile(path, options)
沿折线等距采样地形高程,show=true 时画贴地折线;返回数据供外部画剖面图(演示页有 canvas 图表示例)。
const pf = await an.profile([[117.00, 36.60], [117.10, 36.64]], { samples: 200 });
// pf.distance / pf.minH / pf.maxH;pf.remove() 清除贴地线
| options | 默认 | 说明 |
|---|---|---|
| path | 必填 | [[lon, lat], ...],至少 2 点 |
| samples | 200 |
等距采样点数 |
| show | true |
画贴地折线 |
| color | 0xffc844 |
折线颜色 |
返回 { points: [{ lon, lat, dist, height }], distance, minH, maxH, remove() };height=null 表示该点无 DEM 数据,dist 为距起点水平距(米)。
8.3 两点通视 — an.lineOfSight(from, to, options) / an.lineOfSight(options)
交互模式(推荐演示):省略 from(第一个参数直接给 options)进入交互——点击地面设观察点,鼠标移动实时预览连线(绿=可见段、红=被挡段),点击固化一条,可围绕同一观察点连续落多条;右键结束交互(未固化的预览线不计入)。
const live = an.lineOfSight({ observerHeight: 10 }); // 交互模式
live.setObserverHeight(20); // 观察者高度(距地面,米)实时调整
live.remove(); // 结束并清除全部线段
// 一次性模式:给定观察点/目标点直接计算
const los = await an.lineOfSight([117.03, 36.65], [117.12, 36.66], { observerHeight: 10 });
// los.visible;los.blockedAt = { lon, lat, height, dist, source } | null;los.remove()
// blockedAt.source:'terrain'=被地形挡 / 'model'=被模型挡(BIM 或 3dtiles)
| options | 默认 | 说明 |
|---|---|---|
| from / to | 交互模式缺省 | [lon, lat] 观察点/目标点 |
| observerHeight | 1.8 |
观察点离地高度(米) |
| targetHeight | 0 |
目标点离地高度(米,一次性模式) |
| radius | 3000 |
交互模式观察点周围的 DEM 预取半径(米) |
| models | true |
计入模型遮挡(BIM 全量 + 3dtiles 当前已加载 LOD,分析前自动等瓦片加载收敛;定性口径) |
| settleTimeout | 5000 |
等 3dtiles 收敛的超时(毫秒),超时按当前已加载几何照算 |
| show | true |
画结果线(一次性模式) |
| visibleColor / blockedColor | 0x35e065 / 0xff4545 |
可见/遮挡段颜色 |
一次性模式返回 { visible, blockedAt, distance, remove() }。
8.4 等高线 — an.contours(interval, options)
地形等高线着色(shader 通道,瞬时生效)。options.region 限定范围并在区域内自动布高程标注;region: 'pick' 进入拖框选区(锁相机、左键拖矩形、Esc 取消)。不给 region 为全场景。
const h = await an.contours(50, { region: 'pick' }); // 拖框选区 + 高程标注
await an.contours(50, { region: { bounds: [117.03, 36.59, 117.08, 36.63] } });
an.contours(null); // 关(也可 h.remove())
| options | 默认 | 说明 |
|---|---|---|
| color | 0xffffff |
等高线颜色 |
| region | 全场景 | 范围限定 + 高程标注;'pick' = 拖框选区 |
8.5 淹没分析 — an.flood(options)
水面波动面 + 地形淹没染色(水下越深越暗);extent=true 或给 seed 时在区域 DEM 上计算淹没范围并染色、统计面积。单实例:再次调用自动清除旧的。
const fl = await an.flood({
level: 170, // 必填,水位(原始高程,米)
region: { center: [117.06, 36.58], radius: 2500 },
extent: true,
});
fl.setLevel(180); // 动态调水位(水面/染色/范围联动重算,供滑块驱动)
fl.area; // 淹没面积 m²
fl.minH / fl.maxH; // 区域高程范围(供滑块定界)
fl.remove();
水面会采样区域高度图遮挡陆地(地形高于水位的片元不画水),不会盖住山体。
| options | 默认 | 说明 |
|---|---|---|
| level | 必填 | 水位(原始高程,米) |
| region | 视野目标点 10km | 水面覆盖范围与范围计算区域 |
| extent | false |
计算淹没范围(染色 + area) |
| seed | 无 | [lon, lat] 有源淹没(种子点 4 连通扩散);缺省=无源阈值 |
| water | true |
水面波动面 + 地形染色 |
| models | true |
模型高度烘焙:水面遮挡绕开建筑(视觉正确);面积/范围掩膜保持纯地形洪泛区口径,不扣建筑占地(扣除精度受栅格/LOD 限制易误导,且随模型加载状态波动);3dtiles 分析前按区域定向加载瓦片 |
| settleTimeout | 15000 |
3dtiles 区域加载的超时(毫秒),超时按已加载部分照算 |
| color / opacity | 0x3f8fff / 0.6 |
水面与染色颜色、水面不透明度 |
返回 { setLevel(v), area, minH, maxH, remove() }。
8.6 土方计算 — an.earthwork(options)
多边形范围内 DEM 与设计高程逐格差值积分:挖方(高出设计,红色染色)/填方(低于设计,蓝色染色),深浅映射差值大小。省略 polygon 进入交互圈区(click 加点、右键(或 dblclick)闭合、Esc 取消)。
// 交互圈区:返回 { finished, remove() },finished 在用户闭合区域后 resolve 为结果
const h = an.earthwork();
h.finished.then((r) => console.log(r.cut, r.fill, r.designHeight));
// 直接计算:
const ew = await an.earthwork({
polygon: [[117.04, 36.59], [117.06, 36.59], [117.06, 36.61], [117.04, 36.61]],
designHeight: 150,
});
// ew.cut / ew.fill(m³)、ew.area(m²)、ew.maxCut / ew.maxFill(米);ew.remove()
| options | 默认 | 说明 |
|---|---|---|
| polygon | 交互圈区 | [[lon, lat], ...],至少 3 点 |
| designHeight | 区域平均高程 | 设计高程(原始高程,米) |
| show | true |
填挖染色叠加 |
8.7 可视域分析 — an.viewshed(options)
观察点放射扫描,可见(绿)/不可见(红)分区染色。省略 from 进入交互模式:点击设观察点 → 雷达锥面跟随鼠标预览范围 → 再点击按当前半径计算。
// 交互模式:返回 { finished, remove() },第二次点击后 finished resolve
const live = an.viewshed({ observerHeight: 10, maxRadius: 5000 });
live.setObserverHeight(20); // 观察者高度(距地面,米)实时调整,计算按新高度
live.finished.then((r) => console.log(r.visibleRatio, r.radius));
// 一次性模式:
const vs = await an.viewshed({ from: [117.03, 36.65], observerHeight: 1.8, radius: 3000 });
// vs.visibleRatio(可见占比 0~1);vs.remove()
| options | 默认 | 说明 |
|---|---|---|
| from | 交互模式缺省 | [lon, lat] 观察点 |
| observerHeight | 1.8 |
观察点离地高度(米) |
| radius | 3000 |
分析半径(米,一次性模式) |
| maxRadius | 5000 |
交互模式半径上限(米) |
| models | true |
模型高度烘焙进栅格(BIM 全量;3dtiles 分析前按区域定向加载瓦片,精度≈分析栅格),建筑按占地块遮挡;定性口径 |
| settleTimeout | 15000 |
3dtiles 区域加载的超时(毫秒),超时按已加载部分照算 |
| show | true |
染色叠加 |
| visibleColor / hiddenColor | 0x2aff88 / 0xff5544 |
可见/不可见颜色 |
8.8 日照分析 — an.sunlight(options) / an.setSun(date)
sunlight:按日期/时段逐格 march 太阳方向遮挡,累计日照时长(小时),蓝(短)→红(长)色带叠加。setSun:把场景平行光转到真实太阳方向/强度/色温(氛围用,无阴影贴图,夜晚自动降为微光)。
const sl = await an.sunlight({ date: '2026-06-21', region: { center: [117.05, 36.60], radius: 1200 } });
// sl.min / sl.max / sl.avg(小时);sl.remove()
const sp = an.setSun(new Date()); // -> { azimuth, elevation }(度)
| options | 默认 | 说明 |
|---|---|---|
| date | 今天 | 日期(Date 或字符串) |
| region | 视野目标点 1.5km | 分析区域 |
| start / end / step | 8 / 17 / 1 |
统计时段(本地时,小时) |
| show | true |
时长色带叠加 |
8.9 地下开挖 — an.excavate(options)
多边形坑域裁剪地形(shader discard)+ 坑壁/坑底几何。v1 单坑:再次调用自动清旧坑。省略 polygon 进入交互圈区(click 加点、右键(或 dblclick)闭合、Esc 取消)。
// 交互圈区(返回 Promise,用户闭合后 resolve)
const pit = await an.excavate({ depth: 15 });
pit.setDepth(25); // 动态调深(坑底高程/坑体几何联动;指定了 floor 时不生效)
// 直接指定:
const pit2 = await an.excavate({
polygon: [[117.097, 36.637], [117.103, 36.637], [117.103, 36.643], [117.097, 36.643]],
depth: 15,
});
// pit.floor(实际坑底原始高程);pit.remove()
| options | 默认 | 说明 |
|---|---|---|
| polygon | 交互圈区 | [[lon, lat], ...],至少 3 点 |
| depth | 10 |
开挖深度(米,自坑内最低地形起算) |
| floor | 坑内最低地形−depth | 坑底原始高程(米),给了则忽略 depth |
| wallColor / floorColor | 0x8a7a5f / 0x6b5d47 |
坑壁/坑底颜色 |
裁剪只作用于地形瓦片(tile shader 掩膜 discard):BIM 模型、3dtiles、GeoJSON、地下管线等均不受影响、在坑内正常可见。地层(地质分层)显示为规划项:开挖侧壁按土层数据分段着色,需要外部地质模型数据接入。
8.10 一键清除 — an.clear()
清除全部分析产物与着色(量测/线条/水面/叠加纹理/等高线/开挖),不恢复被 setSun 改动的平行光。
8.11 口径与限制
- 精度取决于 DEM 分辨率(SRTM 级 ~30m),土方量/日照时长等结论为方案/演示级;换高精度 DEM 瓦片即可提升,管线不变。
- 遮挡计算:通视/可视域/水淹计入地形+模型(
models默认开,水淹高度烘焙只让水面绕楼,面积/范围掩膜不扣建筑占地;models:false可退回纯地形)。3dtiles:通视以当前已加载 LOD 为准,可视域/水淹分析前按区域定向加载瓦片、精度≈分析栅格;可视域/水淹的模型参与方式为高度烘焙("最高表面",不表达悬空结构)。日照仍只算地形。淹没水面 mesh 覆盖分析区域,地形染色为全域视觉提示(区域外的蓝色是"示意")。 - 叠加类分析(淹没范围/可视域/土方/日照)共用一张地形叠加纹理,后执行覆盖先执行;等高线/淹没染色/开挖裁剪为独立通道可共存。
- 演示页:
examples/gis.html(「分析功能」折叠分组,含交互引导/滑块/剖面图)。
9 完整示例
见 examples/gis.html(跑 gis/ 源码,含影像 + 地形 + GeoJSON + 各 3DTiles 数据集 + BIM 落位)。
10 常见问题
- 模型巨大/巨小:源数据单位错误,用
options.scale压回(判据:包围盒尺寸比真实大整数倍;CesiumLab 预览正常不代表数据正确)。 - 3DTiles 朝向不对:tileset.json 的 asset 缺
gltfUpAxis,需转换工具重新输出;或数据源轴系不标准,用options.rotation修正。 - 3DTiles 拉很近才细化/不完整:转换数据 geometricError 保守 →
errorTarget调小;LRU 触顶静默丢瓦片 →cacheBytes上调。 - 影像不出/报限流:gis_server 的 tk 必须是天地图「服务端」类型;
cacheOnly模式下未命中直接 404。 - GeoJSON 大文件卡顿:全量渲染定调,>10 万顶点会 console.warn;可先外部抽稀或加大
drapeResolution。
11 版本历史
v1.0(2026年10月18日)
- 整理首个独立接口文档版本,覆盖 GIS 管理器、影像/地形、3DTiles、GeoJSON、坐标挂件及分析模块。
12 版权声明
本文档及其中内容为 魔兜(济南)数字科技有限公司 所有,公开用于产品评估及授权项目开发,未经许可不得转载或用于其他商业用途。