質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • C++

    4522questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

C++でベジェ曲線を描画したいです

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 2,794

前提・実現したいこと

C++のGLUTを使って3次ベジェ曲線を描画したいです。
割と近いところまで行ったのですがこの先どうしたらいいのかわかりません。

発生している問題・エラーメッセージ

自分で書いたのは //制御点を結ぶ線分の描画 からvoidの前までのみなので、そこ以外は間違っていないはずです。
コンパイルは通るのですが、想定と少し違った図形が描画されてしまいます。

クリックで点を4つ打つと、それらを結ぶ"線分"と、それらの内側にベジェ曲線が表示されてほしいのですが、
どうやら4つの点を結んだ四角形になってしまうようです。
GL_LINE_STRIPにしているので、こうならないつもりだったのですが…

ちなみに、点の数が3n+1になった時に曲線を描くようにしてあり、図の例は点4つの場合ですが、7個以上の場合も曲線は正しく描画できています。(ただ謎の四角形は描画され続ける)

イメージ説明

該当のソースコード

#include <cstdlib>
#include <cmath>
#include <vector>
#include <GLUT/glut.h>

// 2次元ベクトルを扱うためのクラス
class Vector2d {
public:
  double x, y;
  Vector2d() { x = y = 0; }
  Vector2d(double _x, double _y) { x = _x; y = _y; }
  void set(double _x, double _y) { x = _x; y = _y; }

  // 長さを1に正規化する
  void normalize() {
    double len = length();
    x /= len; y /= len;
  }

  // 長さを返す
  double length() { return sqrt(x * x + y * y); }

  // s倍する
  void scale(const double s) { x *= s; y *= s; }

  // 加算の定義
  Vector2d operator+(Vector2d v) { return Vector2d(x + v.x, y + v.y); }

  // 減算の定義
  Vector2d operator-(Vector2d v) { return Vector2d(x - v.x, y - v.y); }

  // 内積の定義
  double operator*(Vector2d v) { return x * v.x + y* v.y; }

  // 代入演算の定義
  Vector2d& operator=(const Vector2d& v){ x = v.x; y = v.y; return (*this); }

  // 加算代入の定義
  Vector2d& operator+=(const Vector2d& v) { x += v.x; y += v.y; return (*this); }

  // 減算代入の定義
  Vector2d& operator-=(const Vector2d& v) { x -= v.x; y -= v.y; return (*this); }

  // 値を出力する
  void print() { printf("Vector2d(%f %f)\n", x, y); }
};

// マイナスの符号の付いたベクトルを扱えるようにするための定義 例:b=(-a); のように記述できる
Vector2d operator-( const Vector2d& v ) { return( Vector2d( -v.x, -v.y ) ); }

// ベクトルと実数の積を扱えるようにするための定義 例: c=5*a+2*b; c=b*3; のように記述できる
Vector2d operator*( const double& k, const Vector2d& v ) { return( Vector2d( k*v.x, k*v.y ) );}
Vector2d operator*( const Vector2d& v, const double& k ) { return( Vector2d( v.x*k, v.y*k ) );}

// ベクトルを実数で割る操作を扱えるようにするための定義 例: c=a/2.3; のように記述できる
Vector2d operator/( const Vector2d& v, const double& k ) { return( Vector2d( v.x/k, v.y/k ) );}

// ================================================================================================

std::vector<Vector2d> g_ControlPoints; // 制御点を格納する

// 表示部分をこの関数で記入
void display(void) {
  glClearColor (1.0, 1.0, 1.0, 1.0);  // 消去色指定
  glClear (GL_COLOR_BUFFER_BIT );     // 画面消去

  // 制御点の描画
  glPointSize(5);
  glColor3d(0.0, 0.0, 0.0);
  glBegin(GL_POINTS);
  for(unsigned int i = 0; i < g_ControlPoints.size(); i++) {
    glVertex2d(g_ControlPoints[i].x, g_ControlPoints[i].y);
  }
  glEnd();

  // 制御点を結ぶ線分の描画
  glColor3d(1.0, 0.0, 0.0);
  glLineWidth(1);
  glBegin(GL_LINE_STRIP);
  for(unsigned int i = 0; i < g_ControlPoints.size(); i++) {
    glVertex2d(g_ControlPoints[i].x, g_ControlPoints[i].y);
    if(i%3==0 && i!=0) {
      for(float t=0; t<=1; t+=0.01) {
        glVertex2d((1-t)*(1-t)*(1-t)*g_ControlPoints[i-3].x + 3*(1-t)*(1-t)*t*g_ControlPoints[i-2].x + 3*(1-t)*t*t*g_ControlPoints[i-1].x + t*t*t*g_ControlPoints[i].x, (1-t)*(1-t)*(1-t)*g_ControlPoints[i-3].y + 3*(1-t)*(1-t)*t*g_ControlPoints[i-2].y + 3*(1-t)*t*t*g_ControlPoints[i-1].y + t*t*t*g_ControlPoints[i].y);
      }
    }
  }
  glEnd();
  glutSwapBuffers();
}

void resizeWindow(int w, int h) {
  h = (h == 0) ? 1 : h;
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // ウィンドウ内の座標系設定
  // マウスクリックの座標と描画座標が一致するような正投影
  glOrtho(0, w, h, 0, -10, 10);

  glMatrixMode(GL_MODELVIEW);
}

// キーボードイベント処理
void keyboard(unsigned char key, int x, int y) {
  switch (key) {
  case 'q':
  case 'Q':
  case '\033':
    exit(0);  /* '\033' は ESC の ASCII コード */
  default:
    break;
  }
  glutPostRedisplay();
}

// マウスイベント処理
void mouse(int button, int state, int x, int y) {
  if(state == GLUT_DOWN) {
    switch (button) {
    case GLUT_LEFT_BUTTON:
      // クリックした位置に制御点を追加
      g_ControlPoints.push_back(Vector2d(x, y));
      break;
    case GLUT_MIDDLE_BUTTON:
      break;
    case GLUT_RIGHT_BUTTON:
      // 末尾の制御点の削除
      if(!g_ControlPoints.empty()) {
        g_ControlPoints.pop_back();
      }
      break;
    default:
      break;
    }
    glutPostRedisplay(); // 再描画
  }
}

// メインプログラム
int main (int argc, char *argv[]) {
  glutInit(&argc, argv);          // ライブラリの初期化
  glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE); // 描画モードの指定
  glutInitWindowSize(800 , 800);  // ウィンドウサイズを指定
  glutCreateWindow(argv[0]);      // ウィンドウを作成
  glutDisplayFunc(display);       // 表示関数を指定
  glutReshapeFunc(resizeWindow);  // ウィンドウサイズが変更されたときの関数を指定
  glutKeyboardFunc(keyboard);     // キーボードイベント処理関数を指定
  glutMouseFunc(mouse);           // マウスイベント処理関数を指定
  glutMainLoop();                 // イベント待ち
  return 0;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

こんにちは。

i=0~3の間、下記で4点描画しますね。

glVertex2d(g_ControlPoints[i].x, g_ControlPoints[i].y);

そして、i=3の時、それに続けてfor(float t=0; ...)の中のglVertex2d()を呼び出しますが、
これはt=0の時g_ControlPoints[0]に点を打つと思います。
結果、g_ControlPoints[3]→g_ControlPoints[0]の線が引かれるのではないでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/01 15:49

    言われてみると確かにそうっぽいですね… 皆目検討もつかないので、具体的にどう直せばいいのかも教えてくれると嬉しいです。

    キャンセル

  • 2016/11/01 16:05

    g_ControlPointsを結ぶ曲線とベジェ曲線を分けて、それぞれ別のglBegin()~forループ~glEnd()にするのが一番てっとり早いと思います。

    キャンセル

  • 2016/11/01 18:26

    ありがとうございます、やってみます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C++

    4522questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。