193.Vue3 + OpenLayers 实战:圆孔相机模型推算卫星拍摄区域
一、效果展示实现功能输入经纬度、飞行高度设置拍摄比例一键绘制地面覆盖区域圆形支持清除图层 本质根据高度推算一个地面半径 二、前言在做无人机巡检系统 / 卫星遥感 / 地图可视化项目时经常会遇到一个问题 已知相机或卫星的经纬度、高度如何推算它在地面的拍摄范围这篇文章我将带你用✅ Vue3Composition API✅ OpenLayers✅ 圆孔相机简化模型实现一个拍摄区域可视化 Demo画圆 三、核心原理非常重要这里用的是一个简化版圆孔相机模型 计算逻辑半径 高度 / 拍摄比例即const r alt / proportion 为什么这样算可以这样理解相机在高空alt向地面拍摄拍摄范围随着高度变大而扩大proportion相当于一个“缩放系数”参数含义alt相机高度米proportion拍摄缩放比例r地面覆盖半径⚠️ 注意这个公式是工程简化模型并不是真实物理模型后面会讲️ 四、核心实现思路1️⃣ 经纬度 → 地图坐标OpenLayers 使用的是EPSG:3857墨卡托投影所以必须转换fromLonLat([lon, lat])2️⃣ 使用 Circle 绘制区域new Circle(center, radius)3️⃣ 加入地图图层dataSource.addFeature(feature) 五、完整核心代码!-- * Author: 彭麒 * Date: 2026/3/20 * Email: 1062470959qq.com * Description: 此源码版权归吉檀迦俐所有可供学习和借鉴或商用。 -- template div classcontainer div classw-full flex justify-center flex-wrap div classfont-bold text-[24px] Vue3 Openlayers圆孔相机拍摄区域推算 /div /div div classnav el-input v-modellon sizesmall template #prepend经度/template /el-input el-input v-modellat sizesmall template #prepend纬度/template /el-input el-input v-modelalt sizesmall template #prepend高度/template /el-input el-input v-modelpitch sizesmall disabled template #prepend俯仰角/template /el-input el-input v-modelproportion sizesmall template #prepend拍摄比例/template /el-input el-button typeprimary sizesmall clickshowCircle 显示圆形 /el-button el-button typeprimary sizesmall clickclearLayer 清除图层 /el-button /div div idvue-openlayers/div /div /template script setup import { ref, onMounted } from vue import ol/ol.css import { Map, View } from ol import TileLayer from ol/layer/Tile import VectorLayer from ol/layer/Vector import VectorSource from ol/source/Vector import XYZ from ol/source/XYZ import Feature from ol/Feature import { Circle } from ol/geom import Style from ol/style/Style import Fill from ol/style/Fill import Stroke from ol/style/Stroke import CircleStyle from ol/style/Circle import { fromLonLat } from ol/proj const map ref(null) const dataSource new VectorSource({ wrapX: false }) const lon ref(16.3979471) const lat ref(39.9081726) const alt ref(500000) const pitch ref(0) const proportion ref(2) const featureStyle () { return new Style({ fill: new Fill({ color: rgba(0,0,0,0.1) }), stroke: new Stroke({ width: 2, color: #f00 }), image: new CircleStyle({ radius: 3, fill: new Fill({ color: #0000ff }) }) }) } // 清空图层 const clearLayer () { dataSource.clear() } // 画圆 const showCircle () { const r alt.value / proportion.value const center fromLonLat([lon.value, lat.value]) const circleFeature new Feature({ geometry: new Circle(center, r) }) dataSource.addFeature(circleFeature) } // 初始化地图 const initMap () { const baseLayer new TileLayer({ source: new XYZ({ url: https://www.google.com/maps/vt?lyrsmglenx{x}y{y}z{z}, crossOrigin: anonymous }) }) const vectorLayer new VectorLayer({ source: dataSource, style: featureStyle() }) map.value new Map({ target: vue-openlayers, layers: [baseLayer, vectorLayer], view: new View({ projection: EPSG:3857, center: fromLonLat([16.5, 39.7]), zoom: 5 }) }) } onMounted(() { initMap() }) /script style scoped .container { width: 840px; height: 620px; margin: 50px auto; border: 1px solid #42B983; } #vue-openlayers { width: 600px; height: 500px; border: 1px solid #42B983; float: left; } .nav { float: left; width: 210px; height: 500px; margin-right: 10px; padding-top: 10px; } .nav :deep(.el-input-group) { width: 200px; padding: 0 5px; margin-bottom: 10px; } /style⚠️ 六、这个方案的局限性面试加分点很多人写到这里就结束了但其实这是不严谨的❌ 问题这个“圆形区域”并不真实因为没有考虑相机视场角FOV没有考虑俯仰角pitch忽略了地球曲率忽略了投影畸变实际拍摄区域是矩形而不是圆 七、真实工程中应该怎么做如果你是做 无人机巡检系统 / 航测 / GIS系统建议使用✅ 更真实模型1️⃣ 相机模型针孔相机2️⃣ 关键参数高度alt视场角FOV俯仰角pitch 真实计算公式核心思想地面宽度 ≈ 2 * alt * tan(FOV / 2) 进一步pitch ≠ 0 → 区域会偏移最终是一个倾斜矩形 八、可以怎么优化升级你这个 Demo 可以升级成项目级能力 升级方向✅ 圆 → 矩形真实拍摄范围✅ 加入 pitch倾斜摄影✅ 动态轨迹绘制航线覆盖✅ 多点连续覆盖分析✅ 热力图分析覆盖率✅ WebGL 加速大数据渲染 九、总结本文实现了✔ Vue3 OpenLayers 地图搭建✔ 经纬度转投影坐标✔ 基于高度推算拍摄范围✔ 使用 Circle 绘制覆盖区域 核心一句话总结利用“高度 / 比例”简化模型在地图上快速模拟相机拍摄范围。 十、适用场景这个方案适用于无人机巡检系统快速预览卫星可视化GIS演示系统教学 Demo 十一、结语如果你正在做 无人机 / WebGIS / 三维地图 / 数字孪生这个思路可以作为一个基础能力模块