xxxxxxxxxx
305
// enable cross origin → otherwise, p5 does not allow json to load
const cors = "https://cors-anywhere.herokuapp.com/";
const earthRad = 200;
const distanceISS = 0.06404018208 * earthRad;
const requestTimer = 15000;
// toggle this flag if you want to see ISS
const loadISS = true;
const ISSurl = 'http://api.open-notify.org/iss-now.json';
const launchUrl = 'https://launchlibrary.net/1.3/launch/next/10';
let issPos = null;
let launches = [];
let cities = [];
let cityData = null;
let isTooManyRequests = false;
let isOnline = true;
let font = null;
let mapTexture = null;
let now = 0;
let transimitionCounter = 0;
function preload() {
font = loadFont('SpaceMono-Regular.ttf');
// mapTexture = loadImage('mapUV.png');
cityData = loadJSON('cities.json');
}
function setup() {
createCanvas(600, 600, WEBGL);
issPos = new ISS();
textFont(font);
now = Date.now();
if( loadISS ){
loadJSON(cors + ISSurl, gotDataISS, () => {
isOnline = false;
});
}else{
isOnline = false;
issPos.addPosition(40, 0);
issPos.time = now;
}
loadJSON(launchUrl, gotLaunchData);
for (let c in cityData) {
let city = cityData[c];
let name = city.name +" — "+ city.country;
let lat = city.lat;
let lng = city.lng;
let obj = new City(lat, lng, name);
cities.push(obj);
}
}
function gotDataISS(data) {
console.log('ISS position loaded');
let newLat = data.iss_position.latitude;
let newLng = data.iss_position.longitude;
issPos.addPosition(newLat, newLng);
issPos.time = data.timestamp;
transimitionCounter++;
// update ISS position
setInterval(() => {
loadJSON(cors + ISSurl, (data) => {
if (isOnline) {
newLat = data.iss_position.latitude;
newLng = data.iss_position.longitude;
issPos.addPosition(newLat, newLng);
console.log('added new ISS position');
transimitionCounter++;
}
}, () => {
isOnline = false;
});
}, requestTimer);
}
function gotLaunchData(data) {
for (let id in data.launches) {
let spaceCraft = data.launches[id];
// console.log(spaceCraft)
let name = spaceCraft.name;
let lat = spaceCraft.location.pads[0].latitude;
let lng = spaceCraft.location.pads[0].longitude;
let time = spaceCraft.isostart;
let obj = new Launch(lat, lng, name, time);
launches.push(obj);
}
}
function draw() {
background(10);
if (isTooManyRequests) {
textSize(15);
textAlign(CENTER, CENTER);
text('Sorry, too many requests\n per minute. Try again later.', 0, 0);
noLoop();
} else {
rotateY(frameCount * 0.001);
// EARTH
push();
noFill();
// fill(0,200)
strokeWeight(0.5);
stroke(150, 100);
// noStroke();
// texture(mapTexture);
sphere(earthRad, 24, 24);
pop();
for (let i = 0; i < launches.length; i++) {
launches[i].draw();
}
for (let i = 0; i < cities.length; i++) {
cities[i].draw();
}
issPos.draw();
}
push();
textSize(12);
textAlign(RIGHT, BOTTOM);
rotateY(frameCount * -0.001);
if (isOnline) {
fill(255);
text(transimitionCounter+'/200 — Receiving Transmission', 285, 290);
} else {
fill('red');
text(transimitionCounter+' — Transmission Stopped', 285, 290);
}
pop();
}
class ISS {
constructor() {
this.x = 0;
this.y = 0;
this.z = 0;
this.time = 0;
this.path = [];
this.frameSave = 0;
}
addPosition(lat, lng) {
let issPos = latlngToXYZ(lat, lng, distanceISS);
this.x = issPos.x;
this.y = issPos.y;
this.z = issPos.z;
let dummyArray = this.path;
dummyArray.push(issPos);
this.path = dummyArray;
}
draw() {
// only render if has values
if (this.time) {
// add Path
push();
noFill();
stroke('red');
strokeWeight(2);
beginShape(LINES);
for (let i = 0; i < this.path.length; i++) {
let p = this.path[i];
vertex(p.x, p.y, p.z);
}
endShape();
pop();
// Add ISS
push();
fill(255, 0, 0, 220);
noStroke();
translate(this.x, this.y, this.z);
sphere(8);
pop();
// pulsating effect
let frc = frameCount - this.frameSave;
let mapOpacity = map( frc, 0, 120, 255, 0);
let mapSize = map( frc, 0, 120, 0, 16);
push();
fill(255, 0, 0, mapOpacity);
noStroke();
translate(this.x, this.y, this.z);
sphere(mapSize);
pop();
if( frc >= 120 ){
this.frameSave = frameCount;
}
}
}
}
class Launch {
constructor(lat, lng, name, time) {
this.name = name;
let y = time.substring(0, 4);
let m = time.substring(4, 6);
let d = time.substring(6, 8);
let timestamp = new Date(y,m,d).getTime();
let timeDistance = timestamp-now;
let timeInDays = timeDistance / ( 1000 * 60 * 60 * 24 ) - 30;
// console.log(timeInDays)
this.color = map(timeInDays, 0, 30, 255, 0);
let launchPos = latlngToXYZ(lat, lng)
this.x = launchPos.x;
this.y = launchPos.y;
this.z = launchPos.z;
this.time = y+'-'+m+'-'+d;
}
draw() {
push();
fill(this.color);
noStroke();
translate(this.x, this.y, this.z);
sphere(4);
textSize(8);
push();
rotateY(frameCount * -0.001);
translate(-10, 0, 0);
textAlign(RIGHT, CENTER);
text(this.name, 0, 0);
text(this.time, 0, 10);
pop();
pop();
}
}
class City {
constructor(lat, lng, name) {
this.name = name;
let cityPos = latlngToXYZ(lat, lng)
this.x = cityPos.x;
this.y = cityPos.y;
this.z = cityPos.z;
}
draw() {
push();
fill('red');
noStroke();
translate(this.x, this.y, this.z);
sphere(2);
textSize(8);
push();
rotateY(frameCount * -0.001);
translate(-10, 0, 0);
textAlign(RIGHT, CENTER);
text(this.name, 0, 0);
pop();
pop();
}
}
function latlngToXYZ(lat, lng, altitude = 0) {
let s = lat * PI / -180;
let t = lng * PI / -180;
let x = ( earthRad + altitude ) * cos(s) * cos(t);
let z = ( earthRad + altitude ) * cos(s) * sin(t);
let y = ( earthRad + altitude ) * sin(s);
return ({
x: x,
y: y,
z: z
})
}