|
(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.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; |
|
|
|
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 = 3; |
|
|
|
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); |