196 lines
6.1 KiB
JavaScript
196 lines
6.1 KiB
JavaScript
|
|
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) )))
|
|||
|
|
}
|