opengl学習 -どの球同士を接続するか指定する-
[,left]
前のエントリのプログラムをさらに改良して点のリストと、それらの点を結ぶ2つのインデクスをうけとり描画するようにした。
// spheresColumnLinkedDSL.cpp /* * 以下のフォーマットのテキストファイルを受け取り、指定された場所へ * 球を描画する。また、指定された2点を円柱で結ぶ * * x座標 y座標 z座標 * (0個以上) * (空行) * リンク元インデクス リンク先インデクス * (0個以上) */ #include<iostream> #include<fstream> #include<vector> #include<math.h> #include<GL/glut.h> using namespace std; float cx, cy, cz; // カメラの位置 float sx, sy, sz; // 視点の位置 char *inFileName; typedef struct point_t { point_t(float a, float b, float c): x(a), y(b), z(c){} float x, y, z; } pt; vector<pt> pts; vector< pair<int,int> > links; double perspective() { return (double)glutGet(GLUT_WINDOW_WIDTH) / glutGet(GLUT_WINDOW_HEIGHT); } void sphere(pt p) { glPushMatrix(); { glTranslatef(p.x, p.y, p.z); float red[] = {1, 0, 0}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, red); glutSolidSphere(1.5, 20, 20); } glPopMatrix(); } // 引用元:http://www.wakayama-u.ac.jp/~tokoi/opengl/myCylinder.c #define PI2 (M_PI * 2) /* * 円柱を描く * eadius: 半径 * height: 高さ * sides: 側面の数(数が多いほど滑らかになる) * */ void myCylinder(double radius, double height, int sides) { double step = PI2 / (double)sides; int i; /// 追加部分 float blue[] = {0, 0, 1}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, blue); /// /* 上面 */ glNormal3d(0.0, 1.0, 0.0); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < sides; i++) { double t = step * (double)i; glVertex3d(radius * sin(t), height, radius * cos(t)); } glEnd(); /* 底面 */ glNormal3d(0.0, -1.0, 0.0); glBegin(GL_TRIANGLE_FAN); for (i = sides; --i >= 0;) { double t = step * (double)i; glVertex3d(radius * sin(t), 0.0, radius * cos(t)); } glEnd(); /* 側面 */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= sides; i++) { double t = step * (double)i; double x = sin(t); double z = cos(t); glNormal3d(x, 0.0, z); glVertex3f(radius * x, height, radius * z); glVertex3f(radius * x, 0.0, radius * z); } glEnd(); } // 引用おわり void link(pt p, pt q) { double radius = .5; float x = q.x - p.x; float y = q.y - p.y; float z = q.z - p.z; double dist = sqrt(x*x + y*y + z*z); float rad = acos(y / dist); glPushMatrix(); { glTranslated(p.x, p.y, p.z); #define EQ(a,b) (fabs(b - a) < 1e-3) if (EQ(x, 0.) && EQ(z, 0.)) glRotated(rad*180/M_PI, 1, 0, 0); else glRotated(rad*180/M_PI, z, 0, -x); myCylinder(radius, dist, 20); } glPopMatrix(); } void display() { // カメラの設定 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, perspective(), 1, 1000); gluLookAt(cx, cy, cz, sx, sy, sz, 0, 1, 0); // 描画 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 点の描画 for (int i = 0; i < pts.size(); i++) sphere(pts[i]); // 線の描画 for (int i = 0; i < links.size(); i++){ pt p = pts[ links[i].first ]; pt q = pts[ links[i].second ]; link(p, q); } glutSwapBuffers(); } void reshape(int width, int height) { glViewport(0, 0, width, height); } void keyboard(unsigned char k, int x, int y) { if (k == 'q') exit(0); #define match(keyCode) else if (k == keyCode) match('u') cx += 1; match('j') cx -= 1; match('i') cy += 1; match('k') cy -= 1; match('o') cz += 1; match('l') cz -= 1; match('p') sx += 1; match(';') sx -= 1; match('@') sy += 1; match(':') sy -= 1; match('[') sz += 1; match(']') sz -= 1; #define F "%.1f" match('p') printf(F F F F F F "\n", cx, cy, cz, sx, sy, sz); glutPostRedisplay(); } void loadPoints() { ifstream inFile; float x, y, z; inFile.open(inFileName, ios::in); string in; // 点の読み込み while (getline(inFile, in)){ if (in == "") break; sscanf(in.c_str(), "%f %f %f\n", &x, &y, &z); printf("point (%f, %f, %f)\n", x, y, z); pt p(x, y, z); pts.push_back(p); } printf("complete: load points\n"); // 線の読み込み int src, dst; while (getline(inFile, in)){ sscanf(in.c_str(), "%d %d", &src, &dst); printf("link %d and %d\n", src, dst); links.push_back( pair<int,int>(src, dst) ); } printf("complete: load links\n"); inFile.close(); } void init() { cx = cy = cz = sx = sy = sz = 0; loadPoints(); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glEnable(GL_LINE_SMOOTH); // 照明 float pos0[] = {100, 200, 250, 0}; glLightfv(GL_LIGHT0, GL_POSITION, pos0); glClearColor(1, 1, 1, 0); } int main(int argc, char** argv) { if (argc < 2){ fprintf(stderr, "usage: %s file\n", argv[0]); exit(0); } inFileName = argv[1]; // glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow("shperes"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); init(); glutMainLoop(); return 0; }
入力ファイルは以下
-10 -10 -10 -10 -10 +10 -10 +10 -10 -10 +10 +10 +10 -10 -10 +10 -10 +10 +10 +10 -10 +10 +10 +10 0 1 1 2 2 3 3 4 4 5 5 6 6 7