Created
April 19, 2016 11:57
-
-
Save christianp/df5bc189e04cf33abbf84fc243af3a15 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function canvasApp() { | |
if (!canvasSupport()) { | |
return | |
} | |
;var canvasOne = document.getElementById("canvasOne"); | |
var context = canvasOne.getContext("2d"); | |
setup(); | |
var vec1; | |
var vec2; | |
var angle; | |
var edge_length; | |
var a; | |
var b; | |
var graphics_scale; | |
var v_translate; | |
var nodes; | |
var neighbours; | |
var axis; | |
var turn; | |
var do_redraw; | |
var x; | |
var y; | |
var ox; | |
var oy; | |
var tick_interval; | |
function setup() { | |
vec1 = [0, 0]; | |
vec2 = [0, 0]; | |
angle = 0; | |
graphics_scale = 150; | |
edge_length = 0.1; | |
a = [edge_length, 0]; | |
b = [edge_length * 0.5, edge_length * 0.5 * Math.sqrt(3)]; | |
v_translate = [0, 0]; | |
nodes = []; | |
neighbours = []; | |
setup_coords(); | |
axis = [0., 0.]; | |
turn = 0.; | |
frame(); | |
canvasOne.addEventListener("mousedown", start_drawing, false); | |
} | |
function distance(a, b) { | |
var dx = a[0] - b[0]; | |
var dy = a[1] - b[1]; | |
return Math.sqrt(dx * dx + dy * dy); | |
} | |
function setup_coords() { | |
for (var i = -30; i < 30; ++i) { | |
for (var j = -30; j < 30; ++j) { | |
var vec = [a[0] * i + b[0] * j, a[1] * i + b[1] * j]; | |
if ((i - j) % 3 != 0) { | |
nodes.push(vec) | |
} | |
; | |
} | |
} | |
;for (var i = 0; i < nodes.length; ++i) { | |
for (var j = i + 1; j < nodes.length; ++j) { | |
if (distance(nodes[i], nodes[j]) < edge_length * 1.01) { | |
neighbours.push([i, j]) | |
} | |
} | |
} | |
; | |
} | |
function start_drawing(evt) { | |
var rect = canvasOne.getBoundingClientRect(); | |
x = 2 * (evt.clientX - rect.left) / rect.width - 1; | |
y = 2 * (evt.clientY - rect.top) / rect.height - 1; | |
ox = x; | |
oy = y; | |
do_redraw = true; | |
vec1 = [x, y]; | |
if (do_redraw) { | |
window.addEventListener("mousemove", get_coords, false); | |
tick_interval = setInterval(tick, 1000 / 60); | |
} | |
;canvasOne.removeEventListener("mousedown", start_drawing, false); | |
window.addEventListener("mouseup", stop_drawing, false); | |
if (evt.preventDefault) { | |
evt.preventDefault() | |
} else { | |
if (evt.returnValue) { | |
evt.returnValue = false | |
} | |
} | |
;return false; | |
} | |
function tick() { | |
if (!do_redraw) { | |
clearInterval(tick_interval) | |
} | |
;frame(); | |
} | |
function stop_drawing(evt) { | |
canvasOne.addEventListener("mousedown", start_drawing, false); | |
window.removeEventListener("mouseup", stop_drawing, false); | |
if (do_redraw) { | |
do_redraw = false; | |
window.removeEventListener("mousemove", get_coords, false); | |
} | |
; | |
} | |
function length(a) { | |
return Math.sqrt(a[0] * a[0] + a[1] * a[1]) | |
} | |
function angle_between(a, b) { | |
var theta = Math.asin((a[0] * b[1] - a[1] * b[0]) / length(a) / length(b)); | |
if (a[0] * b[0] + a[1] * b[1] < 0) { | |
if (theta > 0) { | |
theta = Math.PI - theta | |
} else { | |
theta = -Math.PI - theta | |
} | |
} | |
;return theta; | |
} | |
function get_coords(evt) { | |
var rect = canvasOne.getBoundingClientRect(); | |
x = 2 * (evt.clientX - rect.left) / rect.width - 1; | |
y = 2 * (evt.clientY - rect.top) / rect.height - 1; | |
vec1 = [ox, oy]; | |
vec2 = [x, y]; | |
v_translate[0] = vec2[0] - vec1[0]; | |
v_translate[1] = vec2[1] - vec1[1]; | |
var d; | |
if (length(v_translate) < 1e-6) { | |
d = length(vec1) | |
} else { | |
d = length(vec1) - Math.abs(v_translate[0] * vec1[0] + v_translate[1] * vec1[1]) / length(v_translate) | |
} | |
;if (d < 0.) { | |
d = 0. | |
} | |
;if (d > 1.) { | |
d = 1. | |
} | |
;angle = angle_between(vec2, vec1) * d; | |
v_translate[0] *= (1. - d); | |
v_translate[1] *= (1. - d); | |
for (var i = 0; i < nodes.length; ++i) { | |
nodes[i] = transform(nodes[i], -angle, v_translate) | |
} | |
;axis = transform(axis, -angle, v_translate); | |
turn -= angle; | |
while (length(axis) > 3. * edge_length) { | |
var min = 2e19; | |
var min_i = -1; | |
for (var i = 0; i < 6; ++i) { | |
var dotprod = axis[0] * Math.cos(turn + Math.PI / 3. * i) + axis[1] * Math.sin(turn + Math.PI / 3. * i); | |
if (dotprod < min) { | |
min = dotprod; | |
min_i = i; | |
} | |
; | |
} | |
;corr = [3. * edge_length * Math.cos(turn + Math.PI / 3. * min_i), 3. * edge_length * Math.sin(turn + Math.PI / 3. * min_i)]; | |
axis = transform(axis, 0., corr); | |
for (var i = 0; i < nodes.length; ++i) { | |
nodes[i] = transform(nodes[i], 0., corr) | |
} | |
; | |
} | |
;ox = x; | |
oy = y; | |
} | |
function transform(vec, a, translate) { | |
var v_rotated = [Math.cos(a) * vec[0] - Math.sin(a) * vec[1], Math.sin(a) * vec[0] + Math.cos(a) * vec[1]]; | |
var v_out = [v_rotated[0] + translate[0], v_rotated[1] + translate[1]]; | |
return v_out; | |
} | |
function draw() { | |
var scan = new ConvexHullGrahamScan(); | |
var projected_nodes = []; | |
var visible = []; | |
for (var i = 0; i < nodes.length; ++i) { | |
var vec = nodes[i].slice(); | |
var distance_from_origin = length(vec); | |
visible.push(distance_from_origin > Math.PI * 0.5); | |
if (distance_from_origin != 0) { | |
vec[0] *= Math.sin(distance_from_origin) / distance_from_origin; | |
vec[1] *= Math.sin(distance_from_origin) / distance_from_origin; | |
} | |
;projected_nodes.push(vec); | |
if (!visible[i]) { | |
scan.addPoint(vec[0], vec[1]) | |
} | |
; | |
} | |
;context.beginPath(); | |
for (var i = 0; i < neighbours.length; ++i) { | |
if (visible[neighbours[i][0]] || visible[neighbours[i][1]]) { | |
continue | |
} | |
;var start = projected_nodes[neighbours[i][0]]; | |
var end = projected_nodes[neighbours[i][1]]; | |
context.moveTo(start[0] * graphics_scale + graphics_scale, start[1] * graphics_scale + graphics_scale); | |
context.lineTo(end[0] * graphics_scale + graphics_scale, end[1] * graphics_scale + graphics_scale); | |
} | |
;var hull = scan.getHull(); | |
var hull_end = hull[hull.length - 1]; | |
context.moveTo(hull_end.x * graphics_scale + graphics_scale, hull_end.y * graphics_scale + graphics_scale); | |
for (i = 0; i < hull.length; ++i) { | |
context.lineTo(hull[i].x * graphics_scale + graphics_scale, hull[i].y * graphics_scale + graphics_scale); | |
context.moveTo(hull[i].x * graphics_scale + graphics_scale, hull[i].y * graphics_scale + graphics_scale); | |
} | |
;context.strokeStyle = "#000066"; | |
context.stroke(); | |
} | |
function frame() { | |
context.fillStyle = "white"; | |
context.fillRect(0, 0, canvasOne.width, canvasOne.height); | |
draw(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment