1. Quick And Simple Bezier Curve Drawing or other
- Posted by begin Jun 16, 2018
- 1572 views
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.
2. Re: Quick And Simple Bezier Curve Drawing or other
- Posted by begin Jul 02, 2018
- 1144 views
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() */