Moved the 120-cell dodecahedron detection code to its own file, and
tested it colouring every dodecahedron when it builds the 120-cell: looks goodfeature-120-cell-index
parent
585627f140
commit
6436efece2
|
@ -0,0 +1,137 @@
|
|||
// trying to go from faces to dodecahedra
|
||||
|
||||
|
||||
function shared_vertices(f1, f2) {
|
||||
return f1.nodes.filter((f) => f2.nodes.includes(f));
|
||||
}
|
||||
|
||||
|
||||
function adjacent_faces(f1, f2) {
|
||||
// adjacent faces which share an edge, not just a vertex
|
||||
const intersect = shared_vertices(f1, f2);
|
||||
if( intersect.length < 2 ) {
|
||||
return false;
|
||||
}
|
||||
if( intersect.length > 2 ) {
|
||||
console.log(`warning: faces ${f1.id} and ${f2.id} have too many common vertices`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function find_adjacent_faces(faces, face) {
|
||||
const neighbours = faces.filter((f) => f.id !== face.id && adjacent_faces(f, face));
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function find_dodeca_mutuals(faces, f1, f2) {
|
||||
// for any two adjacent faces, find their common neighbours where
|
||||
// all three share exactly one vertex (this, I think, guarantees that
|
||||
// all are on the same dodecahedron)
|
||||
|
||||
const n1 = find_adjacent_faces(faces, f1);
|
||||
const n2 = find_adjacent_faces(faces, f2);
|
||||
const common = n1.filter((f1) => n2.filter((f2) => f1.id === f2.id).length > 0 );
|
||||
// there's one extra here - the third which has two nodes in common with
|
||||
// both f1 and f2 - filter it out
|
||||
const mutuals = common.filter((cf) => {
|
||||
const shared = cf.nodes.filter((n) => f1.nodes.includes(n) && f2.nodes.includes(n));
|
||||
return shared.length === 1
|
||||
});
|
||||
return mutuals;
|
||||
}
|
||||
|
||||
function find_dodeca_next(faces, dodeca, f1, f2) {
|
||||
// of a pair of mutuals, return the one we haven't already got
|
||||
const m = find_dodeca_mutuals(faces, f1, f2);
|
||||
if( dodeca.filter((f) => f.id === m[0].id ).length > 0 ) {
|
||||
m.shift();
|
||||
}
|
||||
return m[0];
|
||||
}
|
||||
|
||||
// from any two mutual faces, return all the faces in their dodecahedron
|
||||
|
||||
function make_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 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
|
||||
|
||||
function find_edge_neighbours(faces, face) {
|
||||
const n1 = face.nodes[0];
|
||||
const n2 = face.nodes[1];
|
||||
return faces.filter((f) => f.id !== face.id && f.nodes.includes(n1) && f.nodes.includes(n2));
|
||||
}
|
||||
|
||||
|
||||
// each face is in two dodecahedra: this returns them both
|
||||
|
||||
function face_to_dodecahedra(faces, f) {
|
||||
const edge_friends = find_edge_neighbours(faces, f);
|
||||
const d1 = make_dodecahedron(faces, f, edge_friends[0]);
|
||||
const d2 = make_dodecahedron(faces, f, edge_friends[1]);
|
||||
return [ d1, d2 ];
|
||||
}
|
||||
|
||||
// brute-force calculation of all dodecahedra
|
||||
|
||||
function dd_fingerprint(dodecahedron) {
|
||||
const ids = dodecahedron.map((face) => face.id);
|
||||
ids.sort()
|
||||
return ids.join(',');
|
||||
}
|
||||
|
||||
export function make_120cell_dodecahedra(faces) {
|
||||
const dodecas = [];
|
||||
const seen = {};
|
||||
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);
|
||||
seen[fp] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dodecas;
|
||||
}
|
115
polytopes.js
115
polytopes.js
|
@ -1,5 +1,7 @@
|
|||
import * as PERMUTE from './permute.js';
|
||||
|
||||
import * as CELL120 from './cell120.js';
|
||||
|
||||
function index_nodes(nodes, scale) {
|
||||
let i = 1;
|
||||
for( const n of nodes ) {
|
||||
|
@ -281,94 +283,14 @@ function label_nodes(nodes, ids, label) {
|
|||
|
||||
|
||||
|
||||
function find_edges(links, nid) {
|
||||
return links.filter((l) => l.source === nid || l.target === nid );
|
||||
}
|
||||
|
||||
|
||||
function find_adjacent(links, nid) {
|
||||
return find_edges(links, nid).map((l) => {
|
||||
if( l.source === nid ) {
|
||||
return l.target;
|
||||
} else {
|
||||
return l.source;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function iterate_graph(nodes, links, n, fn) {
|
||||
const queue = [];
|
||||
const seen = {};
|
||||
const nodes_id = {};
|
||||
nodes.map((n) => nodes_id[n.id] = n);
|
||||
|
||||
queue.push(n.id);
|
||||
seen[n.id] = true;
|
||||
fn(n);
|
||||
|
||||
while( queue.length > 0 ) {
|
||||
const v = queue.shift();
|
||||
find_adjacent(links, v).map((aid) => {
|
||||
if( !(aid in seen) ) {
|
||||
seen[aid] = true;
|
||||
queue.push(aid);
|
||||
fn(nodes_id[aid]);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function dumb_label_120cell(nodes, links) {
|
||||
let l = 0;
|
||||
|
||||
iterate_graph(nodes, links, nodes[0], (n) => {
|
||||
n.label = l;
|
||||
console.log(`Labelled ${n.id} ${n.label}`);
|
||||
l++;
|
||||
if( l > 2 ) {
|
||||
l = 0;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// stupid tetrahedral labelling
|
||||
// keeps getting stuck
|
||||
|
||||
|
||||
function naive_label_120cell(nodes, links, n) {
|
||||
const nodes_id = {};
|
||||
nodes.map((n) => nodes_id[n.id] = n);
|
||||
iterate_graph(nodes, links, nodes[0], (n) => {
|
||||
const cols = new Set();
|
||||
const nbors = find_adjacent(links, n.id);
|
||||
for( const nb of nbors ) {
|
||||
if( nodes_id[nb].label > 0 ) {
|
||||
cols.add(nodes_id[nb].label);
|
||||
}
|
||||
for( const nb2 of find_adjacent(links, nb) ) {
|
||||
if( nb2 !== n.id && nodes_id[nb].label > 0 ) {
|
||||
cols.add(nodes_id[nb2].label);
|
||||
}
|
||||
}
|
||||
}
|
||||
const pcols = [ 1, 2, 3, 4, 5 ].filter((c) => !cols.has(c));
|
||||
if( pcols.length < 1 ) {
|
||||
console.log(`Got stuck, no options at ${n.id}`);
|
||||
return false;
|
||||
} else {
|
||||
n.label = pcols[0];
|
||||
console.log(`found ${pcols.length} colors for node ${n.id}`);
|
||||
console.log(`applied ${pcols[0]} to node ${n.id}`);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function label_faces_120cell(nodes, faces, cfaces, label) {
|
||||
const ns = new Set();
|
||||
console.log(`label faces from ${cfaces}`);
|
||||
for( const fid of cfaces ) {
|
||||
const face = faces.filter((f)=> f.id === fid );
|
||||
console.log(face);
|
||||
|
@ -378,8 +300,6 @@ function label_faces_120cell(nodes, faces, cfaces, label) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
label_nodes(nodes, Array.from(ns), label);
|
||||
}
|
||||
|
||||
|
@ -387,15 +307,30 @@ function label_faces_120cell(nodes, faces, cfaces, label) {
|
|||
function manual_label_120cell(nodes, links) {
|
||||
|
||||
const faces = auto_120cell_faces(links);
|
||||
const dodecas = CELL120.make_120cell_dodecahedra(faces);
|
||||
//const cfaces = [ 1, 2, 4, 145, 169 ];
|
||||
|
||||
console.log(dodecas);
|
||||
let colour = 1;
|
||||
for( const dd of dodecas ) {
|
||||
label_faces_120cell(nodes, faces, dd.map((f) => f.id), colour);
|
||||
colour++;
|
||||
if( colour > 8 ) {
|
||||
colour = 1;
|
||||
}
|
||||
}
|
||||
|
||||
label_faces_120cell(nodes, faces, [
|
||||
1, 2, 4, 169, 626,
|
||||
145, 149, 553, 173, 171,
|
||||
147, 554
|
||||
], 4);
|
||||
// label_faces_120cell(nodes, faces, [
|
||||
// 1, 2, 4, 169, 626,
|
||||
// 145, 149, 553, 173, 171,
|
||||
// 147, 554
|
||||
// ], 2);
|
||||
|
||||
// label_faces_120cell(nodes, faces, [
|
||||
// 1, 5, 3, 193, 641,
|
||||
// 217, 221, 565, 197, 195,
|
||||
// 219, 566
|
||||
// ], 3);
|
||||
|
||||
}
|
||||
|
||||
|
@ -403,6 +338,10 @@ function manual_label_120cell(nodes, links) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const cell120 = () => {
|
||||
const nodes = make_120cell_vertices();
|
||||
const links = auto_detect_edges(nodes, 4);
|
||||
|
|
Loading…
Reference in New Issue