/* * io_tin_simp.c - This code contains allows you to simplify a TIN from a grid * to a supplied error level. It uses tiling to do this task * IO efficiently and maintain a delanuy triangulation on * everywhere but the edges of the tiles. * * Author: Jon Todd * * real-time rednering by rajiv wickremesinghe */ #include #include #include #include #include #ifdef __APPLE__ #include #else #include #endif #include "rtimer.h" #include "refine_tin.h" GLfloat red[3] = {1.0, 0.0, 0.0}; GLfloat green[3] = {0.0, 1.0, 0.0}; GLfloat blue[3] = {0.0, 0.0, 1.0}; GLfloat black[3] = {0.0, 0.0, 0.0}; GLfloat white[3] = {1.0, 1.0, 1.0}; GLfloat gray[3] = {0.5, 0.5, 0.5}; GLfloat yellow[3] = {1.0, 1.0, 0.0}; GLfloat magenta[3] = {1.0, 0.0, 1.0}; GLfloat cyan[3] = {0.0, 1.0, 1.0}; GLint fillmode = 0; GRID *gridGlobal; TIN tinGlobal; TINLIST tinListGlobal=NULL; int resolution = 64; // 1 is best resolution, 2 is 1/2 the resolution of 1... int colorStyle = 0; // Specifies the color to display void init(int *argc, char** argv); void render(); void drawTin(); void colorMap(int h); void display(void); void idle(void); void keypress(unsigned char key, int x, int y); void mainMenu(int value); extern pthread_mutex_t mutex; extern COORD DONE[3]; int main(int argc, char** argv) { GRID *grid; Rtimer refineTime; TINLIST tList; double err; double mem; char buf[1000]; init(&argc,argv); // Initialize the no_draw global for marking NO_DRAW = Q_init(); //debug //printf("DONE = %p\n",(COORD*)DONE); //fflush(stdout); // Validate the number of arguments if (argc < 3){ printf("usage: tin intput-grid error [memory in MB] [render]\n"); return 1; } // import grid grid = gridGlobal = importGrid(argv[1]); // Global for rendering // Only printf if we are not timing if(argc != 5 || (strcmp(argv[4],"time")!=0)) printf("Grid imported...\n"); // convert error value from char to float sscanf(argv[2],"%lf",&err); // set memory if(argc >= 4) sscanf(argv[3],"%lf",&mem); else { printf("Assuming 200.0 MB of memory.\n"); mem = 200.0; } // start timer rt_start(refineTime); // stop timer rt_stop(refineTime); pthread_mutex_init(&mutex, NULL); // refine grids and save into tinlist tinListGlobal = doTiles(grid, err, mem); // decide whether or not to render if(argc == 5){ if(strcmp(argv[4],"render")==0){ // print runtime rt_sprint(buf,refineTime); printf("tin: \t%s\t%s\t%s\n", argv[1], argv[2], buf); render(); } else if(strcmp(argv[4],"time")==0){ rt_sprint(buf,refineTime); printf("tin: \t%s\t%s\t%s", argv[1], argv[2], buf); } } else{ // print runtime if render is not called rt_sprint(buf,refineTime); printf("tin: \t%s\t%s\t%s\n", argv[1], argv[2], buf); } //printTinList(tList); extern pthread_t thd; pthread_join(&thd, NULL); return 0; } /////////////////////////////////////////////////////////////////////// // RENDER CODE //////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// void init(int *argc, char** argv){ // open a window glutInit(argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100,100); glutCreateWindow("tin"); // OpenGL init glClearColor(0, 0, 0, 0); // set background color black // callback functions glutDisplayFunc(display); glutIdleFunc(idle); glutKeyboardFunc(keypress); // creat menu glutCreateMenu(mainMenu); glutAddMenuEntry("Fill/Outline", 1); glutAddMenuEntry("Change Color", 2); glutAddMenuEntry("Quit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); } void render(int argc, char** argv){ // event handler glutMainLoop(); } // drawTinList - given a valid grid, this will draw the elevation grid in 2D // an entire tin list void drawTinList(){ TINLIST tl = tinListGlobal; // tinGlobal = tinGlobal->prev; if(!tl) { return; } //skip dummy head tl = tl->next; while(tl->next != NULL){ if(tl->t) { pthread_mutex_lock(&mutex); drawTin(tl); pthread_mutex_unlock(&mutex); } tl = tl->next; } } // drawTin - given a valid grid, this will draw the elevation grid in 2D // void drawTin(TINLIST tl){ double interval,x0,y0; // Decide whether to fill the triangles if (fillmode) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } // set x1 and y1 to the upper left corner of the data // rows > cols if(gridGlobal->nrows > gridGlobal->ncols){ interval = 2.0/ (gridGlobal->nrows-1); // from JT's code x0 = -((interval*(gridGlobal->ncols-1))/2.0); y0 = 1; /* printf("interval %f, nrows %d, ncols %d\n", */ /* interval, gridGlobal->nrows, gridGlobal->ncols); */ } // cols > rows else{ interval = 2.0/(gridGlobal->ncols-1); // from JT's x0 = -1; y0 = ((interval*(gridGlobal->nrows-1))/2.0); /* printf("interval %f, nrows %d, ncols %d\n", */ /* interval, gridGlobal->nrows, gridGlobal->ncols); */ } // loop through the data and draw the triangles in the tin // printf("interval %f, X0 %f, Y0 %f\n", interval, x0, y0); // if the tin only has two init tris don't print it if(1){ TRIANGLE *curT = tl->t->t; TRIANGLE *prevT = curT; // Create an edge which EDGE curE; curE.type = IN; curE.t1 = NULL; curE.t2 = tl->t->t; curE.p1 = tl->t->e.p1; curE.p2 = tl->t->e.p2; int i,j; i = tl->iOffset; j = tl->jOffset; // Traverse the tin and draw triangles till we get back to the start edge do { // Print triangle if it we are on an IN edge if(curE.type == IN && prevT != NULL){ // Don't print tri if it has a nodata corner point if(prevT->p1[Z] != NODATA_CORNER && prevT->p2[Z] != NODATA_CORNER && prevT->p3[Z] != NODATA_CORNER && prevT->p1[Z] != tl->t->nodata && prevT->p2[Z] != tl->t->nodata && prevT->p3[Z] != tl->t->nodata ){ // Draw the triangle glBegin(GL_POLYGON); colorMap(prevT->p1[Z]); glVertex2f(((double) prevT->p1[Y]+j)*interval+x0, y0 - ((double)prevT->p1[X]+i)*interval); colorMap(prevT->p2[Z]); glVertex2f(((double) prevT->p2[Y]+j)*interval+x0, y0 - ((double) prevT->p2[X]+i)*interval); colorMap(prevT->p3[Z]); glVertex2f(((double) prevT->p3[Y]+j)*interval+x0, y0 - ((double) prevT->p3[X]+i)*interval); glEnd(); } } // Go to next edge prevT = curT; curT = nextEdge(curT,tl->t->v,&curE); assert(curT); } while((curE.p1 != tl->t->e.p1 || curE.p2 != tl->t->e.p2) && (curE.p1 != tl->t->e.p2 || curE.p2 != tl->t->e.p1)); } } // color_map - set the color based on a given height // void colorMap(int h){ double c; c = (1.0/(gridGlobal->max - gridGlobal->min))*(h-gridGlobal->min); if(c < (1.0/5)) glColor3f(1-(5*c),1,0); if(c < 2.0/5 && c >= 1.0/5) glColor3f(0,1,(c-(1.0/5))*5); if(c < 3.0/5 && c >= 2.0/5) glColor3f(0,((3.0/5)-c)*5,1); if(c < 4.0/5 && c >= 3.0/5) glColor3f((c-(3.0/5))*5,0,1); if(c <= 5.0/5 && c >= 4.0/5) glColor3f(1,0,(1-c)*5); } int displayValid = 0; void idle(void) { if(!displayValid) { glutPostRedisplay(); displayValid = 1; } } // display - controls what is drawn to the screen // void display(void) { // clear window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawTinList(); /* execute the drawing commands */ glFlush(); } // keypress - assigns actioins to keypresses // void keypress(unsigned char key, int x, int y) { switch(key) { case 'q': exit(0); break; case '>': // increase resolution if(resolution > 1){ resolution /= 2; glutPostRedisplay(); } break; case '<': // decrease resolution if(resolution < gridGlobal->max){ resolution *= 2; glutPostRedisplay(); } break; } } // main_menu - creates a menu // void mainMenu(int value) { switch (value){ case 1: /* toggle outline/fill */ fillmode = !fillmode; break; case 2: // Change color style colorStyle = !colorStyle; break; case 3: exit(0); } glutPostRedisplay(); } /////////////////////////////////////////////////////////////////////// // END RENDER CODE //////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////