とりあえずベジェ曲線をAndroid上で書きます。別にAndroidじゃなくてもいいけど。
最初に実行例を見せるとこんな感じ。とりあえず最初なので3点を与えたときのベジェ曲線。
解説
ベジェ曲線とは何ぞやという方はまずこちら様のサイトを一読。
中学生でもわかるベジェ曲線
何となく頭のイメージをこんな感じで作る。要はt:(1-t)にどんどん内分していけばいいわけですね。塾講師をしていた時を思い出しながらソースに落とします。
ソース
/** * */ package practice.android.net.joki; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.opengl.GLSurfaceView; /** * @author jonki * */ public class GLRendererBezier implements GLSurfaceView.Renderer { private float sw, sh; private final int VERTICES_NUM = 50; private final Point p0 = new Point(-0.f, -0.8f); private final Point p1 = new Point(-0.6f, 0.5f); private final Point p2 = new Point(0.7f, 0.6f); private Point p3 = new Point(); private Point p4 = new Point(); private Point p5 = new Point(); @Override public void onDrawFrame(GL10 gl10) { gl10.glClearColor(0.f, 0.f, 0.f, 1.f); gl10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl10.glMatrixMode(GL10.GL_PROJECTION); gl10.glLoadIdentity(); gl10.glMatrixMode(GL10.GL_MODELVIEW); gl10.glLoadIdentity(); float[] lineVertices = new float[VERTICES_NUM * 2]; //!< 頂点数×座標分(xとyの2つ) for(int i = 0; i < VERTICES_NUM * 2; i += 2) { //!< tは0~1で動くよ float t = (float)(i) / 2.f / (float)VERTICES_NUM; //!< 内分点を計算していく。*演算子をオーバーロードした方がいいが、今回は勉強のため冗長な書き方 //!< p0とp1をt:(1-t)に内分する点 p3.x = t * p1.x + (1.f - t) * p0.x; p3.y = t * p1.y + (1.f - t) * p0.y; //!< p1とp2をt:(1-t)に内分する点 p4.x = t * p2.x + (1.f - t) * p1.x; p4.y = t * p2.y + (1.f - t) * p1.y; //!< p3とp4をt:(1-t)に内分する点 p5.x = t * p4.x + (1.f - t) * p3.x; p5.y = t * p4.y + (1.f - t) * p3.y; //!< xとyを順番に詰め込んでいく lineVertices[i] = p5.x; lineVertices[i+1] = p5.y; } //!< ベジエ曲線の軌跡がわかりやすいよう点で描く //!< 固定座標なので毎回転送するのは無駄なので、アプリではvertex buffer objectは使うべき { FloatBuffer fb = ByteBuffer.allocateDirect(lineVertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(lineVertices); fb.position(0); gl10.glPointSize(4.f); gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl10.glVertexPointer(2, GL10.GL_FLOAT, 0, fb); gl10.glColor4f(1.f, 0.f, 0.f, 1.f); gl10.glDrawArrays(GL10.GL_POINTS, 0, VERTICES_NUM); } //!< 基準となる制御点を描く //!< 固定座標なので毎回転送するのは無駄なので、アプリではvertex buffer objectは使うべき { float[] baseLineVertices = new float[]{ p0.x, p0.y, p1.x, p1.y, p2.x, p2.y }; FloatBuffer fb = ByteBuffer.allocateDirect(baseLineVertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(baseLineVertices); fb.position(0); gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl10.glVertexPointer(2, GL10.GL_FLOAT, 0, fb); gl10.glColor4f(0.f, 0.f, 1.f, 1.f); gl10.glDrawArrays(GL10.GL_LINE_STRIP, 0, 3); } } @Override public void onSurfaceChanged(GL10 gl10, int width, int height) { sw = (float)width; sh = (float)height; aspect = sw / sh; gl10.glViewport(0, 0, width, height); } @Override public void onSurfaceCreated(GL10 gl10, EGLConfig arg1) { } class Point { public Point() { this.x = 0.f; this.y = 0.f; } public Point(float x, float y) { this.x = x; this.y = y; } public float x; public float y; } }