/*
key 'q' quit
key 'c' clear screen
key 'e' erase curve
鼠标左键点击空白处,添加点
鼠标左键点击点,选中点,此时拖动鼠标,可移动所选中的点
鼠标右键点击点,删除点
*/
#include<cstdlib>
#include<stdio.h>
#include <gl/glut.h>
void keyboard( unsigned char key , int x, int y );
#define MAX_CPTS 1000 // 控制点最大数目
const int MESH = 50; // 切分段数
float bPoints[MESH][3];
GLfloat cpts[MAX_CPTS][3];
GLfloat cpts2[MAX_CPTS][3]; // store points when calculate Bezier
bool trackingMouse = false;
int index = -1;
int ncpts = 0 ;
static int width = 500 , height = 500; // 绘制窗口的宽度和高度
void calPoint( float t ) // t is the parameter in Bezier Curve
{
for( int i = 0 ; i<ncpts ; i++ )
for( int j = 0 ; j<3 ; j++ )
cpts2[i][j] = cpts[i][j];
for( int i = 0 ; i<ncpts-1 ; i++ ) // recur times
for( int j = 0 ; j<ncpts-1-i ; j++ )
for( int k =0 ; k<2 ; k++ ) // coordinate z is not calculated
cpts2[j][k] = (1-t)*cpts2[j][k] + t*cpts2[j+1][k] ;
}
void drawCurves()
{
if( ncpts==1 ) return ;
float interval = 1/(float)MESH;
float t = 0;
bPoints[0][0] = cpts[0][0];
bPoints[0][1] = cpts[0][1];
bPoints[MESH-1][0] = cpts[ncpts-1][0];
bPoints[MESH-1][1] = cpts[ncpts-1][1];
for( int k=1 ; k<MESH-1 ; k++ )
{
t+=interval;
calPoint( t );
for( int i=0 ; i<2 ; i++ )
bPoints[k][i] = cpts2[0][i] ;
}
glColor3f(1.0 , 0.0 , 0.0 ); // chang color to red
glBegin( GL_LINE_STRIP );
for( int i=0 ; i<MESH ; i++ )
glVertex3fv( bPoints[i] );
glEnd();
}
void drawPoints()
{
glColor3f( 0.0 , 0.0 , 0.0); // change color to black
glBegin(GL_POINTS);
for( int i=0 ; i<ncpts ; i++)
{
glVertex3fv(cpts[i]);
}
glEnd();
glColor3f( 0.0 , 1.0 , 1.0 ); // change color to yellow
glBegin(GL_LINE_STRIP);
for( int i=0 ; i<ncpts ; i++ )
glVertex3fv( cpts[i] );
glEnd();
}
void showList()
{
printf("========\n");
for( int i=0 ; i<ncpts ; i++ )
{
printf("\t\t\t%f %f\n" , cpts[i][0] , cpts[i][1] );
}
printf("========\n");
}
void drawElements()
{
drawPoints();
drawCurves();
showList();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
}
int check( float x , float y )
{
// if point(x , y ) is close to any point in array 'cpts' , return the index , else return -1
for( int i=0 ; i<ncpts ; i++ )
{
if( (cpts[i][0]-x)*(cpts[i][0]-x) + (cpts[i][1]-y)*(cpts[i][1]-y) <=0.0003 )
return i;
}
return -1;
}
void addPoint( float wx , float wy )
{
// 判断是否还可以定义更多的控制点
if( ncpts == MAX_CPTS ) return ;
// 储存控制点的位置
cpts[ncpts][0] = wx ;
cpts[ncpts][1] = wy ;
cpts[ncpts][2] = 0.0 ;
ncpts++;
glutPostRedisplay();
drawElements();
glFlush();
}
void action_LeftDown( float wx , float wy)
{
index = check( wx , wy );
if( index>-1 )
{
trackingMouse = true;
printf("start tracking.\n");
}
else
addPoint( wx , wy );
}
void action_LeftUp()
{
trackingMouse = false;
}
void action_DeletePoint(float wx , float wy)
{
printf( "delete point ");
index = check(wx , wy );
if( index==-1 )
{
return ;
}
else // delete the point chosen , and move the rest points forward
{
for( int i=index+1 , j = index ; i<ncpts ; i++ , j++ )
{
for( int k=0 ; k<2 ; k++) // move next point i to point i-1
cpts[j][k]=cpts[i][k];
}
ncpts--;
}
showList();
glutPostRedisplay();
drawElements();
glFlush();
}
void mouse( int button , int state , int x , int y )
{
float wx , wy ;
// 把鼠标的位置逆向变换到世界坐标系
wx = (2.0*x)/ (float)(width-1) - 1.0 ;
wy = (2.0 *(height -1-y) ) / (float)(height-1) -1.0;
if( button==GLUT_RIGHT_BUTTON && state ==GLUT_DOWN )
{
action_DeletePoint(wx , wy );
showList();
}
if( button==GLUT_LEFT_BUTTON )
{
switch( state )
{
case GLUT_DOWN:
action_LeftDown(wx , wy );
break;
case GLUT_UP:
action_LeftUp();
showList();
break;
}
}
}
void mouseMotion( int x , int y)
{
float wx = (2.0*x)/ (float)(width-1) - 1.0 ;
float wy = (2.0 *(height -1-y) ) / (float)(height-1) -1.0;
cpts[index][0] = wx ;
cpts[index][1] = wy ;
glutPostRedisplay();
drawElements();
glFlush();
}
void keyboard(unsigned char key , int x , int y)
{
switch(key)
{
case 'q':case'Q':
exit(0);
break;
case 'c':case'C':
ncpts = 0 ;
glutPostRedisplay();
glFlush();
break;
case'e':case'E':
glutPostRedisplay();
break;
}
}
void reshape( int w , int h)
{
width = w ;
height = h ;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0 , 1.0 , -1.0 , 1.0 , -1.0 , 1.0 );
glMatrixMode(GL_MODELVIEW);
glViewport(0 , 0 , w , h );
}
int main(int argc , char **argv)
{
glutInit(&argc , argv);
glutInitDisplayMode( GLUT_RGB );
glutInitWindowSize(width , height);
glutCreateWindow("Bezier curves");
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutReshapeFunc(reshape);
glClearColor(1.0 , 1.0 , 1.0 , 1.0 );
glColor3f(0.0 , 0.0 , 0.0 );
glPointSize(5.0);
glutMainLoop();
}