Compare commits

...

8 Commits

Author SHA1 Message Date
Mike Lynch 6d9610a1c6 options menu gets sensible default when shape changes 2023-11-01 11:57:46 +11:00
Mike Lynch c481d24f3c Refactored dodecahedron 2023-11-01 11:52:48 +11:00
Mike Lynch 029e6f3161 Added 600-cell and 120-cell 2023-11-01 11:49:42 +11:00
Mike Lynch 4bf38858ea Added 24-cell 2023-11-01 11:43:54 +11:00
Mike Lynch 50214adbe3 Reinstated 5-cell and 16-cell 2023-11-01 11:40:23 +11:00
Mike Lynch 71c6aa62ac Removed old inscribed tesseract 2023-11-01 11:15:18 +11:00
Mike Lynch 76f463ae03 Added refactored tesseract 2023-11-01 11:14:57 +11:00
Mike Lynch 42d1871a9e Improved option defaults and URL params 2023-11-01 10:47:46 +11:00
3 changed files with 87 additions and 141 deletions

16
gui.js
View File

@ -6,7 +6,8 @@ const DEFAULTS = {
nodesize: 1.25, nodesize: 1.25,
linkopacity: 0.5, linkopacity: 0.5,
link2opacity: 0.5, link2opacity: 0.5,
shape: '120-cell inscribed', shape: '',
option: '',
visibility: 5, visibility: 5,
inscribed: false, inscribed: false,
inscribe_all: false, inscribe_all: false,
@ -24,10 +25,16 @@ class FourDGUI {
constructor(shapes, changeShape, setColor, setBackground, setLinkOpacity, setVisibility) { constructor(shapes, changeShape, setColor, setBackground, setLinkOpacity, setVisibility) {
this.gui = new GUI(); this.gui = new GUI();
const SHAPE_NAMES = shapes.map((s) => s.name);
// set default shape + option from the first shape
DEFAULTS.shape = shapes[0].name;
DEFAULTS.option = shapes[0].options[0].name;
this.parseLinkParams(); this.parseLinkParams();
const guiObj = this; const guiObj = this;
this.params = { this.params = {
shape: this.link['shape'], shape: this.link['shape'],
option: this.link['option'],
inscribed: this.link['inscribed'], inscribed: this.link['inscribed'],
inscribe_all: this.link['inscribe_all'], inscribe_all: this.link['inscribe_all'],
thickness: this.link['thickness'], thickness: this.link['thickness'],
@ -44,17 +51,17 @@ class FourDGUI {
dpsi: this.link['dpsi'], dpsi: this.link['dpsi'],
"copy link": function () { guiObj.copyUrl() } "copy link": function () { guiObj.copyUrl() }
}; };
const SHAPE_NAMES = shapes.map((s) => s.name);
let options_ctrl; let options_ctrl;
this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => { this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => {
const options = this.getShapeOptions(shapes, shape); const options = this.getShapeOptions(shapes, shape);
options_ctrl = options_ctrl.options(options).onChange((option) => { options_ctrl = options_ctrl.options(options).onChange((option) => {
setVisibility(option) setVisibility(option)
}); });
options_ctrl.setValue(options[0])
changeShape(shape) changeShape(shape)
}); });
const options = this.getShapeOptions(shapes, this.params['shape']); const options = this.getShapeOptions(shapes, this.params['shape']);
options_ctrl = this.gui.add(this.params, 'options', options).onChange((option) => { options_ctrl = this.gui.add(this.params, 'option', options).onChange((option) => {
setVisibility(option) setVisibility(option)
}); });
this.gui.add(this.params, 'hyperplane', 1.5, 2.25); this.gui.add(this.params, 'hyperplane', 1.5, 2.25);
@ -111,7 +118,7 @@ class FourDGUI {
const guiObj = this; const guiObj = this;
this.urlParams = this.linkUrl.searchParams; this.urlParams = this.linkUrl.searchParams;
for( const param of [ "shape", "rotation", "visiblity" ]) { for( const param of [ "shape", "rotation", "option" ]) {
const value = this.urlParams.get(param); const value = this.urlParams.get(param);
if( value ) { if( value ) {
this.link[param] = value; this.link[param] = value;
@ -137,6 +144,7 @@ class FourDGUI {
copyUrl() { copyUrl() {
const url = new URL(this.linkUrl.origin + this.linkUrl.pathname); const url = new URL(this.linkUrl.origin + this.linkUrl.pathname);
url.searchParams.append("shape", this.params.shape); url.searchParams.append("shape", this.params.shape);
url.searchParams.append("option", this.params.option);
url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n'); url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n');
url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n'); url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n');
url.searchParams.append("thickness", this.params.thickness.toString()); url.searchParams.append("thickness", this.params.thickness.toString());

View File

@ -62,7 +62,7 @@ for( const face_m of face_ms ) {
} }
const STRUCTURES = [ POLYTOPES.cell120_inscribed() ]; const STRUCTURES = POLYTOPES.build_all();
const STRUCTURES_BY_NAME = {}; const STRUCTURES_BY_NAME = {};
@ -74,14 +74,14 @@ let node_show = [];
let link_show = []; let link_show = [];
function createShape(name) { function createShape(name, option) {
if( shape ) { if( shape ) {
scene.remove(shape); scene.remove(shape);
} }
structure = STRUCTURES_BY_NAME[name]; structure = STRUCTURES_BY_NAME[name];
shape = new FourDShape(node_ms, link_ms, face_ms, structure); shape = new FourDShape(node_ms, link_ms, face_ms, structure);
scene.add(shape); scene.add(shape);
setVisibility(structure.options[0].name); setVisibility(option ? option : structure.options[0].name);
} }
// initialise gui and read params from URL // initialise gui and read params from URL
@ -177,7 +177,7 @@ renderer.domElement.addEventListener("pointerup", (event) => {
dragging = false; dragging = false;
}) })
createShape(gui.params.shape); createShape(gui.params.shape, gui.params.option);
function animate() { function animate() {
requestAnimationFrame( animate ); requestAnimationFrame( animate );

View File

@ -84,7 +84,8 @@ export const cell5 = () => {
geometry: { geometry: {
node_size: 0.02, node_size: 0.02,
link_size: 0.02 link_size: 0.02
} },
options: [ { name: '--' }]
}; };
}; };
@ -113,7 +114,8 @@ export const cell16 = () => {
geometry: { geometry: {
node_size: 0.02, node_size: 0.02,
link_size: 0.02 link_size: 0.02
} },
options: [ { name: '--' }]
}; };
}; };
@ -133,6 +135,15 @@ export const tesseract = () => {
scale_nodes(nodes, Math.sqrt(2) / 2); scale_nodes(nodes, Math.sqrt(2) / 2);
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
links.map((l) => { l.label = 0 });
for( const p of [ 1, 2 ] ) {
const nodes16 = nodes.filter((n) => n.label === p);
const links16 = auto_detect_edges(nodes16, 6);
links16.map((l) => l.label = p);
links.push(...links16);
}
return { return {
name: 'tesseract', name: 'tesseract',
@ -142,36 +153,15 @@ export const tesseract = () => {
node_size: 0.02, node_size: 0.02,
link_size: 0.02 link_size: 0.02
}, },
base: {},
options: [ options: [
[ 'One inscribed 16-cell', {} ], { name: 'none', links: [ 0 ] },
[ 'Both inscribed 16-cells', {} ], { name: 'one 16-cell', links: [ 0, 1 ] },
{ name: 'both 16-cells', links: [ 0, 1, 2 ] },
], ],
}; };
} }
const tesseract_some_inscribed = (ps) => {
const t = tesseract();
const i_links = [];
for( const p of ps ) {
const nodes16 = t.nodes.filter((n) => n.label === p);
const links16 = auto_detect_edges(nodes16, 6);
links16.map((l) => l.label = p);
i_links.push(...links16);
}
t.links.push(...i_links);
return t;
}
export const tesseract_inscribed = () => tesseract_some_inscribed([1]);
export const tesseract_all_inscribed = () => tesseract_some_inscribed([1,2]);
const CELL24_INDEXING = { const CELL24_INDEXING = {
x: { y: 1, z: 3, w: 2 }, x: { y: 1, z: 3, w: 2 },
y: { z: 2, w: 3 }, y: { z: 2, w: 3 },
@ -195,7 +185,14 @@ export const cell24 = () => {
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);
for( const p of [ 1, 2, 3 ] ) {
const nodes16 = nodes.filter((n) => n.label === p);
const links16 = auto_detect_edges(nodes16, 6);
links16.map((l) => l.label = p);
links.push(...links16);
}
// links.map((l) => { // links.map((l) => {
// const ls = [ l.source, l.target ].map((nid) => node_by_id(nodes, nid).label); // const ls = [ l.source, l.target ].map((nid) => node_by_id(nodes, nid).label);
// for ( const c of [1, 2, 3] ) { // for ( const c of [1, 2, 3] ) {
@ -206,6 +203,7 @@ export const cell24 = () => {
// }); // });
return { return {
name: '24-cell',
nodes: nodes, nodes: nodes,
links: links, links: links,
geometry: { geometry: {
@ -214,32 +212,14 @@ export const cell24 = () => {
}, },
base: {}, base: {},
options: [ options: [
[ 'One inscribed 16-cell', {} ], { name: 'none', links: [ 0 ] },
[ 'All inscribed 16-cells', {} ], { name: 'one 16-cell', links: [ 0, 1 ] },
{ name: 'three 16-cells', links: [ 0, 1, 2, 3 ] }
] ]
}; };
} }
const cell24_some_inscribed = (ps) => {
const t = cell24();
const i_links = [];
for( const p of ps ) {
const nodes16 = t.nodes.filter((n) => n.label === p);
const links16 = auto_detect_edges(nodes16, 6);
links16.map((l) => l.label = p);
i_links.push(...links16);
}
t.links.push(...i_links);
return t;
}
export const cell24_inscribed = () => cell24_some_inscribed([1]);
export const cell24_all_inscribed = () => cell24_some_inscribed([1,2,3]);
@ -413,28 +393,6 @@ function link_labels(nodes, link) {
export const cell120 = () => {
const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4);
label_120cell(nodes);
return {
name: '120-cell',
nodes: nodes,
links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
},
base: {},
options: [
[ 'One inscribed 600-cell', {} ],
[ 'All inscribed 600-cells', {} ],
]
}
}
export const cell120_layered = (max) => { export const cell120_layered = (max) => {
const nodes = make_120cell_vertices(); const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
@ -473,7 +431,7 @@ export const cell120_inscribed = () => {
} }
return { return {
name: '120-cell inscribed', name: '120-cell',
nodes: nodes, nodes: nodes,
links: links, links: links,
geometry: { geometry: {
@ -482,14 +440,12 @@ export const cell120_inscribed = () => {
}, },
options: [ options: [
{ name: "none", links: [ 0 ]}, { name: "none", links: [ 0 ]},
{ name: "one", links: [ 0, 1 ] }, { name: "one inscribed 600-cell", links: [ 0, 1 ] },
{ name: "all", links: [ 0, 1, 2, 3, 4, 5 ] } { name: "five inscribed 600-cells", links: [ 0, 1, 2, 3, 4, 5 ] }
] ]
} }
} }
// export const cell120_inscribed = () => cell120_some_inscribed([1]);
// export const cell120_all_inscribed = () => cell120_some_inscribed([1,2,3,4,5]);
// Schoute's partition via https://arxiv.org/abs/1010.4353 // Schoute's partition via https://arxiv.org/abs/1010.4353
@ -667,48 +623,31 @@ export const cell600 = () => {
const nodes = make_600cell_vertices(); const nodes = make_600cell_vertices();
const links = auto_detect_edges(nodes, 12); const links = auto_detect_edges(nodes, 12);
links.map((l) => l.label = 0);
for( const p of [1, 2, 3, 4, 5]) {
const nodes24 = nodes.filter((n) => n.label === p);
const links24 = auto_detect_edges(nodes24, 8);
links24.map((l) => l.label = p);
links.push(...links24);
}
return { return {
name: '600-cell',
nodes: nodes, nodes: nodes,
links: links, links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
}
}
}
const cell600_some_inscribed = (ps) => {
const nodes = make_600cell_vertices();
const links = auto_detect_edges(nodes, 12);
const all_links = links;
all_links.map((l) => l.label = 0);
for( const p of ps) {
const nodes24 = nodes.filter((n) => n.label === p);
const links24 = auto_detect_edges(nodes24, 8);
links24.map((l) => l.label = p);
all_links.push(...links24);
}
return {
nodes: nodes,
links: all_links,
geometry: { geometry: {
node_size: 0.02, node_size: 0.02,
link_size: 0.02 link_size: 0.02
}, },
options: [
{ name: "none", links: [ 0 ]},
{ name: "one 24-cell", links: [ 0, 1 ] },
{ name: "five 24-cells", links: [ 0, 1, 2, 3, 4, 5 ] }
]
} }
} }
export const cell600_inscribed = () => cell600_some_inscribed([1]);
export const cell600_all_inscribed = () => cell600_some_inscribed([1,2,3,4,5]);
function make_dodecahedron_vertices() { function make_dodecahedron_vertices() {
const phi = 0.5 * (1 + Math.sqrt(5)); const phi = 0.5 * (1 + Math.sqrt(5));
const phiinv = 1 / phi; const phiinv = 1 / phi;
@ -746,42 +685,41 @@ function make_dodecahedron_vertices() {
export const dodecahedron = () => { export const dodecahedron = () => {
const nodes = make_dodecahedron_vertices(); const nodes = make_dodecahedron_vertices();
const links = auto_detect_edges(nodes, 3); const links = auto_detect_edges(nodes, 3);
links.map((l) => l.label = 0);
for( const p of [ 1, 2, 3, 4, 5 ]) {
const tetran = nodes.filter((n) => n.label === p);
const tetral = auto_detect_edges(tetran, 3);
tetral.map((l) => l.label = p);
links.push(...tetral);
}
return { return {
name: 'dodecahedron',
nodes: nodes, nodes: nodes,
links: links, links: links,
geometry: {
node_size: 0.02,
link_size: 0.02
}
}
}
const dodecahedron_some_inscribed = (ps) => {
const nodes = make_dodecahedron_vertices();
const links = auto_detect_edges(nodes, 3);
const all_links = links;
all_links.map((l) => l.label = 0);
for( const p of ps) {
const tetran = nodes.filter((n) => n.label === p);
const tetral = auto_detect_edges(tetran, 3);
tetral.map((l) => l.label = p);
all_links.push(...tetral);
}
return {
nodes: nodes,
links: all_links,
geometry: { geometry: {
node_size: 0.02, node_size: 0.02,
link_size: 0.02 link_size: 0.02
}, },
options: [
{ name: "none", links: [ 0 ]},
{ name: "one tetrahedron", links: [ 0, 1 ] },
{ name: "five tetrahedra", links: [ 0, 1, 2, 3, 4, 5 ] }
]
} }
} }
export const dodecahedron_inscribed = () => dodecahedron_some_inscribed([1]); export const build_all = () => {
export const dodecahedron_all_inscribed = () => dodecahedron_some_inscribed([1,2,3,4,5]); return [
dodecahedron(),
cell5(),
cell16(),
tesseract(),
cell24(),
cell600(),
cell120_inscribed()
];
}