├── LICENSE ├── README.md ├── go ├── hypercube.gif └── hypercube.go └── js ├── hypercube.gif ├── hypercube.js ├── hypercube_md.gif ├── hypercube_sm.gif └── index.html /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Leon Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hypercube 2 | 3 | A simple hypercube/tesseract animation. Created in Go using the awesome [ln](https://github.com/fogleman/ln) library. An older implementation in three.js also exists in the `js` folder. 4 | 5 |

6 | 7 |

8 | 9 | ### License 10 | 11 | MIT 12 | -------------------------------------------------------------------------------- /go/hypercube.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/transcranial/hypercube/90ffcb8c41109a458a3e7b3970a42349041c3db1/go/hypercube.gif -------------------------------------------------------------------------------- /go/hypercube.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/fogleman/ln/ln" 4 | //import "math" 5 | import "fmt" 6 | 7 | func CalcPath(p1 ln.Vector, p2 ln.Vector, p3 ln.Vector, p4 ln.Vector, t float64) ln.Vector { 8 | 9 | newVec := ln.Vector{0, 0, 0} 10 | 11 | if t >= 0 && t < 0.25 { 12 | newVec.X = p4.X + (p1.X - p4.X ) * t * 4; 13 | newVec.Y = p4.Y + (p1.Y - p4.Y ) * t * 4; 14 | newVec.Z = p4.Z + (p1.Z - p4.Z ) * t * 4; 15 | } else if t >= 0.25 && t < 0.5 { 16 | newVec.X = p1.X + (p2.X - p1.X ) * (t - 0.25) * 4; 17 | newVec.Y = p1.Y + (p2.Y - p1.Y ) * (t - 0.25) * 4; 18 | newVec.Z = p1.Z + (p2.Z - p1.Z ) * (t - 0.25) * 4; 19 | } else if t >= 0.5 && t < 0.75 { 20 | newVec.X = p2.X + (p3.X - p2.X ) * (t - 0.5) * 4; 21 | newVec.Y = p2.Y + (p3.Y - p2.Y ) * (t - 0.5) * 4; 22 | newVec.Z = p2.Z + (p3.Z - p2.Z ) * (t - 0.5) * 4; 23 | } else if t >= 0.75 && t < 1.0 { 24 | newVec.X = p3.X + (p4.X - p3.X ) * (t - 0.75) * 4; 25 | newVec.Y = p3.Y + (p4.Y - p3.Y ) * (t - 0.75) * 4; 26 | newVec.Z = p3.Z + (p4.Z - p3.Z ) * (t - 0.75) * 4; 27 | } 28 | 29 | return newVec; 30 | } 31 | 32 | type Hypercube struct { 33 | Vertices [16]ln.Vector 34 | Box ln.Box 35 | } 36 | 37 | func NewHypercube(t float64) *Hypercube { 38 | min, max := ln.Vector{-1,-1,-1}, ln.Vector{ 1, 1, 1} 39 | 40 | verticesStart := [16]ln.Vector{ 41 | ln.Vector{-0.5, -0.5, -0.5}, 42 | ln.Vector{ 0.5, -0.5, -0.5}, 43 | ln.Vector{ 0.5, 0.5, -0.5}, 44 | ln.Vector{-0.5, 0.5, -0.5}, 45 | 46 | ln.Vector{-0.5, -0.5, 0.5}, 47 | ln.Vector{ 0.5, -0.5, 0.5}, 48 | ln.Vector{ 0.5, 0.5, 0.5}, 49 | ln.Vector{-0.5, 0.5, 0.5}, 50 | 51 | ln.Vector{-1, -1, -1}, 52 | ln.Vector{ 1, -1, -1}, 53 | ln.Vector{ 1, 1, -1}, 54 | ln.Vector{-1, 1, -1}, 55 | 56 | ln.Vector{-1, -1, 1}, 57 | ln.Vector{ 1, -1, 1}, 58 | ln.Vector{ 1, 1, 1}, 59 | ln.Vector{-1, 1, 1}, 60 | } 61 | 62 | verticesNow := [16]ln.Vector{ 63 | CalcPath(verticesStart[8], verticesStart[9], verticesStart[1], verticesStart[0], t), 64 | CalcPath(verticesStart[0], verticesStart[8], verticesStart[9], verticesStart[1], t), 65 | CalcPath(verticesStart[3], verticesStart[11], verticesStart[10], verticesStart[2], t), 66 | CalcPath(verticesStart[11], verticesStart[10], verticesStart[2], verticesStart[3], t), 67 | CalcPath(verticesStart[12], verticesStart[13], verticesStart[5], verticesStart[4], t), 68 | CalcPath(verticesStart[4], verticesStart[12], verticesStart[13], verticesStart[5], t), 69 | CalcPath(verticesStart[7], verticesStart[15], verticesStart[14], verticesStart[6], t), 70 | CalcPath(verticesStart[15], verticesStart[14], verticesStart[6], verticesStart[7], t), 71 | CalcPath(verticesStart[9], verticesStart[1], verticesStart[0], verticesStart[8], t), 72 | CalcPath(verticesStart[1], verticesStart[0], verticesStart[8], verticesStart[9], t), 73 | CalcPath(verticesStart[2], verticesStart[3], verticesStart[11], verticesStart[10], t), 74 | CalcPath(verticesStart[10], verticesStart[2], verticesStart[3], verticesStart[11], t), 75 | CalcPath(verticesStart[13], verticesStart[5], verticesStart[4], verticesStart[12], t), 76 | CalcPath(verticesStart[5], verticesStart[4], verticesStart[12], verticesStart[13], t), 77 | CalcPath(verticesStart[6], verticesStart[7], verticesStart[15], verticesStart[14], t), 78 | CalcPath(verticesStart[14], verticesStart[6], verticesStart[7], verticesStart[15], t), 79 | } 80 | 81 | box := ln.Box{min, max} 82 | return &Hypercube{verticesNow, box} 83 | } 84 | 85 | func (c *Hypercube) Compile() { 86 | } 87 | 88 | func (c *Hypercube) BoundingBox() ln.Box { 89 | return c.Box 90 | } 91 | 92 | func (c *Hypercube) Contains(v ln.Vector, f float64) bool { 93 | min, max := ln.Vector{-1, -1, -1}, ln.Vector{1, 1, 1} 94 | if v.X < min.X-f || v.X > max.X+f { 95 | return false 96 | } 97 | if v.Y < min.Y-f || v.Y > max.Y+f { 98 | return false 99 | } 100 | if v.Z < min.Z-f || v.Z > max.Z+f { 101 | return false 102 | } 103 | return true 104 | } 105 | 106 | func (c *Hypercube) Intersect(r ln.Ray) ln.Hit { 107 | /*min, max := c.Vertices[0], c.Vertices[6] 108 | n := min.Sub(r.Origin).Div(r.Direction) 109 | f := max.Sub(r.Origin).Div(r.Direction) 110 | n, f = n.Min(f), n.Max(f) 111 | t0 := math.Max(math.Max(n.X, n.Y), n.Z) 112 | t1 := math.Min(math.Min(f.X, f.Y), f.Z) 113 | if t0 < 1e-3 && t1 > 1e-3 { 114 | return ln.Hit{c, t1} 115 | } 116 | if t0 >= 1e-3 && t0 < t1 { 117 | return ln.Hit{c, t0} 118 | }*/ 119 | return ln.NoHit 120 | } 121 | 122 | func (c *Hypercube) Paths() ln.Paths { 123 | 124 | vertexJoins := [32][2]int{ 125 | {0, 1}, {1, 2}, {2, 3}, {3, 0}, 126 | {0, 4}, {1, 5}, {2, 6}, {3, 7}, 127 | {4, 5}, {5, 6}, {6, 7}, {7, 4}, 128 | 129 | {0, 8}, {1, 9}, {2, 10}, {3, 11}, 130 | {4, 12}, {5, 13}, {6, 14}, {7, 15}, 131 | 132 | {8, 9}, {9, 10}, {10, 11}, {11, 8}, 133 | {8, 12}, {9, 13}, {10, 14}, {11, 15}, 134 | {12, 13}, {13, 14}, {14, 15}, {15, 12}, 135 | } 136 | 137 | var paths ln.Paths 138 | 139 | for i := 0; i < 32; i++ { 140 | paths = append(paths, ln.Path{c.Vertices[vertexJoins[i][0]], c.Vertices[vertexJoins[i][1]]}) 141 | } 142 | 143 | return paths 144 | } 145 | 146 | func main() { 147 | 148 | eye := ln.Vector{-4, 3, 2} // camera position 149 | center := ln.Vector{0, 0, 0} // camera looks at 150 | up := ln.Vector{0, 0, 1} // up direction 151 | width := 1024.0 // rendered width 152 | height := 1024.0 // rendered height 153 | fovy := 50.0 // vertical field of view, degrees 154 | znear := 0.1 // near z plane 155 | zfar := 10.0 // far z plane 156 | step := 0.01 // how finely to chop the paths for visibility testing 157 | 158 | var scene ln.Scene 159 | var paths ln.Paths 160 | var t float64 161 | 162 | for i := 0; i < 125; i++ { 163 | t = float64(i) / 125.0 164 | 165 | scene = ln.Scene{} 166 | scene.Add(NewHypercube(t)) 167 | paths = scene.Render(eye, center, up, width, height, fovy, znear, zfar, step) 168 | 169 | paths.WriteToSVG(fmt.Sprintf("hypercube_%03d.svg", i), width, height) 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /js/hypercube.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/transcranial/hypercube/90ffcb8c41109a458a3e7b3970a42349041c3db1/js/hypercube.gif -------------------------------------------------------------------------------- /js/hypercube.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let t = 0.0; 4 | 5 | let scene, camera, renderer; 6 | let geometry, material; 7 | 8 | let edges = []; 9 | let vertexCoords = []; 10 | let vertexCoords2 = []; 11 | let vertexJoins = []; 12 | 13 | init(); 14 | render(); 15 | 16 | function path(p1, p2, p3, p4, i) { 17 | 18 | let vec = new THREE.Vector3(0,0,0); 19 | 20 | if (i >= 0 && i < 0.25) { 21 | vec.x = p4.x + (p1.x - p4.x ) * i * 4; 22 | vec.y = p4.y + (p1.y - p4.y ) * i * 4; 23 | vec.z = p4.z + (p1.z - p4.z ) * i * 4; 24 | } else if (i >= 0.25 && i < 0.5) { 25 | vec.x = p1.x + (p2.x - p1.x ) * (i - 0.25) * 4; 26 | vec.y = p1.y + (p2.y - p1.y ) * (i - 0.25) * 4; 27 | vec.z = p1.z + (p2.z - p1.z ) * (i - 0.25) * 4; 28 | } else if (i >= 0.5 && i < 0.75) { 29 | vec.x = p2.x + (p3.x - p2.x ) * (i - 0.5) * 4; 30 | vec.y = p2.y + (p3.y - p2.y ) * (i - 0.5) * 4; 31 | vec.z = p2.z + (p3.z - p2.z ) * (i - 0.5) * 4; 32 | } else if (i >= 0.75 && i < 1.0) { 33 | vec.x = p3.x + (p4.x - p3.x ) * (i - 0.75) * 4; 34 | vec.y = p3.y + (p4.y - p3.y ) * (i - 0.75) * 4; 35 | vec.z = p3.z + (p4.z - p3.z ) * (i - 0.75) * 4; 36 | } 37 | 38 | return vec; 39 | } 40 | 41 | function init() { 42 | 43 | vertexCoords[0] = new THREE.Vector3(-50,-50,-50); 44 | vertexCoords[1] = new THREE.Vector3( 50,-50,-50); 45 | vertexCoords[2] = new THREE.Vector3( 50, 50,-50); 46 | vertexCoords[3] = new THREE.Vector3(-50, 50,-50); 47 | vertexCoords[4] = new THREE.Vector3(-50,-50, 50); 48 | vertexCoords[5] = new THREE.Vector3( 50,-50, 50); 49 | vertexCoords[6] = new THREE.Vector3( 50, 50, 50); 50 | vertexCoords[7] = new THREE.Vector3(-50, 50, 50); 51 | vertexCoords[8] = new THREE.Vector3(-100,-100,-100); 52 | vertexCoords[9] = new THREE.Vector3( 100,-100,-100); 53 | vertexCoords[10] = new THREE.Vector3( 100, 100,-100); 54 | vertexCoords[11] = new THREE.Vector3(-100, 100,-100); 55 | vertexCoords[12] = new THREE.Vector3(-100,-100, 100); 56 | vertexCoords[13] = new THREE.Vector3( 100,-100, 100); 57 | vertexCoords[14] = new THREE.Vector3( 100, 100, 100); 58 | vertexCoords[15] = new THREE.Vector3(-100, 100, 100); 59 | 60 | vertexJoins = [ 61 | [0,1], [1,2], [2,3], [3,0], 62 | [0,4], [1,5], [2,6], [3,7], 63 | [4,5], [5,6], [6,7], [7,4], 64 | 65 | [0,8], [1,9], [2,10], [3,11], 66 | [4,12], [5,13], [6,14], [7,15], 67 | 68 | [8,9], [9,10], [10,11], [11,8], 69 | [8,12], [9,13], [10,14], [11,15], 70 | [12,13], [13,14], [14,15], [15,12] 71 | ]; 72 | 73 | scene = new THREE.Scene(); 74 | camera = new THREE.OrthographicCamera( window.innerWidth / - 4, window.innerWidth / 4, window.innerHeight / 4, window.innerHeight / - 4, 1, 1000 ); 75 | camera.position.set(200,-100,-300); 76 | camera.lookAt(new THREE.Vector3(0,0,0)); 77 | 78 | renderer = new THREE.WebGLRenderer(); 79 | renderer.setSize(window.innerWidth / 2, window.innerHeight / 2); 80 | document.getElementById('hypercube').appendChild(renderer.domElement); 81 | 82 | for (let i = 0; i < vertexJoins.length; i++) { 83 | 84 | geometry = new THREE.Geometry(); 85 | geometry.vertices.push(vertexCoords[vertexJoins[i][0]]); 86 | geometry.vertices.push(vertexCoords[vertexJoins[i][1]]); 87 | let line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ 88 | color: 0x22A7F0, 89 | linewidth: 4 90 | })); 91 | scene.add(line); 92 | edges[i] = line; 93 | 94 | } 95 | 96 | } 97 | 98 | function render() { 99 | t = (t + 0.002) % 1; 100 | 101 | vertexCoords2[0] = path(vertexCoords[8], vertexCoords[9], vertexCoords[1], vertexCoords[0], t); 102 | vertexCoords2[1] = path(vertexCoords[0], vertexCoords[8], vertexCoords[9], vertexCoords[1], t); 103 | vertexCoords2[9] = path(vertexCoords[1], vertexCoords[0], vertexCoords[8], vertexCoords[9], t); 104 | vertexCoords2[8] = path(vertexCoords[9], vertexCoords[1], vertexCoords[0], vertexCoords[8], t); 105 | 106 | vertexCoords2[3] = path(vertexCoords[11], vertexCoords[10], vertexCoords[2], vertexCoords[3], t); 107 | vertexCoords2[2] = path(vertexCoords[3], vertexCoords[11], vertexCoords[10], vertexCoords[2], t); 108 | vertexCoords2[10] = path(vertexCoords[2], vertexCoords[3], vertexCoords[11], vertexCoords[10], t); 109 | vertexCoords2[11] = path(vertexCoords[10], vertexCoords[2], vertexCoords[3], vertexCoords[11], t); 110 | 111 | vertexCoords2[4] = path(vertexCoords[12], vertexCoords[13], vertexCoords[5], vertexCoords[4], t); 112 | vertexCoords2[5] = path(vertexCoords[4], vertexCoords[12], vertexCoords[13], vertexCoords[5], t); 113 | vertexCoords2[13] = path(vertexCoords[5], vertexCoords[4], vertexCoords[12], vertexCoords[13], t); 114 | vertexCoords2[12] = path(vertexCoords[13], vertexCoords[5], vertexCoords[4], vertexCoords[12], t); 115 | 116 | vertexCoords2[7] = path(vertexCoords[15], vertexCoords[14], vertexCoords[6], vertexCoords[7], t); 117 | vertexCoords2[6] = path(vertexCoords[7], vertexCoords[15], vertexCoords[14], vertexCoords[6], t); 118 | vertexCoords2[14] = path(vertexCoords[6], vertexCoords[7], vertexCoords[15], vertexCoords[14], t); 119 | vertexCoords2[15] = path(vertexCoords[14], vertexCoords[6], vertexCoords[7], vertexCoords[15], t); 120 | 121 | requestAnimationFrame(render); 122 | 123 | for (let i = 0; i < edges.length; i++) { 124 | 125 | edges[i].geometry.vertices[0] = vertexCoords2[vertexJoins[i][0]]; 126 | edges[i].geometry.vertices[1] = vertexCoords2[vertexJoins[i][1]]; 127 | edges[i].rotation.x = 0; 128 | edges[i].rotation.y = 0; 129 | edges[i].rotation.z = 0; 130 | edges[i].geometry.verticesNeedUpdate = true; 131 | } 132 | 133 | renderer.render(scene, camera); 134 | } 135 | -------------------------------------------------------------------------------- /js/hypercube_md.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/transcranial/hypercube/90ffcb8c41109a458a3e7b3970a42349041c3db1/js/hypercube_md.gif -------------------------------------------------------------------------------- /js/hypercube_sm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/transcranial/hypercube/90ffcb8c41109a458a3e7b3970a42349041c3db1/js/hypercube_sm.gif -------------------------------------------------------------------------------- /js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | hypercube 4 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | --------------------------------------------------------------------------------