Finished layer-by-layer visualisation of 120-cell

feature-120-cell-layers
Mike Lynch 2023-11-02 14:10:13 +11:00
parent 7323935a1f
commit 6f1c5a58e6
4 changed files with 276 additions and 86 deletions

View File

@ -45,57 +45,48 @@ export const INDEX = {
] ]
}; };
export const LAYERS = { export const LAYERS = {
"0": [ "0": [154,266,158,222,218,250,254,162,268,156,160,252,256,166,270,272,
1,317,221,217,313,341,465,417,469,421,37,165,161,269,33,513,113, 164,220,224,168],
117,517,365 "1": [2,318,314,30,414,510,362,26,506,410,338,458,462,110,
106,6,350,346,34,482,418,474,330,442,450,98,90,14,
364,28,508,476,394,570,572,124,122,478,348,32,480,
512,396,576,574,126,128,8,352,38,422,486,334,454,
446,94,102,514,366,518,342,470,466,114,118,16,368,
36,484,516,398,580,578,130,132,412,316,420,332,452,
444,92,100,4,320,416,340,464,460,108,112,40,488,424,
336,448,456,104,96,520,400,582,584,136,134,344,468,472,120,116],
"2":[246,242,42,170,426,50,434,178,226,322,46,430,174,54,182,438,326,
230,78,558,526,62,494,542,590,142,74,554,386,300,298,202,290,206,
522,58,538,490,138,586,236,234,186,60,540,188,282,378,66,546,194,
68,196,548,382,286,498,82,562,530,146,594,76,556,204,80,208,560,
388,292,588,44,428,492,140,524,64,544,380,238,190,240,192,284,
592,496,432,48,528,144,70,198,550,72,552,200,288,384,502,534,566,
86,598,150,390,302,210,304,214,294,84,212,564,88,568,216,296,392,
596,500,436,52,532,148,324,244,172,248,180,228,176,56,440,184,232,
328,504,536,152,600],
"3":[369,273,275,371,17,353,257,261,357,9,401,305,306,402,21,307,308,
403,22,404,259,263,355,11,359,277,279,373,19,375,309,310,405,23,
406,258,262,354,10,358,274,276,370,18,372,356,260,264,360,12,407,
311,312,408,24,374,278,280,376,20],"4":[229,325,173,45,429,493,
141,525,589,289,385,557,77,205,201,137,521,553,73,585,285,381,
193,65,545,593,145,497,529,225,321,433,49,177,139,587,491,281,377,
539,59,187,283,379,189,61,541,197,287,199,237,239,191,293,389,213,
149,533,565,85,597,295,391,211,147,531,563,83,595,227,323,171,43,
427,523,151,503,535,231,327,439,55,183,599,383,551,71,87,215,567,
169,241,245,181,489,425,41,185,233,235,195,537,57,591,543,63,495,
143,549,69,501,179,499,435,51,175,431,47,527,203,291,387,555,75,
207,299,297,559,79,437,53,209,561,81,301,303,547,67,243,247],
"5":[457,337,461,105,109,469,341,465,117,113,89,97,441,449,329,93,445,
101,453,333,573,395,125,127,575,121,569,393,123,571,451,331,443,
99,91,129,577,131,579,397,107,459,111,339,463,95,447,335,103,455,
133,135,581,583,399,115,119,467,471,343
], ],
"1": [ "6":[1,417,313,409,413,317,421,5,475,345,473,481,349,483,33,513,507,
337,457,409,25,153,265,157,29,413,461,105,109,505,361,509,245,241, 13,363,511,7,487,351,485,37,517,15,519,367,515,3,423,319,415,39,
49,177,97,433,89,41,425,169,225,321,93,101,53,437,181,45,173,429, 25,505,509,477,29,411,27,479,347,31,365,419,35,315,361
325,229,251,255,485,351,453,477,445,347,7,333,249,253,271,163,167,
267,155,219,223,159,481,449,349,473,345,441,329,5,529,561,81,577,
129,65,545,497,145,593,533,565,389,373,277,279,375,19,581,133,85,
69,501,549,597,149,15,367,399,39,519,583,135,487,397,579,515,35,
483,131,303,301,209,293,213
], ],
"2":[ "7":[217,153,221,157,265,161,165,269,249,253,251,255,267,159,155,
521,553,385,557,525,273,275,369,17,371,569,121,73,57,489,537,585, 163,219,271,223,167]
137,13,363,393,27,507,571,123,475,573,125,395,575,511,31,479,127, };
77,61,541,493,141,589,178,226,170,174,242,230,182,246,9,322,357,
498,434,50,530,146,353,257,185,261,193,233,11,355,359,263,259,189,
237,197,326,54,438,502,150,534,335,447,455,95,103,415,319,423,239,
71,199,551,383,287,419,315,411,331,443,451,99,91,3,343,471,467,115,
119,235,67,547,195,285,381,405,309,594,390,562,294,210,82,23,406,
595,310,211,83,566,86,214,598,407,311,24,408,312,599,87,215,567,
563,295,391
],
"3":[
297,201,299,205,289,42,426,490,138,522,494,430,46,526,142,63,543,
191,283,379,339,459,463,111,107,59,187,539,377,281,546,382,286,194,
66,114,118,466,342,470,384,288,550,70,198,503,439,55,535,151,51,435,
499,147,531,212,296,302,304,216
],
"4":[
386,554,290,74,202,586,401,305,558,78,590,206,307,403,21,402,306,
587,75,203,555,79,559,207,291,387,591,308,404,22,462,338,458,110,
106,2,410,314,418,98,90,450,58,186,442,330,234,282,378,538,62,190,
238,94,102,446,334,454,284,380,542,422,414,318,495,431,327,260,264,
356,12,360,47,527,143,200,192,240,43,427,323,247,243,171,227,179,491,
523,139,183,175,231,258,262,358,354,10,196,236,188,130,578,398,596,
548,132,580,84,514,34,482,148,68,500,582,518,400,366,16,134,486,38,
600,552,88,136,584,152,72,504,20,376,392,536,568,374,278,280,532,564
],
"5":[
570,394,298,300,506,14,362,396,574,510,122,474,26,204,208,292,126,
30,478,588,540,76,124,572,140,60,492,18,370,388,524,556,372,276,274,
592,144,80,528,560,544,64,496,222,218,154,266,158,162,270,166,6,346,
350,254,250,332,452,484,444,476,8,348,336,448,480,128,352,488,456,
252,256,328,232,432,176,48,440,56,184,104,96,324,228,172,428,44,
180,52,436,248,244,92,100,516,368,36,272,164,116,520,120,468,420,
40,168,472,424,344
],
"6":[364,268,508,28,156,576,512,108,112,32,160,460,412,464,340,416,
220,224,316,320,4
]
}

View File

@ -5,7 +5,7 @@ export const get_colours = (basis) => {
const hexbasis = basis.toString(16).padStart(6, "0"); const hexbasis = basis.toString(16).padStart(6, "0");
scheme.from_hex(hexbasis).scheme("tetrade").variation("hard").distance(0.5); scheme.from_hex(hexbasis).scheme("tetrade").variation("hard").distance(0.5);
const colours = scheme.colors().map((cs) => parseInt('0x' + cs)); const colours = scheme.colors().map((cs) => parseInt('0x' + cs));
const set = colours.slice(1, 6); const set = colours.slice(1, 9);
set.reverse(); set.reverse();
set.unshift(colours[0]); set.unshift(colours[0]);
return set; return set;

View File

@ -530,6 +530,33 @@ function meridian(nodes, links, faces, startf, startn, dir=11, max=10) {
} }
function meridian_bump(nodes, links, faces, startf, startn, bumpdir=6) {
const o = face_plus_to_dodecahedron(faces, startf, startn);
const dir = 11;
const max = 10;
const colours = colour_dodecahedron_from_face(o, [ 1, 2, 3, 4, 5 ] );
const dds = follow_meridian(nodes, links, faces, colours, o, dir, max);
const dd4 = dds[4];
const nextf = dd4[bumpdir];
const bump = follow_face_to_dodeca(faces, dd4, nextf);
const ncolours = colour_next_dodeca_maybe(nodes, links, faces, colours, dd4, nextf, bump);
add_colours(colours, ncolours);
const labels = { 1: [], 2:[], 3:[], 4:[], 5:[] };
for( const vstr in colours ) {
labels[colours[vstr]].push(Number(vstr));
}
return { dodecahedra: dds, labels: labels };
}
function all_meridians(nodes, links, faces, startf, startn) { function all_meridians(nodes, links, faces, startf, startn) {
const o = face_plus_to_dodecahedron(faces, startf, startn); const o = face_plus_to_dodecahedron(faces, startf, startn);
@ -674,6 +701,116 @@ function arctic(nodes, links, faces, startf, startn, max) {
export function label_120cell(nodes, links, faces, startf, startn) { export function label_120cell(nodes, links, faces, startf, startn) {
const pole = face_plus_to_dodecahedron(faces, startf, startn); const pole = face_plus_to_dodecahedron(faces, startf, startn);
const dds = [ pole ]; const dds = [ pole ];
const seen = {};
seen[dd_fingerprint(pole)] = true;
const colours = colour_dodecahedron_from_face(dds[0], [ 1, 2, 3, 4, 5 ] );
const vs = dodecahedron_vertices(dds[0]);
for( const face of pole ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, pole, face
);
add_colours(colours, ncolours);
dds.push(nextdd);
seen[dd_fingerprint(nextdd)] = true;
}
for( const a of dds.slice(1, 13) ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dds.push(nextdd);
seen[fp] = true;
}
}
}
// meridians = 45
for( const a of dds.slice(1, 13) ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[11]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dds.push(nextdd);
seen[fp] = true;
}
}
// the 30 equatorials?
for( const a of dds.slice(13, 46) ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dds.push(nextdd);
seen[fp] = true;
}
}
}
for( const a of dds.slice(33, 76) ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dds.push(nextdd);
seen[fp] = true;
}
}
}
// this should get the rest or explode!
for( const a of dds ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dds.push(nextdd);
seen[fp] = true;
}
}
}
const labels = { 1: [], 2:[], 3:[], 4:[], 5:[] };
for( const vstr in colours ) {
labels[colours[vstr]].push(Number(vstr));
}
return { dodecahedra: dds, labels: labels };
}
export function cell120_layers(nodes, links, faces, startf, startn, max_layer) {
const pole = face_plus_to_dodecahedron(faces, startf, startn);
const dds = [ pole ];
const dd_families = { "0": [ pole ] } const dd_families = { "0": [ pole ] }
const seen = {}; const seen = {};
@ -682,6 +819,9 @@ export function label_120cell(nodes, links, faces, startf, startn) {
const colours = colour_dodecahedron_from_face(dds[0], [ 1, 2, 3, 4, 5 ] ); const colours = colour_dodecahedron_from_face(dds[0], [ 1, 2, 3, 4, 5 ] );
const vs = dodecahedron_vertices(dds[0]); const vs = dodecahedron_vertices(dds[0]);
// arctic
if( max_layer > 0 ) {
dd_families["1"] = []; dd_families["1"] = [];
for( const face of pole ) { for( const face of pole ) {
@ -693,15 +833,14 @@ export function label_120cell(nodes, links, faces, startf, startn) {
dd_families["1"].push(nextdd); dd_families["1"].push(nextdd);
seen[dd_fingerprint(nextdd)] = true; seen[dd_fingerprint(nextdd)] = true;
} }
}
// go around all of the arctic circle and grow all faces // subarctic - interstitial
// 1, 12, 20, 12, 30 = 75
// 0 1 13, 33, 45
if( max_layer > 1 ) {
dd_families["2"] = []; dd_families["2"] = [];
for( const a of dds.slice(1, 13) ) { for( const a of dd_families["1"] ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) { for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour( const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i] nodes, links, faces, colours, a, a[i]
@ -715,11 +854,13 @@ export function label_120cell(nodes, links, faces, startf, startn) {
} }
} }
} }
}
// tropic of cancer
// meridians = 45 if( max_layer > 2 ) {
dd_families["3"] = []; dd_families["3"] = [];
for( const a of dds.slice(1, 13) ) {
for( const a of dd_families["1"] ) {
const [ nextdd, ncolours ] = follow_and_colour( const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[11] nodes, links, faces, colours, a, a[11]
); );
@ -731,9 +872,10 @@ export function label_120cell(nodes, links, faces, startf, startn) {
seen[fp] = true; seen[fp] = true;
} }
} }
}
// the 30 equatorials? if( max_layer > 3 ) {
// equator
dd_families["4"] = []; dd_families["4"] = [];
@ -751,10 +893,12 @@ export function label_120cell(nodes, links, faces, startf, startn) {
} }
} }
} }
}
if( max_layer > 4 ) {
dd_families["5"] = []; dd_families["5"] = [];
for( const a of dds.slice(33, 76) ) { for( const a of dd_families["4"] ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) { for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour( const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i] nodes, links, faces, colours, a, a[i]
@ -768,28 +912,7 @@ export function label_120cell(nodes, links, faces, startf, startn) {
} }
} }
} }
// this should get the rest or explode!
dd_families["6"] = [];
for( const a of dds ) {
for( const i of [ 6, 7, 8, 9, 10 ] ) {
const [ nextdd, ncolours ] = follow_and_colour(
nodes, links, faces, colours, a, a[i]
);
const fp = dd_fingerprint(nextdd);
if( !(fp in seen) ) {
add_colours(colours, ncolours);
dd_families["6"].push(nextdd);
dds.push(nextdd);
seen[fp] = true;
} }
}
}
const labels = { 1: [], 2:[], 3:[], 4:[], 5:[] }; const labels = { 1: [], 2:[], 3:[], 4:[], 5:[] };
for( const vstr in colours ) { for( const vstr in colours ) {
@ -919,7 +1042,7 @@ function meridian_label_120cell(nodes) {
//label_nodes(nodes, [313], 6); //label_nodes(nodes, [313], 6);
} }
1
function check_120cell_nodes(nodes) { function check_120cell_nodes(nodes) {
nodes.map((n) => { nodes.map((n) => {
const vs = find_adjacent_labels(nodes, links, n.id); const vs = find_adjacent_labels(nodes, links, n.id);
@ -962,29 +1085,105 @@ export function make_labelled_120cell() {
return labelled; return labelled;
} }
export function make_layered_120cell() { // calculate the w-distance of a dodecahedron's centroid
const labelled = make_labelled_120cell();
// relabel by layer export function dd_w_distance(nodes, dd) {
const vertices = new Set();
dd.map((f) => f.nodes.map((n) => vertices.add(n)));
let w = 0;
for( const nid of vertices ) {
const node = node_by_id(nodes, nid);
w += node.w;
}
return w / 20;
}
export function sort_dds_w(nodes, dds) {
dds.sort((a, b) => {
return dd_w_distance(nodes, a) - dd_w_distance(nodes, b)
})
}
export function find_antipode_dd(nodes, links, dd) {
}
// notes because I'm too sick to continue working on this today
// the vertices which aren't counted by the layers are showing
// up in the visualisation because they are labelled "0" by default -
// for this to work better there needs to be a value which is never
// displayed.
// in the current layer algorithm, layer '5' (the one after the equator)
// is too greedy
export function make_layered_120cell(max_layer) {
const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4);
const faces = auto_120cell_faces(links);
const labelled = label_120cell(nodes, links, faces, faces[628], 250, max_layer);
// get layers from sorted w-distance order
const dds = labelled.dodecahedra;
dds.sort((a, b) => dd_w_distance(nodes, b) - dd_w_distance(nodes, a));
const LAYERS = [
[ "0", 1 ],
[ "1", 12 ],
[ "2", 20 ],
[ "3", 12 ],
[ "4", 30 ],
[ "5", 12 ],
[ "6", 20 ],
[ "7", 12 ],
[ "8", 1]
];
const layer_dds = labelled["families"]; const layer_dds = labelled["families"];
const vertices_layers = {}; const vertices_layers = {};
const seen = {}; const seen = {};
let i = 0;
for( const layer of [ "0", "1", "2", "3", "4", "5", "6"] ) { for( const layer of LAYERS ) {
vertices_layers[layer] = []; const label = layer[0];
for( const dd of layer_dds[layer] ) { const n = layer[1];
vertices_layers[label] = [];
console.log(`Layer ${label} starting at ${i}`);
for( const dd of dds.slice(i, i + n) ) {
console.log(dd_w_distance(nodes, dd));
for( const face of dd ) { for( const face of dd ) {
for( const n of face.nodes ) { for( const n of face.nodes ) {
if( !seen[n] ) { if( !seen[n] ) {
vertices_layers[layer].push(n); vertices_layers[label].push(n);
seen[n] = true; seen[n] = true;
} }
} }
} }
} }
i += n;
} }
return vertices_layers; return JSON.stringify(vertices_layers);
}
export function make_meridians(bumpdir) {
const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4);
const faces = auto_120cell_faces(links);
const mbs ={}
for( const bumpdir of [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ] ) {
mbs[bumpdir] = meridian_bump(nodes, links, faces, faces[0], 341, bumpdir)
}
return mbs;
//
} }

View File

@ -23,10 +23,10 @@ scene.add(light);
const amblight = new THREE.AmbientLight(0xffffff, 0.5); const amblight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(amblight); scene.add(amblight);
camera.position.set(1, 1, 3); camera.position.set(0, 0, 4);
camera.lookAt(0, 0, 0); camera.lookAt(0, 0, 0);
camera.position.z = 4; //camera.position.z = 4;
const renderer = new THREE.WebGLRenderer({antialias: true}); const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setSize( window.innerWidth, window.innerHeight );