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), }, }) }