Friday, March 9, 2012

Bezier Curves and Bezier Surfaces generation with C/C++ in Code::Blocks

Brief Theory of Bezier Curve
In order to draw curvy surface we implement Bezier curve algorithm. In drawing Bezier we first define n+1 control point pk = (xk, yk, zk) with k varying from 0 to n. And the coordinate points are blended to produce following position vectors that define the path of an approximation Bezier polynomial function between p0 and pn.
Beizer Polynomial Function
The Bezier blending functions BEZk,n(u) are the Bernstein polynomials:  BEZk,n(u)=C(n,k)uk(1-u)n-k
Where the C(n, k) are binomial coefficients.
Equivalently, we can define Bezier blending functions with the recursion calculation.
BEZk,n (u) = (1-u) BEZk,n-1(u)+u BEZk-1,n-1(u), n>k≥1
With BEZk,k = uk , and BEZ0,k = (1-u)k.



C Source Code
#include <windows.h>
#include <math.h>
#define ROUND(a) ((int) (a + 0.5)) 
/* set window handle */ 
static HWND sHwnd;
int a; 
void SetWindowHandle(HWND hwnd){
    sHwnd=hwnd;
} 
void setPixel(int x,int y,COLORREF color){
    if(sHwnd==NULL){
        MessageBox(NULL,"sHwnd was not initialized !","Error",MB_OK|MB_ICONERROR);
        exit(0);
    }
    HDC hdc=GetDC(sHwnd);
    SetPixel(hdc,x,y,color);
    ReleaseDC(sHwnd,hdc);
    return; 
// NEVERREACH // 
} 
float Coeff (int k, int n)
{
    int j;
    float coeff= 1.0;
    for (j=n; j>k; j--)            coeff *= j;
    for (j=n-k; j>k; j--)          coeff /= j;
    return(coeff);
} 
float BValue (int k, int n, float u, float coeff)
{
    int j;
    float bvl = coeff;
    for (j=1; j<=k; j++)           bvl *=u;
    for (j=1; j<=n-k; j++)      bvl *= (1-u);
    return (bvl);
} 
void BezierCurve (int Points, int col,...)
{
    va_list Cord;
    int xpt[10], ypt[10], i=0, j, CP;
    float x,y,u,b,c;
    va_start (Cord,col);
    while (((xpt[i]=(va_arg (Cord,int))) >= -1) &&
    ((ypt[i]=(va_arg (Cord,int))) >= -1)
    && ( i<=20))
    i++;
    va_end (Cord);
    CP = (i-1); 
    for (i=0; i<=Points; i++)
    {
        u = (float)i/Points;
        x = 0;
        y = 0;
        for (j=0; j<=CP; j++)
        {
            c  = Coeff(j,CP);
            b  = BValue (j,CP,u,c);
           x += xpt[j]*b;
           y += ypt[j]*b;
        }
        setPixel(ceil(0.5+x),y,col);
    }
} 
/* Window Procedure WndProc */ 
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
    switch(message){
        case WM_PAINT:
            SetWindowHandle(hwnd);
            for(a=0;a<=50;a+=1)
            {
                BezierCurve(2000,RGB(a+100,a,50+a),50,200+a,100+a+a,300+a,150,200+a,200,200+a,-1000);
                BezierCurve(2000,RGB(a+100,a,50+a),200,200+a,300+a+a,300+a,400,200+a,500,200+a,-1000);
                BezierCurve(2000,RGB(a+100,a,50+a),500,200+a,550+a+a,300+a,600,200+a,650,200+a,-1000);
            }
            break;
        case WM_CLOSE: // FAIL THROUGH to call DefWindowProc
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
        break; // FAIL to call DefWindowProc //
    }
    return DefWindowProc(hwnd,message,wParam,lParam);
} 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){
    static TCHAR szAppName[] = TEXT("Curves");
    WNDCLASS wndclass;
    wndclass.style         = CS_HREDRAW|CS_VREDRAW ;
    wndclass.lpfnWndProc   = WndProc ;
    wndclass.cbClsExtra    = 0 ;
    wndclass.cbWndExtra    = 0 ;
    wndclass.hInstance     = hInstance ;
    wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
    wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
    wndclass.lpszMenuName  = NULL ;
    wndclass.lpszClassName = szAppName ;
    // Register the window //
    if(!RegisterClass(&wndclass)){
        MessageBox(NULL,"Registering the class failled","Error",MB_OK|MB_ICONERROR);
        exit(0);
    } 
    // Createw indow //
    HWND hwnd=CreateWindow(szAppName,"Bezier Curve - Programming Techniques",
                WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 CW_USEDEFAULT,
                 NULL,
                 NULL,
                 hInstance,
                 NULL);
    if(!hwnd){
        MessageBox(NULL,"Window Creation Failed!","Error",MB_OK);
        exit(0);
    } 
    // ShowWindow and UpdateWindow //
    ShowWindow(hwnd,iCmdShow);
    UpdateWindow(hwnd);
    // Message Loop //
    MSG msg;
    while(GetMessage(&msg,NULL,0,0)){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    /* return no error to the operating system */
    return 0;
} 

Note: to run this code in your machine with Code::blocks IDE, add a link
library libgdi32.a (it is usually inside MinGW\lib )  in linker setting.   

Output
Beizer Surface

4 comments:

  1. wow that is very impressive!!

    Bibek123, I need your help once again, we were discussing about Fractals in our graphing class, and the teacher assigned us to compile any kind of fractal geometry (like the Mandelbrot Set) using C, so I was wondering, do you have any fractal code running in C? I will really appreciate if you can help me with this, I already search on google for fractals using c but most of the code I downloaded doesn't run on codeblocks, so I was hoping if you have something that I can use to present it to our teacher.

    Once Again, thank you very much for your great programming tutorials and help you provide us.

    ReplyDelete
  2. Thanks a lot for this, helped in more ways than one.

    Mike

    ReplyDelete
  3. Can you please tell me what the param (int Points) of the BezierCurve function specify's exactly?

    ReplyDelete
  4. Here is a specific question,

    If we have a bezier curve (cuadratic), and from the center of the curve we have a circle, how to identify by programming the intersection points ? having and specific radio

    ReplyDelete