Successfully auto-coloured a single dodecahedron

feature-120-cell-index
Mike Lynch 2023-08-25 18:08:22 +10:00
parent 2808b256a2
commit 8a926f0552
3 changed files with 174 additions and 22 deletions

View File

@ -5,13 +5,6 @@ Steps forward -
2. using this, generate a list of all 120 dodecahedra: 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. 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

View File

@ -341,6 +341,7 @@ function manual_label_120cell(nodes, links) {
label_nodes(nodes, [217, 413, 457, 361], 4); label_nodes(nodes, [217, 413, 457, 361], 4);
label_nodes(nodes, [313, 157, 461, 505], 5); label_nodes(nodes, [313, 157, 461, 505], 5);
// second dodecahedron needs to have opposite chirality // second dodecahedron needs to have opposite chirality
label_nodes(nodes, [ 165, 33, 117 ], 1); label_nodes(nodes, [ 165, 33, 117 ], 1);
@ -349,10 +350,38 @@ function manual_label_120cell(nodes, links) {
label_nodes(nodes, [ 341, 37, 513 ], 4); label_nodes(nodes, [ 341, 37, 513 ], 4);
label_nodes(nodes, [ 421, 269, 113 ], 5); 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 semiautomatic_label_120cell(nodes, links) {
const COLOURS = {
1: [ 313, 157, 461, 505 ],
2: [ 1, 153, 29, 105 ],
3: [ 317, 409, 265, 109 ],
4: [ 221, 337, 25, 509 ],
5: [ 217, 413, 457, 361 ]
};
for( const col in COLOURS ) {
label_nodes(nodes, COLOURS[col], col);
}
}
@ -362,7 +391,7 @@ export const cell120 = () => {
const nodes = make_120cell_vertices(); const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
manual_label_120cell(nodes, links); semiautomatic_label_120cell(nodes, links);
return { return {
nodes: nodes, nodes: nodes,

View File

@ -360,6 +360,107 @@ function make_dodecahedron(faces, f1, f2) {
return dodecahedron; return dodecahedron;
} }
// goal - a version of the above which collates the nodes to
// a standard 'layout' on the dodecahedron, so that it's then easy
// to colour them automatically
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;
}
// 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;
}
}
function dodecahedron_vertices(dodeca) {
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 ],
];
return VERTEX_MAP.map((vs) => find_dodeca_vertex(...vs.map((v) => dd[v])));
}
function dodecahedron_colours(vertices, left) {
const PARTITION = [
1, 2, 3, 4, 5, 3, 4, 5, 1, 2, 5, 1, 2, 3, 4, 2, 3, 4, 5, 1,
];
const colours = { 1: [], 2: [], 3: [], 4: [], 5: [] };
for( let i = 0; i < 20; i++ ) {
colours[PARTITION[i]].push(vertices[i]);
}
return colours;
}
// for a face, pick an edge, and then find the other two faces which // 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 // share this edge. These can be used as the starting points for the
@ -392,13 +493,20 @@ function dd_fingerprint(dodecahedron) {
function make_120cell_cells(faces) { function make_120cell_cells(faces) {
const dodecas = []; const dodecas = [];
const seen = {}; const seen = {};
let i = 1;
for( const face of faces ) { for( const face of faces ) {
const dds = face_to_dodecahedra(faces, face); const dds = face_to_dodecahedra(faces, face);
for( const dd of dds ) { for( const dd of dds ) {
const fp = dd_fingerprint(dd); const fp = dd_fingerprint(dd);
if( ! (fp in seen) ) { if( ! (fp in seen) ) {
//console.log(`added dodeca ${fp}`); //console.log(`added dodeca ${fp}`);
dodecas.push(dd); const d = {
id: i,
faces: dd
}
dodeca_nodes(d);
dodecas.push(d);
i += 1;
seen[fp] = 1; seen[fp] = 1;
} }
} }
@ -422,22 +530,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 nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
const faces = auto_120cell_faces(links); const faces = auto_120cell_faces(links);
const dodecas = make_120cell_cells(faces); //const dodecas = make_120cell_cells(faces);
const ddfaces = dodecas.map((dd) => dd.map((f) => f.id));
//console.log(JSON.stringify(ddfaces));
const dd0 = dodecas[0];
// for( const dodeca of dodecas ) {
// console.log(dodeca.map((f) => f.id)
// }