Created
April 30, 2017 16:05
-
-
Save ais-one/d497fe5ca3d2ef5276468743442d1aab to your computer and use it in GitHub Desktop.
NASA Space Apps Challenge 2017 Code
This file contains hidden or 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
<!-- | |
https://github.com/abwood/d3cesium | |
https://opensky-network.org/apidoc/rest.html | |
https://www.w3.org/TR/geolocation-API/ | |
https://dev.w3.org/geo/api/spec-source.html#heading | |
var x = document.getElementById("demo"); | |
function getLocation() { | |
if (navigator.geolocation) { | |
navigator.geolocation.getCurrentPosition(showPosition); | |
} else { | |
x.innerHTML = "Geolocation is not supported by this browser."; | |
} | |
} | |
function showPosition(position) { | |
x.innerHTML = "Latitude: " + position.coords.latitude + // decimal degrees | |
"<br>Longitude: " + position.coords.longitude; | |
.heading // degrees | |
.speed | |
} | |
var polylineEntity = viewer.entities.add({ | |
//... | |
}); | |
viewer.entities.remove(polylineEntity); | |
viewer.dataSources.removeAll(); | |
viewer.entities.removeAll(); | |
viewer.scene.primitives.removeAll(); | |
Purpose | |
1) viewing of airborne instrument/sensor | |
- readings in relation to flight path | |
- coverage area | |
2) comparison of airborne readings versus satellite readings of same area and around the same time | |
Coverage | |
Area -118.677007474 34.323718467 -115.198994919 35.96987025 | |
Time (UTC) - 2015-07-14T18:35:00.000 | |
- 2015-07-14T21:06:00.000 | |
Single Instrument - CO2 concentration ppm | |
Challenges | |
- Erratic raw flight data - need to filter readings | |
- Crash occurs due to large data set - down sampling required | |
- Search for data, need to ensure comparable data sets are used (location, time, measurement type) | |
Findings | |
- resolution between airborne and satellite readings may be different | |
- airborne location and data reading needs to be in sync | |
Need to | |
- Altitude | |
- Real aircraft altitude data and visual on 3d virtual map does not match | |
- always flat (0 meters elevation) on 3d virtual map, but different in actual world | |
- improve on results presentation | |
- e.g. aggregate airborne measurements to match with satellite resolution | |
- many other factors which we may not have taken into account | |
Dataset Sources | |
- Flightpath (https://asp-archive.arc.nasa.gov/PV/N806NA/2015-07-14/) ER-2 (N806NA) | |
- CO2 (High-Sensitivity Fast-Response CO2 Analyzer) - https://airbornescience.nasa.gov/tracker/#!/menu/instrument/about?callsign=NASA806&measurements=CO2&instrument=586e98813461353c0a7701d7 | |
- Satellite data | |
http://www.livescience.com/49196-nasa-satellite-oco2-carbon-maps.html | |
(0.1 degree resolution reading) | |
--> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<!-- Use correct character set. --> | |
<meta charset="utf-8"> | |
<!-- Tell IE to use the latest, best version. --> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<!-- Make the application on mobile take up the full browser screen and disable user scaling. --> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> | |
<title>2017 Space Apps Challenge</title> | |
<script src="jquery-3.2.1.min.js"></script> | |
<script src="turf.min.js"></script> | |
<script src="../Build/Cesium/Cesium.js"></script> | |
<style> | |
@import url(../Build/Cesium/Widgets/widgets.css); | |
html, body, #cesiumContainer { | |
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="cesiumContainer"></div> | |
<script> | |
var f_data={}; // flight path data | |
console.log('aaa') | |
//Set the random number seed for consistent results. | |
Cesium.Math.setRandomNumberSeed(3); | |
//Set bounds of our simulation time | |
//var start = Cesium.JulianDate.fromDate(new Date('2015-07-14T17:36:30.000')); | |
var start = Cesium.JulianDate.fromDate(new Date('2015-07-14T18:35:00.000')); | |
var stop = Cesium.JulianDate.fromDate(new Date('2015-07-14T21:06:00.000')); | |
//var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16)); | |
//var stop = Cesium.JulianDate.addSeconds(start, 360, new Cesium.JulianDate()); | |
if (1) { | |
var clock = new Cesium.Clock({ | |
//startTime : Cesium.JulianDate.fromIso8601("2013-12-25"), | |
//currentTime : Cesium.JulianDate.fromIso8601("2013-12-25"), | |
//stopTime : Cesium.JulianDate.fromIso8601("2013-12-26"), | |
startTime : start.clone(), | |
currentTime : start.clone(), | |
stopTime : stop.clone(), | |
clockRange : Cesium.ClockRange.LOOP_STOP, //Loop at the end, | |
//clockStep : Cesium.ClockStep.TICK_DEPENDENT | |
clockStep : Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER, | |
multiplier: 30 | |
}); | |
} | |
// console.log(Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER) | |
var viewer = new Cesium.Viewer('cesiumContainer', { | |
//terrainProviderViewModels : [], //Disable terrain changing | |
//infoBox : false, //Disable InfoBox widget | |
//selectionIndicator : false, //Disable selection indicator | |
clock: clock // pass in clock information | |
}); | |
var credit = new Cesium.Credit('Nasa Space Apps 2017', '', 'https://2017.spaceappschallenge.org/'); | |
viewer.scene.frameState.creditDisplay.addDefaultCredit(credit) | |
//Set timeline to simulation bounds | |
viewer.timeline.zoomTo(start, stop); | |
//For the use of STK World Terrain | |
//viewer.terrainProvider = new Cesium.CesiumTerrainProvider({ | |
// url : 'https://assets.agi.com/stk-terrain/world', | |
// requestWaterMask : true, | |
// requestVertexNormals : true | |
//}); | |
//INTENSIVE - Enable depth testing so things behind the terrain disappear. | |
//viewer.scene.globe.depthTestAgainstTerrain = true; | |
var scene = viewer.scene; | |
//INTENSIVE - Enable lighting based on sun/moon positions | |
//viewer.scene.globe.enableLighting = true; | |
var entity_flyby = null | |
var start_flyby = null | |
var stop_flyby = null | |
var plat = null | |
var plon = null | |
var maxlon = -999, maxlat = -999, minlon = 999, minlat = 999 | |
$.getJSON('IWG1.14Jul2015-2108.json', function(data) { | |
f_data = data; | |
//console.log(f_data) | |
var property_flyby = new Cesium.SampledPositionProperty(); | |
for (var i = 0, len = f_data.length; i < len; i++) { | |
var pt = f_data[i]; | |
if (i == 0) console.log(pt.System_Timestamp) | |
if (i == f_data.length - 1) console.log(pt.System_Timestamp) | |
var lat = pt.Latitude | |
var lon = pt.Longitude | |
var ts = pt.System_Timestamp | |
var alt = pt.GPS_Altitude_MSL | |
var hdg = pt.True_Heading | |
var spd = pt.Ground_Speed | |
if (lat=="" || lon=="" || ts=="") continue; | |
var from = { | |
"type": "Feature", | |
"properties": {}, | |
"geometry": { | |
"type": "Point", | |
"coordinates": [plon, plat] | |
} | |
}; | |
var to = { | |
"type": "Feature", | |
"properties": {}, | |
"geometry": { | |
"type": "Point", | |
"coordinates": [lon, lat] | |
} | |
}; | |
var units = "kilometers"; | |
//// Smooth the results | |
if (plat == null) { | |
plat = lat | |
plon = lon | |
} | |
else { | |
var distance = turf.distance(from, to, units); | |
if (distance < 1.0) continue | |
else { | |
plat = lat | |
plon = lon | |
} | |
} | |
if (lat < minlat) minlat = lat | |
if (lat > maxlat) maxlat = lat | |
if (lon < minlon) minlon = lon | |
if (lon > maxlon) maxlon = lon | |
var CO2 = (380 + (Math.random() * 25) ).toFixed(2) | |
var pos_ll = Cesium.Cartesian3.fromDegrees(lon, lat, alt); | |
var time_flyby = Cesium.JulianDate.fromDate(new Date(ts)); | |
if (start_flyby == null) { | |
start_flyby = time_flyby | |
// console.log('start flyby',ts) // 2015-07-14T17:36:35.003 | |
} | |
stop_flyby = time_flyby | |
//console.log('stop flyby',ts) // 2015-07-14T17:36:35.003 | |
property_flyby.addSample(time_flyby, pos_ll); | |
//Also create a point for each sample we generate. | |
viewer.entities.add({ | |
name : 'Time: '+ts, | |
position : pos_ll, | |
point : { | |
pixelSize : 8, | |
color : Cesium.Color.TRANSPARENT, | |
outlineColor : Cesium.Color.YELLOW, | |
outlineWidth : 3 | |
}, | |
description: 'Lat: '+lat+'<br/>' | |
+ 'Lon: '+lon+'<br/>' | |
+ 'Alt: '+alt+'<br/>' | |
+ 'Spd: '+spd+' kts<br/>' | |
//+ 'CO2: '+CO2+' ppm' | |
, | |
label : { | |
text : CO2, | |
fillColor: (CO2 > 400.0)? Cesium.Color.RED : Cesium.Color.BLUE, | |
font : '12pt monospace', | |
style: Cesium.LabelStyle.FILL_AND_OUTLINE, | |
//outlineWidth : 1, | |
verticalOrigin : Cesium.VerticalOrigin.TOP, | |
pixelOffset : new Cesium.Cartesian2(0, 8) | |
} | |
}); | |
// create radius around | |
viewer.entities.add({ | |
position: pos_ll, | |
name : 'Sensor Radius', | |
ellipse : { | |
semiMinorAxis : 100.0 + (alt / 3), | |
semiMajorAxis : 100.0 + (alt / 3), | |
height: 0.0, | |
//material : Cesium.Color.GREEN, | |
material : Cesium.Color.GREEN.withAlpha(0.25), | |
outline : true, | |
outlineColor : Cesium.Color.YELLOW | |
//extrudedHeight : 200000.0, | |
//rotation : Cesium.Math.toRadians(45) | |
} | |
}); | |
} | |
//console.log( start_flyby ) | |
console.log(minlon, minlat, maxlon, maxlat) | |
//Actually create the entity | |
entity_flyby = viewer.entities.add({ | |
//Set the entity availability to the same interval as the simulation time. | |
//availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start : start_flyby, stop : stop_flyby })]), | |
name: 'Research Aircraft', | |
position : property_flyby, //Use our computed positions | |
orientation : new Cesium.VelocityOrientationProperty(property_flyby), //Automatically compute orientation based on position movement. | |
model : { uri : '../../Apps/SampleData/models/CesiumAir/Cesium_Air.gltf', minimumPixelSize : 128 }, //Load the Cesium plane model to represent the entity | |
//Show the path as a pink line sampled in 1 second increments. | |
path : { | |
resolution : 1, | |
material : new Cesium.PolylineGlowMaterialProperty({ glowPower : 0.1, color : Cesium.Color.YELLOW }), //// DRAW THE LINES | |
width : 8 | |
} | |
}); | |
//viewer.timeline.zoomTo(start_flyby, stop_flyby); | |
viewer.trackedEntity = entity_flyby; | |
}); | |
// Picking Lat/Lon | |
viewer.canvas.addEventListener('click', function(e){ | |
var mousePosition = new Cesium.Cartesian2(e.clientX, e.clientY); | |
var ellipsoid = viewer.scene.globe.ellipsoid; | |
var cartesian = viewer.camera.pickEllipsoid(mousePosition, ellipsoid); | |
if (cartesian) { | |
var cartographic = ellipsoid.cartesianToCartographic(cartesian); | |
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(3); | |
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(3); | |
console.log(longitudeString + ', ' + latitudeString); | |
} else { | |
console.log('Globe was not picked'); | |
} | |
}, false); | |
// PICKING | |
//https://groups.google.com/forum/#!msg/cesium-dev/agtOrHYEhUo/lGlFb5q4EQAJ | |
var leftClickHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas); | |
leftClickHandler.setInputAction(function(action) { | |
////reset visibility of selectionIndicator and infoBox | |
//viewer.selectionIndicator.viewModel.selectionIndicatorElement.style.visibility = 'visible'; | |
//document.getElementsByClassName('cesium-infoBox')[0].style.visibility = "visible"; | |
//console.log(scene) | |
var pickedObject = scene.pick(action.position); | |
//don't do anything if we didn't click on an object | |
if (!Cesium.defined(pickedObject)) { | |
viewer.trackedEntity = null; | |
return; | |
} | |
console.log(pickedObject.id, pickedObject.id.name) // check if 3d mesh or other type of object | |
viewer.trackedEntity = pickedObject; | |
//viewer.trackedEntity = entity; | |
/* | |
//don't do anything if it's not the entity we care about | |
if(entity !== pickedObject.id){ return; } | |
//if this is the entity we care about, hide the selectionIndicator and infoBox | |
viewer.selectionIndicator.viewModel.selectionIndicatorElement.style.visibility = 'hidden'; | |
document.getElementsByClassName('cesium-infoBox')[0].style.visibility = "hidden"; | |
*/ | |
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); | |
/* | |
You can use camera.getPickRay to get the height: | |
var ray = viewer.camera.getPickRay(movement.endPosition); | |
var position = viewer.scene.globe.pick(ray, viewer.scene); | |
if (Cesium.defined(position)) { | |
var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position); | |
var height = cartographic.height | |
} | |
You don't have to use Cesium.Math.toDegrees on the height, it is given in meters. | |
You can also use the ScreenSpaceEventHandler to handle the click event directly. | |
Use ScreenSpaceEventType.LEFT_CLICK. Then, replace movement.endPosition with movement.position in the handler function. | |
) | |
*/ | |
/* | |
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); | |
handler.setInputAction( | |
function (movement) { | |
//var pick = scene.pick(movement.endPosition); | |
var pick = scene.pick(movement.position); | |
if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) { | |
console.log('node: ' + pick.node.name + '. mesh: ' + pick.mesh.name); | |
} | |
}, | |
//Cesium.ScreenSpaceEventType.MOUSE_MOVE | |
Cesium.ScreenSpaceEventType.LEFT_CLICK | |
); | |
*/ | |
var instances = []; | |
for (var lon = -119; lon < -114.0; lon += 0.1) { | |
for (var lat = 34.0; lat < 37.0; lat += 0.1) { | |
instances.push(new Cesium.GeometryInstance({ | |
geometry : new Cesium.RectangleGeometry({ | |
rectangle : Cesium.Rectangle.fromDegrees(lon, lat, lon + 0.1, lat + 0.1), | |
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT | |
}), | |
attributes : { | |
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha : 0.3})) | |
} | |
})); | |
} | |
} | |
scene.primitives.add(new Cesium.Primitive({ | |
geometryInstances : instances, | |
appearance : new Cesium.PerInstanceColorAppearance() | |
})); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment