Published
Edited
Jun 23, 2018
2 stars
Insert cell
Insert cell
Insert cell
naive_star(DOM.context2d(500, 500), nridges).canvas
Insert cell
html`
${naive_star(DOM.context2d(200, 200), nridges).canvas}
${fancy_star(DOM.context2d(200, 200), nridges, 40).canvas}
`
Insert cell
html`
${naive_star(DOM.context2d(100, 100), nridges).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 1).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 2).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 5).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 10).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 20).canvas}
${fancy_star(DOM.context2d(100, 100), nridges, 40).canvas}
`
// ${fancy_star(DOM.context2d(100, 100), nridges, 200).canvas} // this one could be expensive.
Insert cell
Insert cell
naive_star = function naive_star (context, nridges) {
const c = context;
const {width:w, height:h} = c.canvas;
const image = c.getImageData(0, 0, w, h);
const radius = Math.min(w, h) * 0.5;
for (let i = 0; i < image.data.length; i += 4) {
const x = ((i/4) % w - w/2) / radius;
const y = (~~((i/4) / w) - h/2) / radius;
image.data[i] = image.data[i+1] = image.data[i+2] =
255 * star_color(x, y, nridges);
image.data[i+3] = 255 - 255 * ((x*x + y*y) > 1);
}
c.putImageData(image, 0, 0);
return c;
}
Insert cell
star_color = function star_color (x, y, nridges) {
const angle = Math.atan2(y,x);
return .5 + .45 * Math.cos(nridges*angle);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/* matlab stuff

j11 = 3.8317059702075123;
j13 = 10.1734681350627221;
q = 0.376637142746001126;
qpi = 1.1832404807198874;

rr_max = 10.4866871749908048;
c = 1.076061515373882;

windowed_jinc = chebfun(@(x) c * besselj(1, qpi*sqrt(x)) .* besselj(1, sqrt(x)*pi) ./ x, [0, rr_max], 'turbo')

*/
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
plastic = {
const p1 = 0.7548776662466927
const p2 = 0.5698402909980532
return function plastic (index) {
return [(p1 * index) % 1 - .5, (p2 * index) % 1 - .5];
}
}
Insert cell
fancy_star = function fancy_star (context, nridges, samples_per_pixel) {
const c = context;
const {width:w, height:h} = c.canvas;
// c.fillRect(0,0,w,h);
const image = c.getImageData(0, 0, w, h);
const image_data = image.data;
const radius = Math.min(w, h) * 0.5;

const scale = 0.190717999557544128;

let sum = 0
const float_image = new Float32Array(w*h);
const samples = new Float32Array((w+6)*(h+6));

// const alpha = new Float32Array(w*h);
// const alpha_samples = new Float32Array((w+6)*(h+6));
for (let s = 0; s < samples_per_pixel; s++) {
const [offsetx, offsety] = plastic(s);
const offset_weights = [];
for (let j = 0; j <= 6; j++) {
for (let i = 0; i <= 6; i++) {
const x = i - 3 + offsetx;
const y = j - 3 + offsety;
sum += offset_weights[i + 7*j] = chebeval(
windowed_jinc_coeffs,
(x*x + y*y) * scale - 1);
}
}
// Note: re-use same samples array for each set of samples.
for (let j = 0; j < h + 6; j++) {
for (let i = 0; i < w + 6; i++) {
const x = i - 3 + offsetx - w/2;
const y = j - 3 + offsety - h/2;
// TODO: make sure offsets are consistent direction w/ above
samples[i + (w+6)*j] = inverse_gamma(star_color(x, y, nridges));
// alpha_samples[i + (w+6)*j] = ((x*x + y*y) < radius*radius);
}
}
// convolve the array with the offset weights
for (let j = 0; j < h; j++) {
for (let i = 0; i < w; i++) {
for (let jj = 0; jj <= 6; jj++) {
for (let ii = 0; ii <= 6; ii++) {
float_image[i + j*w] +=
samples[(i + ii) + (j + jj)*(w+6)]*offset_weights[ii + jj*7];
// alpha[i + j*w] +=
// alpha_samples[(i + ii) + (j + jj)*(w+6)]*offset_weights[ii + jj*7];
}
}
}
}
}
// normalize float image, apply to canvas
const sum_inv = 1/sum;
for (let j = 0; j < h; j++) {
for (let i = 0; i < w; i++) {
const x = i - w/2;
const y = j - h/2;
const ii = i + j*w;
image_data[4*ii] = image_data[4*ii+1] = image_data[4*ii+2] = 255 * gamma(float_image[ii] * sum_inv);
image_data[4*ii + 3] = 255 * ((x*x + y*y) < radius*radius);
}
}
c.putImageData(image, 0, 0);
return c;
}
Insert cell
Insert cell
four_times_nearest_neighbor = function four_times(context, x0, y0, width, height) {
const c = context;
const image = c.getImageData(x0, y0, width, height);
const image4x = new ImageData(width*4, height*4);
for (let i = 0; i < image.data.length; i+= 4) {
const x = (i/4) % width
const y = (~~((i/4) / height)
}
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more