bxztApp/packages/screen/src/map/utils/pickPosition.js

111 lines
3.2 KiB
JavaScript
Raw Normal View History

/**
* 地图点击位置拾取工具
* 解决标记位置偏移问题
*/
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
}