Files
sdk4.0/src/Global/SheetIndex/index.js
2025-07-03 13:54:01 +08:00

656 lines
19 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 { get2DView } from '../MultiViewportMode'
import { getSdk } from '../SplitScreen'
import { flyTo } from '../global'
import Tools from '../../Tools'
let tools
let state = false
let scale = '1:100万'
function SheetIndexStatusSwitch(sdk, s = false) {
if(!sdk) {
return
}
if (!tools) {
tools = new Tools()
}
state = s ? true : false
if (state) {
changeScale(sdk, scale)
} else {
close(sdk)
}
let sdk2D = get2DView()
if (sdk2D) {
if (state) {
changeScale(sdk, scale)
} else {
close(sdk2D)
}
}
let sdkD = getSdk().sdkD
if(sdkD && sdk !== sdkD) {
SheetIndexStatusSwitch(sdkD, s)
}
// return new Promise(async (resolve, reject) => {
// setTimeout(() => {
// resolve()
// }, 1000);
// })
}
function changeScale(sdk, v) {
scale = v
if (state) {
open(sdk)
}
let sdk2D = get2DView()
if (sdk2D) {
if (state) {
open(sdk2D)
}
}
return new Promise(async (resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000);
})
}
function getStatus() {
return state
}
function open(sdk) {
close(sdk)
let cartographic = sdk.viewer.camera.positionCartographic
let options = {
position: {
lng: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
alt: cartographic.height,
},
}
let viewer = sdk.viewer;
switch (scale) {
case '1:100万':
options.position.alt = 16000000
break
case '1:50万':
options.position.alt = 5000000
break
case '1:25万':
options.position.alt = 2300000
break
case '1:10万':
options.position.alt = 680000
break
case '1:5万':
options.position.alt = 385000
break
case '1:2.5万':
options.position.alt = 180000
break
case '1:1万':
options.position.alt = 90000
break
case '1:5000':
options.position.alt = 46000
break
}
let gridPrimitives
let labelCollection
for (let i = 0; i < viewer.scene.primitives._primitives.length; i++) {
if (viewer.scene.primitives._primitives[i].name === 'SheetIndexGridPrimitives') {
gridPrimitives = viewer.scene.primitives._primitives[i];
for (let j = 0; j < gridPrimitives._primitives.length; j++) {
if (gridPrimitives._primitives[j].name === 'SheetIndexLabelCollection') {
labelCollection = gridPrimitives._primitives[j];
break;
}
}
break;
}
}
if (!gridPrimitives) {
gridPrimitives = new Cesium.PrimitiveCollection();
gridPrimitives.name = 'SheetIndexGridPrimitives';
viewer.scene.primitives.add(gridPrimitives);
}
if (!labelCollection) {
labelCollection = new Cesium.LabelCollection();
labelCollection.name = 'SheetIndexLabelCollection';
}
let stationaryFrames = 0;
let maxRectangle = null;
gridPrimitives.postRenderEvent = () => {
let height = sdk.viewer.camera.positionCartographic.height
switch (scale) {
case '1:100万':
options.position.alt = 16000000
break
case '1:50万':
options.position.alt = 5000000
break
case '1:25万':
options.position.alt = 2300000
break
case '1:10万':
options.position.alt = 680000
break
case '1:5万':
options.position.alt = 385000
break
case '1:2.5万':
options.position.alt = 180000
break
case '1:1万':
options.position.alt = 90000
break
case '1:5000':
options.position.alt = 46000
break
}
if (height > options.position.alt * 5) {
maxRectangle = null;
gridPrimitives.removeAll();
return
}
let isChanged = false
let rectangle = getViewExtend();
let minLng = Cesium.Math.toDegrees(rectangle.west)
let minLat = Cesium.Math.toDegrees(rectangle.south)
let maxLng = Cesium.Math.toDegrees(rectangle.east)
let maxLat = Cesium.Math.toDegrees(rectangle.north)
if (minLng > maxLng) {
maxLng += 360
}
rectangle = { minLng, minLat, maxLng, maxLat }
if (maxRectangle) {
if ((maxRectangle.minLng > rectangle.minLng || maxRectangle.minLat > rectangle.minLat || maxRectangle.maxLng < rectangle.maxLng || maxRectangle.maxLat < rectangle.maxLat) && Cesium.Math.toDegrees(sdk.viewer.camera.pitch) < 0) {
isChanged = true
}
}
else {
countMapSheet(scale)
}
if (isChanged) {
stationaryFrames++;
// 确认相机已经静止足够多帧
if (stationaryFrames >= 50) {
countMapSheet(scale)
isChanged = false
}
} else {
stationaryFrames = 0;
}
}
options.complete = () => {
viewer.scene.postRender.addEventListener(gridPrimitives.postRenderEvent);
}
flyTo(sdk, options, 0.5)
/**
* 根据比例尺创建图幅线
* @param {string} scale - 比例尺(可选值:'1:100万', '1:50万', '1:25万', '1:10万', '1:5万', '1:2.5万', '1:1万', '1:5000'
*/
function countMapSheet(scale) {
labelCollection.removeAll();
gridPrimitives.removeAll();
labelCollection = new Cesium.LabelCollection();
labelCollection.name = 'SheetIndexLabelCollection';
gridPrimitives.add(labelCollection);
let rectangle = getViewExtend();
let lngStep // 经度步长
let latStep // 纬度步长
// let limitLng // 显示界限(根据图幅线数量显隐)
// let limitLat
// Math.abs(maxLng-minLng)/lngStep, Math.abs(maxLat-minLat)/latStep
let scaleByDistance
switch (scale) {
case '1:100万':
lngStep = 6;
latStep = 4;
scaleByDistance = new Cesium.NearFarScalar(
20000000,
1,
80000000,
0
)
break
case '1:50万':
lngStep = 3;
latStep = 2;
scaleByDistance = new Cesium.NearFarScalar(
5000000,
1,
30000000,
0
)
break
case '1:25万':
lngStep = 1.5;
latStep = 1;
scaleByDistance = new Cesium.NearFarScalar(
2300000,
1,
20000000,
0
)
break
case '1:10万':
lngStep = 0.5;
latStep = 1 / 3;
scaleByDistance = new Cesium.NearFarScalar(
680000,
1,
5000000,
0
)
break
case '1:5万':
lngStep = 0.25;
latStep = 1 / 6;
scaleByDistance = new Cesium.NearFarScalar(
385000,
1,
2400000,
0
)
break
case '1:2.5万':
lngStep = 0.125;
latStep = 1 / 12;
scaleByDistance = new Cesium.NearFarScalar(
180000,
1,
1200000,
0
)
break
case '1:1万':
lngStep = 0.0625;
latStep = 1 / 24;
scaleByDistance = new Cesium.NearFarScalar(
90000,
1,
700000,
0
)
break
case '1:5000':
lngStep = 0.03125;
latStep = 1 / 48;
scaleByDistance = new Cesium.NearFarScalar(
46000,
1,
300000,
0
)
break
// case '1:1000':
// lngStep = 0.01041667;
// latStep = 0.00694444;
// break
// case '1:2000':
// lngStep = 0.00520833;
// latStep = 0.00347222;
// break
}
let minLng = Math.floor((180 + Cesium.Math.toDegrees(rectangle.west)) / lngStep) * lngStep - 180;
let minLat = Math.floor((88 + Cesium.Math.toDegrees(rectangle.south)) / latStep) * latStep - 88;
let maxLng = Math.ceil((180 + Cesium.Math.toDegrees(rectangle.east)) / lngStep) * lngStep - 180;
let maxLat = Math.ceil((88 + Cesium.Math.toDegrees(rectangle.north)) / latStep) * latStep - 88;
if (minLng > maxLng) {
maxLng += 360
}
maxRectangle = { minLng, minLat, maxLng, maxLat }
if (minLat < -88) {
minLat = -88
}
if (maxLat > 88) {
maxLat = 88
}
if (((maxRectangle.maxLng - maxRectangle.minLng) / lngStep) * ((maxRectangle.maxLat - maxRectangle.minLat) / latStep) > 7000) {
maxRectangle = null
return
}
// 绘制经线
for (let lng = minLng; lng <= maxLng; lng += lngStep) {
const positions = [];
let a = []
for (let lat = minLat; Math.floor(lat * 1000000000) / 1000000000 <= maxLat; lat += (latStep / 2)) {
a.push([lng, lat])
positions.push(Cesium.Cartesian3.fromDegrees(lng, lat, 8848));
}
if (maxLat != 88 && maxLat + (latStep / 2) >= 88) {
positions.push(Cesium.Cartesian3.fromDegrees(lng, 88, 8848));
}
const geometryInstances = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: positions,
width: 1,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
arcType: Cesium.ArcType.RHUMB,
})
});
gridPrimitives.add(new Cesium.Primitive({
geometryInstances: geometryInstances,
appearance: new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.fromCssColorString('#fcfc00')
})
})
}));
if (lng < maxLng) {
// 计算图幅中心坐标
for (let lat = minLat; lat < maxLat; lat += latStep) {
let position = { lng: lng + (lngStep / 2), lat: lat + (latStep / 2) };
if (position.lat > maxLat) {
break
}
let sheetNumber = calculateMapSheetNumber(position.lng, position.lat, scale);
labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 8848),
text: sheetNumber,
font: '16px Inter, sans-serif',
fillColor: Cesium.Color.fromCssColorString('#fcfc00'),
// backgroundColor: Cesium.Color.fromCssColorString('#FFA145'),
// backgroundPadding: new Cesium.Cartesian2(8, 4),
pixelOffset: new Cesium.Cartesian2(0, 0),
showBackground: false,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
scale: 1.0,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 80000000),
scaleByDistance: scaleByDistance
})
// labelCollection.add({
// position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 10000),
// text: position.lng + ' , ' + position.lat,
// font: '16px Inter, sans-serif',
// fillColor: Cesium.Color.WHITE,
// backgroundColor: Cesium.Color.fromCssColorString('#165DFF').withAlpha(0.8),
// backgroundPadding: new Cesium.Cartesian2(8, 4),
// pixelOffset: new Cesium.Cartesian2(0, 30),
// showBackground: true,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// scale: 1.0,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000000),
// scaleByDistance: new Cesium.NearFarScalar(
// 5000000,
// 1,
// 20000000,
// 0
// )
// })
}
}
}
// 绘制纬线
for (let lat = minLat; Math.floor(lat * 1000000000) / 1000000000 <= maxLat; lat += latStep) {
const positions = [];
let a = []
for (let lng = minLng; lng <= maxLng; lng += (lngStep / 2)) {
a.push([lng, lat])
positions.push(Cesium.Cartesian3.fromDegrees(lng, lat, 8848));
}
const geometryInstances = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: positions,
width: 1,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
arcType: Cesium.ArcType.RHUMB,
})
});
gridPrimitives.add(new Cesium.Primitive({
geometryInstances: geometryInstances,
appearance: new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.fromCssColorString('#fcfc00')
})
})
}));
}
}
/**
* 根据经纬度和比例尺计算地图图幅编号
* @param {number} longitude - 经度(十进制格式)
* @param {number} latitude - 纬度(十进制格式)
* @param {string} scale - 比例尺(可选值:'1:100万', '1:50万', '1:25万', '1:10万', '1:5万', '1:2.5万', '1:1万', '1:5000'
* @returns {string} 对应的图幅编号
*/
function calculateMapSheetNumber(lng, lat, scale) {
let lngStep // 经度步长
let latStep // 纬度步长
switch (scale) {
case '1:100万':
lngStep = 6;
latStep = 4;
break
case '1:50万':
lngStep = 3;
latStep = 2;
break
case '1:25万':
lngStep = 1.5;
latStep = 1;
break
case '1:10万':
lngStep = 0.5;
latStep = 1 / 3;
break
case '1:5万':
lngStep = 0.25;
latStep = 1 / 6;
break
case '1:2.5万':
lngStep = 0.125;
latStep = 1 / 12;
break
case '1:1万':
lngStep = 0.0625;
latStep = 1 / 24;
break
case '1:5000':
lngStep = 0.03125;
latStep = 1 / 48;
break
// case '1:1000':
// lngStep = 0.01041667;
// latStep = 0.00694444;
// break
// case '1:2000':
// lngStep = 0.00520833;
// latStep = 0.00347222;
// break
}
// 确保纬度在 -88 到 88 度之间(因为 88° 以上采用特殊分幅)
lat = Math.max(-88, Math.min(88, lat));
lat = Math.abs(lat); // 取绝对值
let B6 = 'ABCDEFGHIJKLMNOPQRSTUV'
let B2 = lng
let B3 = lat
// 计算 1:100 万地形图的列号
const col100W = Math.floor(B2 / 6 + 31);
// 1:100 万地形图的行号对应的字母A-V
const rowChar = B6.charAt(Math.floor(B3 / 4 + 1) - 1);
// 比例尺代码映射
const scaleCodeMap = {
'1:100万': '', // 1:100万不需要额外代码
'1:50万': 'B',
'1:25万': 'C',
'1:10万': 'D',
'1:5万': 'E',
'1:2.5万': 'F',
'1:1万': 'G',
'1:5000': 'H'
};
// 获取比例尺代码
const scaleCode = scaleCodeMap[scale];
if (!scaleCode && scale !== '1:100万') {
throw new Error('不支持的比例尺,请使用: 1:100万, 1:50万, 1:25万, 1:10万, 1:5万, 1:2.5万, 1:1万, 1:5000');
}
// 计算在 1:100 万图幅内的行列号(根据不同比例尺)
let rowIn100W, colIn100W;
rowIn100W = rowChar + col100W;
const num1 = Math.floor((Math.ceil(B3 / 4) * 4 - B3) / latStep) + 1;
const rowNum = ("000" + num1).slice(-3);
const remainder = B2 - Math.floor(B2 / 6) * 6;
const num2 = Math.floor(remainder / lngStep) + 1;
const colNum = ("000" + num2).slice(-3);
switch (scale) {
case '1:100万':
// 1:100万直接使用行号和列号
return rowIn100W;
case '1:50万':
break;
case '1:25万':
break;
case '1:10万':
break;
case '1:5万':
break;
case '1:2.5万':
break;
case '1:1万':
break;
case '1:5000':
break;
default:
throw new Error('不支持的比例尺');
}
// 生成最终编号
return rowIn100W + scaleCode + rowNum + colNum;
}
// 获取当前视角矩形范围(二维模式)
function getViewExtend() {
let params = {};
let extend = viewer.camera.computeViewRectangle();
if (viewer.scene.mode == 2) {
//2D下会可能拾取不到坐标extend返回undefined,所以做以下转换
let canvas = viewer.scene.canvas;
let upperLeft = new Cesium.Cartesian2(0, 0);//canvas左上角坐标转2d坐标
let lowerRight = new Cesium.Cartesian2(
canvas.clientWidth,
canvas.clientHeight
);//canvas右下角坐标转2d坐标
let ellipsoid = viewer.scene.globe.ellipsoid;
let upperLeft3 = viewer.camera.pickEllipsoid(
upperLeft,
ellipsoid
);//2D转3D世界坐标
let lowerRight3 = viewer.camera.pickEllipsoid(
lowerRight,
ellipsoid
);//2D转3D世界坐标
if (!upperLeft3) {
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, { x: 0, y: 0, z: 6356755 });
upperLeft.y = cartesian2.y + 5
upperLeft3 = viewer.camera.pickEllipsoid(
upperLeft,
ellipsoid
);
}
if (!lowerRight3) {
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, { x: 0, y: 0, z: -6356755 });
lowerRight.y = cartesian2.y - 5
lowerRight3 = viewer.camera.pickEllipsoid(
lowerRight,
ellipsoid
);
// console.log('lowerRight3', lowerRight, lowerRight3)
}
let upperLeftCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(
upperLeft3
);//3D世界坐标转弧度
let lowerRightCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(
lowerRight3
);//3D世界坐标转弧度
if ((lowerRight.y - upperLeft.y) / (lowerRight.x - upperLeft.x) <= 0.49998752339363695) {
extend = new Cesium.Rectangle(Cesium.Math.toRadians(-180), Cesium.Math.toRadians(-90), Cesium.Math.toRadians(180), Cesium.Math.toRadians(90))
}
else {
extend = new Cesium.Rectangle(upperLeftCartographic.longitude, lowerRightCartographic.latitude, lowerRightCartographic.longitude, upperLeftCartographic.latitude);
}
// console.log("经度:" + minx + "----" + maxx);
// console.log("纬度:" + miny + "----" + maxy);
return extend;
} else {
//3D获取方式
return extend;
}
}
}
function close(sdk) {
let viewer = sdk.viewer;
let gridPrimitives
let labelCollection
for (let i = 0; i < viewer.scene.primitives._primitives.length; i++) {
if (viewer.scene.primitives._primitives[i].name === 'SheetIndexGridPrimitives') {
gridPrimitives = viewer.scene.primitives._primitives[i];
for (let j = 0; j < gridPrimitives._primitives.length; j++) {
if (gridPrimitives._primitives[j].name === 'SheetIndexLabelCollection') {
labelCollection = gridPrimitives._primitives[j];
break;
}
}
break;
}
}
labelCollection && (labelCollection.removeAll());
gridPrimitives && (gridPrimitives.removeAll());
gridPrimitives && (viewer.scene.postRender.removeEventListener(gridPrimitives.postRenderEvent));
}
export { SheetIndexStatusSwitch, changeScale, getStatus }