feature-120-cell-more-inscriptions #24
@ -1,6 +1,11 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
## v1.1 - 1/1/2025
|
||||
|
||||
The 120-cell now includes a visualisation of its inscribed 5-cells, which honestly
|
||||
looks like less of a mess than I expected it to.
|
||||
|
||||
## v1.0 - 16/11/2025
|
||||
|
||||
It's been [two years](https://mikelynch.org/2023/Sep/02/120-cell/)</a> since
|
||||
|
||||
26
NOTES.md
Normal file
26
NOTES.md
Normal file
@ -0,0 +1,26 @@
|
||||
# NOTES
|
||||
|
||||
|
||||
New approach for the 5-cells:
|
||||
|
||||
Pick a tetrahedron of an inscribed 600-cell with vertices A, B, C, D
|
||||
|
||||
This gives pairs of vertices:
|
||||
|
||||
AB
|
||||
AC
|
||||
AD
|
||||
BC
|
||||
BD
|
||||
CD
|
||||
|
||||
Each of these gives rise to seven pairs of 5-cells which are on neighboring vertices
|
||||
of the 5 600-cells.
|
||||
|
||||
Try enumerating these and inspecting them to find one or more coherent sets of four
|
||||
5-cells which lie on one tetrahedron from each of the 600-cells.
|
||||
|
||||
(I expect there to be more than one, like how there are two ways to partition the
|
||||
120-cell vertices into 600-cells)
|
||||
|
||||
|
||||
849
cellindex.js
849
cellindex.js
@ -104,6 +104,855 @@ export const LAYERS120 = {
|
||||
163,219,271,223,167]
|
||||
};
|
||||
|
||||
export const CELL120_CELL5 = {
|
||||
"tetras": {
|
||||
},
|
||||
"cell5s": {
|
||||
"1": [
|
||||
27,
|
||||
28,
|
||||
264,
|
||||
309,
|
||||
275
|
||||
],
|
||||
"2": [
|
||||
223,
|
||||
76,
|
||||
238,
|
||||
84,
|
||||
225
|
||||
],
|
||||
"3": [
|
||||
253,
|
||||
44,
|
||||
283,
|
||||
304,
|
||||
42
|
||||
],
|
||||
"4": [
|
||||
419,
|
||||
112,
|
||||
197,
|
||||
578,
|
||||
521
|
||||
],
|
||||
"5": [
|
||||
339,
|
||||
14,
|
||||
384,
|
||||
382,
|
||||
337
|
||||
],
|
||||
"6": [
|
||||
331,
|
||||
4,
|
||||
335,
|
||||
390,
|
||||
386
|
||||
],
|
||||
"7": [
|
||||
427,
|
||||
160,
|
||||
551,
|
||||
146,
|
||||
557
|
||||
],
|
||||
"8": [
|
||||
265,
|
||||
60,
|
||||
64,
|
||||
295,
|
||||
246
|
||||
],
|
||||
"9": [
|
||||
473,
|
||||
100,
|
||||
495,
|
||||
213,
|
||||
462
|
||||
],
|
||||
"10": [
|
||||
393,
|
||||
6,
|
||||
328,
|
||||
397,
|
||||
326
|
||||
],
|
||||
"11": [
|
||||
539,
|
||||
164,
|
||||
439,
|
||||
561,
|
||||
142
|
||||
],
|
||||
"12": [
|
||||
511,
|
||||
122,
|
||||
456,
|
||||
595,
|
||||
181
|
||||
],
|
||||
"13": [
|
||||
555,
|
||||
154,
|
||||
152,
|
||||
545,
|
||||
429
|
||||
],
|
||||
"14": [
|
||||
95,
|
||||
202,
|
||||
486,
|
||||
500,
|
||||
465
|
||||
],
|
||||
"15": [
|
||||
471,
|
||||
208,
|
||||
502,
|
||||
484,
|
||||
89
|
||||
],
|
||||
"16": [
|
||||
347,
|
||||
21,
|
||||
348,
|
||||
374,
|
||||
373
|
||||
],
|
||||
"17": [
|
||||
487,
|
||||
203,
|
||||
94,
|
||||
468,
|
||||
497
|
||||
],
|
||||
"18": [
|
||||
165,
|
||||
139,
|
||||
542,
|
||||
568,
|
||||
434
|
||||
],
|
||||
"19": [
|
||||
367,
|
||||
18,
|
||||
355,
|
||||
368,
|
||||
353
|
||||
],
|
||||
"20": [
|
||||
231,
|
||||
78,
|
||||
86,
|
||||
236,
|
||||
217
|
||||
],
|
||||
"21": [
|
||||
356,
|
||||
17,
|
||||
366,
|
||||
354,
|
||||
365
|
||||
],
|
||||
"22": [
|
||||
503,
|
||||
205,
|
||||
470,
|
||||
92,
|
||||
481
|
||||
],
|
||||
"23": [
|
||||
527,
|
||||
106,
|
||||
584,
|
||||
195,
|
||||
421
|
||||
],
|
||||
"24": [
|
||||
239,
|
||||
73,
|
||||
222,
|
||||
228,
|
||||
81
|
||||
],
|
||||
"25": [
|
||||
543,
|
||||
138,
|
||||
168,
|
||||
435,
|
||||
565
|
||||
],
|
||||
"26": [
|
||||
48,
|
||||
46,
|
||||
302,
|
||||
281,
|
||||
255
|
||||
],
|
||||
"27": [
|
||||
248,
|
||||
62,
|
||||
293,
|
||||
58,
|
||||
267
|
||||
],
|
||||
"28": [
|
||||
440,
|
||||
141,
|
||||
562,
|
||||
540,
|
||||
163
|
||||
],
|
||||
"29": [
|
||||
274,
|
||||
30,
|
||||
312,
|
||||
261,
|
||||
29
|
||||
],
|
||||
"30": [
|
||||
179,
|
||||
128,
|
||||
597,
|
||||
450,
|
||||
505
|
||||
],
|
||||
"31": [
|
||||
376,
|
||||
22,
|
||||
375,
|
||||
346,
|
||||
345
|
||||
],
|
||||
"32": [
|
||||
320,
|
||||
11,
|
||||
405,
|
||||
401,
|
||||
319
|
||||
],
|
||||
"33": [
|
||||
448,
|
||||
173,
|
||||
130,
|
||||
587,
|
||||
519
|
||||
],
|
||||
"34": [
|
||||
460,
|
||||
102,
|
||||
211,
|
||||
489,
|
||||
479
|
||||
],
|
||||
"35": [
|
||||
388,
|
||||
2,
|
||||
392,
|
||||
329,
|
||||
333
|
||||
],
|
||||
"36": [
|
||||
512,
|
||||
182,
|
||||
596,
|
||||
121,
|
||||
455
|
||||
],
|
||||
"37": [
|
||||
592,
|
||||
170,
|
||||
516,
|
||||
443,
|
||||
133
|
||||
],
|
||||
"38": [
|
||||
120,
|
||||
189,
|
||||
529,
|
||||
570,
|
||||
411
|
||||
],
|
||||
"39": [
|
||||
420,
|
||||
198,
|
||||
577,
|
||||
522,
|
||||
111
|
||||
],
|
||||
"40": [
|
||||
272,
|
||||
69,
|
||||
65,
|
||||
290,
|
||||
243
|
||||
],
|
||||
"41": [
|
||||
488,
|
||||
93,
|
||||
498,
|
||||
204,
|
||||
467
|
||||
],
|
||||
"42": [
|
||||
156,
|
||||
150,
|
||||
547,
|
||||
553,
|
||||
431
|
||||
],
|
||||
"43": [
|
||||
252,
|
||||
53,
|
||||
286,
|
||||
297,
|
||||
55
|
||||
],
|
||||
"44": [
|
||||
532,
|
||||
192,
|
||||
117,
|
||||
410,
|
||||
571
|
||||
],
|
||||
"45": [
|
||||
400,
|
||||
7,
|
||||
321,
|
||||
396,
|
||||
323
|
||||
],
|
||||
"46": [
|
||||
580,
|
||||
199,
|
||||
417,
|
||||
110,
|
||||
523
|
||||
],
|
||||
"47": [
|
||||
296,
|
||||
63,
|
||||
245,
|
||||
266,
|
||||
59
|
||||
],
|
||||
"48": [
|
||||
600,
|
||||
125,
|
||||
178,
|
||||
508,
|
||||
451
|
||||
],
|
||||
"49": [
|
||||
68,
|
||||
72,
|
||||
269,
|
||||
242,
|
||||
291
|
||||
],
|
||||
"50": [
|
||||
324,
|
||||
8,
|
||||
399,
|
||||
322,
|
||||
395
|
||||
],
|
||||
"51": [
|
||||
499,
|
||||
96,
|
||||
485,
|
||||
466,
|
||||
201
|
||||
],
|
||||
"52": [
|
||||
406,
|
||||
12,
|
||||
317,
|
||||
318,
|
||||
402
|
||||
],
|
||||
"53": [
|
||||
563,
|
||||
144,
|
||||
437,
|
||||
162,
|
||||
537
|
||||
],
|
||||
"54": [
|
||||
234,
|
||||
88,
|
||||
219,
|
||||
229,
|
||||
80
|
||||
],
|
||||
"55": [
|
||||
350,
|
||||
24,
|
||||
349,
|
||||
371,
|
||||
372
|
||||
],
|
||||
"56": [
|
||||
444,
|
||||
134,
|
||||
515,
|
||||
169,
|
||||
591
|
||||
],
|
||||
"57": [
|
||||
258,
|
||||
40,
|
||||
39,
|
||||
277,
|
||||
307
|
||||
],
|
||||
"58": [
|
||||
285,
|
||||
56,
|
||||
251,
|
||||
54,
|
||||
298
|
||||
],
|
||||
"59": [
|
||||
546,
|
||||
151,
|
||||
153,
|
||||
430,
|
||||
556
|
||||
],
|
||||
"60": [
|
||||
98,
|
||||
215,
|
||||
475,
|
||||
493,
|
||||
464
|
||||
],
|
||||
"61": [
|
||||
474,
|
||||
214,
|
||||
99,
|
||||
461,
|
||||
496
|
||||
],
|
||||
"62": [
|
||||
357,
|
||||
20,
|
||||
363,
|
||||
359,
|
||||
364
|
||||
],
|
||||
"63": [
|
||||
490,
|
||||
212,
|
||||
459,
|
||||
101,
|
||||
480
|
||||
],
|
||||
"64": [
|
||||
185,
|
||||
116,
|
||||
415,
|
||||
533,
|
||||
574
|
||||
],
|
||||
"65": [
|
||||
378,
|
||||
16,
|
||||
343,
|
||||
341,
|
||||
380
|
||||
],
|
||||
"66": [
|
||||
218,
|
||||
85,
|
||||
235,
|
||||
77,
|
||||
232
|
||||
],
|
||||
"67": [
|
||||
342,
|
||||
15,
|
||||
377,
|
||||
379,
|
||||
344
|
||||
],
|
||||
"68": [
|
||||
458,
|
||||
209,
|
||||
491,
|
||||
477,
|
||||
104
|
||||
],
|
||||
"69": [
|
||||
514,
|
||||
135,
|
||||
441,
|
||||
590,
|
||||
172
|
||||
],
|
||||
"70": [
|
||||
226,
|
||||
83,
|
||||
75,
|
||||
237,
|
||||
224
|
||||
],
|
||||
"71": [
|
||||
530,
|
||||
119,
|
||||
569,
|
||||
190,
|
||||
412
|
||||
],
|
||||
"72": [
|
||||
38,
|
||||
37,
|
||||
257,
|
||||
308,
|
||||
278
|
||||
],
|
||||
"73": [
|
||||
414,
|
||||
113,
|
||||
188,
|
||||
575,
|
||||
536
|
||||
],
|
||||
"74": [
|
||||
362,
|
||||
19,
|
||||
358,
|
||||
361,
|
||||
360
|
||||
],
|
||||
"75": [
|
||||
334,
|
||||
1,
|
||||
330,
|
||||
387,
|
||||
391
|
||||
],
|
||||
"76": [
|
||||
438,
|
||||
161,
|
||||
538,
|
||||
143,
|
||||
564
|
||||
],
|
||||
"77": [
|
||||
550,
|
||||
157,
|
||||
426,
|
||||
560,
|
||||
147
|
||||
],
|
||||
"78": [
|
||||
566,
|
||||
167,
|
||||
137,
|
||||
544,
|
||||
436
|
||||
],
|
||||
"79": [
|
||||
126,
|
||||
177,
|
||||
452,
|
||||
507,
|
||||
599
|
||||
],
|
||||
"80": [
|
||||
284,
|
||||
41,
|
||||
254,
|
||||
43,
|
||||
303
|
||||
],
|
||||
"81": [
|
||||
494,
|
||||
97,
|
||||
476,
|
||||
463,
|
||||
216
|
||||
],
|
||||
"82": [
|
||||
200,
|
||||
109,
|
||||
418,
|
||||
524,
|
||||
579
|
||||
],
|
||||
"83": [
|
||||
263,
|
||||
25,
|
||||
26,
|
||||
276,
|
||||
310
|
||||
],
|
||||
"84": [
|
||||
300,
|
||||
50,
|
||||
52,
|
||||
249,
|
||||
287
|
||||
],
|
||||
"85": [
|
||||
558,
|
||||
145,
|
||||
428,
|
||||
159,
|
||||
552
|
||||
],
|
||||
"86": [
|
||||
403,
|
||||
9,
|
||||
316,
|
||||
315,
|
||||
407
|
||||
],
|
||||
"87": [
|
||||
74,
|
||||
82,
|
||||
227,
|
||||
221,
|
||||
240
|
||||
],
|
||||
"88": [
|
||||
289,
|
||||
66,
|
||||
244,
|
||||
271,
|
||||
70
|
||||
],
|
||||
"89": [
|
||||
306,
|
||||
34,
|
||||
280,
|
||||
33,
|
||||
259
|
||||
],
|
||||
"90": [
|
||||
572,
|
||||
118,
|
||||
531,
|
||||
409,
|
||||
191
|
||||
],
|
||||
"91": [
|
||||
207,
|
||||
90,
|
||||
472,
|
||||
483,
|
||||
501
|
||||
],
|
||||
"92": [
|
||||
369,
|
||||
23,
|
||||
370,
|
||||
351,
|
||||
352
|
||||
],
|
||||
"93": [
|
||||
585,
|
||||
132,
|
||||
175,
|
||||
517,
|
||||
446
|
||||
],
|
||||
"94": [
|
||||
105,
|
||||
196,
|
||||
528,
|
||||
583,
|
||||
422
|
||||
],
|
||||
"95": [
|
||||
241,
|
||||
67,
|
||||
292,
|
||||
71,
|
||||
270
|
||||
],
|
||||
"96": [
|
||||
425,
|
||||
148,
|
||||
559,
|
||||
549,
|
||||
158
|
||||
],
|
||||
"97": [
|
||||
525,
|
||||
193,
|
||||
108,
|
||||
423,
|
||||
582
|
||||
],
|
||||
"98": [
|
||||
174,
|
||||
129,
|
||||
588,
|
||||
447,
|
||||
520
|
||||
],
|
||||
"99": [
|
||||
313,
|
||||
10,
|
||||
404,
|
||||
408,
|
||||
314
|
||||
],
|
||||
"100": [
|
||||
413,
|
||||
187,
|
||||
576,
|
||||
535,
|
||||
114
|
||||
],
|
||||
"101": [
|
||||
573,
|
||||
186,
|
||||
416,
|
||||
115,
|
||||
534
|
||||
],
|
||||
"102": [
|
||||
49,
|
||||
51,
|
||||
299,
|
||||
288,
|
||||
250
|
||||
],
|
||||
"103": [
|
||||
449,
|
||||
180,
|
||||
127,
|
||||
598,
|
||||
506
|
||||
],
|
||||
"104": [
|
||||
469,
|
||||
91,
|
||||
206,
|
||||
504,
|
||||
482
|
||||
],
|
||||
"105": [
|
||||
513,
|
||||
171,
|
||||
589,
|
||||
136,
|
||||
442
|
||||
],
|
||||
"106": [
|
||||
279,
|
||||
35,
|
||||
305,
|
||||
260,
|
||||
36
|
||||
],
|
||||
"107": [
|
||||
389,
|
||||
3,
|
||||
385,
|
||||
336,
|
||||
332
|
||||
],
|
||||
"108": [
|
||||
593,
|
||||
183,
|
||||
509,
|
||||
454,
|
||||
124
|
||||
],
|
||||
"109": [
|
||||
149,
|
||||
155,
|
||||
554,
|
||||
432,
|
||||
548
|
||||
],
|
||||
"110": [
|
||||
325,
|
||||
5,
|
||||
394,
|
||||
327,
|
||||
398
|
||||
],
|
||||
"111": [
|
||||
453,
|
||||
123,
|
||||
510,
|
||||
184,
|
||||
594
|
||||
],
|
||||
"112": [
|
||||
383,
|
||||
13,
|
||||
338,
|
||||
340,
|
||||
381
|
||||
],
|
||||
"113": [
|
||||
311,
|
||||
31,
|
||||
273,
|
||||
32,
|
||||
262
|
||||
],
|
||||
"114": [
|
||||
581,
|
||||
107,
|
||||
526,
|
||||
424,
|
||||
194
|
||||
],
|
||||
"115": [
|
||||
61,
|
||||
57,
|
||||
268,
|
||||
247,
|
||||
294
|
||||
],
|
||||
"116": [
|
||||
87,
|
||||
79,
|
||||
230,
|
||||
220,
|
||||
233
|
||||
],
|
||||
"117": [
|
||||
301,
|
||||
47,
|
||||
45,
|
||||
256,
|
||||
282
|
||||
],
|
||||
"118": [
|
||||
131,
|
||||
176,
|
||||
445,
|
||||
518,
|
||||
586
|
||||
],
|
||||
"119": [
|
||||
210,
|
||||
103,
|
||||
457,
|
||||
478,
|
||||
492
|
||||
],
|
||||
"120": [
|
||||
140,
|
||||
166,
|
||||
567,
|
||||
433,
|
||||
541
|
||||
]
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Schoute's partition via https://arxiv.org/abs/1010.4353
|
||||
|
||||
export const PARTITION600 = {
|
||||
|
||||
@ -14,6 +14,7 @@ export const get_colours = (basis) => {
|
||||
const hsl = colours.map((c) => Color("#" + c).hsl());
|
||||
const resaturated = hsl.map((hslc) => hslc.saturationl(saturation).rgbNumber());
|
||||
resaturated.unshift(basis);
|
||||
console.log(resaturated);
|
||||
return resaturated;
|
||||
}
|
||||
|
||||
@ -34,4 +35,4 @@ export const get_plain_colours = (basis) => {
|
||||
0xff9900,
|
||||
0x000000,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
1
explore_120
Normal file
1
explore_120
Normal file
@ -0,0 +1 @@
|
||||
|
||||
492
explore_120cell.js
Normal file
492
explore_120cell.js
Normal file
@ -0,0 +1,492 @@
|
||||
|
||||
import * as POLYTOPES from './polytopes.js';
|
||||
|
||||
// exploring more inscriptions of the 120-cell
|
||||
|
||||
|
||||
function choice(a) {
|
||||
const r = Math.floor(Math.random() * a.length);
|
||||
return a[r];
|
||||
}
|
||||
|
||||
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 dist(n1, n2) {
|
||||
return Math.sqrt((n1.x - n2.x) ** 2 + (n1.y - n2.y) ** 2 + (n1.z - n2.z) ** 2 + (n1.w - n2.w) ** 2);
|
||||
}
|
||||
|
||||
|
||||
export function make_120cell() {
|
||||
const nodes = POLYTOPES.make_120cell_vertices();
|
||||
const links = POLYTOPES.auto_detect_edges(nodes, 4);
|
||||
return {
|
||||
nodes: nodes,
|
||||
links: links
|
||||
}
|
||||
}
|
||||
|
||||
function round_dist(raw) {
|
||||
return Math.floor(raw * 100000) / 100000;
|
||||
}
|
||||
|
||||
export function distance_groups(cell120) {
|
||||
// get list of other nodes by distance
|
||||
// sort them and dump them out
|
||||
const dists = {};
|
||||
|
||||
cell120.nodes.map((n) => {
|
||||
const draw = dist(cell120.nodes[0], n);
|
||||
const dtrunc = round_dist(draw);
|
||||
if( !(dtrunc in dists) ) {
|
||||
dists[dtrunc] = [];
|
||||
}
|
||||
dists[dtrunc].push(n);
|
||||
});
|
||||
return dists;
|
||||
}
|
||||
|
||||
function distance_group(cell120, n0, chord) {
|
||||
const nodes = []
|
||||
cell120.nodes.map((n) => {
|
||||
const d = round_dist(dist(n0, n));
|
||||
if( d == chord ) {
|
||||
nodes.push(n);
|
||||
}
|
||||
});
|
||||
// filter and return those whose chord is also the same
|
||||
const equidistant = [];
|
||||
for( const n1 of nodes ) {
|
||||
for( const n2 of nodes ) {
|
||||
if( n2.id > n1.id ) {
|
||||
if( round_dist(dist(n1, n2)) == chord ) {
|
||||
equidistant.push([n1, n2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return equidistant;
|
||||
}
|
||||
|
||||
|
||||
export function chord_survey() {
|
||||
const cell120 = POLYTOPES.cell120_inscribed();
|
||||
|
||||
const dgroups = distance_groups(cell120);
|
||||
|
||||
const dists = Object.keys(dgroups);
|
||||
|
||||
dists.sort();
|
||||
|
||||
for( const d of dists ) {
|
||||
const g0 = dgroups[d][0];
|
||||
dgroups[d].map((g) => {
|
||||
console.log(`${g0.id}-${g.id}: ${round_dist(dist(g0, g))}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function overlap(c1, c2) {
|
||||
for( const l in c1 ) {
|
||||
if( c1[l] === c2[l] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function c5match(c1, c2) {
|
||||
for( const l in c1 ) {
|
||||
if( c1[l] != c2[l] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
export function gather_5cells(cell120) {
|
||||
const CHORD5 = round_dist(Math.sqrt(2.5));
|
||||
const bins = [];
|
||||
const all = [];
|
||||
cell120.nodes.filter((n) => n.label === 1).map((n) => {
|
||||
const cells = [ ];
|
||||
const g = distance_group(cell120, n, CHORD5);
|
||||
for( const pair of g ) {
|
||||
let seen = false;
|
||||
for( const cell of cells ) {
|
||||
const c = Object.values(cell);
|
||||
if( c.includes(pair[0].id) || c.includes(pair[1].id) ) {
|
||||
if( !c.includes(pair[0].id) ) {
|
||||
cell[pair[0].label] = pair[0].id;
|
||||
}
|
||||
if( !c.includes(pair[1].id) ) {
|
||||
cell[pair[1].label] = pair[1].id;
|
||||
}
|
||||
seen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !seen ) {
|
||||
const cell = {};
|
||||
cell[1]= n.id;
|
||||
cell[pair[0].label] = pair[0].id;
|
||||
cell[pair[1].label] = pair[1].id;
|
||||
cells.push(cell);
|
||||
}
|
||||
}
|
||||
all.push(...cells);
|
||||
});
|
||||
return all;
|
||||
}
|
||||
|
||||
function audit_5cells(cells) {
|
||||
// this verifies that for each label (a 600-cell set), each of its
|
||||
// vertices is in exactly 7 5-cells. It checks out.
|
||||
|
||||
['1','2','3','4','5'].map((l) => {
|
||||
const sets = {};
|
||||
for( const cell of cells ) {
|
||||
const lv = cell[l];
|
||||
if( !(lv in sets) ) {
|
||||
sets[lv] = [];
|
||||
}
|
||||
sets[lv].push(cell);
|
||||
}
|
||||
for( const lv in sets ) {
|
||||
const ok = ( sets[lv].length === 7 ) ? 'ok' : 'miss';
|
||||
console.log(`${l},${lv},${sets[lv].length},${ok}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function try_120_5_cells_fails(cell120, cells, l) {
|
||||
// iterate over every vertex in the 600-cell defined by label l,
|
||||
// get all 7 5-cells including that vertex, and add them if they are
|
||||
// disjoint with what we already have
|
||||
|
||||
// this always runs out of disjoint nodes early
|
||||
|
||||
const vertices = cell120.nodes.filter((n) => n.label === l);
|
||||
|
||||
const cellset = [];
|
||||
for( const v of vertices ) {
|
||||
console.log(`Vertex ${v.id}`);
|
||||
const vcells = cells.filter((c) => c[l] === v.id);
|
||||
const overlap_any = (cs, c) => {
|
||||
for( const seen of cs ) {
|
||||
if( overlap(seen, c) ) {
|
||||
console.log("overlap");
|
||||
console.log(c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const disjoint = vcells.filter((c) => ! overlap_any(cellset, c));
|
||||
console.log(`Found ${disjoint.length} disjoint cells`);
|
||||
if( disjoint.length > 0 ) {
|
||||
cellset.push(choice(disjoint));
|
||||
}
|
||||
}
|
||||
console.log(`Found total of ${cellset.length} disjoint cells`);
|
||||
//console.log(cellset);
|
||||
}
|
||||
|
||||
function overlap_any(cs, c) {
|
||||
for( const seen of cs ) {
|
||||
if( overlap(seen, c) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function explore_disjoint(cell120, all5, l) {
|
||||
const a = all5[0];
|
||||
|
||||
const overlaps = all5.filter((c) => overlap(c, a));
|
||||
|
||||
console.log(a);
|
||||
|
||||
console.log(overlaps.length);
|
||||
console.log(overlaps);
|
||||
}
|
||||
|
||||
// select a five-cell from a starting vertex v
|
||||
// find a neighbor of v vn on its 600 cell, find all of the 5-cells which include
|
||||
// vn. Then see if we can find any from that set which are similiar neighbours to
|
||||
// the other four vertices in the first 5-cell
|
||||
|
||||
// the idea is that the 600-cells are a guide to finding the right subset of
|
||||
// 5-cells
|
||||
|
||||
function neighbours600(cell120, vid) {
|
||||
const v = cell120.nodes.filter((node) => node.id === vid)[0];
|
||||
const label = v.label;
|
||||
const links = cell120.links.filter((l) => {
|
||||
return l.label === v.label && (l.source === v.id || l.target == v.id );
|
||||
});
|
||||
const nodes = links.map((l) => {
|
||||
if( l.source === v.id ) {
|
||||
return l.target;
|
||||
} else {
|
||||
return l.source;
|
||||
}
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function cell120node(cell120, nid) {
|
||||
return cell120.nodes.filter((n) => n.id === nid)[0];
|
||||
}
|
||||
|
||||
function node_dist(cell120, aid, bid) {
|
||||
const a = cell120node(cell120, aid);
|
||||
const b = cell120node(cell120, bid);
|
||||
return dist(a, b);
|
||||
}
|
||||
|
||||
function print_row(v1, v2, p, v5) {
|
||||
console.log(`${v1.id},${v2.id},${p},${v5[1]},${v5[2]},${v5[3]},${v5[4]},${v5[5]}`);
|
||||
}
|
||||
|
||||
// for a pair of vertices which are on the same inscribed 600 cell,
|
||||
// this returns all 7 pairs of 5-cells which contain v1 and v2 and
|
||||
// which are also evenly spaced (ie every pair of vertices on the
|
||||
// same 600-cell is one edge apart)
|
||||
|
||||
|
||||
function find_adjoining_5cells(cell120, all5, v1, v2) {
|
||||
const DIST600 = round_dist(node_dist(cell120, v1.id, v2.id));
|
||||
const v15s = all5.filter((c5) => c5[v1.label] === v1.id);
|
||||
const v25s = all5.filter((c5) => c5[v2.label] === v2.id);
|
||||
let p = 0;
|
||||
const c5pairs = [];
|
||||
for( const v5a of v15s ) {
|
||||
for( const v5b of v25s ) {
|
||||
let match = true;
|
||||
const d = {};
|
||||
for( const label in v5a ) {
|
||||
d[label] = round_dist(node_dist(cell120, v5a[label], v5b[label]));
|
||||
if( d[label] != DIST600 ) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if( match ) {
|
||||
c5pairs.push([ v5a, v5b ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return c5pairs;
|
||||
}
|
||||
|
||||
function tetras(cell120, v) {
|
||||
// given a vertex v, find all of the 600-cell tetras it's on
|
||||
|
||||
const n600s = neighbours600(cell120, v.id);
|
||||
// need to find all sets of three neighbours which are neighbours: there
|
||||
// should be 20 of these because they're faces of an icosahedron
|
||||
const tetras = new Set;
|
||||
for( const v2id of n600s ) {
|
||||
// find mutual neighbours of the first two
|
||||
const n2600s = neighbours600(cell120, v2id);
|
||||
const mutuals = n2600s.filter((nid) => {
|
||||
return nid != v2id && nid != v.id && n600s.includes(nid)
|
||||
});
|
||||
for( const nm of mutuals ) {
|
||||
const nnms = neighbours600(cell120, nm);
|
||||
const mutuals2 = nnms.filter((nid) => {
|
||||
return nid != nm && nid != v2id && nid != v.id && mutuals.includes(nid)
|
||||
});
|
||||
for( const m2 of mutuals2 ) {
|
||||
const t = [ v.id, v2id, nm, m2 ];
|
||||
t.sort((a, b) => a - b);
|
||||
const tstr = t.join(',');
|
||||
tetras.add(tstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
const tarray = [];
|
||||
for( const t of tetras ) {
|
||||
const ta = t.split(',').map((v) => Number(v));
|
||||
tarray.push(ta);
|
||||
}
|
||||
return tarray;
|
||||
}
|
||||
|
||||
function vertices(hedra) {
|
||||
const v = new Set;
|
||||
for ( const h of hedra) {
|
||||
for( const p of h ) {
|
||||
v.add(p);
|
||||
}
|
||||
}
|
||||
return Array.from(v);
|
||||
}
|
||||
|
||||
function str5cell(c5) {
|
||||
return ["1","2","3","4","5"].map((l) => String(c5[l]).padStart(3, '0')).join('-');
|
||||
}
|
||||
|
||||
function tetra_sets(cell120, all5, tetra) {
|
||||
// given a tetrahedron on a 600-cell, find the sets of adjacent 5-cells on
|
||||
// all of the pairs
|
||||
// this is ass-backwards. Need to find tetras on the other 4 vertices of a 5-cell
|
||||
|
||||
const vs = tetra.map((tid) => cell120node(cell120, tid));
|
||||
const pairs = [[0,1], [0,2], [0, 3], [1, 2], [1, 3], [2, 3]];
|
||||
for( const p of pairs ) {
|
||||
const v1 = vs[p[0]];
|
||||
const v2 = vs[p[1]];
|
||||
const c5pairs = find_adjoining_5cells(cell120, all5, v1, v2);
|
||||
console.log(v1.id, v2.id);
|
||||
console.log(c5pairs.map((p) => str5cell(p[0]) + " " + str5cell(p[1])));
|
||||
}
|
||||
}
|
||||
|
||||
function cell5_neighbourhoods(cell120, all5, c5) {
|
||||
const neighbours = {}
|
||||
|
||||
for( const l in c5 ) {
|
||||
const v = cell120node(cell120, c5[l]);
|
||||
neighbours[l] = vertices(tetras(cell120, v));
|
||||
}
|
||||
|
||||
// now take the set of all 5-cells and filter it to only those whose vertices
|
||||
// are in the neighour sets. On first inspection there are 13?
|
||||
|
||||
const n5cells = all5.filter((c5) => {
|
||||
for( const l in c5 ) {
|
||||
if( ! neighbours[l].includes(c5[l]) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return n5cells;
|
||||
}
|
||||
|
||||
|
||||
function cell5_tetras(cell120, all5, c5) {
|
||||
const nb = cell5_neighbourhoods(cell120, all5, c5);
|
||||
const v1 = cell120node(cell120, c5["1"]);
|
||||
const ts = tetras(cell120, v1);
|
||||
|
||||
const c5s = [];
|
||||
for( const t of ts ) {
|
||||
const nt = nb.filter((n) => {
|
||||
for( const l in n ) {
|
||||
if( t.includes(n[l]) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
});
|
||||
for( const nc5 of nt ) {
|
||||
const exact = c5s.filter((c) => c5match(c, nc5));
|
||||
if( exact.length === 0 ) {
|
||||
const o = c5s.filter((c) => overlap(c, nc5));
|
||||
if( o.length > 0 ) {
|
||||
console.log("Overlap", c5, o);
|
||||
} else {
|
||||
c5s.push(nc5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c5s;
|
||||
}
|
||||
|
||||
|
||||
function coherent_5cells_r(cell120, all5, c5s, c50) {
|
||||
// Find next set of c5s, see if there are any we haven't seen,
|
||||
// recurse into those ones
|
||||
const c5ns = cell5_tetras(cell120, all5, c50);
|
||||
const c5unseen = c5ns.filter((c5) => {
|
||||
const matched = c5s.filter((c5b) => c5match(c5b, c5));
|
||||
return matched.length === 0;
|
||||
});
|
||||
for( const c5u of c5unseen ) {
|
||||
c5s.push(c5u);
|
||||
}
|
||||
for( const c5u of c5unseen ) {
|
||||
coherent_5cells_r(cell120, all5, c5s, c5u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function coherent_5cells(cell120, all5) {
|
||||
// pick a starting point, collect coherent 5_cells, continue till
|
||||
// there aren't any new ones
|
||||
|
||||
const c5set = [];
|
||||
let c5 = all5[0];
|
||||
|
||||
const c5s = [];
|
||||
coherent_5cells_r(cell120, all5, c5s, c5);
|
||||
return c5s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cell120 = POLYTOPES.cell120_inscribed();
|
||||
const all5 = gather_5cells(cell120);
|
||||
|
||||
const c5s = coherent_5cells(cell120, all5);
|
||||
|
||||
const celli = c5s.map((c5) => [ "1", "2", "3", "4", "5" ].map((l) => c5[l]));
|
||||
|
||||
|
||||
// check it because I don't believe it yet
|
||||
|
||||
const vertex_check = {};
|
||||
|
||||
for( const c5 of celli ) {
|
||||
for( const l in c5 ) {
|
||||
const v = c5[l];
|
||||
if( v in vertex_check ) {
|
||||
console.log(`Double count vertex ${v}`);
|
||||
}
|
||||
vertex_check[v] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for( let i = 1; i < 601; i++ ) {
|
||||
if( !vertex_check[i] ) {
|
||||
console.log(`v ${i} missing`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const idict = {};
|
||||
for( let i = 1; i < 121; i++ ) {
|
||||
idict[i] = celli[i - 1];
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(idict, null, 2));
|
||||
@ -62,7 +62,7 @@ class FourDShape extends THREE.Group {
|
||||
const s1 = this.link_scale * n1.scale;
|
||||
const s2 = this.link_scale * n2.scale;
|
||||
link.object.update(n1, n2, s1, s2);
|
||||
link.object.visible = (!links_show || link.label in links_show);
|
||||
link.object.visible = (!links_show || links_show.includes(link.label));
|
||||
}
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ class FourDShape extends THREE.Group {
|
||||
this.nodes3[n.id].scale = k * this.foreshortening;
|
||||
this.nodes3[n.id].object.position.copy(v3);
|
||||
this.nodes3[n.id].object.scale.copy(s3);
|
||||
this.nodes3[n.id].object.visible = ( !nodes_show || n.label in nodes_show );
|
||||
this.nodes3[n.id].object.visible = ( !nodes_show || nodes_show.includes(n.label) );
|
||||
}
|
||||
for( const l of this.links ) {
|
||||
this.updateLink(l, links_show);
|
||||
|
||||
53
gui.js
53
gui.js
@ -7,6 +7,7 @@ const DEFAULTS = {
|
||||
linksize: 1.0,
|
||||
linkopacity: 0.75,
|
||||
shape: '120-cell',
|
||||
link2opacity: 0.75,
|
||||
option: 'none',
|
||||
visibility: 5,
|
||||
inscribed: false,
|
||||
@ -15,8 +16,8 @@ const DEFAULTS = {
|
||||
background: 0xd4d4d4,
|
||||
hyperplane: 0.93,
|
||||
zoom: 1,
|
||||
xRotate: 'YW',
|
||||
yRotate: 'XW',
|
||||
xRotate: 'YZ',
|
||||
yRotate: 'XZ',
|
||||
dtheta: 0,
|
||||
damping: false,
|
||||
captions: true,
|
||||
@ -27,9 +28,10 @@ const DEFAULTS = {
|
||||
|
||||
class FourDGUI {
|
||||
|
||||
constructor(shapes, changeShape, setColor, setBackground, setNodeOpacity,setLinkOpacity, setVisibility, showDocs) {
|
||||
constructor(funcs) {
|
||||
this.shapes = funcs.shapes;
|
||||
this.gui = new GUI();
|
||||
const SHAPE_NAMES = shapes.map((s) => s.name);
|
||||
const SHAPE_NAMES = this.shapes.map((s) => s.name);
|
||||
|
||||
this.parseLinkParams();
|
||||
const guiObj = this;
|
||||
@ -40,6 +42,7 @@ class FourDGUI {
|
||||
inscribe_all: this.link['inscribe_all'],
|
||||
linksize: this.link['linksize'],
|
||||
linkopacity: this.link['linkopacity'],
|
||||
link2opacity: this.link['link2opacity'],
|
||||
nodesize: this.link['nodesize'],
|
||||
nodeopacity: this.link['nodeopacity'],
|
||||
depth: this.link['depth'],
|
||||
@ -53,39 +56,52 @@ class FourDGUI {
|
||||
captions: true,
|
||||
dtheta: this.link['dtheta'],
|
||||
dpsi: this.link['dpsi'],
|
||||
"copy link": function () { guiObj.copyUrl() }
|
||||
"copy link": function () { guiObj.copyUrl() },
|
||||
};
|
||||
if( funcs.extras ) {
|
||||
for( const label in funcs.extras ) {
|
||||
console.log(label);
|
||||
console.log(funcs.extras[label]);
|
||||
this.params[label] = funcs.extras[label];
|
||||
}
|
||||
}
|
||||
let options_ctrl;
|
||||
this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => {
|
||||
const options = this.getShapeOptions(shapes, shape);
|
||||
const options = this.getShapeOptions(shape);
|
||||
options_ctrl = options_ctrl.options(options).onChange((option) => {
|
||||
setVisibility(option)
|
||||
funcs.setVisibility(option)
|
||||
});
|
||||
options_ctrl.setValue(options[0])
|
||||
changeShape(shape)
|
||||
funcs.changeShape(shape)
|
||||
});
|
||||
const options = this.getShapeOptions(shapes, this.params['shape']);
|
||||
const options = this.getShapeOptions(this.params['shape']);
|
||||
options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => {
|
||||
setVisibility(option)
|
||||
funcs.setVisibility(option)
|
||||
});
|
||||
this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8);
|
||||
this.gui.add(this.params, 'zoom', 0.1, 2.0);
|
||||
this.gui.add(this.params, 'nodesize', 0, 1.5);
|
||||
this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(setNodeOpacity);
|
||||
this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(funcs.setNodeOpacity);
|
||||
this.gui.add(this.params, 'linksize', 0, 2);
|
||||
this.gui.add(this.params, 'linkopacity', 0, 1).onChange(setLinkOpacity);
|
||||
this.gui.addColor(this.params, 'color').onChange(setColor);
|
||||
this.gui.addColor(this.params, 'background').onChange(setBackground);
|
||||
console.log(funcs.setLinkOpacity);
|
||||
this.gui.add(this.params, 'linkopacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, true));
|
||||
this.gui.add(this.params, 'link2opacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, false));
|
||||
this.gui.addColor(this.params, 'color').onChange(funcs.setColor);
|
||||
this.gui.addColor(this.params, 'background').onChange(funcs.setBackground);
|
||||
this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]);
|
||||
this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]);
|
||||
this.gui.add(this.params, 'captions').onChange(showDocs);
|
||||
this.gui.add(this.params, 'captions').onChange(this.showDocs);
|
||||
this.gui.add(this.params, 'damping');
|
||||
this.gui.add(this.params, 'copy link');
|
||||
|
||||
if( funcs.extras ) {
|
||||
for( const label in funcs.extras ) {
|
||||
this.gui.add(this.params, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getShapeOptions(shapes, shape) {
|
||||
const spec = shapes.filter((s) => s.name === shape);
|
||||
getShapeOptions(shape) {
|
||||
const spec = this.shapes.filter((s) => s.name === shape);
|
||||
if( spec && spec[0].options ) {
|
||||
return spec[0].options.map((o) => o.name);
|
||||
} else {
|
||||
@ -136,6 +152,7 @@ class FourDGUI {
|
||||
this.link['zoom'] = this.numParam('zoom', parseFloat);
|
||||
this.link['linksize'] = this.numParam('linksize', parseFloat);
|
||||
this.link['linkopacity'] = this.numParam('linkopacity', parseFloat);
|
||||
this.link['link2opacity'] = this.numParam('link2opacity', parseFloat);
|
||||
this.link['nodesize'] = this.numParam('nodesize', parseFloat);
|
||||
this.link['nodeopacity'] = this.numParam('nodeopacity', parseFloat);
|
||||
this.link['color'] = this.numParam('color', (s) => guiObj.stringToHex(s));
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
<script type="module" src="/main.js"></script>
|
||||
<div id="description"></div>
|
||||
<div id="release_notes"></div>
|
||||
<div id="info"><a href="#" id="show_notes">release 1.0</a> |
|
||||
<div id="info"><a href="#" id="show_notes">release 1.1</a> |
|
||||
|
||||
by <a target="_blank" href="https://mikelynch.org/">Mike Lynch</a> |
|
||||
<a target="_blank" href="https://git.tilde.town/bombinans/fourdjs">source</a></div>
|
||||
|
||||
27
main.js
27
main.js
@ -68,6 +68,7 @@ link_ms.map((m) => {
|
||||
}
|
||||
);
|
||||
|
||||
console.log("link_ms", link_ms);
|
||||
|
||||
|
||||
const face_ms = [
|
||||
@ -168,7 +169,11 @@ function setBackground(c) {
|
||||
function setLinkOpacity(o, primary) {
|
||||
link_ms.map((lm) => lm.opacity = o);
|
||||
if( shape ) {
|
||||
shape.links.map((l) => l.object.material.opacity = o);
|
||||
shape.links.map((l) => {
|
||||
if( (primary && l.label == 0) || (!primary && l.label !== 0) ) {
|
||||
l.object.material.opacity = o
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +191,8 @@ function changeShape() {
|
||||
}
|
||||
|
||||
function setVisibility(option_name) {
|
||||
console.log("setVisibility", option_name);
|
||||
console.log(structure.options);
|
||||
const option = structure.options.filter((o) => o.name === option_name);
|
||||
if( option.length ) {
|
||||
node_show = option[0].nodes;
|
||||
@ -197,14 +204,16 @@ function setVisibility(option_name) {
|
||||
|
||||
|
||||
gui = new FourDGUI(
|
||||
STRUCTURES,
|
||||
changeShape,
|
||||
setColors,
|
||||
setBackground,
|
||||
setNodeOpacity,
|
||||
setLinkOpacity,
|
||||
setVisibility,
|
||||
showDocs
|
||||
{
|
||||
shapes: STRUCTURES,
|
||||
changeShape: changeShape,
|
||||
setColors: setColors,
|
||||
setBackground: setBackground,
|
||||
setNodeOpacity: setNodeOpacity,
|
||||
setLinkOpacity: setLinkOpacity,
|
||||
setVisibility: setVisibility,
|
||||
showDocs: showDocs,
|
||||
}
|
||||
);
|
||||
|
||||
// these are here to pick up colour settings from the URL params
|
||||
|
||||
41
polytopes.js
41
polytopes.js
@ -443,6 +443,15 @@ export const cell120_inscribed = () => {
|
||||
links.push(...links600);
|
||||
}
|
||||
|
||||
const CELL5S = CELLINDEX.CELL120_CELL5.cell5s;
|
||||
|
||||
for( const c5 in CELL5S ) {
|
||||
const nodes5 = nodes.filter((n) => CELL5S[c5].includes(n.id));
|
||||
const links5 = auto_detect_edges(nodes5, 5);
|
||||
links5.map((l) => l.label = 8);
|
||||
links.push(...links5);
|
||||
}
|
||||
|
||||
return {
|
||||
name: '120-cell',
|
||||
nodes: nodes,
|
||||
@ -450,17 +459,44 @@ export const cell120_inscribed = () => {
|
||||
options: [
|
||||
{ name: "none", links: [ 0 ]},
|
||||
{ name: "one inscribed 600-cell", links: [ 0, 1 ] },
|
||||
{ name: "five inscribed 600-cells", links: [ 0, 1, 2, 3, 4, 5 ] }
|
||||
{ name: "five inscribed 600-cells", links: [ 0, 1, 2, 3, 4, 5 ] },
|
||||
{ name: "120 inscribed 5-cells", links: [ 0, 8 ] },
|
||||
],
|
||||
description: `The 120-cell is the four-dimensional analogue of the
|
||||
dodecahedron, and consists of 120 dodecahedra joined at 720 faces,
|
||||
with three dodecahedra around each edge. It is dual to the 600-cell,
|
||||
and five 600-cells can be inscribed in its vertices.`,
|
||||
and five 600-cells can be inscribed in its vertices. The converse
|
||||
of this allows 120 5-cells (each of which has one vertex in each
|
||||
of the 5 600-cells) to be inscribed in the 120-cell.`,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const cell120_inscribed_cell5 = () => {
|
||||
const nodes = make_120cell_vertices();
|
||||
const links = auto_detect_edges(nodes, 4);
|
||||
|
||||
for( const cstr in CELLINDEX.INDEX120 ) {
|
||||
label_nodes(nodes, CELLINDEX.INDEX120[cstr], Number(cstr));
|
||||
}
|
||||
|
||||
links.map((l) => l.label = 0);
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
name: '120-cell-5-cell',
|
||||
nodes: nodes,
|
||||
links: links,
|
||||
options: [
|
||||
{ name: "5-cells", links: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] },
|
||||
],
|
||||
description: `The 120-cell with one of its 5-cells.`,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function partition_coord(i, coords, invert) {
|
||||
@ -864,7 +900,6 @@ export const icosahedron = () => {
|
||||
|
||||
export const build_all = () => {
|
||||
return [
|
||||
linkTest(),
|
||||
tetrahedron(),
|
||||
octahedron(),
|
||||
cube(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user