bxztApp/packages/screen/src/map/utils/pickPosition.js
Zzc b432d8d6b7 feat(map): 集成Cesium 3D地图系统与控件和服务
使用Cesium添加全面的3D地图功能,包括:
- 地图视口和控件组件
- 图层管理,含底图切换器和目录控制
- 相机、实体和查询服务
- 罗盘和场景模式切换UI组件
- 支持工具、存储和数据配置

更新构建配置以支持Cesium集成和SVG图标。
2025-11-07 15:04:37 +08:00

111 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 地图点击位置拾取工具
* 解决标记位置偏移问题
*/
import * as Cesium from 'cesium'
/**
* 更准确的地图位置拾取方法
* @param {Cesium.Viewer} viewer - Cesium viewer实例
* @param {Cesium.Cartesian2} clickPosition - 屏幕点击位置
* @returns {Object|null} 返回 {cartesian3: Cesium.Cartesian3, cartographic: Object} 或 null
*/
export function pickMapPosition(viewer, clickPosition) {
if (!viewer || !clickPosition) {
return null
}
let pickedPosition = null
try {
// 方法1: 尝试使用场景拾取(最准确,考虑地形)
const ray = viewer.camera.getPickRay(clickPosition)
if (ray) {
// 先尝试拾取地形表面
pickedPosition = viewer.scene.globe.pick(ray, viewer.scene)
if (!pickedPosition) {
// 如果地形拾取失败使用椭球面拾取作为fallback
pickedPosition = viewer.camera.pickEllipsoid(clickPosition, viewer.scene.globe.ellipsoid)
}
}
// 方法2: 如果上述方法都失败,使用椭球面拾取
if (!pickedPosition) {
pickedPosition = viewer.camera.pickEllipsoid(clickPosition, viewer.scene.globe.ellipsoid)
}
if (pickedPosition) {
// 转换为地理坐标
const cartographic = Cesium.Cartographic.fromCartesian(pickedPosition)
const longitude = Cesium.Math.toDegrees(cartographic.longitude)
const latitude = Cesium.Math.toDegrees(cartographic.latitude)
const height = cartographic.height
return {
cartesian3: pickedPosition,
cartographic: {
longitude,
latitude,
height,
lon: longitude, // 兼容现有代码
lat: latitude // 兼容现有代码
}
}
}
} catch (error) {
console.warn('Position picking failed:', error)
}
return null
}
/**
* 创建标记实体的统一配置
* @param {Object} coordinates - 地理坐标 {lat, lng}
* @param {Object} options - 标记选项
* @returns {Object} Cesium实体配置
*/
export function createMarkerEntityConfig(coordinates, options = {}) {
const {
id = 'map-marker',
imageUrl = '/src/assets/images/marker-red.svg',
width = 32,
height = 32,
showLabel = true,
labelOffset = 40,
fontSize = '12pt'
} = options
const config = {
id,
billboard: {
image: imageUrl,
width,
height,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
// 添加像素偏移补偿
pixelOffset: new Cesium.Cartesian2(0, 0),
// 禁用深度测试以确保标记总是可见
disableDepthTestDistance: Number.POSITIVE_INFINITY
}
}
if (showLabel) {
config.label = {
text: `${coordinates.lat.toFixed(6)}, ${coordinates.lng.toFixed(6)}`,
font: `${fontSize} sans-serif`,
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.TOP,
pixelOffset: new Cesium.Cartesian2(0, labelOffset),
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
// 确保标签在标记上方
eyeOffset: new Cesium.Cartesian3(0, 0, -100)
}
}
return config
}