Merge branch 'feature-120-cell-index'
commit
f3bd62d2c2
|
@ -5,13 +5,6 @@ Steps forward -
|
|||
|
||||
2. using this, generate a list of all 120 dodecahedra:
|
||||
|
||||
[ a b c d e f g h i j k l m n o p q r s t ] <- 20 vertices
|
||||
|
||||
Check that each vertex appears in four of these
|
||||
|
||||
Then - either manually start labelling them, or build an interface to help
|
||||
with the manual labelling
|
||||
|
||||
|
||||
|
||||
1.
|
||||
|
@ -30,7 +23,31 @@ the last five.
|
|||
|
||||
|
||||
|
||||
2. have tried manual labelling and it will drive me crazy before I finish
|
||||
|
||||
3. Automated approach based on what I've got so far:
|
||||
|
||||
- should be possible to colour a single dodecahedron from a single face and
|
||||
one other vertex (to pick a chirality)
|
||||
|
||||
- write a function to do this - the compound-of-four-tetrahedra map can be
|
||||
more or less hard coded: follow the pattern 1-2-3-4-5, 3-4-5-1-2, etc out
|
||||
from the inner ring, and map the original face's permutation
|
||||
|
||||
From this:
|
||||
|
||||
- colour the first dodecahedron, picking a chirality
|
||||
|
||||
- the next vertices from each of this dodecahedron's vertices have colours
|
||||
which come from the first dodeca
|
||||
|
||||
- these can be used to colour the next layer of dodecahedra
|
||||
|
||||
- and so on
|
||||
|
||||
Alternatively:
|
||||
|
||||
- do it by the discrete Hopf fibration, one fibre at a time
|
||||
|
||||
|
||||
|
||||
|
|
111
polytopes.js
111
polytopes.js
|
@ -303,7 +303,7 @@ function label_faces_120cell(nodes, faces, cfaces, label) {
|
|||
}
|
||||
|
||||
|
||||
function manual_label_120cell(nodes, links) {
|
||||
function basic_auto_label_120cell(nodes, links) {
|
||||
|
||||
const faces = auto_120cell_faces(links);
|
||||
const dodecas = DODECAHEDRA.DODECAHEDRA;
|
||||
|
@ -332,11 +332,118 @@ function manual_label_120cell(nodes, links) {
|
|||
|
||||
}
|
||||
|
||||
// manual compound-of-tetrahedra colouring
|
||||
|
||||
function manual_label_120cell(nodes, links) {
|
||||
label_nodes(nodes, [1, 153, 29, 105], 1);
|
||||
label_nodes(nodes, [317, 409, 265, 109], 2);
|
||||
label_nodes(nodes, [221, 337, 25, 509], 3);
|
||||
label_nodes(nodes, [217, 413, 457, 361], 4);
|
||||
label_nodes(nodes, [313, 157, 461, 505], 5);
|
||||
|
||||
|
||||
// second dodecahedron needs to have opposite chirality
|
||||
|
||||
label_nodes(nodes, [ 165, 33, 117 ], 1);
|
||||
label_nodes(nodes, [ 161, 465, 517 ], 2);
|
||||
label_nodes(nodes, [ 417, 469, 365 ], 3);
|
||||
label_nodes(nodes, [ 341, 37, 513 ], 4);
|
||||
label_nodes(nodes, [ 421, 269, 113 ], 5);
|
||||
|
||||
// third
|
||||
|
||||
label_nodes(nodes, [ 45, 101, 181 ], 1);
|
||||
label_nodes(nodes, [ 241, 429, 53 ], 2);
|
||||
label_nodes(nodes, [ 93, 229 ], 3);
|
||||
label_nodes(nodes, [ 173, 437 ], 4);
|
||||
label_nodes(nodes, [ 245, 325 ], 5);
|
||||
|
||||
// fourth (id = 3)
|
||||
|
||||
label_nodes(nodes, [ 89, 169, 49 ], 1);
|
||||
label_nodes(nodes, [ 321 ], 2);
|
||||
label_nodes(nodes, [ 425, 177 ], 3);
|
||||
label_nodes(nodes, [ 97, 225 ], 4);
|
||||
label_nodes(nodes, [ 41, 433], 5);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function meridian_label_120cell(nodes, links) {
|
||||
|
||||
const DODECAS = [
|
||||
[
|
||||
313, 1, 317, 221, 217, 417,
|
||||
341, 421, 165, 161, 465, 469,
|
||||
37, 269, 33, 113, 117, 517,
|
||||
365, 513
|
||||
],
|
||||
[
|
||||
513, 365, 517, 117, 113, 577,
|
||||
15, 581, 565, 561, 397, 399,
|
||||
85, 389, 81, 301, 303, 213,
|
||||
293, 209
|
||||
],
|
||||
[
|
||||
301, 209, 293, 213, 303,
|
||||
211, 309, 294, 311, 215,
|
||||
310, 210, 214, 312, 295,
|
||||
212, 302, 304, 216, 296
|
||||
],
|
||||
[
|
||||
304, 302, 212, 296, 216, 400,
|
||||
398, 84, 392, 88, 16, 580,
|
||||
564, 568, 584, 368, 516, 116,
|
||||
120, 520
|
||||
],
|
||||
[
|
||||
368, 516, 116, 120, 520, 272,
|
||||
36, 468, 472, 40, 164, 420,
|
||||
344, 424, 168, 220, 316, 4,
|
||||
320, 224
|
||||
],
|
||||
[
|
||||
316, 4, 320, 224, 220, 412,
|
||||
340, 416, 160, 156, 460, 464,
|
||||
32, 268, 28, 108, 112, 512,
|
||||
364, 508
|
||||
],
|
||||
[
|
||||
508, 364, 512, 112, 108, 572,
|
||||
14, 576, 560, 556, 394, 396,
|
||||
80, 388, 76, 298, 300, 208,
|
||||
292, 204
|
||||
],
|
||||
[
|
||||
300, 298, 204, 292, 208,
|
||||
206, 202, 306, 291, 308,
|
||||
290, 305, 203, 207, 307,
|
||||
289, 201, 297, 299, 205
|
||||
],
|
||||
[
|
||||
299, 297, 201, 289, 205, 395,
|
||||
393, 73, 385, 77, 13, 569,
|
||||
553, 557, 573, 361, 505, 105,
|
||||
109, 509
|
||||
],
|
||||
[
|
||||
361, 505, 105, 109, 509, 265,
|
||||
25, 457, 461, 29, 153, 409,
|
||||
337, 413, 157, 217, 313, 1,
|
||||
317, 221
|
||||
]
|
||||
]
|
||||
|
||||
let col = 1;
|
||||
for( const dd of DODECAS ) {
|
||||
label_nodes(nodes, dd, 5);
|
||||
col++;
|
||||
if( col > 5 ) {
|
||||
col = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -344,7 +451,7 @@ export const cell120 = () => {
|
|||
const nodes = make_120cell_vertices();
|
||||
const links = auto_detect_edges(nodes, 4);
|
||||
|
||||
manual_label_120cell(nodes, links);
|
||||
meridian_label_120cell(nodes, links);
|
||||
|
||||
return {
|
||||
nodes: nodes,
|
||||
|
|
170
testbed.js
170
testbed.js
|
@ -361,6 +361,148 @@ function make_dodecahedron(faces, f1, f2) {
|
|||
}
|
||||
|
||||
|
||||
function faces_to_dodecahedron(faces, f1, f2) {
|
||||
const dodecahedron = [ f1, f2 ];
|
||||
|
||||
// take f1 as the 'center', get the other four around it from f2
|
||||
const fs = find_dodeca_mutuals(faces, f1, f2);
|
||||
const f3 = fs[0];
|
||||
const f6 = fs[1];
|
||||
dodecahedron.push(f3);
|
||||
const f4 = find_dodeca_next(faces, dodecahedron, f1, f3);
|
||||
dodecahedron.push(f4);
|
||||
const f5 = find_dodeca_next(faces, dodecahedron, f1, f4);
|
||||
dodecahedron.push(f5);
|
||||
dodecahedron.push(f6);
|
||||
|
||||
// get the next ring
|
||||
|
||||
const f7 = find_dodeca_next(faces, dodecahedron, f6, f2);
|
||||
dodecahedron.push(f7);
|
||||
const f8 = find_dodeca_next(faces, dodecahedron, f2, f3);
|
||||
dodecahedron.push(f8);
|
||||
const f9 = find_dodeca_next(faces, dodecahedron, f3, f4);
|
||||
dodecahedron.push(f9);
|
||||
const f10 = find_dodeca_next(faces, dodecahedron, f4, f5);
|
||||
dodecahedron.push(f10);
|
||||
const f11 = find_dodeca_next(faces, dodecahedron, f5, f6);
|
||||
dodecahedron.push(f11);
|
||||
|
||||
// get the last
|
||||
|
||||
const f12 = find_dodeca_next(faces, dodecahedron, f7, f8);
|
||||
dodecahedron.push(f12);
|
||||
|
||||
return dodecahedron;
|
||||
}
|
||||
|
||||
// from a face and one neighbouring node, return a dodecahedron
|
||||
|
||||
function face_plus_to_dodecahedron(faces, f1, node) {
|
||||
const neighbours = find_adjacent_faces(faces, f1);
|
||||
const nodens = neighbours.filter((f) => f.nodes.includes(node));
|
||||
return faces_to_dodecahedron(faces, f1, nodens[0]); // does it matter which?
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// for three faces, return their common vertex (if they have one)
|
||||
|
||||
function find_dodeca_vertex(f1, f2, f3) {
|
||||
const v12 = f1.nodes.filter((n) => f2.nodes.includes(n));
|
||||
const v123 = v12.filter((n) => f3.nodes.includes(n));
|
||||
if( v123.length === 1 ) {
|
||||
return v123[0];
|
||||
} else {
|
||||
console.log(`warning: faces ${f1.id} ${f2.id} ${f3.id} don't share 1 vertex`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const VERTEX_MAP = [
|
||||
[ 0, 1, 5 ],
|
||||
[ 0, 1, 2 ],
|
||||
[ 0, 2, 3 ],
|
||||
[ 0, 3, 4 ],
|
||||
[ 0, 4, 5 ],
|
||||
[ 1, 5, 6 ],
|
||||
[ 1, 2, 7 ],
|
||||
[ 2, 3, 8 ],
|
||||
[ 3, 4, 9 ],
|
||||
[ 4, 5, 10 ],
|
||||
[ 1, 6, 7 ],
|
||||
[ 2, 7, 8 ],
|
||||
[ 3, 8, 9 ],
|
||||
[ 4, 9, 10 ],
|
||||
[ 5, 6, 10 ],
|
||||
[ 6, 7, 11 ],
|
||||
[ 7, 8, 11 ],
|
||||
[ 8, 9, 11 ],
|
||||
[ 9, 10, 11 ],
|
||||
[ 6, 10, 11 ],
|
||||
];
|
||||
|
||||
|
||||
|
||||
function dodecahedron_vertices(faces) {
|
||||
const face_sets = VERTEX_MAP.map((vs) => vs.map((v) => faces[v]));
|
||||
return face_sets.map((fs) => find_dodeca_vertex(...fs));
|
||||
}
|
||||
|
||||
// p is the permutation of the first face
|
||||
|
||||
function dodecahedron_colours(vertices, p) {
|
||||
const LEFT_PART = [
|
||||
1, 2, 3, 4, 5, 3, 4, 5, 1, 2, 5, 1, 2, 3, 4, 2, 3, 4, 5, 1,
|
||||
];
|
||||
const RIGHT_PART = [
|
||||
1, 2, 3, 4, 5, 4, 5, 1, 2, 3, 3, 4, 5, 1, 2, 1, 2, 3, 4, 5,
|
||||
];
|
||||
const part = LEFT_PART;
|
||||
const colours = {};
|
||||
for( let i = 0; i < 20; i++ ) {
|
||||
const v = vertices[i];
|
||||
const colour = p[part[i] - 1];
|
||||
colours[v] = colour;
|
||||
}
|
||||
return colours;
|
||||
}
|
||||
|
||||
|
||||
// p is the permutation of the first face
|
||||
|
||||
function colour_one_dodecahedron(faces, face, node, p) {
|
||||
const dd = face_plus_to_dodecahedron(faces, face, node);
|
||||
const vertices = dodecahedron_vertices(dd);
|
||||
return dodecahedron_colours(vertices, p);
|
||||
}
|
||||
|
||||
|
||||
// go along a meridian
|
||||
|
||||
function meridian(faces, startf, startn) {
|
||||
const dds = [ face_plus_to_dodecahedron(faces, startf, startn) ];
|
||||
|
||||
while( dds.length < 10 ) {
|
||||
const dd = dds[dds.length - 1];
|
||||
const nextf = dd[11]; // opposite to startf
|
||||
const neighbours = find_adjacent_faces(faces, nextf);
|
||||
const nextnbors = neighbours.filter((f) => !dd.includes(f));
|
||||
|
||||
const nextdd = faces_to_dodecahedron(faces, nextf, nextnbors[0]);
|
||||
|
||||
|
||||
dds.push(nextdd);
|
||||
}
|
||||
|
||||
return dds;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// for a face, pick an edge, and then find the other two faces which
|
||||
// share this edge. These can be used as the starting points for the
|
||||
// first face's two dodecahedra
|
||||
|
@ -392,13 +534,20 @@ function dd_fingerprint(dodecahedron) {
|
|||
function make_120cell_cells(faces) {
|
||||
const dodecas = [];
|
||||
const seen = {};
|
||||
let i = 1;
|
||||
for( const face of faces ) {
|
||||
const dds = face_to_dodecahedra(faces, face);
|
||||
for( const dd of dds ) {
|
||||
const fp = dd_fingerprint(dd);
|
||||
if( ! (fp in seen) ) {
|
||||
//console.log(`added dodeca ${fp}`);
|
||||
dodecas.push(dd);
|
||||
const d = {
|
||||
id: i,
|
||||
faces: dd,
|
||||
nodes: dodecahedron_vertices(dd),
|
||||
}
|
||||
dodecas.push(d);
|
||||
i += 1;
|
||||
seen[fp] = 1;
|
||||
}
|
||||
}
|
||||
|
@ -422,19 +571,20 @@ const cell120 = () => {
|
|||
}
|
||||
|
||||
|
||||
function dodeca_nodes(dd) {
|
||||
const ns = new Set();
|
||||
for( const face of dd.faces ) {
|
||||
for( const node of face.nodes ) {
|
||||
ns.add(node);
|
||||
}
|
||||
}
|
||||
dd.nodes = Array.from(ns);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const nodes = make_120cell_vertices();
|
||||
const links = auto_detect_edges(nodes, 4);
|
||||
const faces = auto_120cell_faces(links);
|
||||
const dodecas = make_120cell_cells(faces);
|
||||
|
||||
const ddfaces = dodecas.map((dd) => dd.map((f) => f.id));
|
||||
|
||||
console.log(JSON.stringify(ddfaces));
|
||||
|
||||
// for( const dodeca of dodecas ) {
|
||||
// console.log(dodeca.map((f) => f.id)
|
||||
// }
|
||||
//const dodecas = make_120cell_cells(faces);
|
||||
|
||||
|
|
Loading…
Reference in New Issue