ss-dp/src/views/Home/MapCtrl/M3D/utils/cesutil.js

196 lines
6.1 KiB
JavaScript
Raw Normal View History

2026-02-06 11:00:16 +08:00
import { config } from "../../../../../config";
const { Cesium } = window;
export function getPolygonHierarchy(geom) {
if (typeof geom === 'string') {
try {
geom = JSON.parse(geom);
} catch (e) {
return null;
}
}
const type = geom.type;
let polygons = [];
if (type === 'Polygon') {
polygons.push(geom.coordinates);
} else if (type === 'MultiPolygon') {
polygons = geom.coordinates;
} else if (type === 'LineString' || type === 'Ring') {
polygons.push([geom.coordinates]);
} else if (type === 'MultiLineString') {
for (const item of geom.coordinates) {
polygons.push([item]);
}
}
if (polygons.length === 0) {
return null;
}
const ret = [];
for (const lines of polygons) {
let positions = null;
const holes = [];
for (const linedata of lines) {
const coordarr = [];
for (const curpt of linedata) {
const h = curpt[2] ? curpt[2] : 0;
coordarr.push(curpt[0], curpt[1], h);
}
if (!positions) {
positions = Cesium.Cartesian3.fromDegreesArrayHeights(coordarr);
} else {
holes.push({
positions: Cesium.Cartesian3.fromDegreesArrayHeights(coordarr),
});
}
}
if (!positions) {
return null;
}
let hierarchy;
if (holes.length === 0) {
hierarchy = positions;
} else {
hierarchy = {
positions,
holes,
};
}
ret.push(hierarchy);
}
return ret;
}
//根据经纬度和zoom获取相机位置
export function getCameraViewPosition(mapCenter) {
const verticalHeight = zoomToHeight(mapCenter.zoom)//相机垂直高度
const lon = mapCenter.center[0]
const lat = mapCenter.center[1]
const pitchRad = Cesium.Math.toRadians(config.pitch3d);//相机俯仰角
const distance = verticalHeight / Math.abs(Math.sin(pitchRad));
// 2. 计算水平后退距离朝向0度所以后退方向是正南
const horizontalDistance = distance * Math.cos(Math.abs(pitchRad));
// 3. 计算相机在目标点ENU坐标系中的偏移
// 朝向0度时东偏移=0北偏移=-水平距离(向南),上偏移=高度
const eastOffset = 0;
const northOffset = -horizontalDistance; // 向南
const upOffset = distance * Math.sin(Math.abs(pitchRad));
// 4. 将偏移应用到目标点
const targetCartesian = Cesium.Cartesian3.fromDegrees(lon, lat, 0);
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(targetCartesian);
const destination = Cesium.Matrix4.multiplyByPoint(
transform,
new Cesium.Cartesian3(eastOffset, northOffset, upOffset),
new Cesium.Cartesian3()
);
return destination
}
//获取摄像机焦点经纬度和高度
export function getCameraViewCenter(viewer) {
// 1. 获取屏幕中心点的射线(从相机到屏幕中心)
const ray = viewer.camera.getPickRay(new Cesium.Cartesian2(
viewer.canvas.clientWidth / 2,
viewer.canvas.clientHeight / 2
));
// 2. 计算射线与地球表面的交点
const intersection = viewer.scene.globe.pick(ray, viewer.scene);
if (intersection) {
// 如果有交点(看向地球)
const cartographic = Cesium.Cartographic.fromCartesian(intersection);
return {
lon: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
height: heigjtToZoom(viewer.camera.positionCartographic.height)//cartographic.height
};
} else {
// 如果看向天空或太空,获取射线与椭球体的交点
const ellipsoid = viewer.scene.globe.ellipsoid;
const intersection2 = viewer.scene.camera.pickEllipsoid(
new Cesium.Cartesian2(
viewer.canvas.clientWidth / 2,
viewer.canvas.clientHeight / 2
),
ellipsoid
);
if (intersection2) {
const cartographic = Cesium.Cartographic.fromCartesian(intersection2);
return {
lon: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Cartographic.toDegrees(cartographic.latitude),
height: 0
};
}
}
}
/**
* 获取屏幕中心点对准的地球表面点与摄像机之间的距离
* @param {Cesium.Viewer} viewer - Cesium的Viewer对象
* @returns {number|null} 距离单位如果中心点不在地球表面则返回null
*/
export function getDistanceFromCameraToCenterFocus(viewer) {
// 获取屏幕中心点Canvas的中心坐标
const canvas = viewer.canvas;
const centerX = canvas.clientWidth / 2;
const centerY = canvas.clientHeight / 2;
// 获取屏幕中心点的三维射线
const ray = viewer.camera.getPickRay(new Cesium.Cartesian2(centerX, centerY));
if (!ray) {
console.warn('无法获取屏幕中心点的射线');
return null;
}
// 计算射线与地球椭球体的交点
const ellipsoid = viewer.scene.globe.ellipsoid;
const intersection = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid);
if (!intersection) {
// 如果中心点没有对准地球(如指向天空),则尝试获取地形上的点
try {
const centerPosition = viewer.scene.pickPosition(new Cesium.Cartesian2(centerX, centerY));
if (centerPosition) {
const cameraPosition = viewer.camera.positionWC;
return Cesium.Cartesian3.distance(cameraPosition, centerPosition);
}
} catch (error) {
console.warn('无法获取屏幕中心点对应的地形位置');
return null;
}
return null;
}
// 获取交点坐标
const intersectionPoint = Cesium.Ray.getPoint(ray, intersection.start);
// 获取相机位置(世界坐标)
const cameraPosition = viewer.camera.positionWC;
// 计算相机位置与交点之间的距离
const distance = Cesium.Cartesian3.distance(cameraPosition, intersectionPoint);
return distance;
}
//openlayers的zoom转cesium的摄像机height
export function zoomToHeight(olZoom) {
return (120000000 / Math.pow(2, olZoom))+400
}
//cesium的摄像机height转openlayers的zoom
export function heigjtToZoom(height) {
return Math.max(0, Math.min(28, Math.log2(120000000 / (height - 400) )))
}