├── 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 |
--------------------------------------------------------------------------------