import Tuple.*;
import SGCamera.*;
import SGBackground.*;
 
SGCamera cam;
 
HikePoint [] hike;
String [] txtlog;
 
Sky sky;
 
PImage tex;
 
float scalor = 1000;
float heightScale = 80.f;
float demWide, demHigh;
 
int step = 1;
 
float seaLevel = 100;
 
int which = 0;
 
float lx = -119.577080;
float ly = 37.710972;
float rx = -119.507919;
float uy = 37.760414;
 
int nrows = 179/2;
int ncols = 250/2;
 
float [][] hts;
 
PImage hmap = new PImage(nrows,ncols);
 
PFont font;
 
int running = 0;
int hide = 0;
 
void setup(){
 
float delta= (2685-1208);
 
demWide = (lx - rx)/ncols;
demHigh = (uy - ly)/nrows;
size(550,550,P3D);
frameRate(30);
 
font = loadFont("writing.vlw");
tex = loadImage("yosemite.jpg");
 
String [] heights = loadStrings("yosemite.txt");
 
 
StringTokenizer ht = new StringTokenizer(heights[0]);
hts = new float[ncols][nrows];
for (int j =0; j < nrows; j++){
for (int i =0; i < ncols; i++){
hts[ncols-i-1][j] = new Float(ht.nextToken()).floatValue();
 
}
 
}
 
 
 
 
String [] mapSource = loadStrings("hike.txt");
hike = new HikePoint[mapSource.length];
for (int i = 0; i < mapSource.length; i++){
 
String [] tokens = mapSource[i].split("\t");
hike[i] = new HikePoint(tokens[1],tokens[2],tokens[9]);
 
}
 
for (int i=0; i < hike.length-1; i++){
 
if(hike[i].distanceSquared(hike[i+1]) > 2){
hike[i].endPoint = true;
}
 
}
 
int mid = hike.length/2;
 
cam = new SGCamera(this,37742,-35,-119501,hike[mid].x,hike[mid].z,hike[mid].y);
cam.setMouseMode(LEFT,SGCamera.ORBIT);
cam.setMouseMode(RIGHT,SGCamera.DOLLY);
cam.setVerticalLimits(0,1.6);
cam.setFOV(1.5);
 
((PGraphics3D)g).triangle.setCulling(true);
 
 
int currLog = 0;
txtlog = loadStrings("log.txt");
String [] logChunk = txtlog[currLog].split("@");
 
Date logTime = parseTime(logChunk[0]);
 
for (int i =0; i < hike.length; i++){
if (logTime.compareTo(hike[i].gpsTime) > 0 && logTime.compareTo(hike[i+1].gpsTime) < 0){
hike[i].setText(logChunk[1],logChunk[2]);
 
currLog++;
if (currLog < txtlog.length){
logChunk = txtlog[currLog].split("@");
logTime = parseTime(logChunk[0]);
}
}
}
 
sky = new Sky(this,cam);
sky.setTurbidity(1.9f);
 
}
 
 
float fixHeight(float lat, float lon, float alt){
 
float bLat = abs((ly-lat)/demWide);
float bLon = abs((rx-lon)/demHigh);
 
int bx = (int)bLat;
int by = (int)bLon;
 
float remX = bLat - bx;
float remY = bLon - by;
 
float ex1 = lerp(hts[by][bx], hts[by][bx+1],remX);
float ex2 = lerp(hts[by+1][bx], hts[by+1][bx+1],remX);
 
return -(lerp(ex1,ex2,remY))-5;
 
 
}
 
void draw(){
 
if (running != 0){
for (int i=0; i < 2; i++){
which+=running;
which = (int)constrain(which,0,hike.length-1);
if (hike[which].logText != null){
running = 0;
hide = 0;
break;
}
}
}
sky.draw(30);
cam.feed();
 
float sx = screenX(hike[which].x,hike[which].z,hike[which].y);
float sy = screenY(hike[which].x,hike[which].z,hike[which].y);
 
unhint(DISABLE_DEPTH_TEST);
 
stroke(255,255,0);
noFill();
 
int h =0;
while(h < hike.length){
beginShape();
for ( ; h < hike.length; h++){
vertex(hike[h].x,hike[h].z,hike[h].y);
if (hike[h].endPoint){
h++;
break;
}
}
endShape();
}
 
noStroke();
fill(255,255,255,100);
textureMode(NORMALIZED);
 
translate(ly*scalor,0,rx*scalor);
 
float fcols = (float)ncols;
float frows = (float)nrows;
 
for (int j = 0; j < nrows-step; j += step){
beginShape(QUAD_STRIP);
for (int i = 0; i < ncols-step; i+=step){
texture(tex);
vertex(scalor*(j+step)*demHigh, -hts[i][j+step]/heightScale , scalor*(i)*demWide,1-(i)/fcols,1-(j+step)/frows);
vertex(scalor*(j)*demHigh, -hts[i][j]/heightScale , scalor*(i)*demWide,1-(i)/fcols,1-(j)/frows);
}
endShape();
}
 
cam.lookAt(hike[which].x,hike[which].z,hike[which].y);
 
Calendar cal = new GregorianCalendar();
cal.setTime(hike[which].gpsTime);
sky.setSunByTime(0,hike[which].getLon(),cal.get(Calendar.DAY_OF_YEAR),hike[which].gpsTime.getHours() + hike[which].gpsTime.getMinutes()/60.f ,-8);
 
camera();
perspective();
 
 
 
fill(255,255,255,200);
noStroke();
textFont(font);
textMode(SCREEN);
hint(DISABLE_DEPTH_TEST);
if (hide == 0){
int bx = 260;
int by = 10;
int border = 5;
int gutter = 10;
 
if (hike[which].img != null){
bx = hike[which].img.width + 2*border;
by = hike[which].img.height + 2*border;
}
 
gutter += 15*hike[which].txtHeight + border;
 
gutter += 15;
 
int lx = 5;
int ly = 5;
int wd = 30;
 
beginShape();
vertex(sx,sy);
vertex(lx + bx - 60,ly + by + gutter);
vertex(lx + bx - 60 - wd,ly + by + gutter);
endShape();
 
beginShape();
vertex(lx,ly);
vertex(lx + bx,ly);
vertex(lx + bx,ly + by + gutter);
vertex(lx,ly + by + gutter);
endShape();
 
fill(0);
 
text("" + hike[which].gpsTime,lx + 10,ly + by + 10);
 
if (hike[which].logText != null) {
text("" + hike[which].logText,lx + 10,ly + by + 25);
}
 
if (hike[which].img != null){
image(hike[which].img,lx + 5,ly + 5);
}
}
else{
fill(255);
 
beginShape();
vertex(sx,sy);
vertex(sx+5,sy-20);
vertex(sx-5,sy-20);
endShape();
 
}
}
 
void keyPressed(){
if (key == 'a') step++;
if (key == 'z') step--;
if (key == 's') running = 1;
if (key == 'x') running = -1;
if (step < 1) step = 1;
if (key == ' ' ) hide = 1-hide;
if (key == 'g') which++;
}
 
Date parseTime(String time){
 
Date date = null;
try {
DateFormat formatter = new SimpleDateFormat("M/d/y hh:mm:ss a");
date = (Date)formatter.parse(time);
 
}
catch (ParseException e) {
println(e);
}
return date;
}