Compare commits

...

8 Commits

Author SHA1 Message Date
Mike Lynch f79a90e0d9 Added the rest of the regular 3-d polyhedra 2024-04-25 12:38:40 +10:00
Mike Lynch 78ebb381ee Played around with the hyperplane and zoom so that it all looks
better with unit radius normalisation
2024-04-25 11:25:01 +10:00
Mike Lynch f99901f1b0 Normalised dodecahedron to unit radius 2024-04-25 11:07:21 +10:00
Mike Lynch 39fe6e5e40 Normalised 120-cell to unit radius 2024-04-25 11:05:23 +10:00
Mike Lynch 836e0d5ab6 Normalised 600-cell and snub 24-cell to unit radius 2024-04-25 11:03:11 +10:00
Mike Lynch 0be8c47608 Normalised 24-cell to unit radius 2024-04-25 11:00:14 +10:00
Mike Lynch 5e31403420 Normalised tesseract to unit radius 2024-04-25 10:58:41 +10:00
Mike Lynch aba20124db Normalised 5-cell and 16-cell to unit radius 2024-04-25 10:57:03 +10:00
3 changed files with 172 additions and 20 deletions

12
gui.js
View File

@ -2,8 +2,8 @@ import { GUI } from 'lil-gui';
const DEFAULTS = { const DEFAULTS = {
thickness: 1.0, thickness: 0.5,
nodesize: 2.0, nodesize: 1.5,
linkopacity: 0.5, linkopacity: 0.5,
link2opacity: 0.5, link2opacity: 0.5,
shape: '120-cell', shape: '120-cell',
@ -13,10 +13,10 @@ const DEFAULTS = {
inscribe_all: false, inscribe_all: false,
color: 0x3293a9, color: 0x3293a9,
background: 0xd4d4d4, background: 0xd4d4d4,
hyperplane: 1.5, hyperplane: 0.93,
zoom: 1, zoom: 1,
xRotate: 'YW', xRotate: 'YW',
yRotate: 'XZ', yRotate: 'XW',
dtheta: 0, dtheta: 0,
dpsi: 0, dpsi: 0,
} }
@ -65,9 +65,9 @@ class FourDGUI {
options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => { options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => {
setVisibility(option) setVisibility(option)
}); });
this.gui.add(this.params, 'hyperplane', 1.4, 2.0); this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8);
this.gui.add(this.params, 'zoom', 0.1, 2.0); this.gui.add(this.params, 'zoom', 0.1, 2.0);
this.gui.add(this.params, 'thickness', 0, 2); this.gui.add(this.params, 'thickness', 0, 1);
this.gui.add(this.params, 'linkopacity', 0, 1).onChange( this.gui.add(this.params, 'linkopacity', 0, 1).onChange(
(v) => setLinkOpacity(v, true) (v) => setLinkOpacity(v, true)
); );

View File

@ -9,7 +9,7 @@ import { FourDShape } from './fourDShape.js';
import { get_colours } from './colours.js'; import { get_colours } from './colours.js';
const FACE_OPACITY = 0.3; const FACE_OPACITY = 0.3;
const CAMERA_K = 10; const CAMERA_K = 5;
// scene, lights and camera // scene, lights and camera
@ -213,8 +213,8 @@ function animate() {
rotfn[gui.params.xRotate](theta), rotfn[gui.params.xRotate](theta),
rotfn[gui.params.yRotate](psi) rotfn[gui.params.yRotate](psi)
]; ];
shape.hyperplane = gui.params.hyperplane; shape.hyperplane = 1 / gui.params.hyperplane;
camera.position.set(0, 0, gui.params.zoom * CAMERA_K / gui.params.hyperplane); camera.position.set(0, 0, gui.params.zoom * CAMERA_K * gui.params.hyperplane);
shape.link_scale = gui.params.thickness; shape.link_scale = gui.params.thickness;
shape.node_scale = gui.params.nodesize; shape.node_scale = gui.params.nodesize;

View File

@ -58,16 +58,15 @@ export function auto_detect_edges(nodes, neighbours, debug=false) {
// too small and simple to calculate // too small and simple to calculate
export const cell5 = () => { export const cell5 = () => {
const r5 = Math.sqrt(5); const c1 = Math.sqrt(5) / 4;
const r2 = Math.sqrt(2) / 2;
return { return {
name: '5-cell', name: '5-cell',
nodes: [ nodes: [
{id:1, label: 1, x: r2, y: r2, z: r2, w: -r2 / r5 }, {id:1, label: 1, x: c1, y: c1, z: c1, w: -0.25 },
{id:2, label: 2, x: r2, y: -r2, z: -r2, w: -r2 / r5 }, {id:2, label: 2, x: c1, y: -c1, z: -c1, w: -0.25 },
{id:3, label: 3, x: -r2, y: r2, z: -r2, w: -r2 / r5 }, {id:3, label: 3, x: -c1, y: c1, z: -c1, w: -0.25 },
{id:4, label: 4, x: -r2, y: -r2, z: r2, w: -r2 / r5 }, {id:4, label: 4, x: -c1, y: -c1, z: c1, w: -0.25 },
{id:5, label: 5, x: 0, y: 0, z: 0, w: 4 * r2 / r5 }, {id:5, label: 5, x: 0, y: 0, z: 0, w: 1 },
], ],
links: [ links: [
{ id:1, source:1, target: 2}, { id:1, source:1, target: 2},
@ -109,7 +108,7 @@ export const cell16 = () => {
nodes[1].label = 4; nodes[1].label = 4;
index_nodes(nodes); index_nodes(nodes);
scale_nodes(nodes, 0.75); scale_nodes(nodes, 0.5);
const links = auto_detect_edges(nodes, 6); const links = auto_detect_edges(nodes, 6);
return { return {
@ -142,7 +141,7 @@ export const tesseract = () => {
} }
} }
scale_nodes(nodes, Math.sqrt(2) / 2); scale_nodes(nodes, 0.5);
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
links.map((l) => { l.label = 0 }); links.map((l) => { l.label = 0 });
@ -198,6 +197,7 @@ export const cell24 = () => {
n.label = CELL24_INDEXING[axes[0]][axes[1]]; n.label = CELL24_INDEXING[axes[0]][axes[1]];
} }
scale_nodes(nodes, Math.sqrt(2) / 2);
index_nodes(nodes); index_nodes(nodes);
const links = auto_detect_edges(nodes, 8); const links = auto_detect_edges(nodes, 8);
links.map((l) => l.label = 0); links.map((l) => l.label = 0);
@ -338,7 +338,7 @@ export function make_120cell_vertices() {
PERMUTE.coordinates([2, 1, phi, phiinv], 0, true), PERMUTE.coordinates([2, 1, phi, phiinv], 0, true),
].flat(); ].flat();
index_nodes(nodes); index_nodes(nodes);
scale_nodes(nodes, 0.5); scale_nodes(nodes, 0.25 * Math.sqrt(2));
return nodes; return nodes;
} }
@ -540,7 +540,7 @@ export function make_600cell_vertices() {
index_nodes(nodes); index_nodes(nodes);
scale_nodes(nodes, 0.75); scale_nodes(nodes, 0.5);
return nodes; return nodes;
} }
@ -715,6 +715,7 @@ function make_dodecahedron_vertices() {
{ x: -phi, y: phiinv, z:0, w: 0 , label: 4}, { x: -phi, y: phiinv, z:0, w: 0 , label: 4},
{ x: -phi, y: -phiinv, z:0, w: 0 , label: 2}, { x: -phi, y: -phiinv, z:0, w: 0 , label: 2},
]; ];
scale_nodes(nodes, 1 / Math.sqrt(3));
index_nodes(nodes); index_nodes(nodes);
return nodes; return nodes;
} }
@ -754,8 +755,155 @@ export const dodecahedron = () => {
} }
export const tetrahedron = () => {
const r2 = Math.sqrt(2);
const r3 = Math.sqrt(3);
return {
name: 'Tetrahedron',
nodes: [
{id:1, label: 1, x: 2 * r2 / 3, y: 0, z: -1/3, w: 0 },
{id:2, label: 2, x: -r2 / 3, y: r2 / r3, z: -1/3, w: 0 },
{id:3, label: 3, x: -r2 / 3, y: -r2 / r3, z: -1/3, w: 0 },
{id:4, label: 4, x: 0, y: 0, z: 1, w: 0 },
],
links: [
{ id:1, source:1, target: 2},
{ id:2, source:1, target: 3},
{ id:3, source:1, target: 4},
{ id:4, source:2, target: 3},
{ id:5, source:2, target: 4},
{ id:6, source:3, target: 4},
],
geometry: {
node_size: 0.02,
link_size: 0.02
},
options: [ { name: '--' }],
description: `The simplest three-dimensional polytope, consisting of four triangles joined at six edges. The 5-cell is its four-dimensional analogue.`,
};
};
export const octahedron = () => {
const nodes = [
{id: 1, label: 1, x: 1, y: 0, z: 0, w: 0},
{id: 2, label: 1, x: -1, y: 0, z: 0, w: 0},
{id: 3, label: 2, x: 0, y: 1, z: 0, w: 0},
{id: 4, label: 2, x: 0, y: -1, z: 0, w: 0},
{id: 5, label: 3, x: 0, y: 0, z: 1, w: 0},
{id: 6, label: 3, x: 0, y: 0, z: -1, w: 0},
];
const links = [
{id:1, source: 1, target: 3},
{id:2, source: 1, target: 4},
{id:3, source: 1, target: 5},
{id:4, source: 1, target: 6},
{id:5, source: 2, target: 3},
{id:6, source: 2, target: 4},
{id:7, source: 2, target: 5},
{id:8, source: 2, target: 6},
{id:9, source: 3, target: 5},
{id:10, source: 3, target: 6},
{id:11, source: 4, target: 5},
{id:12, source: 4, target: 6},
]
links.map((l) => { l.label = 0 });
return {
name: 'Octahedron',
nodes: nodes,
links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
},
options: [ { name: '--' }],
description: `The three-dimensional cross-polytope, the 16-cell is its four-dimensional analogue.`,
};
}
export const cube = () => {
const nodes = [
{id: 1, label: 1, x: 1, y: 1, z: 1, w: 0},
{id: 2, label: 2, x: -1, y: 1, z: 1, w: 0},
{id: 3, label: 2, x: 1, y: -1, z: 1, w: 0},
{id: 4, label: 1, x: -1, y: -1, z: 1, w: 0},
{id: 5, label: 2, x: 1, y: 1, z: -1, w: 0},
{id: 6, label: 1, x: -1, y: 1, z: -1, w: 0},
{id: 7, label: 1, x: 1, y: -1, z: -1, w: 0},
{id: 8, label: 2, x: -1, y: -1, z: -1, w: 0},
];
scale_nodes(nodes, 1/Math.sqrt(3));
const links = auto_detect_edges(nodes, 3);
links.map((l) => { l.label = 0 });
return {
name: 'Cube',
nodes: nodes,
links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
},
options: [ { name: '--' }],
description: `The three-dimensional measure polytope, the tesseract is its four-dimensional analogue.`,
};
}
function make_icosahedron_vertices() {
const phi = 0.5 * (1 + Math.sqrt(5));
const nodes = [
{ x: 0, y: 1, z: phi, w: 0, label: 1 },
{ x: 0, y: -1, z: phi, w: 0, label: 1 },
{ x: 0, y: 1, z: -phi, w: 0, label: 1 },
{ x: 0, y: -1, z: -phi, w: 0, label: 1 },
{ x: 1, y: phi, z: 0, w: 0, label: 2 },
{ x: -1, y: phi, z: 0, w: 0, label: 2 },
{ x: 1, y: -phi, z: 0, w: 0, label: 2 },
{ x: -1, y: -phi, z: 0, w: 0, label: 2 },
{ x: phi, y: 0, z: 1, w: 0, label: 3},
{ x: phi, y: 0, z: -1, w: 0, label: 3},
{ x: -phi, y: 0, z: 1, w: 0, label: 3},
{ x: -phi, y: 0, z: -1, w: 0, label: 3},
];
scale_nodes(nodes, 1/Math.sqrt((5 + Math.sqrt(5)) / 2));
index_nodes(nodes);
return nodes;
}
export const icosahedron = () => {
const nodes = make_icosahedron_vertices();
const links = auto_detect_edges(nodes, 5);
links.map((l) => l.label = 0);
return {
name: 'Icosahedron',
nodes: nodes,
links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
},
options: [
{ name: "--"},
],
description: `The icosahedron is a twenty-sided polyhedron and is dual to the dodecahedron. Its four-dimensional analogue is the 600-cell.`
}
}
export const build_all = () => { export const build_all = () => {
return [ return [
tetrahedron(),
octahedron(),
cube(),
icosahedron(),
dodecahedron(), dodecahedron(),
cell5(), cell5(),
cell16(), cell16(),
@ -768,3 +916,7 @@ export const build_all = () => {
cell120_layered() cell120_layered()
]; ];
} }
export const radii = (shape) => {
return shape.nodes.map(n => Math.sqrt(n.x * n.x + n.y * n.y + n.z * n.z + n.w * n.w))
}