1. Quick And Simple Bezier Curve Drawing or other

for my CEEMD statistics i needed a Bezier function. i hope somebody else can use it.

-- Graphics Gems 5, Edited by Alan W. Paeth 
-- http://www.amazon.com/Graphics-Version-Morgan-Kaufmann-Computer/dp/0125434553/ 
-- Chapter IV.8  -  Quick And Simple Bezier Curve Drawing 
-- By Robert D. Miller 
 
-- Setup Bezier coefficient array once for each control polygon 
function BezierForm2D(integer NumCtlPoints, object px, object py) 
  atom  choose 
  integer k, n = NumCtlPoints-1 
  object cx = repeat(0.0, NumCtlPoints) 
  object cy = repeat(0.0, NumCtlPoints) 
  for k = 0 to n do 
    if k = 0 then  
      choose = 1.0 
    elsif k = 1 then  
      choose = n 
    else   
      choose *= (n-k+1.0)/ (k*1.0) 
    end if     
    cx[k+1] = px[k+1] * choose 
    cy[k+1] = py[k+1] * choose 
  end for 
  return {cx, cy} 
end function 
 
-- Return ptx,pty, t <= 0 <= 1, t specifies the point on the curve you want to get. t has to be between 0.0 and 1.0. 
-- given the number of Points in control polygon, 
-- BezierForm2D must be called once for any given control polygon 
function BezierCurve2D(integer NumCtlPoints, object cx, object cy, atom t) 
  integer k, n 
  atom t1, tt, u, ptx, pty 
  object bbx = repeat(0, NumCtlPoints) 
  object bby = repeat(0, NumCtlPoints) 
  n = NumCtlPoints-1 
  u = t 
  bbx[1] = cx[1] 
  bby[1] = cy[1] 
  for k = 2 to NumCtlPoints do 
    bbx[k] = cx[k] * u 
    bby[k] = cy[k] * u 
    u *= t 
  end for 
  ptx = bbx[NumCtlPoints] 
  pty = bby[NumCtlPoints] 
  t1    = 1-t 
  tt    = t1 
  k     = n 
  while k >= 0 do 
    ptx += (bbx[k+1] * tt) 
    pty += (bby[k+1] * tt) 
    tt *= t1 
    k -= 1 
  end while 
  return {ptx, pty} 
end function 
 
function CalcBezierCurve(atom x1, atom y1, atom x2, atom y2, atom x3, atom y3, atom x4, atom y4, atom stepSize) 
  atom ptx, pty, oldPtx, oldPty 
  integer k 
  object pnx = repeat(0, 4), pny = repeat(0.0, 4) 
  pnx[1] = x1   pny[1] = y1              --SCREEN COORDINATES 
  pnx[2] = x2   pny[2] = y2 
  pnx[3] = x3   pny[3] = y3 
  pnx[4] = x4   pny[4] = y4 
   
  object bcx = repeat(0, 4), bcy = repeat(0, 4) 
  {bcx, bcy} = BezierForm2D(4, pnx, pny) 
  for k = 0 to stepSize do 
    {ptx, pty} = BezierCurve2D(4, bcx, bcy, k/(stepSize*1.0)) 
  ?"--------------" 
      ?ptx 
      ?pty 
  ?"--------------" 
    if k = 0 then 
      oldPtx = ptx 
      oldPty = pty 
    else 
      -- do something with oldPtx, oldPty, ptx, pty maybe - such as draw a line 
      oldPtx = ptx 
      oldPty = pty 
    end if 
  end for 
  return 1 
end function 
 
?CalcBezierCurve(100,300, 300,100, 500,600, 700,300, 50) 
 
maybe_any_key() 

should you be able to streamline it or make it more phix like please share.

richard

EDIT

You control the interpolation with the stepSize. If you use a small stepSize like 5, you get only 6 points (including start and end point of your screen coordinates) and if you draw lines between the points, it is most likely not a very nice curve. If you use a higher stepSize like 50, you get 51 interpolated points... and your curve looks smoother. the functions allows you to have points that go backward or close the Bezier.

new topic     » topic index » view message » categorize

2. Re: Quick And Simple Bezier Curve Drawing or other

here another spline i use for timelines.

namespace QSPLINE 
 
 
ifdef BITS32 then 
  constant FAIL = #3FFFFFFF 
elsedef 
  constant FAIL = #3FFFFFFFFFFFFFFF 
end ifdef 
 
 
sequence SetUpSplineDerived = {} 
atom LOWEST_X = FAIL 
 
--Routine returns the table of 2nd derivatives needed for the cubic spline 
--interpolation routine spline(). x[*] and y[*] are the input vectors. 
--It is assumed that the x values are ordered but not necessarily equally spaced. 
--That is, xin[0] < xin[1] < xin[2] < ... xin[n-1]. 
public function SetUpSpline(sequence x, sequence y) 
  atom tmp, dx, dx0, dx1, h 
  integer n = length(x) 
  if n != length(y) then SetUpSplineDerived = {} return false end if 
  if n <= 1 then SetUpSplineDerived = {} return false end if 
  integer im1, ip1, n1 = n - 1  
  sequence g = repeat(0.0, n) 
  sequence temp = repeat(0.0, n1) 
  temp = repeat(0.0, n1) 
  SetUpSplineDerived = {} 
  g[1] = 0.0   
  temp[1] = 0.0 
  for i = 2 to n1 do 
    ip1 = i+1 
    im1 = i-1 
    dx = x[i] - x[im1] 
    dx0 = x[ip1] - x[i] 
    dx1 = x[ip1] - x[im1] 
    if dx <= 0.0 or dx0 <= 0.0 or dx1 <= 0.0 then 
      SetUpSplineDerived = {} 
      return false 
    end if 
    tmp = dx/dx1 
    h = 2.0 + tmp*g[im1] 
    g[i] = (tmp - 1)/h 
    temp[i] = (y[ip1]-y[i])/dx0 - (y[i] -y[im1])/dx 
    temp[i] = (temp[i]*6.0/dx1 - tmp*temp[im1])/h 
  end for 
  g[n1] = 0.0 
  for j = n-1 to 1 by -1 do 
    g[j] = temp[j] + g[j] * g[j+1] 
  end for 
  LOWEST_X = x[1] 
  SetUpSplineDerived = g 
  return true 
end function 
 
--This routine returns the cubic spline interpolation at the point x0. 
--g[*] is the table of 2nd derivatives needed for the cubic spline formula 
--(see the spline0() function). 
--x[*] and y[*] are the input vectors of x-y data. 
--All of the vectors are of length n. 
--It is assumed that the x values are ordered but not necessarily equally spaced. 
--That is, xin[0] < xin[1] < xin[2] < ... xin[n-1]. 
public function Spliner(atom  x0, sequence x, sequence y) 
  if SetUpSplineDerived={} then return FAIL end if 
  atom tmp, dx, xi, xi1, xi1d, xid, y0 
  integer i, top, bot, n = length(x) 
  bot = 0 
  top = n 
  while (top-bot) > 1 do -- find location in table through bisection 
    i = shift_bits((top+bot), 1) 
    if x[i] <= x0 then 
      bot = i 
    else  
      top = i 
    end if 
  end while 
  dx = x[top]-x[bot] 
  xi1 = x[top]-x0 
  xi = x0-x[bot] 
  xi1d = xi1/dx 
  xid = xi/dx 
  tmp = (SetUpSplineDerived[bot]*(xi1d*xi1-dx)*xi1 + SetUpSplineDerived[top]*(xid*xi-dx)*xi) / 6.0 
  y0 = tmp + y[bot]*xi1d + y[top]*xid 
  return y0 
end function 
 
public function spline_from_to(sequence x, sequence y, atom from_x1, atom to_x2, atom step_by=1) 
  if SetUpSplineDerived={} then return {} end if 
  if FAIL >= from_x1 and to_x2 <= from_x1 then return {} end if 
  if step_by <= 0 then return {} end if 
  sequence output={} 
  atom counter = from_x1 
  while counter <= to_x2 do 
    output &= Spliner(counter,x,y) -- interpolate with spline 
    counter += step_by 
  end while 
  return output 
end function 
 
/* 

procedure splinetest() 
  integer i, k, n=7, nout=19 
  atom delta, delta3, truth 
  atom x0, y0, twopi_ = PI*2 
  sequence x, y, deriv 
  y = repeat(0.0, n) 
  x = repeat(0.0, n) 
  delta = twopi_/(n-1) 
  delta3 = delta/3 
  -- define  unequally spaced x values 
  x[1]=delta*0  x[2]=delta/3 
  x[3]=delta    x[4]=delta*2.33333333 
  x[5]=delta*3  x[6]=delta*4.33333333 
  x[7]=delta*6 
  -- generate one cycle of a sinusoid; with nonequally spaced samples 
  for i = 1 to n do 
    y[i]=sin(x[i]) 
  end for 
  printf(1,"           interpolated         original     truth:\n") 
  printf(1,"    x           y         k       y[k]       sin(x)\n\n") 
  k=1 
   
  bool worked = SetUpSpline(x, y)   -- find 2nd derivative of data 
  for i = 0 to nout-1 do 
    truth = sin(twopi_*i/(nout-1)) 
    x0 = i*delta3 
    y0 = Spliner(x0, x, y) -- interpolate with spline 
    if  abs(x0-x[k]) < 10e-6 then 
       printf(1,"%9.6f   ", x0) 
       printf(1,"%9.6f    ", y0) 
       printf(1,"%2d    ", k) 
       printf(1,"%9.6f   ", y[k]) 
       printf(1,"%9.6f\n", truth) 
       k += 1 
    else   
      printf(1,"%9.6f   ", x0) 
      printf(1,"%9.6f                      ", y0) 
      printf(1,"%9.6f\n", truth) 
    end if 
  end for 
end procedure 
 
splinetest() 
maybe_any_key() 
*/ 
 
/* 

sequence x={1,10,20,30,40,50} 
sequence y={0, 100, 50, 100, 50, 10} 
bool worked = SetUpSpline(x, y) 
?spline_from_to(x, y, 1, 50, 1) 
maybe_any_key() 
*/ 
new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu