Bitmap/Bézier curves/Quadratic

Revision as of 12:26, 6 December 2008 by rosettacode>Blue Prawn (added C)

Using the data storage type defined on this page for raster images, and the draw_line function defined in this one, draw a quadratic bezier curves (definition on Wikipedia).

Task
Bitmap/Bézier curves/Quadratic
You are encouraged to solve this task according to the task description, using any language you may know.


C

<C>#include <math.h>

/* number of segments for the curve */

  1. define N_SEG 20
  1. define plot(x, y) put_pixel_clip(img, x, y, r, g, b)
  2. define line(x0,y0,x1,y1) draw_line(img, x0,y0,x1,y1, r,g,b)

void quad_bezier(

       image img,
       unsigned int x1, unsigned int y1,
       unsigned int x2, unsigned int y2,
       unsigned int x3, unsigned int y3,
       color_component r,
       color_component g,
       color_component b )

{

   unsigned int i;
   double pts[N_SEG+1][2];
   for (i=0; i <= N_SEG; ++i)
   {
       double t = (double)i / (double)N_SEG;
       double a = pow((1.0 - t), 2.0);
       double b = 2.0 * t * (1.0 - t);
       double c = pow(t, 2.0);
       double x = a * x1 + b * x2 + c * x3;
       double y = a * y1 + b * y2 + c * y3;
       pts[i][0] = x;
       pts[i][1] = y;
   }

  1. if 0
   /* draw only points */
   for (i=0; i <= N_SEG; ++i)
   {
       plot( pts[i][0],
             pts[i][1] );
   }
  1. else
   /* draw segments */
   for (i=0; i < N_SEG; ++i)
   {
       int j = i + 1;
       line( pts[i][0], pts[i][1],
             pts[j][0], pts[j][1] );
   }
  1. endif

}

  1. undef plot
  2. undef line</C>


OCaml

<ocaml>let quad_bezier ~img ~color

       ~p1:(_x1, _y1)
       ~p2:(_x2, _y2)
       ~p3:(_x3, _y3) =
 let (x1, y1, x2, y2, x3, y3) =
   (float _x1, float _y1, float _x2, float _y2, float _x3, float _y3)
 in
 let bz t =
   let a = (1.0 -. t) ** 2.0
   and b = 2.0 *. t *. (1.0 -. t)
   and c = t ** 2.0
   in
   let x = a *. x1 +. b *. x2 +. c *. x3
   and y = a *. y1 +. b *. y2 +. c *. y3
   in
   (int_of_float x, int_of_float y)
 in
 let rec loop _t acc =
   if _t > 20 then acc else
   begin
     let t = (float _t) /. 20.0 in
     let x, y = bz t in
     loop (succ _t) ((x,y)::acc)
   end
 in
 let pts = loop 0 [] in
 (*
 (* draw only points *)
 List.iter (fun (x, y) -> put_pixel img color x y) pts;
 *)
 (* draw segments *)
 let line = draw_line ~img ~color in
 let by_pair li f =
   let rec aux prev = function
     | [] -> ()
     | x::xs ->
         f prev x;
         aux x xs
   in
   aux (List.hd li) (List.tl li)
 in
 by_pair pts (fun p0 p1 -> line ~p0 ~p1);
</ocaml>