Compare commits
20 Commits
bf8356b0a2
...
c281c4569a
Author | SHA1 | Date |
---|---|---|
bombinans | c281c4569a | |
Mike Lynch | c883bd7406 | |
Mike Lynch | 6f1c5a58e6 | |
Mike Lynch | 7323935a1f | |
Mike Lynch | 6d9610a1c6 | |
Mike Lynch | c481d24f3c | |
Mike Lynch | 029e6f3161 | |
Mike Lynch | 4bf38858ea | |
Mike Lynch | 50214adbe3 | |
Mike Lynch | 71c6aa62ac | |
Mike Lynch | 76f463ae03 | |
Mike Lynch | 42d1871a9e | |
Mike Lynch | 203850ba39 | |
Mike Lynch | 06c1b074b3 | |
Mike Lynch | 2f59c0b3a5 | |
Mike Lynch | 944416f92b | |
Mike Lynch | 8c256629b1 | |
Mike Lynch | fb1d6ddd45 | |
Mike Lynch | 1f6c35c7b8 | |
Mike Lynch | 88049ca891 |
93
cellindex.js
93
cellindex.js
|
@ -1 +1,92 @@
|
||||||
export const INDEX = {"1": [ 27,38,48,49,61,68,74,87,95,98,105,120, 126,131,140,149,156,165,174,179,185,200,207,210,218,223,226,231,234,239,241,248,252,253,258,263,265,272,274,279,284,285,289,296,300,301,306,311,313,320,324,325,331,334,339,342,347,350,356,357,362,367,369,376,378,383,388,389,393,400,403,406,413,414,419,420,425,427,438,440,444,448,449,453,458,460,469,471,473,474,487,488,490,494,499,503,511,512,513,514,525,527,530,532,539,543,546,550,555,558,563,566,572,573,580,581,585,592,593,600],"2":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,28,30,31,34,35,37,40,41,44,46,47,50,51,53,56,57,60,62,63,66,67,69,72,73,76,78,79,82,83,85,88,90,91,93,96,97,100,102,103,106,107,109,112,113,116,118,119,122,123,125,128,129,132,134,135,138,139,141,144,145,148,150,151,154,155,157,160,161,164,166,167,170,171,173,176,177,180,182,183,186,187,189,192,193,196,198,199,202,203,205,208,209,212,214,215],"3":[26,39,45,52,64,65,75,86,94,99,108,117,127,130,137,152,153,168,175,178,188,197,206,211,219,222,227,230,235,238,244,245,251,254,257,264,268,269,273,280,283,286,292,293,299,302,305,312,316,317,321,328,330,335,338,343,348,349,355,358,363,366,370,375,377,384,385,392,394,399,404,405,415,416,417,418,426,428,437,439,441,445,452,456,457,459,470,472,475,476,485,486,491,495,498,502,509,510,515,516,526,528,529,531,538,542,547,551,554,559,562,567,569,576,577,584,588,589,596,597],"4":[32,33,43,54,58,71,77,84,92,101,110,115,121,136,143,146,159,162,169,184,190,195,204,213,220,221,228,229,236,237,242,247,249,256,260,261,266,271,276,277,281,288,290,295,297,304,308,309,315,318,322,327,329,336,340,341,346,351,354,359,361,368,371,374,379,382,387,390,396,397,401,408,409,410,423,424,430,432,433,435,443,447,450,454,461,463,466,468,477,478,483,484,489,493,500,504,507,508,517,518,522,524,533,535,540,544,545,549,553,560,561,568,570,575,578,583,587,590,595,598],"5":[29,36,42,55,59,70,80,81,89,104,111,114,124,133,142,147,158,163,172,181,191,194,201,216,217,224,225,232,233,240,243,246,250,255,259,262,267,270,275,278,282,287,291,294,298,303,307,310,314,319,323,326,332,333,337,344,345,352,353,360,364,365,372,373,380,381,386,391,395,398,402,407,411,412,421,422,429,431,434,436,442,446,451,455,462,464,465,467,479,480,481,482,492,496,497,501,505,506,519,520,521,523,534,536,537,541,548,552,556,557,564,565,571,574,579,582,586,591,594,599]};
|
export const INDEX = {
|
||||||
|
"1": [
|
||||||
|
27,38,48,49,61,68,74,87,95,98,105,120, 126,131,140,149,156,165,174,
|
||||||
|
179,185,200,207,210,218,223,226,231,234,239,241,248,252,253,258,263,
|
||||||
|
265,272,274,279,284,285,289,296,300,301,306,311,313,320,324,325,331,
|
||||||
|
334,339,342,347,350,356,357,362,367,369,376,378,383,388,389,393,400,
|
||||||
|
403,406,413,414,419,420,425,427,438,440,444,448,449,453,458,460,469,
|
||||||
|
471,473,474,487,488,490,494,499,503,511,512,513,514,525,527,530,532,
|
||||||
|
539,543,546,550,555,558,563,566,572,573,580,581,585,592,593,600
|
||||||
|
],
|
||||||
|
"2":[
|
||||||
|
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,28,
|
||||||
|
30,31,34,35,37,40,41,44,46,47,50,51,53,56,57,60,62,63,66,67,69,72,73,
|
||||||
|
76,78,79,82,83,85,88,90,91,93,96,97,100,102,103,106,107,109,112,113,
|
||||||
|
116,118,119,122,123,125,128,129,132,134,135,138,139,141,144,145,148,
|
||||||
|
150,151,154,155,157,160,161,164,166,167,170,171,173,176,177,180,182,
|
||||||
|
183,186,187,189,192,193,196,198,199,202,203,205,208,209,212,214,215
|
||||||
|
],
|
||||||
|
"3":[
|
||||||
|
26,39,45,52,64,65,75,86,94,99,108,117,127,130,137,152,153,168,175,
|
||||||
|
178,188,197,206,211,219,222,227,230,235,238,244,245,251,254,257,264,
|
||||||
|
268,269,273,280,283,286,292,293,299,302,305,312,316,317,321,328,330,
|
||||||
|
335,338,343,348,349,355,358,363,366,370,375,377,384,385,392,394,399,
|
||||||
|
404,405,415,416,417,418,426,428,437,439,441,445,452,456,457,459,470,
|
||||||
|
472,475,476,485,486,491,495,498,502,509,510,515,516,526,528,529,531,
|
||||||
|
538,542,547,551,554,559,562,567,569,576,577,584,588,589,596,597
|
||||||
|
],
|
||||||
|
"4":[
|
||||||
|
32,33,43,54,58,71,77,84,92,101,110,115,121,136,143,146,159,162,169,
|
||||||
|
184,190,195,204,213,220,221,228,229,236,237,242,247,249,256,260,261,
|
||||||
|
266,271,276,277,281,288,290,295,297,304,308,309,315,318,322,327,329,
|
||||||
|
336,340,341,346,351,354,359,361,368,371,374,379,382,387,390,396,397,
|
||||||
|
401,408,409,410,423,424,430,432,433,435,443,447,450,454,461,463,466,
|
||||||
|
468,477,478,483,484,489,493,500,504,507,508,517,518,522,524,533,535,
|
||||||
|
540,544,545,549,553,560,561,568,570,575,578,583,587,590,595,598
|
||||||
|
],
|
||||||
|
"5":[
|
||||||
|
29,36,42,55,59,70,80,81,89,104,111,114,124,133,142,147,158,163,172,
|
||||||
|
181,191,194,201,216,217,224,225,232,233,240,243,246,250,255,259,262,
|
||||||
|
267,270,275,278,282,287,291,294,298,303,307,310,314,319,323,326,332,
|
||||||
|
333,337,344,345,352,353,360,364,365,372,373,380,381,386,391,395,398,
|
||||||
|
402,407,411,412,421,422,429,431,434,436,442,446,451,455,462,464,465,
|
||||||
|
467,479,480,481,482,492,496,497,501,505,506,519,520,521,523,534,536,
|
||||||
|
537,541,548,552,556,557,564,565,571,574,579,582,586,591,594,599
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const LAYERS = {
|
||||||
|
"0": [154,266,158,222,218,250,254,162,268,156,160,252,256,166,270,272,
|
||||||
|
164,220,224,168],
|
||||||
|
"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
|
||||||
|
],
|
||||||
|
"6":[1,417,313,409,413,317,421,5,475,345,473,481,349,483,33,513,507,
|
||||||
|
13,363,511,7,487,351,485,37,517,15,519,367,515,3,423,319,415,39,
|
||||||
|
25,505,509,477,29,411,27,479,347,31,365,419,35,315,361
|
||||||
|
],
|
||||||
|
"7":[217,153,221,157,265,161,165,269,249,253,251,255,267,159,155,
|
||||||
|
163,219,271,223,167]
|
||||||
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -61,7 +61,7 @@ class FourDShape extends THREE.Group {
|
||||||
return edge;
|
return edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLink(link) {
|
updateLink(link, links_show) {
|
||||||
const n1 = this.nodes3[link.source].v3;
|
const n1 = this.nodes3[link.source].v3;
|
||||||
const n2 = this.nodes3[link.target].v3;
|
const n2 = this.nodes3[link.target].v3;
|
||||||
const length = n1.distanceTo(n2);
|
const length = n1.distanceTo(n2);
|
||||||
|
@ -71,6 +71,7 @@ class FourDShape extends THREE.Group {
|
||||||
link.object.position.copy(centre);
|
link.object.position.copy(centre);
|
||||||
link.object.lookAt(n2);
|
link.object.lookAt(n2);
|
||||||
link.object.children[0].rotation.x = Math.PI / 2.0;
|
link.object.children[0].rotation.x = Math.PI / 2.0;
|
||||||
|
link.object.visible = (!links_show || link.label in links_show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,6 +116,7 @@ class FourDShape extends THREE.Group {
|
||||||
const material = this.getMaterial(n, this.node_ms);
|
const material = this.getMaterial(n, this.node_ms);
|
||||||
this.nodes3[n.id] = {
|
this.nodes3[n.id] = {
|
||||||
v3: v3,
|
v3: v3,
|
||||||
|
label: n.label,
|
||||||
object: this.makeNode(material, v3)
|
object: this.makeNode(material, v3)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -129,17 +131,17 @@ class FourDShape extends THREE.Group {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render3(rotations) {
|
render3(rotations, nodes_show, links_show) {
|
||||||
this.scalev3 = new THREE.Vector3(this.node_scale, this.node_scale, this.node_scale);
|
this.scalev3 = new THREE.Vector3(this.node_scale, this.node_scale, this.node_scale);
|
||||||
for( const n of this.nodes4 ) {
|
for( const n of this.nodes4 ) {
|
||||||
const v3 = this.fourDtoV3(n.x, n.y, n.z, n.w, rotations);
|
const v3 = this.fourDtoV3(n.x, n.y, n.z, n.w, rotations);
|
||||||
this.nodes3[n.id].v3 = v3;
|
this.nodes3[n.id].v3 = v3;
|
||||||
this.nodes3[n.id].object.position.copy(v3);
|
this.nodes3[n.id].object.position.copy(v3);
|
||||||
this.nodes3[n.id].object.scale.copy(this.scalev3);
|
this.nodes3[n.id].object.scale.copy(this.scalev3);
|
||||||
|
this.nodes3[n.id].object.visible = ( !nodes_show || n.label in nodes_show );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( const l of this.links ) {
|
for( const l of this.links ) {
|
||||||
this.updateLink(l);
|
this.updateLink(l, links_show);
|
||||||
}
|
}
|
||||||
|
|
||||||
for( const f of this.faces ) {
|
for( const f of this.faces ) {
|
||||||
|
@ -147,7 +149,6 @@ class FourDShape extends THREE.Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { FourDShape };
|
export { FourDShape };
|
||||||
|
|
48
gui.js
48
gui.js
|
@ -1,13 +1,14 @@
|
||||||
import { GUI } from 'lil-gui';
|
import { GUI } from 'lil-gui';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const DEFAULTS = {
|
const DEFAULTS = {
|
||||||
thickness: 0.25,
|
thickness: 0.25,
|
||||||
nodesize: 1.25,
|
nodesize: 1.25,
|
||||||
linkopacity: 0.5,
|
linkopacity: 0.5,
|
||||||
link2opacity: 0.5,
|
link2opacity: 0.5,
|
||||||
shape: '120-cell',
|
shape: '',
|
||||||
|
option: '',
|
||||||
|
visibility: 5,
|
||||||
inscribed: false,
|
inscribed: false,
|
||||||
inscribe_all: false,
|
inscribe_all: false,
|
||||||
color: 0x3293a9,
|
color: 0x3293a9,
|
||||||
|
@ -22,18 +23,25 @@ const DEFAULTS = {
|
||||||
|
|
||||||
class FourDGUI {
|
class FourDGUI {
|
||||||
|
|
||||||
constructor(changeShape, setColor, setBackground, setLinkOpacity) {
|
constructor(shapes, changeShape, setColor, setBackground, setLinkOpacity, setVisibility) {
|
||||||
this.gui = new GUI();
|
this.gui = new GUI();
|
||||||
|
const SHAPE_NAMES = shapes.map((s) => s.name);
|
||||||
|
// set default shape + option from the first shape
|
||||||
|
DEFAULTS.shape = shapes[0].name;
|
||||||
|
DEFAULTS.option = shapes[0].options[0].name;
|
||||||
|
|
||||||
this.parseLinkParams();
|
this.parseLinkParams();
|
||||||
const guiObj = this;
|
const guiObj = this;
|
||||||
this.params = {
|
this.params = {
|
||||||
shape: this.link['shape'],
|
shape: this.link['shape'],
|
||||||
|
option: this.link['option'],
|
||||||
inscribed: this.link['inscribed'],
|
inscribed: this.link['inscribed'],
|
||||||
inscribe_all: this.link['inscribe_all'],
|
inscribe_all: this.link['inscribe_all'],
|
||||||
thickness: this.link['thickness'],
|
thickness: this.link['thickness'],
|
||||||
linkopacity: this.link['linkopacity'],
|
linkopacity: this.link['linkopacity'],
|
||||||
link2opacity: this.link['linkopacity'],
|
link2opacity: this.link['linkopacity'],
|
||||||
nodesize: this.link['nodesize'],
|
nodesize: this.link['nodesize'],
|
||||||
|
depth: this.link['depth'],
|
||||||
color: this.link['color'],
|
color: this.link['color'],
|
||||||
background: this.link['background'],
|
background: this.link['background'],
|
||||||
hyperplane: this.link['hyperplane'],
|
hyperplane: this.link['hyperplane'],
|
||||||
|
@ -43,13 +51,19 @@ class FourDGUI {
|
||||||
dpsi: this.link['dpsi'],
|
dpsi: this.link['dpsi'],
|
||||||
"copy link": function () { guiObj.copyUrl() }
|
"copy link": function () { guiObj.copyUrl() }
|
||||||
};
|
};
|
||||||
|
let options_ctrl;
|
||||||
this.gui.add(this.params, 'shape',
|
this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => {
|
||||||
[ 'dodecahedron', '5-cell', '16-cell', 'tesseract',
|
const options = this.getShapeOptions(shapes, shape);
|
||||||
'24-cell', '600-cell', '120-cell' ]
|
options_ctrl = options_ctrl.options(options).onChange((option) => {
|
||||||
).onChange(changeShape)
|
setVisibility(option)
|
||||||
this.gui.add(this.params, 'inscribed').onChange(changeShape);
|
});
|
||||||
this.gui.add(this.params, 'inscribe_all').onChange(changeShape);
|
options_ctrl.setValue(options[0])
|
||||||
|
changeShape(shape)
|
||||||
|
});
|
||||||
|
const options = this.getShapeOptions(shapes, this.params['shape']);
|
||||||
|
options_ctrl = this.gui.add(this.params, 'option', options).onChange((option) => {
|
||||||
|
setVisibility(option)
|
||||||
|
});
|
||||||
this.gui.add(this.params, 'hyperplane', 1.5, 2.25);
|
this.gui.add(this.params, 'hyperplane', 1.5, 2.25);
|
||||||
this.gui.add(this.params, 'thickness', 0.1, 2);
|
this.gui.add(this.params, 'thickness', 0.1, 2);
|
||||||
this.gui.add(this.params, 'linkopacity', 0, 1).onChange(
|
this.gui.add(this.params, 'linkopacity', 0, 1).onChange(
|
||||||
|
@ -65,7 +79,16 @@ class FourDGUI {
|
||||||
this.gui.add(this.params, 'damping');
|
this.gui.add(this.params, 'damping');
|
||||||
this.gui.add(this.params, 'copy link');
|
this.gui.add(this.params, 'copy link');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShapeOptions(shapes, shape) {
|
||||||
|
const spec = shapes.filter((s) => s.name === shape);
|
||||||
|
if( spec && spec[0].options ) {
|
||||||
|
return spec[0].options.map((o) => o.name);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
numParam(param, parser) {
|
numParam(param, parser) {
|
||||||
|
@ -95,7 +118,7 @@ class FourDGUI {
|
||||||
const guiObj = this;
|
const guiObj = this;
|
||||||
|
|
||||||
this.urlParams = this.linkUrl.searchParams;
|
this.urlParams = this.linkUrl.searchParams;
|
||||||
for( const param of [ "shape", "rotation" ]) {
|
for( const param of [ "shape", "rotation", "option" ]) {
|
||||||
const value = this.urlParams.get(param);
|
const value = this.urlParams.get(param);
|
||||||
if( value ) {
|
if( value ) {
|
||||||
this.link[param] = value;
|
this.link[param] = value;
|
||||||
|
@ -121,6 +144,7 @@ class FourDGUI {
|
||||||
copyUrl() {
|
copyUrl() {
|
||||||
const url = new URL(this.linkUrl.origin + this.linkUrl.pathname);
|
const url = new URL(this.linkUrl.origin + this.linkUrl.pathname);
|
||||||
url.searchParams.append("shape", this.params.shape);
|
url.searchParams.append("shape", this.params.shape);
|
||||||
|
url.searchParams.append("option", this.params.option);
|
||||||
url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n');
|
url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n');
|
||||||
url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n');
|
url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n');
|
||||||
url.searchParams.append("thickness", this.params.thickness.toString());
|
url.searchParams.append("thickness", this.params.thickness.toString());
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
//testbed for playing with stuff in node repl
|
// code for generating the 120-cell labels
|
||||||
|
// has some overlap with permute - FIXME
|
||||||
|
|
||||||
const THREE =require('three');
|
const THREE = require('three');
|
||||||
|
|
||||||
function pandita(a) {
|
function pandita(a) {
|
||||||
const n = a.length;
|
const n = a.length;
|
||||||
|
@ -133,7 +134,7 @@ function dist2(n1, n2) {
|
||||||
return (n1.x - n2.x) ** 2 + (n1.y - n2.y) ** 2 + (n1.z - n2.z) ** 2 + (n1.w - n2.w) ** 2;
|
return (n1.x - n2.x) ** 2 + (n1.y - n2.y) ** 2 + (n1.z - n2.z) ** 2 + (n1.w - n2.w) ** 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function auto_detect_edges(nodes, neighbours, debug=false) {
|
export function auto_detect_edges(nodes, neighbours, debug=false) {
|
||||||
const seen = {};
|
const seen = {};
|
||||||
const nnodes = nodes.length;
|
const nnodes = nodes.length;
|
||||||
const links = [];
|
const links = [];
|
||||||
|
@ -168,7 +169,7 @@ function auto_detect_edges(nodes, neighbours, debug=false) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function make_120cell_vertices() {
|
export function make_120cell_vertices() {
|
||||||
const phi = 0.5 * (1 + Math.sqrt(5));
|
const phi = 0.5 * (1 + Math.sqrt(5));
|
||||||
const r5 = Math.sqrt(5);
|
const r5 = Math.sqrt(5);
|
||||||
const phi2 = phi * phi;
|
const phi2 = phi * phi;
|
||||||
|
@ -230,7 +231,7 @@ function fingerprint(ids) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function auto_120cell_faces(links) {
|
export function auto_120cell_faces(links) {
|
||||||
const faces = [];
|
const faces = [];
|
||||||
const seen = {};
|
const seen = {};
|
||||||
let id = 1;
|
let id = 1;
|
||||||
|
@ -486,7 +487,7 @@ function colour_next_dodeca_maybe(nodes, links, faces, colours, dd, nextf, nextd
|
||||||
const nextvs = dodecahedron_vertices(nextdd);
|
const nextvs = dodecahedron_vertices(nextdd);
|
||||||
// get the initial colour permutations from the existing labels;
|
// get the initial colour permutations from the existing labels;
|
||||||
const p = [];
|
const p = [];
|
||||||
for( i = 0; i < 5; i ++ ) {
|
for( let i = 0; i < 5; i ++ ) {
|
||||||
p[i] = colours[nextvs[i]];
|
p[i] = colours[nextvs[i]];
|
||||||
}
|
}
|
||||||
const nlabels = colour_dodecahedron_from_face(nextdd, p);
|
const nlabels = colour_dodecahedron_from_face(nextdd, p);
|
||||||
|
@ -529,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);
|
||||||
|
|
||||||
|
@ -668,8 +696,9 @@ function arctic(nodes, links, faces, startf, startn, max) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// this is the final one that works for the whole 120-cell
|
||||||
|
|
||||||
function arctic_two(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 ];
|
||||||
|
|
||||||
|
@ -688,10 +717,6 @@ function arctic_two(nodes, links, faces, startf, startn) {
|
||||||
seen[dd_fingerprint(nextdd)] = true;
|
seen[dd_fingerprint(nextdd)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// go around all of the arctic circle and grow all faces
|
|
||||||
|
|
||||||
// 1, 12, 20, 12, 30 = 75
|
|
||||||
// 0 1 13, 33, 45
|
|
||||||
|
|
||||||
for( const a of dds.slice(1, 13) ) {
|
for( const a of dds.slice(1, 13) ) {
|
||||||
for( const i of [ 6, 7, 8, 9, 10 ] ) {
|
for( const i of [ 6, 7, 8, 9, 10 ] ) {
|
||||||
|
@ -722,6 +747,8 @@ function arctic_two(nodes, links, faces, startf, startn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// the 30 equatorials?
|
// the 30 equatorials?
|
||||||
|
|
||||||
|
|
||||||
for( const a of dds.slice(13, 46) ) {
|
for( const a of dds.slice(13, 46) ) {
|
||||||
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(
|
||||||
|
@ -750,7 +777,10 @@ function arctic_two(nodes, links, faces, startf, startn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// this should get the rest or explode!
|
// this should get the rest or explode!
|
||||||
|
|
||||||
|
|
||||||
for( const a of dds ) {
|
for( const a of dds ) {
|
||||||
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(
|
||||||
|
@ -778,6 +808,124 @@ function arctic_two(nodes, links, faces, startf, startn) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 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]);
|
||||||
|
|
||||||
|
// arctic
|
||||||
|
|
||||||
|
if( max_layer > 0 ) {
|
||||||
|
dd_families["1"] = [];
|
||||||
|
|
||||||
|
for( const face of pole ) {
|
||||||
|
const [ nextdd, ncolours ] = follow_and_colour(
|
||||||
|
nodes, links, faces, colours, pole, face
|
||||||
|
);
|
||||||
|
add_colours(colours, ncolours);
|
||||||
|
dds.push(nextdd);
|
||||||
|
dd_families["1"].push(nextdd);
|
||||||
|
seen[dd_fingerprint(nextdd)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// subarctic - interstitial
|
||||||
|
|
||||||
|
if( max_layer > 1 ) {
|
||||||
|
dd_families["2"] = [];
|
||||||
|
|
||||||
|
for( const a of dd_families["1"] ) {
|
||||||
|
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);
|
||||||
|
dd_families["2"].push(nextdd);
|
||||||
|
seen[fp] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// tropic of cancer
|
||||||
|
|
||||||
|
if( max_layer > 2 ) {
|
||||||
|
dd_families["3"] = [];
|
||||||
|
|
||||||
|
for( const a of dd_families["1"] ) {
|
||||||
|
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);
|
||||||
|
dd_families["3"].push(nextdd);
|
||||||
|
seen[fp] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( max_layer > 3 ) {
|
||||||
|
// equator
|
||||||
|
|
||||||
|
dd_families["4"] = [];
|
||||||
|
|
||||||
|
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);
|
||||||
|
dd_families["4"].push(nextdd);
|
||||||
|
dds.push(nextdd);
|
||||||
|
seen[fp] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( max_layer > 4 ) {
|
||||||
|
dd_families["5"] = [];
|
||||||
|
|
||||||
|
for( const a of dd_families["4"] ) {
|
||||||
|
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);
|
||||||
|
dd_families["5"].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, families: dd_families };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
||||||
// first face's two dodecahedra
|
// first face's two dodecahedra
|
||||||
|
@ -815,7 +963,6 @@ function make_120cell_cells(faces) {
|
||||||
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}`);
|
|
||||||
const d = {
|
const d = {
|
||||||
id: i,
|
id: i,
|
||||||
faces: dd,
|
faces: dd,
|
||||||
|
@ -895,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);
|
||||||
|
@ -927,9 +1074,120 @@ function make_dodecahedron_vertices() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// const nodes = make_120cell_vertices();
|
// this one does the coherent indexing / partition into 600-cells
|
||||||
// const links = auto_detect_edges(nodes, 4);
|
|
||||||
// const faces = auto_120cell_faces(links);
|
export function make_labelled_120cell() {
|
||||||
|
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[0], 341);
|
||||||
|
return labelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the w-distance of a dodecahedron's centroid
|
||||||
|
|
||||||
|
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 vertices_layers = {};
|
||||||
|
const seen = {};
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
for( const layer of LAYERS ) {
|
||||||
|
const label = layer[0];
|
||||||
|
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 n of face.nodes ) {
|
||||||
|
if( !seen[n] ) {
|
||||||
|
vertices_layers[label].push(n);
|
||||||
|
seen[n] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += n;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// console.log("Calculating 120-cell colours")
|
// console.log("Calculating 120-cell colours")
|
79
main.js
79
main.js
|
@ -23,7 +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.z = 4;
|
camera.position.set(0, 0, 4);
|
||||||
|
|
||||||
|
camera.lookAt(0, 0, 0);
|
||||||
|
//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 );
|
||||||
|
@ -59,51 +62,26 @@ for( const face_m of face_ms ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const STRUCTURES = {
|
const STRUCTURES = POLYTOPES.build_all();
|
||||||
'5-cell': POLYTOPES.cell5(),
|
|
||||||
'16-cell': POLYTOPES.cell16(),
|
|
||||||
'tesseract': POLYTOPES.tesseract(),
|
|
||||||
'24-cell': POLYTOPES.cell24(),
|
|
||||||
'dodecahedron': POLYTOPES.dodecahedron(),
|
|
||||||
'120-cell': POLYTOPES.cell120(),
|
|
||||||
'600-cell': POLYTOPES.cell600(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const INSCRIBED = {
|
const STRUCTURES_BY_NAME = {};
|
||||||
'tesseract': POLYTOPES.tesseract_inscribed(),
|
|
||||||
'24-cell': POLYTOPES.cell24_inscribed(),
|
|
||||||
'120-cell': POLYTOPES.cell120_inscribed(),
|
|
||||||
'600-cell': POLYTOPES.cell600_inscribed(),
|
|
||||||
'dodecahedron': POLYTOPES.dodecahedron_inscribed(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const ALL_INSCRIBED = {
|
STRUCTURES.map((s) => STRUCTURES_BY_NAME[s.name] = s);
|
||||||
'tesseract': POLYTOPES.tesseract_all_inscribed(),
|
|
||||||
'24-cell': POLYTOPES.cell24_all_inscribed(),
|
|
||||||
'120-cell': POLYTOPES.cell120_all_inscribed(),
|
|
||||||
'600-cell': POLYTOPES.cell600_all_inscribed(),
|
|
||||||
'dodecahedron': POLYTOPES.dodecahedron_all_inscribed(),
|
|
||||||
}
|
|
||||||
|
|
||||||
let shape = false;
|
let shape = false;
|
||||||
|
let structure = false;
|
||||||
|
let node_show = [];
|
||||||
|
let link_show = [];
|
||||||
|
|
||||||
function createShape(name, inscribed, all) {
|
|
||||||
|
function createShape(name, option) {
|
||||||
if( shape ) {
|
if( shape ) {
|
||||||
scene.remove(shape);
|
scene.remove(shape);
|
||||||
}
|
}
|
||||||
let structure = STRUCTURES[name];
|
structure = STRUCTURES_BY_NAME[name];
|
||||||
if( inscribed ) {
|
|
||||||
if( name in INSCRIBED ) {
|
|
||||||
if( all ) {
|
|
||||||
structure = ALL_INSCRIBED[name];
|
|
||||||
} else {
|
|
||||||
structure = INSCRIBED[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shape = new FourDShape(node_ms, link_ms, face_ms, structure);
|
shape = new FourDShape(node_ms, link_ms, face_ms, structure);
|
||||||
scene.add(shape);
|
scene.add(shape);
|
||||||
|
setVisibility(option ? option : structure.options[0].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialise gui and read params from URL
|
// initialise gui and read params from URL
|
||||||
|
@ -136,12 +114,31 @@ function setLinkOpacity(o, primary) {
|
||||||
|
|
||||||
let gui; //
|
let gui; //
|
||||||
|
|
||||||
|
|
||||||
function changeShape() {
|
function changeShape() {
|
||||||
console.log("change shape!")
|
createShape(gui.params.shape);
|
||||||
createShape(gui.params.shape, gui.params.inscribed, gui.params.inscribe_all);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gui = new FourDGUI(changeShape, setColors, setBackground, setLinkOpacity);
|
function setVisibility(option_name) {
|
||||||
|
const option = structure.options.filter((o) => o.name === option_name);
|
||||||
|
if( option.length ) {
|
||||||
|
node_show = option[0].nodes;
|
||||||
|
link_show = option[0].links;
|
||||||
|
} else {
|
||||||
|
console.log(`Error: option '${option_name}' not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gui = new FourDGUI(
|
||||||
|
STRUCTURES,
|
||||||
|
changeShape,
|
||||||
|
setColors,
|
||||||
|
setBackground,
|
||||||
|
setLinkOpacity,
|
||||||
|
setVisibility
|
||||||
|
);
|
||||||
|
|
||||||
// these are here to pick up colour settings from the URL params
|
// these are here to pick up colour settings from the URL params
|
||||||
setColors(gui.params.color);
|
setColors(gui.params.color);
|
||||||
|
@ -184,7 +181,7 @@ renderer.domElement.addEventListener("pointerup", (event) => {
|
||||||
dragging = false;
|
dragging = false;
|
||||||
})
|
})
|
||||||
|
|
||||||
createShape(gui.params.shape, gui.params.inscribed, gui.params.inscribe_all);
|
createShape(gui.params.shape, gui.params.option);
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
requestAnimationFrame( animate );
|
requestAnimationFrame( animate );
|
||||||
|
@ -203,7 +200,7 @@ function animate() {
|
||||||
shape.hyperplane = gui.params.hyperplane;
|
shape.hyperplane = gui.params.hyperplane;
|
||||||
shape.link_scale = gui.params.thickness;
|
shape.link_scale = gui.params.thickness;
|
||||||
shape.node_scale = gui.params.nodesize;
|
shape.node_scale = gui.params.nodesize;
|
||||||
shape.render3(rotations);
|
shape.render3(rotations, node_show, link_show);
|
||||||
|
|
||||||
renderer.render( scene, camera );
|
renderer.render( scene, camera );
|
||||||
}
|
}
|
||||||
|
|
276
polytopes.js
276
polytopes.js
|
@ -61,6 +61,7 @@ export const cell5 = () => {
|
||||||
const r5 = Math.sqrt(5);
|
const r5 = Math.sqrt(5);
|
||||||
const r2 = Math.sqrt(2) / 2;
|
const r2 = Math.sqrt(2) / 2;
|
||||||
return {
|
return {
|
||||||
|
name: '5-cell',
|
||||||
nodes: [
|
nodes: [
|
||||||
{id:1, label: 1, x: r2, y: r2, z: r2, w: -r2 / r5 },
|
{id:1, label: 1, x: r2, y: r2, z: r2, w: -r2 / r5 },
|
||||||
{id:2, label: 2, x: r2, y: -r2, z: -r2, w: -r2 / r5 },
|
{id:2, label: 2, x: r2, y: -r2, z: -r2, w: -r2 / r5 },
|
||||||
|
@ -83,7 +84,8 @@ export const cell5 = () => {
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
}
|
},
|
||||||
|
options: [ { name: '--' }]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,12 +108,14 @@ export const cell16 = () => {
|
||||||
const links = auto_detect_edges(nodes, 6);
|
const links = auto_detect_edges(nodes, 6);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: '16-cell',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
}
|
},
|
||||||
|
options: [ { name: '--' }]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,39 +135,33 @@ export const tesseract = () => {
|
||||||
|
|
||||||
scale_nodes(nodes, Math.sqrt(2) / 2);
|
scale_nodes(nodes, Math.sqrt(2) / 2);
|
||||||
const links = auto_detect_edges(nodes, 4);
|
const links = auto_detect_edges(nodes, 4);
|
||||||
|
links.map((l) => { l.label = 0 });
|
||||||
|
|
||||||
|
for( const p of [ 1, 2 ] ) {
|
||||||
|
const nodes16 = nodes.filter((n) => n.label === p);
|
||||||
|
const links16 = auto_detect_edges(nodes16, 6);
|
||||||
|
links16.map((l) => l.label = p);
|
||||||
|
links.push(...links16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: 'tesseract',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
}
|
},
|
||||||
|
options: [
|
||||||
|
{ name: 'none', links: [ 0 ] },
|
||||||
|
{ name: 'one 16-cell', links: [ 0, 1 ] },
|
||||||
|
{ name: 'both 16-cells', links: [ 0, 1, 2 ] },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const tesseract_some_inscribed = (ps) => {
|
|
||||||
const t = tesseract();
|
|
||||||
|
|
||||||
const i_links = [];
|
|
||||||
|
|
||||||
for( const p of ps ) {
|
|
||||||
const nodes16 = t.nodes.filter((n) => n.label === p);
|
|
||||||
const links16 = auto_detect_edges(nodes16, 6);
|
|
||||||
links16.map((l) => l.label = p);
|
|
||||||
i_links.push(...links16);
|
|
||||||
}
|
|
||||||
|
|
||||||
t.links.push(...i_links);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const tesseract_inscribed = () => tesseract_some_inscribed([1]);
|
|
||||||
export const tesseract_all_inscribed = () => tesseract_some_inscribed([1,2]);
|
|
||||||
|
|
||||||
|
|
||||||
const CELL24_INDEXING = {
|
const CELL24_INDEXING = {
|
||||||
x: { y: 1, z: 3, w: 2 },
|
x: { y: 1, z: 3, w: 2 },
|
||||||
y: { z: 2, w: 3 },
|
y: { z: 2, w: 3 },
|
||||||
|
@ -187,7 +185,14 @@ export const cell24 = () => {
|
||||||
|
|
||||||
index_nodes(nodes);
|
index_nodes(nodes);
|
||||||
const links = auto_detect_edges(nodes, 8);
|
const links = auto_detect_edges(nodes, 8);
|
||||||
|
links.map((l) => l.label = 0);
|
||||||
|
|
||||||
|
for( const p of [ 1, 2, 3 ] ) {
|
||||||
|
const nodes16 = nodes.filter((n) => n.label === p);
|
||||||
|
const links16 = auto_detect_edges(nodes16, 6);
|
||||||
|
links16.map((l) => l.label = p);
|
||||||
|
links.push(...links16);
|
||||||
|
}
|
||||||
// links.map((l) => {
|
// links.map((l) => {
|
||||||
// const ls = [ l.source, l.target ].map((nid) => node_by_id(nodes, nid).label);
|
// const ls = [ l.source, l.target ].map((nid) => node_by_id(nodes, nid).label);
|
||||||
// for ( const c of [1, 2, 3] ) {
|
// for ( const c of [1, 2, 3] ) {
|
||||||
|
@ -198,35 +203,23 @@ export const cell24 = () => {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: '24-cell',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
}
|
},
|
||||||
|
base: {},
|
||||||
|
options: [
|
||||||
|
{ name: 'none', links: [ 0 ] },
|
||||||
|
{ name: 'one 16-cell', links: [ 0, 1 ] },
|
||||||
|
{ name: 'three 16-cells', links: [ 0, 1, 2, 3 ] }
|
||||||
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const cell24_some_inscribed = (ps) => {
|
|
||||||
const t = cell24();
|
|
||||||
|
|
||||||
const i_links = [];
|
|
||||||
|
|
||||||
for( const p of ps ) {
|
|
||||||
const nodes16 = t.nodes.filter((n) => n.label === p);
|
|
||||||
const links16 = auto_detect_edges(nodes16, 6);
|
|
||||||
links16.map((l) => l.label = p);
|
|
||||||
i_links.push(...links16);
|
|
||||||
}
|
|
||||||
|
|
||||||
t.links.push(...i_links);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const cell24_inscribed = () => cell24_some_inscribed([1]);
|
|
||||||
export const cell24_all_inscribed = () => cell24_some_inscribed([1,2,3]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,6 +325,8 @@ function make_120cell_vertices() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function label_nodes(nodes, ids, label) {
|
function label_nodes(nodes, ids, label) {
|
||||||
nodes.filter((n) => ids.includes(n.id)).map((n) => n.label = label);
|
nodes.filter((n) => ids.includes(n.id)).map((n) => n.label = label);
|
||||||
}
|
}
|
||||||
|
@ -339,16 +334,8 @@ function label_nodes(nodes, ids, label) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function label_faces_120cell(nodes, faces, cfaces, label) {
|
function label_faces_120cell(nodes, faces, cfaces, label) {
|
||||||
const ns = new Set();
|
const ns = new Set();
|
||||||
console.log(`label faces from ${cfaces}`);
|
|
||||||
for( const fid of cfaces ) {
|
for( const fid of cfaces ) {
|
||||||
const face = faces.filter((f)=> f.id === fid );
|
const face = faces.filter((f)=> f.id === fid );
|
||||||
if( face.length > 0 ) {
|
if( face.length > 0 ) {
|
||||||
|
@ -361,33 +348,6 @@ function label_faces_120cell(nodes, faces, cfaces, label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function basic_auto_label_120cell(nodes, links) {
|
|
||||||
|
|
||||||
const faces = auto_120cell_faces(links);
|
|
||||||
const dodecas = DODECAHEDRA.DODECAHEDRA;
|
|
||||||
//const cfaces = [ 1, 2, 4, 145, 169 ];
|
|
||||||
|
|
||||||
let colour = 1;
|
|
||||||
for( const dd of dodecas ) {
|
|
||||||
label_faces_120cell(nodes, faces, dd, colour);
|
|
||||||
colour++;
|
|
||||||
if( colour > 8 ) {
|
|
||||||
colour = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function label_120cell(nodes) {
|
|
||||||
|
|
||||||
for( const cstr in CELL120.INDEX ) {
|
|
||||||
label_nodes(nodes, CELL120.INDEX[cstr], Number(cstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function link_labels(nodes, link) {
|
function link_labels(nodes, link) {
|
||||||
const n1 = nodes.filter((n) => n.id === link.source);
|
const n1 = nodes.filter((n) => n.id === link.source);
|
||||||
const n2 = nodes.filter((n) => n.id === link.target);
|
const n2 = nodes.filter((n) => n.id === link.target);
|
||||||
|
@ -395,52 +355,88 @@ function link_labels(nodes, link) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// version of the 120-cell where nodes are partitioned by
|
||||||
|
// layer and the links follow that
|
||||||
|
|
||||||
export const cell120 = () => {
|
export const cell120_layered = (max) => {
|
||||||
const nodes = make_120cell_vertices();
|
const nodes = make_120cell_vertices();
|
||||||
const links = auto_detect_edges(nodes, 4);
|
const links = auto_detect_edges(nodes, 4);
|
||||||
|
|
||||||
label_120cell(nodes);
|
nodes.map((n) => n.label = 9); // make all invisible by default
|
||||||
|
|
||||||
|
for (const cstr in CELL120.LAYERS ) {
|
||||||
|
label_nodes(nodes, CELL120.LAYERS[cstr], Number(cstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
links.map((l) => {
|
||||||
|
const labels = link_labels(nodes, l);
|
||||||
|
if( labels[0] >= labels[1] ) {
|
||||||
|
l.label = labels[0];
|
||||||
|
} else {
|
||||||
|
l.label = labels[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = [];
|
||||||
|
const layers = [];
|
||||||
|
|
||||||
|
for( const i of [ 0, 1, 2, 3, 4, 5, 6, 7 ] ) {
|
||||||
|
layers.push(i);
|
||||||
|
options.unshift({
|
||||||
|
name: "Layer " + String(i),
|
||||||
|
links: [...layers],
|
||||||
|
nodes: [...layers]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: '120-cell layered',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
},
|
},
|
||||||
|
options: options
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const cell120_some_inscribed = (ps) => {
|
|
||||||
|
|
||||||
|
export const cell120_inscribed = () => {
|
||||||
const nodes = make_120cell_vertices();
|
const nodes = make_120cell_vertices();
|
||||||
const links = auto_detect_edges(nodes, 4);
|
const links = auto_detect_edges(nodes, 4);
|
||||||
|
|
||||||
label_120cell(nodes);
|
for( const cstr in CELL120.INDEX ) {
|
||||||
|
label_nodes(nodes, CELL120.INDEX[cstr], Number(cstr));
|
||||||
|
}
|
||||||
|
|
||||||
const all_links = links;
|
links.map((l) => l.label = 0);
|
||||||
all_links.map((l) => l.label = 0);
|
|
||||||
|
|
||||||
for( const p of ps) {
|
for( const p of [ 1, 2, 3, 4, 5 ]) {
|
||||||
const nodes600 = nodes.filter((n) => n.label === p);
|
const nodes600 = nodes.filter((n) => n.label === p);
|
||||||
const links600 = auto_detect_edges(nodes600, 12);
|
const links600 = auto_detect_edges(nodes600, 12);
|
||||||
links600.map((l) => l.label = p);
|
links600.map((l) => l.label = p);
|
||||||
all_links.push(...links600);
|
links.push(...links600);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: '120-cell',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: all_links,
|
links: links,
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
},
|
},
|
||||||
|
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 ] }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cell120_inscribed = () => cell120_some_inscribed([1]);
|
|
||||||
export const cell120_all_inscribed = () => cell120_some_inscribed([1,2,3,4,5]);
|
|
||||||
|
|
||||||
|
|
||||||
// Schoute's partition via https://arxiv.org/abs/1010.4353
|
// Schoute's partition via https://arxiv.org/abs/1010.4353
|
||||||
|
@ -618,48 +614,31 @@ export const cell600 = () => {
|
||||||
const nodes = make_600cell_vertices();
|
const nodes = make_600cell_vertices();
|
||||||
const links = auto_detect_edges(nodes, 12);
|
const links = auto_detect_edges(nodes, 12);
|
||||||
|
|
||||||
|
links.map((l) => l.label = 0);
|
||||||
|
|
||||||
|
for( const p of [1, 2, 3, 4, 5]) {
|
||||||
|
const nodes24 = nodes.filter((n) => n.label === p);
|
||||||
|
const links24 = auto_detect_edges(nodes24, 8);
|
||||||
|
links24.map((l) => l.label = p);
|
||||||
|
links.push(...links24);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: '600-cell',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
|
||||||
node_size: 0.02,
|
|
||||||
link_size: 0.02
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cell600_some_inscribed = (ps) => {
|
|
||||||
const nodes = make_600cell_vertices();
|
|
||||||
const links = auto_detect_edges(nodes, 12);
|
|
||||||
|
|
||||||
const all_links = links;
|
|
||||||
all_links.map((l) => l.label = 0);
|
|
||||||
|
|
||||||
for( const p of ps) {
|
|
||||||
const nodes24 = nodes.filter((n) => n.label === p);
|
|
||||||
const links24 = auto_detect_edges(nodes24, 8);
|
|
||||||
links24.map((l) => l.label = p);
|
|
||||||
all_links.push(...links24);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
nodes: nodes,
|
|
||||||
links: all_links,
|
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
},
|
},
|
||||||
|
options: [
|
||||||
|
{ name: "none", links: [ 0 ]},
|
||||||
|
{ name: "one 24-cell", links: [ 0, 1 ] },
|
||||||
|
{ name: "five 24-cells", links: [ 0, 1, 2, 3, 4, 5 ] }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const cell600_inscribed = () => cell600_some_inscribed([1]);
|
|
||||||
export const cell600_all_inscribed = () => cell600_some_inscribed([1,2,3,4,5]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function make_dodecahedron_vertices() {
|
function make_dodecahedron_vertices() {
|
||||||
const phi = 0.5 * (1 + Math.sqrt(5));
|
const phi = 0.5 * (1 + Math.sqrt(5));
|
||||||
const phiinv = 1 / phi;
|
const phiinv = 1 / phi;
|
||||||
|
@ -697,41 +676,42 @@ function make_dodecahedron_vertices() {
|
||||||
export const dodecahedron = () => {
|
export const dodecahedron = () => {
|
||||||
const nodes = make_dodecahedron_vertices();
|
const nodes = make_dodecahedron_vertices();
|
||||||
const links = auto_detect_edges(nodes, 3);
|
const links = auto_detect_edges(nodes, 3);
|
||||||
|
links.map((l) => l.label = 0);
|
||||||
|
|
||||||
|
for( const p of [ 1, 2, 3, 4, 5 ]) {
|
||||||
|
const tetran = nodes.filter((n) => n.label === p);
|
||||||
|
const tetral = auto_detect_edges(tetran, 3);
|
||||||
|
tetral.map((l) => l.label = p);
|
||||||
|
links.push(...tetral);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: 'dodecahedron',
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
links: links,
|
links: links,
|
||||||
geometry: {
|
|
||||||
node_size: 0.02,
|
|
||||||
link_size: 0.02
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dodecahedron_some_inscribed = (ps) => {
|
|
||||||
const nodes = make_dodecahedron_vertices();
|
|
||||||
const links = auto_detect_edges(nodes, 3);
|
|
||||||
const all_links = links;
|
|
||||||
all_links.map((l) => l.label = 0);
|
|
||||||
|
|
||||||
for( const p of ps) {
|
|
||||||
const tetran = nodes.filter((n) => n.label === p);
|
|
||||||
const tetral = auto_detect_edges(tetran, 3);
|
|
||||||
tetral.map((l) => l.label = p);
|
|
||||||
all_links.push(...tetral);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
nodes: nodes,
|
|
||||||
links: all_links,
|
|
||||||
geometry: {
|
geometry: {
|
||||||
node_size: 0.02,
|
node_size: 0.02,
|
||||||
link_size: 0.02
|
link_size: 0.02
|
||||||
},
|
},
|
||||||
|
options: [
|
||||||
|
{ name: "none", links: [ 0 ]},
|
||||||
|
{ name: "one tetrahedron", links: [ 0, 1 ] },
|
||||||
|
{ name: "five tetrahedra", links: [ 0, 1, 2, 3, 4, 5 ] }
|
||||||
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const dodecahedron_inscribed = () => dodecahedron_some_inscribed([1]);
|
export const build_all = () => {
|
||||||
export const dodecahedron_all_inscribed = () => dodecahedron_some_inscribed([1,2,3,4,5]);
|
return [
|
||||||
|
dodecahedron(),
|
||||||
|
cell5(),
|
||||||
|
cell16(),
|
||||||
|
tesseract(),
|
||||||
|
cell24(),
|
||||||
|
cell600(),
|
||||||
|
cell120_inscribed(),
|
||||||
|
cell120_layered()
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in New Issue