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