pack.cpp | main.cpp | menu.cpp | grs.cpp | ||||
pack.h | zoom.h | menu.h | grs.h |
// (c) Bernie Freidin 1999-2000 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <gl/glut.h> #include "zoom.h" #include "pack.h" #define _min3(a,b,c) ((a)<(b)?((a)<(c)?(a):(c)):((b)<(c)?(b):(c))) #define _max3(a,b,c) ((a)>(b)?((a)>(c)?(a):(c)):((b)>(c)?(b):(c))) #define PI2 6.28318530717958647692528676655901 // Pi times 2 static packinfo_t *INFO; static zoom_t *Z; static int SHADOW_MODE; static double VIEW_X; static double VIEW_Y; static double VIEW_ASPECT; static pack_t *PACK[2] = {NULL, NULL}; static pack_t A = {0.0, +0.0, -1.0}; static pack_t B = {0.0, +1.0, +2.0}; static pack_t C = {0.0, -1.0, +2.0}; static pack_t *SEARCH_RESULT; void PACK_Initialize(packinfo_t *packinfo) { INFO = packinfo; INFO->obj_total = 3; for(int i = 0; i < 3; i++) { A.child[i] = NULL, A.depth = -1; B.child[i] = NULL, B.depth = 0; C.child[i] = NULL, C.depth = 0; } } void PACK_SetView(double view_x, double view_y) { VIEW_X = view_x; VIEW_Y = view_y; VIEW_ASPECT = view_x / view_y; } pack_t *PACK_Create(pack_t *a, pack_t *b, pack_t *c, int depth) { if(c->z > INFO->max_render_z*Z->z) return NULL; if(c->z < 0.0) return NULL; //FIXME: really necessary? double ax = a->x, ay = a->y, az = a->z; double bx = b->x, by = b->y, bz = b->z; double cx = c->x, cy = c->y, cz = c->z; // **************************************************** // Compute next circle (this is a 7th-order equation!!) // **************************************************** double dz = az + bz + cz + 2.0*sqrt(az*bz + bz*cz + cz*az); double vx = ax*bz - az*bx; double vy = ay*bz - az*by; double mx = az*(ax*(1.0 - bx*bx + by*by) - 2.0*ay*(bx*by)) + bz*(bx*(1.0 - ax*ax + ay*ay) - 2.0*by*(ax*ay)) ; double my = az*(ay*(1.0 + bx*bx - by*by) - 2.0*ax*(bx*by)) + bz*(by*(1.0 + ax*ax - ay*ay) - 2.0*bx*(ax*ay)) ; double ex = mx*dz + 2.0*vx*(az-bz); double ey = my*dz + 2.0*vy*(az-bz); double fx = az*az*az*bx*(1.0 - bx*bx - by*by) + bz*bz*bz*ax*(1.0 - ax*ax - ay*ay) ; double fy = az*az*az*by*(1.0 - bx*bx - by*by) + bz*bz*bz*ay*(1.0 - ax*ax - ay*ay) ; double nx = az*bz*ex - dz*fx; double ny = az*bz*ey - dz*fy; double s = 4.0*az*bz*sqrt(az*bz + bz*dz + dz*az); double nz = 2.0*az*bz*(az+bz)*(az+bz); double dx = (nx - vy*s)/nz; double dy = (ny + vx*s)/nz; pack_t *d = (pack_t*)malloc(sizeof(pack_t)); d->x = dx; d->y = dy; d->z = dz; d->parent[0] = a; d->parent[1] = b; d->parent[2] = c; d->child[0] = PACK_Create(a, b, d, depth+1); d->child[1] = PACK_Create(b, c, d, depth+1); d->child[2] = PACK_Create(c, a, d, depth+1); d->depth = depth; d->error = (fabs(dx-floor(dx)) > 0.1 || fabs(dy-floor(dy)) > 0.1 || fabs(dz-floor(dz)) > 0.1 ) ? 1 : 0; INFO->obj_created++; INFO->obj_total++; // ************************* // Compute bounding triangle // ************************* double abx = (ax+bx)/(az+bz); double aby = (ay+by)/(az+bz); double bcx = (bx+cx)/(bz+cz); double bcy = (by+cy)/(bz+cz); double cax = (cx+ax)/(cz+az); double cay = (cy+ay)/(cz+az); // ******************** // Compute bounding box // ******************** d->box[0] = _min3(abx, bcx, cax); d->box[1] = _min3(aby, bcy, cay); d->box[2] = _max3(abx, bcx, cax); d->box[3] = _max3(aby, bcy, cay); return d; } static void DrawText(char *s) { while(*s != '\0') { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int)(*s++)); } } static void DrawCircleVector1(pack_t *pack, double r) { char s[10]; if(INFO->show_depth) sprintf(s, "%i", (int)pack->depth); else sprintf(s, "%i", (int)pack->z); double len = (double)strlen(s); if(r*VIEW_Y*Z->z > 12.0*len) { double x = r*pack->x; double y = r*pack->y; glRasterPos2d(x - 8.0/(VIEW_Y*Z->z)*len, y - 13.0/(VIEW_Y*Z->z)); DrawText(s); } } static void DrawCircleVector3(pack_t *pack, double r) { char s1[10]; char s2[10]; char s3[10]; sprintf(s1, "%i", (int)pack->x); sprintf(s2, "%i", (int)pack->y); sprintf(s3, "%i", (int)pack->z); double len1 = (double)strlen(s1); double len2 = (double)strlen(s2); double len3 = (double)strlen(s3); double len = _max3(len1, len2, len3); if(len1 + len2 + len3 > 4.0) { if(r*VIEW_Y*Z->z > 15.0*len) { double x = r*pack->x; double y = r*pack->y; double x_loc = x - 8.0/(VIEW_Y*Z->z)*len; double y_loc = y - 39.0/(VIEW_Y*Z->z); double dy = 26.0/(VIEW_Y*Z->z); glRasterPos2d(x_loc + 16.0*(len-len3)/(VIEW_Y*Z->z), y_loc); DrawText(s3); y_loc += dy; glRasterPos2d(x_loc + 16.0*(len-len2)/(VIEW_Y*Z->z), y_loc); DrawText(s2); y_loc += dy; glRasterPos2d(x_loc + 16.0*(len-len1)/(VIEW_Y*Z->z), y_loc); DrawText(s1); } } else { char s4[40]; sprintf(s4, "%s,%s,%s", s1, s2, s3); len = (double)strlen(s4); if(r*VIEW_Y*Z->z > 12.0*len) { double x = r*pack->x; double y = r*pack->y; glRasterPos2d(x - 8.0/(VIEW_Y*Z->z)*len, y - 13.0/(VIEW_Y*Z->z)); DrawText(s4); } } } void PACK_DrawCircle(pack_t *pack) { double r = 1.0/fabs(pack->z); double x = r*pack->x; double y = r*pack->y; // ************** // Trivial reject // ************** if((y - r + Z->y)*Z->z > +1.0) return; if((y + r + Z->y)*Z->z < -1.0) return; if((x - r + Z->x)*Z->z > +VIEW_ASPECT) return; if((x + r + Z->x)*Z->z < -VIEW_ASPECT) return; double q = 1.0 - pow(r*INFO->max_render_z*Z->z, INFO->fade_exponent); if(!SHADOW_MODE && pack->z > 0.0) { if(pack->error) glColor3d(0.7, 0.3, 0.3); else glColor3d(0.0, 1.0, 1.0); if(INFO->show_vec_3) { DrawCircleVector3(pack, r); } else { DrawCircleVector1(pack, r); } } if(pack->error) { if(SHADOW_MODE) glColor3d(0.3, 0.0, 0.0); else glColor3d(1.0, 0.0, 0.0); } else { //NOTE: in a dark room: use q*0.1, q*0.3 if(SHADOW_MODE) glColor3d(q*0.0, q*0.3, q*0.6); else glColor3d(q*0.2, q*0.2, q*1.0); } // ******************************************************* // Compute dTHETA based on LOD heuristic: radial deviation // ******************************************************* double err = fabs(pack->z)/(INFO->lod_constant*Z->z); double dtheta = acos(err>1.0?-1.0 : 1.0 - 4.0*err + 2.0*err*err); // *************************************** // Draw circle (this should be tight code) // *************************************** double xx = r, x2; double yy = 0.0; double c = cos(dtheta); double s = sin(dtheta); glBegin(GL_LINE_STRIP); for(double theta = 0.0; theta <= PI2; theta += dtheta) { glVertex2d(x + xx, y + yy); x2 = xx*c - yy*s; yy = xx*s + yy*c; xx = x2; } glVertex2d(x + r, y); glEnd(); if(pack == SEARCH_RESULT) { // ********************************** // Draw lines to children and parents // ********************************** glBegin(GL_LINES); for(int i = 0; i < 3; i++) { if(pack->parent[i]) { double pr = 1.0/pack->parent[i]->z; double px = pr*pack->parent[i]->x; double py = pr*pack->parent[i]->y; glColor3d(1.0, 1.0, 1.0); glVertex2d(x, y); glColor3d(0.0, 0.0, 0.0); glVertex2d(px, py); } if(pack->child[i]) { double cr = 1.0/pack->child[i]->z; double cx = cr*pack->child[i]->x; double cy = cr*pack->child[i]->y; glColor3d(0.0, 1.0, 0.0); glVertex2d(x, y); glColor3d(0.0, 0.0, 0.0); glVertex2d(cx, cy); } } glEnd(); } INFO->obj_in_view++; } void PACK_Draw(pack_t *pack, pack_t *up) { if(pack) { if(pack->depth > 1) { // ************************************* // Trivial reject if circle is too small // ************************************* if(pack->z > INFO->max_render_z*Z->z) { //don't count as node rejection return; } // ************************************ // Trivial reject if box is out of view // ************************************ double lft = (pack->box[0] + Z->x)*Z->z; double top = (pack->box[1] + Z->y)*Z->z; double rgt = (pack->box[2] + Z->x)*Z->z; double bot = (pack->box[3] + Z->y)*Z->z; if(lft > +VIEW_ASPECT || top > +1.0 || rgt < -VIEW_ASPECT || bot < -1.0 ) { INFO->node_reject++; return; } } // *********************** // Draw circle and recurse // *********************** PACK_DrawCircle(pack); PACK_Draw(pack->child[0], pack); PACK_Draw(pack->child[1], pack); PACK_Draw(pack->child[2], pack); } else if(up) { if(!INFO->dynamic) return; if(!INFO->dynamic_shadow && INFO->shadow_mode) return; // *********************************** // Dynamic generation of more TSP data // *********************************** for(int i = 0; i < 3; i++) { if(up->child[i]) continue; // already done it pack_t *a = up->parent[i]; pack_t *b = up->parent[i<2?i+1:0]; up->child[i] = PACK_Create(up, a, b, up->depth+1); } } } void PACK_Draw(int shadow_mode, zoom_t *zoom) { SHADOW_MODE = shadow_mode, Z = zoom; // ********************** // Root of circle packing // ********************** INFO->obj_created = 0; INFO->obj_in_view = 0; INFO->node_reject = 0; // ******************************** // Initialize packing, if necessary // ******************************** if(!PACK[0]) PACK[0] = PACK_Create(&A, &B, &C, 1); if(!PACK[1]) PACK[1] = PACK_Create(&A, &C, &B, 1); // ************** // Render packing // ************** PACK_DrawCircle(&A); PACK_DrawCircle(&B); PACK_DrawCircle(&C); PACK_Draw(PACK[0], NULL); PACK_Draw(PACK[1], NULL); } int PACK_Search(double x, double y, pack_t *pack) { if(!pack) return 0; if(pack->depth > 0) { double lft = (pack->box[0] + Z->x)*Z->z; double top = (pack->box[1] + Z->y)*Z->z; double rgt = (pack->box[2] + Z->x)*Z->z; double bot = (pack->box[3] + Z->y)*Z->z; if(lft > x || top > y || rgt < x || bot < y ) { return 0; } double r0 = Z->z/pack->z; double x0 = pack->x*r0 + Z->x*Z->z; double y0 = pack->y*r0 + Z->y*Z->z; if((x-x0)*(x-x0) + (y-y0)*(y-y0) <= r0*r0) { SEARCH_RESULT = pack; return 1; } } if(PACK_Search(x, y, pack->child[0])) return 1; if(PACK_Search(x, y, pack->child[1])) return 1; if(PACK_Search(x, y, pack->child[2])) return 1; return 0; } pack_t *PACK_Search(double x, double y, int show) { SEARCH_RESULT = NULL; if(show) { double xd = +(2.0*(double)x/VIEW_X - 1.0)*VIEW_ASPECT; double yd = -(2.0*(double)y/VIEW_Y - 1.0); if(PACK_Search(xd, yd, PACK[0])) return SEARCH_RESULT; if(PACK_Search(xd, yd, PACK[1])) return SEARCH_RESULT; } return NULL; } void PACK_ClearTSPMemory(pack_t *pack) { if(!pack) return; for(int i = 0; i < 3; i++) { PACK_ClearTSPMemory(pack->child[i]); } free(pack); INFO->obj_total--; } void PACK_ClearTSPMemory(void) { PACK_ClearTSPMemory(PACK[0]); PACK_ClearTSPMemory(PACK[1]); PACK[0] = NULL; PACK[1] = NULL; if(INFO->obj_total != 0) { printf("what???"); } }
This page © Bernie Freidin, 2000.