import * as Cesium from 'cesium'
|
|
export const getBoundsFromCartesians = positions => {
|
const cartographics = positions
|
.map(pos => (pos?.longitude ? pos : Cesium.Cartographic.fromCartesian(pos)))
|
.filter(Boolean)
|
|
if (!cartographics.length) return null
|
|
let west = cartographics[0].longitude
|
let east = cartographics[0].longitude
|
let south = cartographics[0].latitude
|
let north = cartographics[0].latitude
|
|
cartographics.forEach(carto => {
|
west = Math.min(west, carto.longitude)
|
east = Math.max(east, carto.longitude)
|
south = Math.min(south, carto.latitude)
|
north = Math.max(north, carto.latitude)
|
})
|
|
return { west, east, south, north }
|
}
|
|
export const getBoundsFromLngLats = points => {
|
if (!points?.length) return null
|
let west = points[0].lng
|
let east = points[0].lng
|
let south = points[0].lat
|
let north = points[0].lat
|
points.forEach(point => {
|
west = Math.min(west, point.lng)
|
east = Math.max(east, point.lng)
|
south = Math.min(south, point.lat)
|
north = Math.max(north, point.lat)
|
})
|
return {
|
west: Cesium.Math.toRadians(west),
|
east: Cesium.Math.toRadians(east),
|
south: Cesium.Math.toRadians(south),
|
north: Cesium.Math.toRadians(north),
|
}
|
}
|
|
export const rectanglePositionsFromBounds = bounds => {
|
if (!bounds) return []
|
const { west, east, south, north } = bounds
|
return [
|
Cesium.Cartesian3.fromRadians(west, south),
|
Cesium.Cartesian3.fromRadians(east, south),
|
Cesium.Cartesian3.fromRadians(east, north),
|
Cesium.Cartesian3.fromRadians(west, north),
|
]
|
}
|
|
export const getCenterFromBounds = bounds => {
|
if (!bounds) return null
|
return new Cesium.Cartographic(
|
(bounds.west + bounds.east) / 2,
|
(bounds.south + bounds.north) / 2,
|
0
|
)
|
}
|
|
export const getMetersBetween = (start, end) => {
|
const geodesic = new Cesium.EllipsoidGeodesic(start, end)
|
return geodesic.surfaceDistance
|
}
|
|
export const buildEllipsePositions = (centerCartesian, semiMajor, semiMinor, steps = 60) => {
|
if (!centerCartesian || !semiMajor || !semiMinor) return []
|
const positions = []
|
const frame = Cesium.Transforms.eastNorthUpToFixedFrame(centerCartesian)
|
for (let i = 0; i < steps; i += 1) {
|
const angle = (i / steps) * Math.PI * 2
|
const x = Math.cos(angle) * semiMajor
|
const y = Math.sin(angle) * semiMinor
|
const local = new Cesium.Cartesian3(x, y, 0)
|
const world = Cesium.Matrix4.multiplyByPoint(frame, local, new Cesium.Cartesian3())
|
positions.push(world)
|
}
|
return positions
|
}
|
|
export const cartesianToLocal = (centerCartesian, positionCartesian) => {
|
const frame = Cesium.Transforms.eastNorthUpToFixedFrame(centerCartesian)
|
const inverse = Cesium.Matrix4.inverse(frame, new Cesium.Matrix4())
|
return Cesium.Matrix4.multiplyByPoint(inverse, positionCartesian, new Cesium.Cartesian3())
|
}
|
|
export const formatBufferRadius = meters => {
|
if (!Number.isFinite(meters)) return ''
|
if (meters >= 1000) return `${(meters / 1000).toFixed(2)} km`
|
return `${meters.toFixed(2)} m`
|
}
|
|
export const getBufferRadiusPoint = (centerCartesian, radius) => {
|
if (!centerCartesian || !Number.isFinite(radius)) return null
|
const frame = Cesium.Transforms.eastNorthUpToFixedFrame(centerCartesian)
|
const local = new Cesium.Cartesian3(radius, 0, 0)
|
return Cesium.Matrix4.multiplyByPoint(frame, local, new Cesium.Cartesian3())
|
}
|
|
export const getBufferRadiusLabelStyle = () => ({
|
font: '14px Source Han Sans CN',
|
fillColor: Cesium.Color.WHITE,
|
outlineColor: Cesium.Color.fromBytes(24, 48, 92, 255),
|
outlineWidth: 2,
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
showBackground: true,
|
backgroundColor: Cesium.Color.fromBytes(8, 12, 22, 180),
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
pixelOffset: new Cesium.Cartesian2(0, -12),
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
})
|
|
export const addBufferRadiusLabelEntity = (dataSource, centerCartesian, radius, options = {}) => {
|
if (!dataSource) return null
|
const position = getBufferRadiusPoint(centerCartesian, radius)
|
if (!position) return null
|
const { name, customData } = options
|
return dataSource.entities.add({
|
...(name ? { name } : {}),
|
...(customData ? { customData } : {}),
|
position,
|
label: {
|
...getBufferRadiusLabelStyle(),
|
text: formatBufferRadius(radius),
|
},
|
})
|
}
|