import * as POLYTOPES from './polytopes.js'; // face detection for the 600-cell export function nodes_links(links, nodeid) { return links.filter((l) => l.source === nodeid || l.target === nodeid); } export function linked(links, n1, n2) { const ls = nodes_links(nodes_links(links, n1), n2); if( ls.length ) { return ls[0] } else { return false; } } function fingerprint(ids) { const sids = [...ids]; sids.sort(); return sids.join(','); } export function make_600cell() { const nodes = POLYTOPES.make_600cell_vertices(); const links = POLYTOPES.auto_detect_edges(nodes, 12); return { nodes: nodes, links: links } } export function link_to_tetras(nodes, links, link) { const n1 = link.source; const n2 = link.target; const nl1 = nodes_links(links, n1).filter((l) => l.id !== link.id); const nl2 = nodes_links(links, n2).filter((l) => l.id !== link.id); const p1 = new Set(); const p = new Set(); for( const nl of nl1 ) { if( nl.source !== n1 ) { p1.add(nl.source); } if( nl.target !== n1 ) { p1.add(nl.target); } } for( const nl of nl2 ) { if( nl.source !== n2 && p1.has(nl.source) ) { p.add(nl.source); } if( nl.target !== n2 && p1.has(nl.target) ) { p.add(nl.target); } } const lp = Array.from(p); const seen = {}; const tetras = []; for( const p1 of lp ) { for( const p2 of lp ) { if( p1 != p2 ) { if( linked(links, p1, p2) ) { const fp = fingerprint([n1, n2, p1, p2]); if( !seen[fp] ) { seen[fp] = true; tetras.push({fingerprint: fp, nodes: [n1, n2, p1, p2]}) } } } } } return tetras; } export function auto_600cell_cells(nodes, links) { const seen = {}; const tetras = []; links.map((link) => { link_to_tetras(nodes, links, link).map((lt) => { if( !seen[lt.fingerprint] ) { seen[lt.fingerprint] = true; tetras.push(lt.nodes); } }) }); return tetras; } function node_by_id(nodes, nid) { const ns = nodes.filter((n) => n.id === nid); return ns[0]; } export function tetra_w(nodes, tetra) { let w = 0; for( const nid of tetra ) { const node = node_by_id(nodes, nid); w += node.w; } return w / 4; } export function sorted_600cells() { const cell600 = make_600cell(); const tetras = auto_600cell_cells(cell600.nodes, cell600.links); const layers = tetras.map((t) => { return { "nodes": t, w: tetra_w(cell600.nodes, t) } }); layers.sort((a, b) => b.w - a.w); return layers; } // const cell600 = make_600cell(); // const layers = sorted_600cells(cell600.nodes, cell600.links); // for( const cell of layers ) { // // const fp = fingerprint(cell.nodes); // console.log(`${cell.w} ${cell.nodes}`); // } export function make_layered_600cell() { const tetras = sorted_600cells() const LAYERS = [ [ "00", 20 ], [ "01", 20 ], [ "02", 30 ], [ "03", 60 ], [ "04", 60 ], [ "05", 60 ], [ "06", 20 ], [ "07", 60 ], [ "08", 20 ], [ "09", 60 ], [ "10", 60 ], [ "11", 60 ], [ "12", 30 ], [ "13", 20 ], [ "14", 20 ] ]; const vertices = {}; const seen = {}; let i = 0; for( const layer of LAYERS ) { const label = layer[0]; const n = layer[1]; vertices[label] = []; console.log(`Layer ${label} starting at ${i}`); for( const t of tetras.slice(i, i + n) ) { console.log(t); for( const n of t.nodes ) { if( !seen[n] ) { vertices[label].push(n); seen[n] = true; } } } i += n; } return JSON.stringify(vertices); }