(function() { // noprotect; var BLUR, CX, CY, MAX_D, R, canvas_left, canvas_right, ctx_left, ctx_right, cx_tool, cy_tool, df, dist, dist_tool, edit, height, pixel_x, pixel_y, r_tool, redraw, side, svg, tool, width; 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; ctx_left = canvas_left.node().getContext('2d'); ctx_right = canvas_right.node().getContext('2d'); /* define the distance function for the original circle */ CX = 0.5; CY = 0.5; R = 0.25; dist = function(x, y) { return R - (Math.abs(x - CX) + Math.abs(y - CY)); }; /* 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.sqrt(Math.pow(x - cx_tool, 2) + Math.pow(y - cy_tool, 2)); }; 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; 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 === 'intersection') { df[pixel_x][pixel_y] = Math.min(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() { return redraw(); }); }; MAX_D = Math.sqrt(2) / 4; BLUR = 1.5; redraw = function() { /* Draw the distance field... */ var Fxy, a, b, g, image_left, image_right, pixel_i, r, value, _i, _j, _ref; image_left = ctx_left.createImageData(side, side); /* ...and the reconstructed shape */ image_right = ctx_right.createImageData(side, side); 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]; image_left.data[r] = -Fxy / MAX_D * 255; image_left.data[g] = 0; image_left.data[b] = Fxy / MAX_D * 255; image_left.data[a] = 255; value = Math.min(1 + Fxy / (BLUR / side), 1); image_right.data[r] = 255; image_right.data[g] = 255; image_right.data[b] = 255; image_right.data[a] = value * 255; } } ctx_left.putImageData(image_left, (width - side) / 2, (height - side) / 2); return ctx_right.putImageData(image_right, (width - side) / 2, (height - side) / 2); }; redraw(); }).call(this);