/* tenseggl.c structures in three dimensions with tension members */ /* The simplest tensegrety structure has three thin cylinders of length 1 * Label them A, B, C with ends A1, A2, B1, B2, C1, C2 * There are nine strings labeled 1 through 9 with ends 1-1, 1-2, 2-1 etc. * Strings are approximately 2/3 as long as cylinders. * * The connections are three string ends to each cylinder end: * A1 1-1 3-1 4-1 * B1 1-2 2-1 5-1 * C1 2-2 3-2 6-1 * A2 6-2 7-1 9-1 * B2 4-2 7-2 8-1 * C2 5-2 8-2 9-2 * * In order to "anchor" the 3D structure: * Place A1 at 0, 0, 0 * Place B1 on the positive X axis * Place C1 in the Z=0 plane with positive X and positive Y * A2, B2 and C2 should all have the same positive Z coordinate */ /* Mouse buttons control axis of rotation */ /* "O" and "o" make centroid offset bigger and smaller */ /* "C" and "c" make color distinct or same */ /* "F" and "f" make rotation faster or slower */ /* "S" and "s" scale larger or smaller */ #include #include #include #define sumcent(A) {centroid[0]+=A[0];centroid[1]+=A[1];centroid[2]+=A[2];} static GLfloat A1[3] = { 0.0000, 0.0000, 0.0000}; static GLfloat A2[3] = { 0.6046, 0.4938, 0.6250}; static GLfloat B1[3] = { 0.6850, 0.0000, 0.0000}; static GLfloat B2[3] = {-0.0450, 0.2767, 0.6250}; static GLfloat C1[3] = { 0.3425, 0.5932, 0.0000}; static GLfloat C2[3] = { 0.4678, -0.1773, 0.6250}; GLfloat colors[][3] = {{1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {0.0,1.0,1.0}}; static GLfloat theta[] = {0.0,0.0,0.0}; static GLint axis = 2; static int colorset = 1; /* 'C' or 'c' */ static double rotation = 1.0; /* 'F' or 'f' */ static GLfloat myScale = 0.5; /* 'S' or 's' */ static GLfloat centroid[3]= { 0.0, 0.0, 0.0}; /* 'O' or 'o' */ static int winWidth = 500; static int winHeight = 500; /* internal functions */ static void myInit(void); static void drawString(int color, GLfloat *A, GLfloat *B); static void drawCylinder(int color, GLfloat *A, GLfloat *B); static void draw_tenseg(void); static void display(void); static void drawText(void); static void spin_tenseg(void); static void mouse(int btn, int state, int x, int y); static void keyboard(unsigned char key, int x, int y); static void myReshape(int w, int h); static void myInit(void) { /* compute centroid, average of vertices */ sumcent(A1); sumcent(A2); sumcent(B1); sumcent(B2); sumcent(C1); sumcent(C2); centroid[0] /= 6.0; centroid[1] /= 6.0; centroid[2] /= 6.0; } static void drawString(int color, GLfloat *A, GLfloat *B) { GLfloat Ac[3], Bc[3]; int i, lcolor; lcolor=color; if(colorset==0) lcolor=1; for(i=0; i<3; i++) { Ac[i] = A[i]-centroid[i]; Bc[i] = B[i]-centroid[i]; } glLineWidth(1.0/myScale); glBegin(GL_LINES); glColor3fv(colors[lcolor]); glVertex3fv(Ac); glVertex3fv(Bc); glEnd(); } static void drawCylinder(int color, GLfloat *A, GLfloat *B) { GLfloat Ac[3], Bc[3]; int i, lcolor; lcolor=color; if(colorset==0) lcolor=1; for(i=0; i<3; i++) { Ac[i] = A[i]-centroid[i]; Bc[i] = B[i]-centroid[i]; } /* draw a cylinder */ glLineWidth(6.0/myScale); glBegin(GL_LINES); glColor3fv(colors[lcolor]); glVertex3fv(Ac); glVertex3fv(Bc); glEnd(); } static void draw_tenseg(void) { /* 9 strings and 3 cylinders */ drawString(0, A1, B1); drawString(0, B1, C1); drawString(0, C1, A1); drawString(1, A1, B2); drawString(1, B1, C2); drawString(1, C1, A2); drawString(4, A2, B2); drawString(4, B2, C2); drawString(4, C2, A2); drawCylinder(3, A1, A2); drawCylinder(3, B1, B2); drawCylinder(3, C1, C2); } static void display(void) { /* display callback, clear frame buffer and z buffer, */ /* rotate tenseg and draw, swap buffers */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0], 1.0, 0.0, 0.0); glRotatef(theta[1], 0.0, 1.0, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); draw_tenseg(); drawText(); glFlush(); glutSwapBuffers(); } static void drawText(void) { char msg1[] = "'S' or 's' for size, 'F' or 'f' for rotation speed"; char msg2[] = "'O' or 'o' to offset, 'C' or 'c' for color"; char msg3[] = "mouse button for rotation axis change"; int i, len; /* Draw text */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, winWidth, 0, winHeight, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3f(1.0f, 1.0f, 0.0f); glRasterPos2i(10, 10); len = strlen(msg1); for (i=0; i 360.0) theta[axis] = theta[axis] - 360.0; /* display(); */ glutPostRedisplay(); } static void mouse(int btn, int state, int x, int y) { /* mouse callback, selects an axis about which to rotate */ if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; } static void keyboard(unsigned char key, int x, int y) { switch (key) { case 'O': centroid[0] *= 1.25; /* increase by 25% each press */ centroid[1] *= 1.25; centroid[2] *= 1.25; break; case 'o': centroid[0] /= 1.25; centroid[1] /= 1.25; centroid[2] /= 1.25; break; case 'C': colorset=1; break; case 'c': colorset=0; break; case 'F': rotation=rotation+0.25; if(rotation>5.0) rotation=5.0; break; case 'f': rotation=rotation-0.25; if(rotation<0.0) rotation=0.0; break; case 's': myScale *= 1.25; /* decrease size by 25% */ myReshape(winWidth, winHeight); break; case 'S': myScale /= 1.25; /* increase size by 25% */ myReshape(winWidth, winHeight); break; } } static void myReshape(int w, int h) { winWidth = w; winHeight = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w <= h) glOrtho(-2.0*myScale, 2.0*myScale, -2.0*myScale * (GLfloat)h / (GLfloat)w, 2.0*myScale * (GLfloat)h / (GLfloat)w, -10.0*myScale, 10.0*myScale); else glOrtho(-2.0*myScale * (GLfloat)w / (GLfloat)h, 2.0*myScale * (GLfloat)w / (GLfloat)h, -2.0*myScale, 2.0*myScale, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char *argv[]) { glutInit(&argc, argv); /* need both double buffering and z buffer */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(winWidth, winHeight); glutCreateWindow("tensegGL"); glutReshapeFunc(myReshape); glutDisplayFunc(display); /* draws screen */ glutIdleFunc(spin_tenseg); /* "spin_tenseg" setup */ glutMouseFunc(mouse); /* "mouse" setup */ glutKeyboardFunc(keyboard); /* "keyboard" setup */ glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */ myInit(); glutMainLoop(); return 0; }