WebGIS室内地图怎么做?导航功能如何实现?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

引言:WebGIS室内地图怎么做?导航功能如何实现?

很多做校园、商场、医院、园区项目的同学都会遇到同一个问题:WebGIS室内地图怎么做?导航功能如何实现? 室外 WebGIS 通常依赖天地图、高德、OSM 或自建矢量瓦片,但室内地图更关注楼层、房间、通道、电梯、楼梯、出入口和 POI 点位,数据组织和导航算法都不一样。

本文按一个可落地的 WebGIS 室内地图项目来讲:先说明室内地图数据怎么建,再讲前端如何展示多楼层地图,最后讲室内导航功能如何用网络图和最短路径实现。适合 GIS 学生、WebGIS 开发者、GIS 工程实施人员参考。

WebGIS室内地图怎么做 室内地图导航功能实现流程图
WebGIS 室内地图从数据建模到导航路径计算的基本流程。

背景:室内地图和普通 WebGIS 地图有什么不同

普通 WebGIS 地图通常解决“在城市或区域范围内显示地理要素”的问题,核心对象是道路、建筑、河流、行政区、影像底图等。室内地图则解决“在一栋建筑内部定位和引导”的问题,核心对象变成了楼层、房间、走廊、门、电梯、楼梯、扶梯、卫生间、服务台和商铺。

做 WebGIS 室内地图时,常见需求包括:

  • 展示某栋楼不同楼层的平面图。
  • 点击楼层按钮切换 F1、F2、B1 等楼层。
  • 搜索房间、商铺、科室或设备点位。
  • 点击起点和终点后生成室内导航路线。
  • 跨楼层时自动经过楼梯、电梯或扶梯。
  • 在移动端或大屏端显示当前路径和文字引导。

因此,WebGIS 室内地图不是简单把 CAD 平面图放到网页上,而是要把室内空间变成可查询、可渲染、可计算路径的 GIS 数据。

原理:WebGIS室内地图怎么做的核心是数据模型

WebGIS室内地图怎么做,关键不在前端用了 Leaflet、OpenLayers 还是 Mapbox GL,而在于室内数据是否结构化。只要数据模型清楚,前端展示和导航计算都会变得可控。

1. 室内地图至少需要三类数据

数据类型 常见几何类型 用途
空间底图数据 面、线 表示房间、墙体、走廊、楼梯、电梯、建筑边界
POI 数据 表示商铺、办公室、科室、设备、卫生间、出入口
导航网络数据 线、点 用于计算起点到终点的最短路径或最优路径

2. 楼层字段是室内地图的关键字段

室内地图必须明确楼层。建议每个图层都保留统一的楼层字段,例如 floor_idbuilding_idlevel。否则后期做楼层切换、跨楼层导航、按楼层查询时会非常麻烦。

一个简单的 POI 属性表可以设计为:

字段 示例 说明
poi_id P001 POI 唯一编号
name 急诊科 显示名称
building_id A 建筑编号
floor_id F2 楼层编号
category department POI 类型
geom Point 点几何

3. 室内导航功能实现依赖“可通行网络”

室内导航功能不是直接沿房间边界计算,而是沿“可通行网络”计算。可通行网络可以理解为走廊中心线、门口连接线、楼梯电梯连接线组成的一张图。

在图论中,通道交叉点、门口、电梯口可以视为节点,走廊中心线可以视为边。边有长度、通行类型、楼层、是否可通行等属性。导航时通过 Dijkstra 或 A* 等最短路径算法,从起点节点计算到终点节点。

步骤:从零搭建 WebGIS 室内地图

步骤一:整理原始 CAD 或平面图资料

多数室内地图项目的原始资料来自 CAD,例如 DWG 或 DXF。第一步不要急着写前端代码,而是先清理数据。

  1. 删除无关图层,例如标注框、施工说明、尺寸线、图签。
  2. 保留房间边界、走廊、楼梯、电梯、出入口等核心要素。
  3. 统一单位,确认 CAD 坐标单位是米、毫米还是图纸单位。
  4. 按楼层拆分数据,避免多个楼层叠在一个图层里。
  5. 给每个楼层设置明确的 floor_id

如果 CAD 没有真实坐标,可以先使用局部坐标系做室内展示;如果要和室外地图叠加,则需要做配准,把建筑平面图放到真实地理坐标位置。

步骤二:将室内数据转换为 GIS 格式

WebGIS 前端更适合读取 GeoJSON、矢量瓦片、PostGIS 服务或 WFS 服务。常见处理路线有两种:

  • 小型项目:CAD 转 GeoJSON,前端直接加载。
  • 中大型项目:CAD 转 PostGIS,再发布为矢量瓦片或接口服务。

使用 QGIS 可以完成基础转换:

  1. 打开 QGIS,加载 DXF 数据。
  2. 检查图层几何类型和坐标系。
  3. 按房间、走廊、POI、导航线分别导出。
  4. 导出格式选择 GeoJSON、GeoPackage 或 PostGIS。
  5. 检查属性字段是否包含 building_idfloor_id

如果数据量较大,不建议前端一次性加载所有楼层 GeoJSON。可以按建筑和楼层拆分文件,例如 building-a-f1.geojsonbuilding-a-f2.geojson

步骤三:设计室内地图图层结构

一个实用的 WebGIS 室内地图图层结构可以这样设计:

图层名 几何类型 建议用途
building_floor Polygon 楼层范围或建筑轮廓
room Polygon 房间、商铺、科室
corridor Polygon 或 LineString 走廊和通道区域
facility Point 电梯、楼梯、卫生间、服务设施
poi Point 可搜索目标点
nav_node Point 导航网络节点
nav_edge LineString 导航网络边

前端显示时,通常先显示楼层底图,再显示房间和设施,最后叠加 POI 标注和导航路线。这样层级清晰,也方便控制样式。

步骤四:实现楼层切换

WebGIS室内地图怎么做楼层切换,思路其实很直接:所有室内图层都带楼层字段,前端只显示当前楼层的数据。

如果使用 GeoJSON 文件,可以按楼层加载:

const currentFloor = 'F2';

async function loadFloor(buildingId, floorId) {
  const url = `/data/indoor/${buildingId}-${floorId}.geojson`;
  const response = await fetch(url);
  const geojson = await response.json();

  // 清空旧楼层图层
  indoorSource.clear();

  // 添加当前楼层数据
  const features = new ol.format.GeoJSON().readFeatures(geojson, {
    featureProjection: 'EPSG:3857'
  });

  indoorSource.addFeatures(features);
}

如果数据在 PostGIS 中,可以通过接口传参查询:

SELECT id, name, floor_id, category, ST_AsGeoJSON(geom) AS geometry
FROM indoor_poi
WHERE building_id = 'A'
  AND floor_id = 'F2';

核心原则是:不要让前端靠图层名称猜楼层,而要让数据字段明确表达楼层关系。

步骤五:构建室内导航网络

室内导航功能实现的核心,是把人可以走的路线抽象为网络。不要直接用房间面、墙线或 CAD 线作为导航网络,因为这些数据通常不具备拓扑关系。

建议按下面步骤构建导航网络:

  1. 沿走廊中心绘制可通行线。
  2. 在走廊交叉口、门口、电梯口、楼梯口打断线段。
  3. 为每条线添加起点节点、终点节点、长度、楼层、通行类型。
  4. 跨楼层位置用特殊边连接,例如电梯边、楼梯边。
  5. 检查线段是否真正相交和连通,避免视觉相交但拓扑不连通。

导航边表可以设计为:

字段 示例 说明
edge_id E1001 边编号
source N001 起点节点
target N002 终点节点
floor_id F1 所属楼层
length 12.6 通行距离
walk_type corridor 走廊、电梯、楼梯等类型
cost 12.6 路径计算权重

步骤六:实现起点和终点匹配

用户点击地图上的某个房间或 POI 后,不能直接把房间中心点当作导航网络节点。正确做法是把起点和终点吸附到最近的可通行节点或边上。

在 PostGIS 中,可以用距离查询找到最近节点:

SELECT node_id, floor_id
FROM nav_node
WHERE building_id = 'A'
  AND floor_id = 'F2'
ORDER BY geom <-> ST_SetSRID(ST_MakePoint(121.5001, 31.2302), 4326)
LIMIT 1;

如果室内使用的是局部平面坐标,也可以把点击点的 x、y 坐标传给后端,然后在同一坐标系中查最近节点。注意不要混用经纬度坐标和米制平面坐标。

步骤七:计算最短路径

室内导航功能如何实现,常用方法是把导航网络交给后端计算。PostGIS 可以存储空间数据,pgRouting 可以进行路径分析。对于轻量项目,也可以在 Node.js、Python 或前端内存中实现 Dijkstra 算法。

使用 pgRouting 的思路如下:

SELECT *
FROM pgr_dijkstra(
  'SELECT edge_id AS id, source, target, cost, cost AS reverse_cost
   FROM nav_edge
   WHERE building_id = ''A''',
  101,
  205,
  directed := false
);

上面 SQL 中,101 是起点节点编号,205 是终点节点编号。返回结果通常还需要关联 nav_edge 表,把路径边的几何取出来,再返回给前端高亮显示。

WITH route AS (
  SELECT * FROM pgr_dijkstra(
    'SELECT edge_id AS id, source, target, cost, cost AS reverse_cost
     FROM nav_edge
     WHERE building_id = ''A''',
    101,
    205,
    directed := false
  )
)
SELECT e.edge_id, e.floor_id, ST_AsGeoJSON(e.geom) AS geometry
FROM route r
JOIN nav_edge e ON r.edge = e.edge_id
WHERE r.edge <> -1
ORDER BY r.seq;

步骤八:前端高亮显示导航路线

前端拿到路径 GeoJSON 后,可以在 OpenLayers、Leaflet 或 Mapbox GL 中单独创建一个路线图层。建议路线样式和普通室内底图区分明显,例如使用蓝色或橙色粗线。

function showRoute(routeGeojson) {
  routeSource.clear();

  const features = new ol.format.GeoJSON().readFeatures(routeGeojson, {
    featureProjection: 'EPSG:3857'
  });

  routeSource.addFeatures(features);
}

如果路径跨楼层,前端还需要把路线按 floor_id 分组。当前显示 F1 时只显示 F1 的路线,切换到 F2 时显示 F2 的路线,同时在电梯或楼梯位置提示“上到 2 层”或“下到 B1”。

常见坑:室内地图导航功能最容易出错的地方

1. CAD 看起来能用,但实际没有 GIS 拓扑

CAD 线条主要服务于制图和施工表达,不一定适合 GIS 分析。很多线段只是视觉上接触,实际端点没有重合。做室内导航功能实现时,这会导致路径中断。

  • 检查线段端点是否真正吸附。
  • 检查节点编号是否正确。
  • 检查交叉口是否打断线段。
  • 检查跨楼层连接点是否成对出现。

2. 楼层编码不统一

同一项目中不要同时出现 1FF1floor1一层。楼层编码不统一会导致查询、渲染和路径分组全部出问题。

建议统一采用一种编码方式,例如地上楼层用 F1F2,地下楼层用 B1B2

3. 坐标系混乱

WebGIS室内地图怎么做都绕不开坐标问题。如果室内数据是局部坐标,前端可以用自定义坐标系或简单二维坐标显示;如果需要叠加室外底图,则必须配准到真实坐标系。

常见错误包括:

  • 把 CAD 毫米单位当作米使用。
  • 把经纬度坐标直接用于米制距离计算。
  • GeoJSON 坐标顺序写反。
  • 前端以 EPSG:3857 显示,但后端返回 EPSG:4326 后没有转换。

4. 只做视觉路线,不做真实可通行网络

有些项目直接在前端画一条折线作为导航路线,看起来像导航,但不能自动避开墙体、门禁或不可通行区域。真正的室内导航功能实现必须依赖可通行网络和路径算法。

5. 跨楼层导航没有成本控制

电梯、楼梯、扶梯都可以连接不同楼层,但通行成本不一定相同。比如无障碍导航应优先使用电梯,普通导航可以使用楼梯。建议为不同通行类型设置不同 cost

方法比较:室内地图前端和导航实现方案怎么选

方案 适合场景 优点 限制
GeoJSON + Leaflet 小型楼宇、教学演示、数据量较小 上手快,部署简单 大数据量性能一般,复杂样式能力有限
GeoJSON + OpenLayers 常规 WebGIS 室内地图项目 GIS 能力强,坐标系和图层控制灵活 需要一定 WebGIS 基础
PostGIS + 接口服务 多建筑、多楼层、需要查询统计 数据管理规范,便于扩展 需要后端开发和数据库维护
PostGIS + pgRouting 需要真实室内导航功能 路径计算能力成熟,可处理网络分析 导航网络建模要求高
矢量瓦片 + 前端渲染 大型商场、园区、机场、医院 加载快,适合大规模数据 制瓦片和样式维护成本更高

如果只是展示一栋楼的简单室内图,GeoJSON 加 OpenLayers 就够用。如果要做搜索、权限、导航、跨楼层、多建筑管理,建议使用 PostGIS 管理数据,并用后端接口提供楼层数据和路径计算服务。

检查清单:上线前逐项检查

  • 是否为每个图层设置了统一的 building_idfloor_id
  • 房间、走廊、POI、导航网络是否分层存储。
  • 楼层切换时是否只显示当前楼层数据。
  • POI 搜索结果是否能定位到正确楼层。
  • 导航网络线段是否在交叉口打断。
  • 起点和终点是否能吸附到最近导航节点。
  • 跨楼层路径是否经过电梯、楼梯或扶梯连接点。
  • 路径结果是否按楼层分组显示。
  • 坐标系、单位和前端投影是否一致。
  • 移动端点击、缩放、标注遮挡是否测试过。

FAQ:WebGIS室内地图和导航功能常见问题

Q1:WebGIS室内地图怎么做,必须使用真实地理坐标吗?

不一定。如果只是展示建筑内部,不和室外地图叠加,可以使用局部平面坐标。但如果要在城市底图上显示建筑位置,或需要室内外一体化导航,就应该把室内地图配准到真实坐标系。

Q2:室内地图导航功能实现一定要用 pgRouting 吗?

不一定。pgRouting 适合已经使用 PostGIS 的项目。如果数据量很小,也可以用 Python、Node.js 或前端 JavaScript 实现 Dijkstra 算法。但从工程维护角度看,PostGIS 加 pgRouting 更适合多楼层、多建筑、可持续更新的项目。

Q3:CAD 平面图能不能直接作为 WebGIS 室内地图使用?

不建议直接使用。CAD 图纸通常缺少统一属性、楼层字段和导航拓扑。更稳妥的做法是先清理 CAD,再转换为 GeoJSON、GeoPackage 或 PostGIS 数据,并补充 POI 和导航网络。

Q4:室内导航为什么算出来的路径会穿墙?

通常是因为导航网络画错了,或者起终点吸附到了错误的节点。路径算法只认识网络边,不理解墙体含义。要避免穿墙,必须保证导航边只画在真实可通行区域,并检查门口、走廊、电梯和楼梯连接关系。

Q5:多楼层室内导航怎么显示比较合理?

建议把路径按楼层拆分显示。当前楼层显示当前楼层路线,跨楼层节点用电梯或楼梯图标提示。用户切换楼层时,再显示对应楼层的路径段。不要把所有楼层路线叠在同一个平面上,否则容易误导用户。

Q6:WebGIS室内地图适合用三维吗?

如果只是找房间、找店铺、找科室,二维室内地图通常更清晰。如果要展示大型综合体、地下空间、管线或数字孪生场景,可以考虑 Cesium、Three.js 或其他三维方案。但三维会增加建模、性能和交互成本。

结论:先做好数据,再实现导航

WebGIS室内地图怎么做,核心顺序是:先整理 CAD 或平面图,再建立楼层、房间、POI 和导航网络数据,最后用 WebGIS 前端进行楼层展示、搜索和路径高亮。

室内导航功能如何实现,关键不是画一条好看的线,而是构建真实可通行的网络,并用最短路径算法计算起点到终点的路线。对于小型项目,可以用 GeoJSON 加 OpenLayers 快速实现;对于正式工程,建议使用 PostGIS 管理室内数据,并结合 pgRouting 或后端路径服务完成导航计算。

只要楼层字段统一、坐标系清楚、导航网络连通,WebGIS 室内地图就能从“能看”进一步做到“能查、能搜、能导航”。