Last active
April 1, 2025 16:18
-
-
Save Tymek/40de61993218206f78fa0737e5d843c9 to your computer and use it in GitHub Desktop.
CesiumJS tests - https://sandcastle.cesium.com/?gist=40de61993218206f78fa0737e5d843c9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const viewer = new Cesium.Viewer("cesiumContainer", { shouldAnimate: true }); | |
viewer.scene.globe.enableLighting = true; | |
// Distance threshold in meters for label visibility | |
const LABEL_VISIBILITY_DISTANCE = 5000000; | |
const updateLabelVisibility = () => { | |
const cameraPosition = viewer.camera.position; | |
const entities = viewer.entities.values; | |
for (let i = 0; i < entities.length; i++) { | |
const entity = entities[i]; | |
if (entity.label) { | |
const entityPosition = entity.position.getValue(); | |
const distance = Cesium.Cartesian3.distance(cameraPosition, entityPosition); | |
entity.label.show = distance < LABEL_VISIBILITY_DISTANCE; | |
} | |
} | |
}; | |
viewer.camera.moveEnd.addEventListener(updateLabelVisibility); | |
Sandcastle.addDefaultToolbarButton("Ham Radio Bounces", () => { | |
viewer.entities.removeAll(); | |
const warsaw = { callsign: "SN5H", lon: 21.0122, lat: 52.2297 }; | |
const contacts = [ | |
{ callsign: "K1ABC", lat: 40.7128, lon: -74.0060, frequency: 14.070 }, | |
{ callsign: "G4XYZ", lat: 51.5074, lon: -0.1278, frequency: 7.070 }, | |
{ callsign: "JA1DEF", lat: 35.6895, lon: 139.6917, frequency: 14.250 }, | |
{ callsign: "VK2HIJ", lat: -33.8688, lon: 151.2093, frequency: 7.250 }, | |
{ callsign: "DL1KLM", lat: 52.5200, lon: 13.4050, frequency: 14.060 }, | |
{ callsign: "F6NOP", lat: 48.8566, lon: 2.3522, frequency: 7.040 }, | |
{ callsign: "SM0PQR", lat: 47.4979, lon: 19.0402, frequency: 14.320 }, | |
{ callsign: "ZS6RST", lat: 30.0333, lon: 31.2333, frequency: 7.090 }, | |
{ callsign: "W1STU", lat: 29.7604, lon: -95.3698, frequency: 14.070 }, | |
{ callsign: "OE1XYZ", lat: 48.2082, lon: 16.3738, frequency: 7.050 }, | |
{ callsign: "DL7ABC", lat: 48.1351, lon: 11.5810, frequency: 14.080 }, | |
{ callsign: "F1DEF", lat: 45.7640, lon: 4.8357, frequency: 7.030 }, | |
{ callsign: "LU1GHI", lat: 50.1109, lon: 8.6821, frequency: 14.065 }, | |
{ callsign: "OH2JKL", lat: 37.9838, lon: 23.7275, frequency: 7.085 }, | |
{ callsign: "PY3MNO", lat: 55.9533, lon: -3.1883, frequency: 14.320 }, | |
{ callsign: "VE3ABC", lat: 43.6532, lon: -79.3832, frequency: 3.750 }, | |
{ callsign: "JH1DEF", lat: 35.6762, lon: 139.6503, frequency: 21.250 }, | |
{ callsign: "EA4GHI", lat: 40.4168, lon: -3.7038, frequency: 28.450 }, | |
{ callsign: "ZL2JKL", lat: -41.2865, lon: 174.7762, frequency: 10.120 }, | |
{ callsign: "PA0MNO", lat: 52.3676, lon: 4.9041, frequency: 1.850 }, | |
{ callsign: "HB9PQR", lat: 47.3769, lon: 8.5417, frequency: 5.350 }, | |
{ callsign: "9A1STU", lat: 45.8150, lon: 15.9819, frequency: 21.300 }, | |
{ callsign: "YB3VWX", lat: -6.2088, lon: 106.8456, frequency: 28.500 } | |
]; | |
const bands = [ | |
{ label: "160m", altitude: 200000, color: Cesium.Color.PURPLE, freqRange: { min: 1.8, max: 2.0 } }, | |
{ label: "80m", altitude: 225000, color: Cesium.Color.BLUE, freqRange: { min: 3.5, max: 4.0 } }, | |
{ label: "60m", altitude: 250000, color: Cesium.Color.GREEN, freqRange: { min: 5.3, max: 5.4 } }, | |
{ label: "40m", altitude: 275000, color: Cesium.Color.YELLOW, freqRange: { min: 7.0, max: 7.3 } }, | |
{ label: "30m", altitude: 300000, color: Cesium.Color.ORANGE, freqRange: { min: 10.1, max: 10.15 } }, | |
{ label: "20m", altitude: 325000, color: Cesium.Color.RED, freqRange: { min: 14.0, max: 14.35 } }, | |
{ label: "15m", altitude: 350000, color: Cesium.Color.CYAN, freqRange: { min: 21.0, max: 21.45 } }, | |
{ label: "10m", altitude: 375000, color: Cesium.Color.MAGENTA, freqRange: { min: 28.0, max: 29.7 } }, | |
]; | |
const earthRadius = Cesium.Ellipsoid.WGS84.maximumRadius; | |
const addEntity = (entity) => { viewer.entities.add(entity); }; | |
addEntity({ | |
name: warsaw.callsign, | |
position: Cesium.Cartesian3.fromDegrees(warsaw.lon, warsaw.lat), | |
point: { pixelSize: 12, color: Cesium.Color.WHITE }, | |
label: { | |
text: warsaw.callsign, | |
font: "14pt sans-serif", | |
fillColor: Cesium.Color.WHITE, | |
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, | |
pixelOffset: new Cesium.Cartesian2(0, -14), | |
}, | |
}); | |
for (const contact of contacts) { | |
addEntity({ | |
name: `${contact.callsign} (${contact.frequency} MHz)`, | |
position: Cesium.Cartesian3.fromDegrees(contact.lon, contact.lat), | |
point: { pixelSize: 10, color: Cesium.Color.GRAY }, | |
label: { | |
show: false, | |
text: `${contact.callsign}`, | |
font: "12pt sans-serif", | |
fillColor: Cesium.Color.WHITE, | |
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, | |
pixelOffset: new Cesium.Cartesian2(0, -12), | |
}, | |
}); | |
} | |
const groundPoint = (lon, lat, fraction, endLon, endLat) => { | |
const startCart = Cesium.Cartographic.fromDegrees(lon, lat, 0); | |
const endCart = Cesium.Cartographic.fromDegrees(endLon, endLat, 0); | |
const geodesic = new Cesium.EllipsoidGeodesic(startCart, endCart); | |
const pointCart = geodesic.interpolateUsingFraction(fraction); | |
pointCart.height = 0; | |
return Cesium.Cartesian3.fromRadians(pointCart.longitude, pointCart.latitude, pointCart.height); | |
}; | |
for (const contact of contacts) { | |
const band = bands.find(b => { | |
const freq = contact.frequency; | |
return freq >= b.freqRange.min && freq <= b.freqRange.max; | |
}); | |
if (band) { | |
const startCart = Cesium.Cartographic.fromDegrees(warsaw.lon, warsaw.lat, 0); | |
const endCart = Cesium.Cartographic.fromDegrees(contact.lon, contact.lat, 0); | |
const fullGeo = new Cesium.EllipsoidGeodesic(startCart, endCart); | |
const totalDistance = fullGeo.surfaceDistance; | |
const maxHopDistance = 2 * Math.sqrt(2 * earthRadius * band.altitude); | |
const hops = Math.max(1, Math.ceil(totalDistance / maxHopDistance)); | |
const positions = []; | |
for (let i = 0; i < hops; i++) { | |
const p0 = groundPoint(warsaw.lon, warsaw.lat, i / hops, contact.lon, contact.lat); | |
const p1 = groundPoint(warsaw.lon, warsaw.lat, (i + 1) / hops, contact.lon, contact.lat); | |
if (i === 0) positions.push(p0); | |
const hopStartCart = Cesium.Cartographic.fromDegrees( | |
Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(p0).longitude), | |
Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(p0).latitude), | |
0 | |
); | |
const hopEndCart = Cesium.Cartographic.fromDegrees( | |
Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(p1).longitude), | |
Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(p1).latitude), | |
0 | |
); | |
const hopGeo = new Cesium.EllipsoidGeodesic(hopStartCart, hopEndCart); | |
const midCart = hopGeo.interpolateUsingFraction(0.5); | |
midCart.height = band.altitude; | |
const bounce = Cesium.Cartesian3.fromRadians(midCart.longitude, midCart.latitude, midCart.height); | |
positions.push(bounce, p1); | |
} | |
addEntity({ | |
name: `${warsaw.callsign} → ${contact.callsign} (${band.label}, ${hops} bounce${hops > 1 ? "s" : ""})`, | |
polyline: { | |
arcType: Cesium.ArcType.NONE, | |
positions, | |
width: 2, | |
material: band.color, | |
}, | |
}); | |
} | |
} | |
viewer.camera.flyTo({ | |
destination: Cesium.Cartesian3.fromDegrees(warsaw.lon, warsaw.lat, 20000000), | |
duration: 7, | |
}); | |
}); | |
Sandcastle.reset = () => viewer.entities.removeAll(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment