// // main.cpp // RotatingCube // // Created by Peter Horak on 9/3/12. // Copyright (c) 2012 Peter Horak. All rights reserved. // //Can compile on ubuntu using the following command, assuming to have the appropriate libraries //g++ -L/usr/lib main.cpp math_3d.cpp -lsfml-graphics -lsfml-window -lsfml-system -lGL -lglut -lGLU -o main #include #include #include /*/usr/include/GL/*/ #include /*/usr/include/SFML/*/ #include "math_3d.h" #include #include #include using namespace std; float dirx,diry,dirz; float Vtot; bool follow_goPro=true; bool display_help=false; float speed_multiplier=1; int side_num=1; //value must be hardcoded. Could let the user change it as the program runs, but it might mess up/complicate calculations float data_fraction=1; float solar; float v_estimate; const float pi = 3.14159; int ww = 750; int wh = 750; GLfloat vertices[8][3] = {{-2.0,-1.0,-1.0},{2.0,-1.0,-1.0},{2.0,1.0,-1.0}, {-2.0,1.0,-1.0},{-2.0,-1.0,1.0}, {2.0,-1.0,1.0},{2.0,1.0,1.0},{-2.0,1.0,1.0}}; static GLdouble v_r = 5; static GLdouble v_theta = 0; static GLdouble v_fi = 0; GLuint tex[8]; static GLfloat light_pos[] = {3.0, 3.0, 10.0, 1.0}; ifstream fin; Vector3f mag_world(4.9858,-18.1809,-49.7536); Vector3f acc_world(0,0,1); Vector3f acc(0,0,0); Vector3f mag(0,0,0); Vector3f camera(0,0,1); Vector3f sun; Vector3f partial_rotate; float rotation1; Vector3f axis1; float rotation2; Vector3f axis2; float temp=0; int global_count=0; static float curr_time = 0; static int d0,d1,d2,d3; void polygon(int a, int b, int c, int d) { GLfloat u[3]; for (int i=0;i<3;i++) u[i] = vertices[a][i] - vertices[c][i]; GLfloat v[3]; for (int i=0;i<3;i++) v[i] = vertices[b][i] - vertices[c][i]; GLfloat n[3] = {u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]}; GLfloat len = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); for (int i=0;i<3;i++) n[i] = n[i]/len; glNormal3fv(n); glBegin(GL_POLYGON); glTexCoord2f(0.0, 0.0); glVertex3fv(vertices[a]); glTexCoord2f(1.0, 0.0); glVertex3fv(vertices[b]); glTexCoord2f(1.0, 1.0); glVertex3fv(vertices[c]); glTexCoord2f(0.0, 1.0); glVertex3fv(vertices[d]); glEnd(); } void colorcube() { glBindTexture(GL_TEXTURE_2D, tex[5]); polygon(1,0,3,2); // bottom glBindTexture(GL_TEXTURE_2D, tex[4]); polygon(7,6,2,3); // side glBindTexture(GL_TEXTURE_2D, tex[2]); polygon(3,0,4,7); // end glBindTexture(GL_TEXTURE_2D, tex[3]); polygon(5,1,2,6); // end glBindTexture(GL_TEXTURE_2D, tex[1]); polygon(6,7,4,5); // top glBindTexture(GL_TEXTURE_2D, tex[0]); polygon(5,4,0,1); // side } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); if(follow_goPro==false){ gluLookAt(v_r*cos(v_theta)*cos(v_fi),v_r*sin(v_theta)*cos(v_fi),v_r*sin(v_fi),0,0,0,0,0,1); } else{ gluLookAt(0,0,0,camera.x,camera.y,camera.z,0,0,1); } glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); // Overlay text glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0.0, ww, 0.0, wh); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3f(1.0, 0.0, 0.5); // Green int line = wh - 20; glRasterPos2i(10, line); ostringstream ss; ss.precision(2); if(display_help==false){ float hour; float min; float sec; hour=floor(curr_time/3600); min=floor(60*(curr_time/3600 - hour)); sec=60*(60*(curr_time/3600 - hour)-min); float tof=curr_time-52450; float vid_sec=42.42; int vid_num=42; if(tof < 45){ vid_sec=tof+1010; vid_num=0; } else if(tof<1100){ vid_sec=tof-45; vid_num=1; } else if(tof<2155){ vid_sec=tof-1100; vid_num=2; } else if(tof<3210){ vid_sec=tof-2155; vid_num=3; } else if(tof<4265){ vid_sec=tof-3210; vid_num=4; } else if(tof<5320){ vid_sec=tof-4265; vid_num=5; } else if(tof<5613){ vid_sec=tof-5320; vid_num=6; } float vid_min; vid_min=floor(vid_sec/60); vid_sec=(vid_sec/60-vid_min)*60; ss << fixed << "Time: " << (curr_time-52450) << "_Time of Day: " << (int)hour << ":" <<(int)min << ":" << sec << " (" << curr_time << ")" << "_GoPro Footage Time: Video " << vid_num << ", " << (int)vid_min << ":" << vid_sec <<"_PV Voltage: " << Vtot <<"_Voltage Estimate: " << v_estimate << "_Directional Cosine (x): " << dirx << "_Directional Cosine (y): " << diry << "_Directional Cosine (z): " << dirz << "_Speed Multiplier: " << speed_multiplier << "_Data Fraction: " << (float)100/data_fraction << "%" << "_Press h for help"; } else{ ss << "_h --- help" << "_z --- zoom in" << "_x --- zoom out" << "_w,a,s,d --- rotate camera viewpoint" << "_c --- switch between free view and goPro view" << "_n --- switch the side the goPro view shows" << "_q --- quit" << "_+/- --- speed up/slow down" << "_ --- change data fraction"; } string s = ss.str(); void * font = GLUT_BITMAP_9_BY_15; for (string::iterator i = s.begin(); i != s.end(); ++i) { char c = *i; if (c == '_') { glColor3f(0.0, 1.0, 0.0); line -= 20; glRasterPos2i(10, line); } else glutBitmapCharacter(font, c); } glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); // Draw vector lines glColor3d(1, 0, 0); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(5,0,0); glEnd(); glColor3d(0, 1, 0); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(0,5,0); glEnd(); glColor3d(0, 0, 1); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(0,0,5); glEnd(); glColor3d(1, 1, 0); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(5*sun.x,5*sun.y,5*sun.z); glEnd(); glColor3d(1, 1, 1); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(3*camera.x,3*camera.y,3*camera.z); glEnd(); // glColor3d(0, 1, 1); // glBegin(GL_LINE_LOOP); // glVertex3f(0, 0, 0); // glVertex3f(3*partial_rotate.x,3*partial_rotate.y,3*partial_rotate.z); // glEnd(); glColor3d(0, 1, 1); glBegin(GL_LINE_LOOP); glVertex3f(0, 0, 0); glVertex3f(3*mag_world.x,3*mag_world.y,3*mag_world.z); glEnd(); // glColor3d(1, 0.5, 0); // glBegin(GL_LINE_LOOP); // glVertex3f(0, 0, 0); // glVertex3f(3*acc.x,3*acc.y,3*acc.z); // glEnd(); // glColor3d(0.5, 0, 1); // glBegin(GL_LINE_LOOP); // glVertex3f(0, 0, 0); // glVertex3f(3*mag.x,3*mag.y,3*mag.z); // glEnd(); glEnable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_POSITION, light_pos); //draw the ground glBindTexture(GL_TEXTURE_2D, tex[6]); glNormal3f(0, 0, 1); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(20, -20, -2); glTexCoord2f(10.0, 0.0); glVertex3f(20, 20, -2); glTexCoord2f(10.0, 10.0); glVertex3f(-20, 20, -2); glTexCoord2f(0.0, 10.0); glVertex3f(-20, -20, -2); glEnd(); // //draw the (messy) skybox glCullFace(GL_FRONT); glBindTexture(GL_TEXTURE_2D, tex[7]); glNormal3f(0, 0, 1); //glNormal3fv(n); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(20, -20, 10); glTexCoord2f(1.0, 0.0); glVertex3f(20, 20, 10); glTexCoord2f(1.0, 1.0); glVertex3f(-20, 20, 10); glTexCoord2f(0.0, 1.0); glVertex3f(-20, -20, 10); glEnd(); glBindTexture(GL_TEXTURE_2D, tex[7]); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(20, 10, 10); glTexCoord2f(1.0, 0.0); glVertex3f(20, 10, -2); glTexCoord2f(1.0, 1.0); glVertex3f(-20, 10, -2); glTexCoord2f(0.0, 1.0); glVertex3f(-20, 10, 10); glEnd(); glBindTexture(GL_TEXTURE_2D, tex[7]); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(-10, -10, 20); glTexCoord2f(1.0, 0.0); glVertex3f(-10, 10, 20); glTexCoord2f(1.0, 1.0); glVertex3f(-10, 10, -2); glTexCoord2f(0.0, 1.0); glVertex3f(-10, -10, -2); glEnd(); glCullFace(GL_BACK); glBindTexture(GL_TEXTURE_2D, tex[7]); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(20, -10, 10); glTexCoord2f(1.0, 0.0); glVertex3f(20, -10, -2); glTexCoord2f(1.0, 1.0); glVertex3f(-20, -10, -2); glTexCoord2f(0.0, 1.0); glVertex3f(-20, -10, 10); glEnd(); glBindTexture(GL_TEXTURE_2D, tex[7]); glBegin(GL_POLYGON); glColor3f(0.3, 0.3, 0.3); glTexCoord2f(0.0, 0.0); glVertex3f(10, -10, 20); glTexCoord2f(1.0, 0.0); glVertex3f(10, 10, 20); glTexCoord2f(1.0, 1.0); glVertex3f(10, 10, -2); glTexCoord2f(0.0, 1.0); glVertex3f(10, -10, -2); glEnd(); Vector3f vectors[8] = {Vector3f(-2.0,-1.0,-1.0),Vector3f(2.0,-1.0,-1.0),Vector3f(2.0,1.0,-1.0),Vector3f(-2.0,1.0,-1.0),Vector3f(-2.0,-1.0,1.0),Vector3f(2.0,-1.0,1.0),Vector3f(2.0,1.0,1.0),Vector3f(-2.0,1.0,1.0)}; for (int i = 0; i < 8; i++) { vectors[i].Rotate(rotation1, axis1); vectors[i].Rotate(rotation2, axis2); vertices[i][0] = vectors[i].x; vertices[i][1] = vectors[i].y; vertices[i][2] = vectors[i].z; } Vector3f vec1,vec2; // sides if(side_num==1 || side_num==2){ vec1.x=vertices[6][0]-vertices[5][0]; vec1.y=vertices[6][1]-vertices[5][1]; vec1.z=vertices[6][2]-vertices[5][2]; vec2.x=vertices[7][0]-vertices[6][0]; vec2.y=vertices[7][1]-vertices[6][1]; vec2.z=vertices[7][2]-vertices[6][2]; if(side_num==1){ camera=vec1.Cross(vec2); } else{ camera=vec2.Cross(vec1); } } //front and back if(side_num==3 || side_num==4){ vec1.x=vertices[6][0]-vertices[2][0]; vec1.y=vertices[6][1]-vertices[2][1]; vec1.z=vertices[6][2]-vertices[2][2]; vec2.x=vertices[2][0]-vertices[1][0]; vec2.y=vertices[2][1]-vertices[1][1]; vec2.z=vertices[2][2]-vertices[1][2]; if(side_num==3){ camera=vec1.Cross(vec2); } else{ camera=vec2.Cross(vec1); } } //top and bottom if(side_num==5 || side_num==6){ vec1.x=vertices[6][0]-vertices[7][0]; vec1.y=vertices[6][1]-vertices[7][1]; vec1.z=vertices[6][2]-vertices[7][2]; vec2.x=vertices[6][0]-vertices[2][0]; vec2.y=vertices[6][1]-vertices[2][1]; vec2.z=vertices[6][2]-vertices[2][2]; if(side_num==5){ camera=vec1.Cross(vec2); } else{ camera=vec2.Cross(vec1); } } colorcube(); glFlush(); glutSwapBuffers(); } void spinCube(int n) { float lat, lng, alt; int ax,ay,az,mx,my,mz; fin >> solar >> ax >> az >> ay >> mx >> mz >> my; //convert raw solar data to voltage float Vsense = (float)5.0*solar/1024; float Istar = (float)Vsense/39; Vtot = (float)Istar*128; float ele_at_launch=46.98; float azi_at_launch=249.58; float solar_elevation=(float)(ele_at_launch-0.0028*(curr_time-52450)); float solar_azimuth=(float)azi_at_launch+.003296*(curr_time-52450); sun=mag_world; cout.precision(10); Vector3f elevation_axis=mag_world.Cross(acc_world); sun.Rotate(solar_elevation,elevation_axis); partial_rotate=sun; sun.Rotate(-solar_azimuth,acc_world); float diff=(float)Angle(sun,camera); v_estimate=(float)11.0*cos(ToRadian(diff)); //cout << curr_time << " " << v_estimate << " " << Vtot << endl; //direction cosines dirz = camera.z/sqrt(camera.x*camera.x+camera.y*camera.y+camera.z*camera.z); diry = camera.y/sqrt(camera.x*camera.x+camera.y*camera.y+camera.z*camera.z); dirx = camera.x/sqrt(camera.x*camera.x+camera.y*camera.y+camera.z*camera.z); //string line; //getline(inputFile,line); //sscanf(line.c_str(), " %f %f %f %d %d %d %d %d %d %d %d %d %d",&lat,&lng,&alt,&az,&ax,&ay,&mz,&mx,&my,&d0,&d1,&d2,&d3); //when data comes very quickly, the program can't keep up with it and the visualization takes longer to update than it should. //"solved" by only performing the calculations and updating the orientation for a fraction of the total data points global_count++; if(global_count>=data_fraction){ acc = Vector3f(ax,ay,az); mag = Vector3f(mx,my,mz); acc.Normalize(); mag.Normalize(); Vector3f perp = mag.Cross(acc); mag = acc.Cross(perp); mag.Normalize(); rotation1 = Angle(acc, acc_world); axis1 = Axis(acc, acc_world); mag.Rotate(rotation1, axis1); rotation2 = Angle(mag, mag_world); axis2 = Axis(mag, mag_world); /* rotation1 = Angle(mag, mag_world); axis1 = Axis(mag, mag_world); acc.Rotate(rotation1, axis1); rotation2 = Angle(acc, acc_world); axis2 = mag_world;*/ mag.Rotate(-rotation1, axis1); // undo rotation float next_time; fin >> next_time; float prev_time = curr_time; curr_time = next_time; float time_change=curr_time-prev_time; global_count=0; glutPostRedisplay(); //divide by 1000 to convert microseconds to milliseconds //multiply by 1000 to convert seconds to milliseconds glutTimerFunc(1000*(time_change+temp)/speed_multiplier, spinCube, n); temp=0; } //do not bother updating calculations for a certain fraction of data points, so that to program can keep up else{ float next_time; fin >> next_time; float prev_time = curr_time; curr_time = next_time; float time_change=curr_time-prev_time; //temp is used to keep track of the time that should elapse for all the data points that are being skipped, so they can be factored in to the wait time when the next update is performed temp=temp+time_change; glutPostRedisplay(); glutTimerFunc(0, spinCube, n); } } void keysDown(unsigned char key, int x, int y) { if (key=='q' or key=='Q') exit(0); double speed = 64.0; if (key=='h'){ if(display_help==false){ display_help=true; } else{ display_help=false; } } if (key=='w') { v_fi += M_PI/speed; if (v_fi > M_PI/4.0) v_fi = M_PI/4.0; } if (key=='s') { v_fi -= M_PI/speed; if (v_fi < -M_PI/4.0) v_fi = -M_PI/4.0; } if (key=='d') { v_theta += M_PI/speed; if (v_theta > M_PI) v_theta -= 2.0*M_PI; } if (key=='a') { v_theta -= M_PI/speed; if (v_theta < -M_PI) v_theta += 2.0*M_PI; } if (key=='+' || key=='='){ if(speed_multiplier<20){ speed_multiplier+=.25; } else if(speed_multiplier<100){ speed_multiplier+=1; } else{ speed_multiplier+=5; } } if (key=='-' && speed_multiplier > .25){ if(speed_multiplier<20){ speed_multiplier-=.25; } else if(speed_multiplier < 100){ speed_multiplier-=1; } else{ speed_multiplier-=5; } } if (key=='<'){ data_fraction+=1; } if (key=='>' && data_fraction > 1){ data_fraction-=1; } if (key=='x') v_r += 0.2; if (key=='z') v_r -= 0.2; if (key=='c'){ if(follow_goPro==false){ follow_goPro=true; } else{ follow_goPro=false; } } if (key=='n'){ if(side_num==6){ side_num=1; } else{ side_num++; } } glutPostRedisplay(); } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); ww = w; wh = h; if (w <= h) glFrustum(-1.0, 1.0, -1.0 * (GLfloat) h / (GLfloat) w, 1.0 * (GLfloat) h / (GLfloat) w, 1.0, 20.0); else glFrustum(-1.0, 1.0, -1.0 * (GLfloat) w / (GLfloat) h, 1.0 * (GLfloat) w / (GLfloat) h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); } void initLighting(void) { // Enable lighting and specifiy model glShadeModel(GL_FLAT); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); //glEnable(GL_COLOR_MATERIAL); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); //glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); // Define light properties GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_ambient[] = {0.3, 0.3, 0.3, 1.0}; GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; // Set light properties glLightfv(GL_LIGHT0, GL_POSITION, light_pos); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); //glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f); //glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.2f); //glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.04f); // Define material properties GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_ambient[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_shininess = 100.0; // Set material properties glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(ww, wh); glutCreateWindow("Payload"); glutReshapeFunc(myReshape); glutDisplayFunc(display); initLighting(); int n = 60; // refresh rate glutTimerFunc(100, spinCube, n); // glutIdleFunc(spinCube); glutKeyboardFunc(keysDown); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glGenTextures(8, tex); for (int i = 0; i < 8; i++) { sf::Image image; string fileName = "Payload"; fileName += static_cast(i+48); fileName += ".jpg"; if (i == 6) fileName = "Grass.jpg"; if(i==7){ fileName="clouds.jpg"; } if( !image.LoadFromFile(fileName) ) { std::cerr<<"Load image error!"<> curr_time; glutMainLoop(); }