B-spline
- Task
Generate a B-spline curve with a list of 12 points and plot or save image.
Coordinates of control points:
start=171,171 1 185,111, 2 202,109, 3 202,189 4 328,160 5 208,254 6 241,330 7 164,252 8 69,278 9 139,208 10 72,148 end=168,172
Rules!!!!
Do not use third party libraries or functions
- See also
Julia
Choose BSpline D of 2, ie degree 1. <lang julia>using Graphics, Plots
Point(t::Tuple) = Vec2(Float64(t[1]), Float64(t[2])) const controlpoints = Point.([(171, 171), (185, 111), (202, 109), (202, 189), (328, 160),
(208, 254), (241, 330), (164,252), (69, 278), (139, 208), (72, 148), (168, 172)])
plt = plot(map(a -> a.x, controlpoints), map(a -> a.y, controlpoints)) savefig(plt, "BSplineplot.png")</lang>
Mathematica/Wolfram Language
<lang Mathematica>Graphics[
BSplineCurve[{{171, 171}, {185, 111}, {202, 109}, {202, 189}, {328, 160}, {208, 254}, {241, 330}, {164, 252}, {69, 278}, {139, 208}, {72, 148}, {168, 172}}, SplineClosed -> True, SplineDegree -> 2]]</lang>
- Output:
Outputs a graphical representation of a B-spline.
Phix
You can run this online here.
-- -- demo\rosetta\B-spline.exw -- ========================= -- -- Use +/- to change the order between k = 1 and k = 4. -- with javascript_semantics include pGUI.e include IupGraph.e constant ctrl_points = {{171, 171}, {185, 111}, {202, 109}, {202, 189}, {328, 160}, {208, 254}, {241, 330}, {164, 252}, { 69, 278}, {139, 208}, { 72, 148}, {168, 172}} integer k = 2, n sequence t function w(integer i, k, x) // B-spline helper function return iff(t[i+k]!=t[i] ? (x-t[i])/(t[i+k]-t[i]) : 0 ) end function function b(integer i, k, x) // B-spline function if k==1 then return iff(t[i]<=x and x<t[i+1] ? 1 : 0) end if return w(i,k-1,x)*b(i,k-1,x) + (1-w(i+1,k-1,x))*b(i+1,k-1,x) end function function b_spline(Ihandle graph) n = length(ctrl_points) t = tagset(n+1+k) // use a uniform knot vector, delta = 1 assert(k<=n+1 and k>=1,"k (= %d) cannot be more than %d or less than 1.",{k,n+1}) sequence px = {}, py = {} for x=t[k] to t[n+1] do atom sumX = 0, sumY = 0 for i=1 to n do atom f = b(i,k,x) sumX += f*ctrl_points[i][1] sumY += f*ctrl_points[i][2] end for px &= round(sumX) py &= round(sumY) end for integer xtick = 40, ytick = 40, xmin = trunc(min(px)/xtick)*xtick, xmax = ceil(max(px)/xtick)*xtick, ymin = trunc(min(py)/ytick)*ytick, ymax = ceil(max(py)/ytick)*ytick IupSetInt(graph,"XTICK",xtick) IupSetInt(graph,"XMIN",xmin) IupSetInt(graph,"XMAX",xmax) IupSetInt(graph,"YTICK",ytick) IupSetInt(graph,"YMIN",ymin) IupSetInt(graph,"YMAX",ymax) sequence graphdata = {{px,py,CD_BLUE}} return graphdata end function procedure set_title(Ihandle dlg) IupSetStrAttribute(dlg, "TITLE", "B-spline curve (order k = %d)",{k}) end procedure function key_cb(Ihandle dlg, atom c) if c=K_ESC then return IUP_CLOSE end if if c='+' then k = min(k+1,4) end if if c='-' then k = max(k-1,1) end if set_title(dlg) IupRedraw(dlg) return IUP_IGNORE end function procedure main() IupOpen() Ihandle graph = IupGraph(b_spline,`RASTERSIZE=600x600`) Ihandle dlg = IupDialog(graph) IupSetCallback(dlg, "KEY_CB", Icallback("key_cb")) set_title(dlg) IupShow(dlg) if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()
Wren
In the absence of any clarification on what to use (see Talk page), the following uses a degree of 3 (i.e order k = 4) and a uniform knot vector from 1 to 16 (as there are 12 control points) with a delta of 1.
If one uses a value for k of 1, then the script will simply plot the control points as in the Julia example. <lang ecmascript>import "dome" for Window, Process import "graphics" for Canvas, Color
class BSpline {
construct new(width, height, cpoints, k) { Window.resize(width, height) Canvas.resize(width, height) Window.title = "B-spline curve" _p = cpoints _n = cpoints.count - 1 _k = k _t = (1.._n + 1 + k).toList // use a uniform knot vector, delta = 1 }
// B-spline helper function w(i, k, x) { (_t[i+k] != _t[i]) ? (x - _t[i]) / (_t[i+k] - _t[i]) : 0 } // B-spline function b(i, k, x) { if (k == 1) return (_t[i] <= x && x < _t[i + 1]) ? 1 : 0 return w(i, k-1, x) * b(i, k-1, x) + (1 - w(i+1, k-1, x)) * b(i+1, k-1, x) }
// B-spline points p() { var bpoints = [] for (x in _t[_k-1]..._t[_n + 1]) { var sumX = 0 var sumY = 0 for (i in 0.._n) { var f = b(i, _k, x) sumX = sumX + f * _p[i][0] sumY = sumY + f * _p[i][1] } bpoints.add([sumX.round, sumY.round]) } return bpoints }
init() { if (_k > _n + 1 || _k < 1) { System.print("k (= %(_k)) can't be more than %(_n+1) or less than 1.") Process.exit() } var bpoints = p() // plot the curve for (i in 1...bpoints.count) { Canvas.line(bpoints[i-1][0], bpoints[i-1][1], bpoints[i][0], bpoints[i][1], Color.white) } }
update() {}
draw(alpha) {}
}
var cpoints = [
[171, 171], [185, 111], [202, 109], [202, 189], [328, 160], [208, 254], [241, 330], [164, 252], [ 69, 278], [139, 208], [ 72, 148], [168, 172]
] var k = 4 // polynomial degree is one less than this i.e. cubic var Game = BSpline.new(400, 400, cpoints, k)</lang>