(function() { // noprotect; /* BEGIN */ var CX, CY, R, canvas_left, canvas_right, cx_tool, cy_tool, df, dist, dist_tool, edit, hcl_linear_rainbow, height, pixel_x, pixel_y, r_tool, redraw, side, svg, tool, width; hcl_linear_rainbow = function() { var chroma_range, domain, hue_range, luminance_range, scale; domain = [0, 1]; hue_range = [340, 340 - 480]; chroma_range = [0, 40]; luminance_range = [0, 100]; scale = function(x) { var c, ext, h, l, xn; ext = domain[1] - domain[0]; xn = (x - domain[0]) / ext; h = hue_range[0] + (hue_range[1] - hue_range[0]) * xn; c = chroma_range[0] + (chroma_range[1] - chroma_range[0]) * (1 - Math.pow(1 - 2 * xn, 2)); l = luminance_range[0] + (luminance_range[1] - luminance_range[0]) * xn; h = Math.max(Math.min(h, d3.max(hue_range)), d3.min(hue_range)); c = Math.max(Math.min(c, d3.max(chroma_range)), d3.min(chroma_range)); l = Math.max(Math.min(l, d3.max(luminance_range)), d3.min(luminance_range)); return d3.hcl(h, c, l); }; scale.domain = function(x) { if (!arguments.length) { return domain; } domain = x; return scale; }; scale.hue_range = function(x) { if (!arguments.length) { return hue_range; } hue_range = x; return scale; }; scale.chroma_range = function(x) { if (!arguments.length) { return chroma_range; } chroma_range = x; return scale; }; scale.luminance_range = function(x) { if (!arguments.length) { return luminance_range; } luminance_range = x; return scale; }; return scale; }; /* END */ canvas_left = d3.select('#left'); canvas_right = d3.select('#right'); width = canvas_left.node().getBoundingClientRect().width; height = canvas_left.node().getBoundingClientRect().height; side = Math.min(width, height) - 20; /* define the distance function for the original circle */ CX = 0.5; CY = 0.5; R = 0.25; dist = function(x, y) { return R - (Math.pow(x - CX, 2) + Math.pow(y - CY, 2)) / R; }; /* compute the field */ df = (function() { var _i, _results; _results = []; for (pixel_x = _i = 0; 0 <= side ? _i < side : _i > side; pixel_x = 0 <= side ? ++_i : --_i) { _results.push((function() { var _j, _results1; _results1 = []; for (pixel_y = _j = 0; 0 <= side ? _j < side : _j > side; pixel_y = 0 <= side ? ++_j : --_j) { _results1.push(dist(pixel_x / side, pixel_y / side)); } return _results1; })()); } return _results; })(); /* edit tool */ svg = d3.select('svg'); cx_tool = 0; cy_tool = 0; r_tool = 0.125; dist_tool = function(x, y) { return r_tool - (Math.pow(x - cx_tool, 2) + Math.pow(y - cy_tool, 2)) / r_tool; }; tool = svg.append('circle').attr({ id: 'tool', r: r_tool * side }); svg.on('mousemove', function() { var x, y, _ref, _ref1; _ref = d3.mouse(this), x = _ref[0], y = _ref[1]; _ref1 = [x / side, y / side], cx_tool = _ref1[0], cy_tool = _ref1[1]; return tool.attr({ cx: x + 0.5, cy: y + 0.5 }); }); svg.on('click', function() { return edit('union'); }); svg.on('contextmenu', function() { edit('sub'); return d3.event.preventDefault(); }); svg.on('mousewheel', function() { if (d3.event.wheelDelta > 0) { r_tool *= 1.2; } else { r_tool /= 1.2; } return tool.attr({ r: r_tool * side }); }); edit = function(op) { var _i, _j; d3.select('body').classed('wait', true); for (pixel_x = _i = 0; 0 <= side ? _i < side : _i > side; pixel_x = 0 <= side ? ++_i : --_i) { for (pixel_y = _j = 0; 0 <= side ? _j < side : _j > side; pixel_y = 0 <= side ? ++_j : --_j) { if (op === 'union') { df[pixel_x][pixel_y] = Math.max(df[pixel_x][pixel_y], dist_tool(pixel_x / side, pixel_y / side)); } else if (op === 'sub') { df[pixel_x][pixel_y] = Math.min(df[pixel_x][pixel_y], -dist_tool(pixel_x / side, pixel_y / side)); } } } return window.requestAnimationFrame(function() { redraw(); return d3.select('body').classed('wait', false); }); }; redraw = function() { /* Draw the distance function */ var BLUR, Fxy, MAX_D, a, b, color, colorize_inner, colorize_outer, ctx, g, image, pixel_i, r, value, _i, _j, _k, _l, _ref, _ref1; ctx = canvas_left.node().getContext('2d'); image = ctx.createImageData(side, side); /* define a default cubehelix-style hcl linear rainbow scale */ MAX_D = Math.sqrt(2) / 4; colorize_inner = hcl_linear_rainbow().domain([MAX_D, 0]).hue_range([200, 200 + 90]); colorize_outer = hcl_linear_rainbow().domain([-MAX_D, 0]).hue_range([200 - 180, 200 - 180 + 90]); console.debug('Coloring...'); for (pixel_x = _i = 0; 0 <= side ? _i < side : _i > side; pixel_x = 0 <= side ? ++_i : --_i) { for (pixel_y = _j = 0; 0 <= side ? _j < side : _j > side; pixel_y = 0 <= side ? ++_j : --_j) { pixel_i = (pixel_y * side + pixel_x) * 4; _ref = [pixel_i + 0, pixel_i + 1, pixel_i + 2, pixel_i + 3], r = _ref[0], g = _ref[1], b = _ref[2], a = _ref[3]; Fxy = df[pixel_x][pixel_y]; if (Fxy > 0) { color = d3.rgb(colorize_inner(Fxy)); } else { color = d3.rgb(colorize_outer(Fxy)); } image.data[r] = color.r; image.data[g] = color.g; image.data[b] = color.b; image.data[a] = 255; } } ctx.putImageData(image, (width - side) / 2, (height - side) / 2); /* Draw the reconstructed shape */ ctx = canvas_right.node().getContext('2d'); image = ctx.createImageData(side, side); BLUR = 3; for (pixel_x = _k = 0; 0 <= side ? _k < side : _k > side; pixel_x = 0 <= side ? ++_k : --_k) { for (pixel_y = _l = 0; 0 <= side ? _l < side : _l > side; pixel_y = 0 <= side ? ++_l : --_l) { pixel_i = (pixel_y * side + pixel_x) * 4; _ref1 = [pixel_i + 0, pixel_i + 1, pixel_i + 2, pixel_i + 3], r = _ref1[0], g = _ref1[1], b = _ref1[2], a = _ref1[3]; Fxy = df[pixel_x][pixel_y]; value = Math.min(1 + Fxy / (BLUR / side), 1); image.data[r] = 255; image.data[g] = 255; image.data[b] = 255; image.data[a] = value * 255; } } return ctx.putImageData(image, (width - side) / 2, (height - side) / 2); }; redraw(); }).call(this);