Last active
August 29, 2015 14:19
-
-
Save ympbyc/63438b62f39473519a5b to your computer and use it in GitHub Desktop.
Draw n-dimentional hypercube on canvas. http://ympbyc.hatenablog.com/entry/2015/04/13/high-dimentional-cube
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
/* | |
* Author: 2015 Minori Yamashita ympbyc@gmail.com | |
*/ | |
var origin = {x: 160, y:340}; | |
var canvas = document.getElementById("space"); | |
//http://stackoverflow.com/questions/9960908/permutations-in-javascript | |
function permutate (arr) { | |
return arr.reduce(function permute(res, item, key, arr) { | |
return res.concat(arr.length > 1 | |
&& arr.slice(0, key) | |
.concat(arr.slice(key + 1)) | |
.reduce(permute, []) | |
.map(function(perm) { | |
return [item].concat(perm); | |
}) | |
|| [[item]]); | |
}, []); | |
} | |
_.mixin({ | |
second: function (arr) { return arr[1]; } | |
}); | |
var edgeColors = { | |
x: "#D04255", | |
y: "#64C99B", | |
z: "#208DC3", | |
p: "#F0BA32", | |
q: "#DB7BB1", | |
r: "#CFE283" | |
}; | |
function vec () { | |
return _.toArray(arguments); | |
} | |
function revY (x) { | |
return origin.y - x; | |
} | |
function circle (r, theta) { | |
return { | |
x: r * Math.cos(theta), | |
y: r * Math.sin(theta) | |
} | |
} | |
function render (ctx, dimentions, xAxisAngle, yAxisAngle, transform) { | |
var axisAngles = renderAxis(ctx, dimentions, { | |
x: xAxisAngle, y: yAxisAngle | |
}, 200); | |
var allOne = _.range(dimentions.length).fill(1); | |
vec = transform | |
? $V(transform).toDiagonalMatrix().multiply($V(allOne)).elements | |
: allOne; | |
permutate(_.zip(dimentions, vec)).forEach(function (route, i) { | |
requestAnimationFrame(function () { | |
plotVertex(ctx, | |
route.map(_.first), | |
axisAngles, | |
route.map(_.second)); | |
}); | |
}); | |
} | |
function renderAxis (ctx, dimentions, axisAngles, length) { | |
var fixedAxisAngles = axisAngles || { | |
x: - Math.PI/4, | |
y: Math.PI/2 | |
}; | |
var restAngle = fixedAxisAngles.y - fixedAxisAngles.x; | |
var anglePerAxis = restAngle / (dimentions.length-1); | |
ctx.lineWidth = 0.2; | |
dimentions.forEach(function (axisName, i) { | |
if (_.isNumber(fixedAxisAngles[axisName])) | |
var dest = circle(length, fixedAxisAngles[axisName]); | |
else { | |
var angle = fixedAxisAngles.x | |
+ anglePerAxis * (i-1) + 0.1; | |
fixedAxisAngles[axisName] = angle; | |
var dest = circle(length, angle); | |
} | |
ctx.beginPath(); | |
ctx.moveTo(origin.x, origin.y); | |
ctx.lineTo(dest.x + origin.x, revY(dest.y)); | |
ctx.stroke(); | |
ctx.closePath(); | |
}); | |
return fixedAxisAngles; | |
} | |
function plotVertex (ctx, dimentions, axisAngles, vertex) { | |
ctx.lineWidth = 2; | |
var localOrigin = origin; | |
vertex.forEach(function (p, i) { | |
var axisName = dimentions[i]; | |
var dest = circle(p*100, axisAngles[axisName]); | |
var dest = { | |
x: dest.x + localOrigin.x, | |
y: localOrigin.y - dest.y | |
}; | |
ctx.strokeStyle = edgeColors[axisName] || "#D04255"; | |
ctx.beginPath(); | |
ctx.moveTo(localOrigin.x, localOrigin.y); | |
ctx.lineTo(dest.x, dest.y); | |
ctx.stroke(); | |
ctx.closePath(); | |
localOrigin = dest; | |
}); | |
} | |
var canvas = document.getElementById("space"); | |
function test (xAxisAngle, d, transform) { | |
var ctx = canvas.getContext("2d"); | |
ctx.clearRect(0,0,500,600); | |
render(ctx, | |
["x", "y", "z", "p", "q", "r", | |
"s", "t", "u", "v", "w", "a", | |
"b", "c", "d", "e", "f", "g", | |
"h", "i", "j", "k", "l", "m", "n", "o"].slice(0,d), | |
xAxisAngle || 0, | |
Math.PI/2, | |
transform); | |
} | |
var state = { | |
theta: -Math.PI*1.5, | |
delta: 0.02, | |
dimention: 5, //CHANGE ME! | |
transform: null //scale | |
}; | |
function frame () { | |
if (state.dimention < 7) requestAnimationFrame(frame); | |
test(Math.PI/2 * Math.sin(state.theta) - Math.PI/2, | |
state.dimention, | |
state.transform); | |
state.theta += state.delta; | |
} | |
requestAnimationFrame(frame); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment