Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitaku/5d307c5c0095aa22a439 to your computer and use it in GitHub Desktop.
Save nitaku/5d307c5c0095aa22a439 to your computer and use it in GitHub Desktop.
Distance fields (empty space)

TBC

A bigger circle is subtracted from a smaller one. Even though there are no resulting shapes, the distance field still contains traces of the original circle.

`// noprotect`
### BEGIN ###
hcl_linear_rainbow = () ->
# H and L are linear, C is quadratic
domain = [0,1]
hue_range = [340, 340-480]
chroma_range = [0, 40]
luminance_range = [0, 100]
scale = (x) ->
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
# clamp
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 = (x) ->
return domain if(!arguments.length)
domain = x
return scale
scale.hue_range = (x) ->
return hue_range if(!arguments.length)
hue_range = x
return scale
scale.chroma_range = (x) ->
return chroma_range if(!arguments.length)
chroma_range = x
return scale
scale.luminance_range = (x) ->
return luminance_range if(!arguments.length)
luminance_range = x
return scale
return scale
### END ###
### define the distance function for two circles ###
CX1 = 0.5
CY1 = 0.5
R1 = 0.25
dist1 = (x, y) -> R1 - ( Math.pow(x-CX1, 2) + Math.pow(y-CY1, 2) )/R1
CX2 = 0.5
CY2 = 0.5
R2 = 0.4
dist2 = (x, y) -> R2 - ( Math.pow(x-CX2, 2) + Math.pow(y-CY2, 2) )/R2
### Draw the distance function ###
canvas = d3.select('#left')
width = canvas.node().getBoundingClientRect().width
height = canvas.node().getBoundingClientRect().height
side = Math.min(width, height) - 20
ctx = canvas.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 in [0...side]
for pixel_y in [0...side]
pixel_i = (pixel_y*side + pixel_x)*4
[r,g,b,a] = [pixel_i+0, pixel_i+1, pixel_i+2, pixel_i+3]
[x,y] = [pixel_x/side, pixel_y/side]
Fxy = Math.min( dist1(x, y), -dist2(x, 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 ###
canvas = d3.select('#right')
width = canvas.node().getBoundingClientRect().width
height = canvas.node().getBoundingClientRect().height
side = Math.min(width, height) - 20
ctx = canvas.node().getContext('2d')
image = ctx.createImageData(side, side)
BLUR = 3
for pixel_x in [0...side]
for pixel_y in [0...side]
pixel_i = (pixel_y*side + pixel_x)*4
[r,g,b,a] = [pixel_i+0, pixel_i+1, pixel_i+2, pixel_i+3]
[x,y] = [pixel_x/side, pixel_y/side]
Fxy = Math.min( dist1(x, y), -dist2(x, 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
ctx.putImageData(image,(width-side)/2,(height-side)/2)
html, body {
padding: 0;
margin: 0;
}
canvas {
background: #222;
position: absolute;
}
#left {
top: 0;
left: 0;
}
#right {
top: 0;
left: 480px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="Distance fields (empty space)" />
<title>Distance fields (empty space)</title>
<link rel="stylesheet" href="index.css">
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<canvas id="left" width="480" height="500"></canvas>
<canvas id="right" width="480" height="500"></canvas>
<script src="index.js"></script>
</body>
</html>
(function() {
// noprotect;
/* BEGIN
*/
var BLUR, CX1, CX2, CY1, CY2, Fxy, MAX_D, R1, R2, a, b, canvas, color, colorize_inner, colorize_outer, ctx, dist1, dist2, g, hcl_linear_rainbow, height, image, pixel_i, pixel_x, pixel_y, r, side, value, width, x, y, _i, _j, _k, _l, _ref, _ref1, _ref2, _ref3;
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
*/
/* define the distance function for two circles
*/
CX1 = 0.5;
CY1 = 0.5;
R1 = 0.25;
dist1 = function(x, y) {
return R1 - (Math.pow(x - CX1, 2) + Math.pow(y - CY1, 2)) / R1;
};
CX2 = 0.5;
CY2 = 0.5;
R2 = 0.4;
dist2 = function(x, y) {
return R2 - (Math.pow(x - CX2, 2) + Math.pow(y - CY2, 2)) / R2;
};
/* Draw the distance function
*/
canvas = d3.select('#left');
width = canvas.node().getBoundingClientRect().width;
height = canvas.node().getBoundingClientRect().height;
side = Math.min(width, height) - 20;
ctx = canvas.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];
_ref1 = [pixel_x / side, pixel_y / side], x = _ref1[0], y = _ref1[1];
Fxy = Math.min(dist1(x, y), -dist2(x, 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
*/
canvas = d3.select('#right');
width = canvas.node().getBoundingClientRect().width;
height = canvas.node().getBoundingClientRect().height;
side = Math.min(width, height) - 20;
ctx = canvas.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;
_ref2 = [pixel_i + 0, pixel_i + 1, pixel_i + 2, pixel_i + 3], r = _ref2[0], g = _ref2[1], b = _ref2[2], a = _ref2[3];
_ref3 = [pixel_x / side, pixel_y / side], x = _ref3[0], y = _ref3[1];
Fxy = Math.min(dist1(x, y), -dist2(x, 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;
}
}
ctx.putImageData(image, (width - side) / 2, (height - side) / 2);
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment