More shape experiments

feature-faces
Mike Lynch 2023-07-28 17:06:42 +10:00
parent 8a581a9d64
commit 19c73d0f80
3 changed files with 130 additions and 3 deletions

View File

@ -10,13 +10,15 @@ const LINK_SIZE = 0.01;
class FourDShape extends THREE.Group { class FourDShape extends THREE.Group {
constructor(node_ms, link_ms, structure) { constructor(node_ms, link_ms, face_ms, structure) {
super(); super();
this.node_ms = node_ms; this.node_ms = node_ms;
this.link_ms = link_ms; this.link_ms = link_ms;
this.face_ms = face_ms;
this.nodes4 = structure.nodes; this.nodes4 = structure.nodes;
this.nodes3 = {}; this.nodes3 = {};
this.links = structure.links; this.links = structure.links;
this.faces = ( "faces" in structure ) ? structure.faces : [];
this.hyperplane = HYPERPLANE; this.hyperplane = HYPERPLANE;
this.initShapes(); this.initShapes();
} }
@ -71,6 +73,32 @@ class FourDShape extends THREE.Group {
link.object.children[0].rotation.x = Math.PI / 2.0; link.object.children[0].rotation.x = Math.PI / 2.0;
} }
setFaceGeometry(face, geometry) {
const values = [];
for( const f of face.nodes ) {
const v3 = this.nodes3[f].v3;
values.push(v3.x);
values.push(v3.y);
values.push(v3.z);
}
const v3 = this.nodes3[face.nodes[0]].v3;
values.push(v3.x);
values.push(v3.y);
values.push(v3.z);
const vertices = new Float32Array(values);
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
}
makeFace(material, face) {
const geometry = new THREE.BufferGeometry();
this.setFaceGeometry(face, geometry)
const mesh = new THREE.Mesh( geometry, material );
this.add(mesh);
return mesh;
}
fourDtoV3(x, y, z, w, rotations) { fourDtoV3(x, y, z, w, rotations) {
const v4 = new THREE.Vector4(x, y, z, w); const v4 = new THREE.Vector4(x, y, z, w);
for ( const m4 of rotations ) { for ( const m4 of rotations ) {
@ -94,6 +122,10 @@ class FourDShape extends THREE.Group {
const material = this.getMaterial(l, this.link_ms); const material = this.getMaterial(l, this.link_ms);
l.object = this.makeLink(material, l); l.object = this.makeLink(material, l);
} }
// for( const f of this.faces ) {
// const material = this.getMaterial(f, this.face_ms);
// f.object = this.makeFace(material, f);
// }
} }
@ -108,6 +140,10 @@ class FourDShape extends THREE.Group {
for( const l of this.links ) { for( const l of this.links ) {
this.updateLink(l); this.updateLink(l);
} }
// for( const f of this.faces ) {
// this.setFaceGeometry(f, f.object.geometry);
// }
} }

15
main.js
View File

@ -112,6 +112,7 @@ document.body.appendChild( renderer.domElement );
const NODE_OPACITY = 1.0; const NODE_OPACITY = 1.0;
const LINK_OPACITY = 1.0; const LINK_OPACITY = 1.0;
const FACE_OPACITY = 0.2;
const node_ms = [ const node_ms = [
new THREE.MeshStandardMaterial( { color: 0x90ebff } ) new THREE.MeshStandardMaterial( { color: 0x90ebff } )
@ -140,6 +141,17 @@ for( const link_m of link_ms ) {
} }
} }
const face_ms = [
new THREE.MeshLambertMaterial( { color: 0x44ff44 } )
];
for( const face_m of face_ms ) {
face_m.transparent = true;
face_m.opacity = FACE_OPACITY;
}
const STRUCTURES = { const STRUCTURES = {
'5-cell': POLYTOPES.cell5(), '5-cell': POLYTOPES.cell5(),
'16-cell': POLYTOPES.cell16(), '16-cell': POLYTOPES.cell16(),
@ -156,7 +168,8 @@ function createShape(name) {
if( shape ) { if( shape ) {
scene.remove(shape); scene.remove(shape);
} }
shape = new FourDShape(node_ms, link_ms, STRUCTURES[name]); console.log(STRUCTURES[name]);
shape = new FourDShape(node_ms, link_ms, face_ms, STRUCTURES[name]);
scene.add(shape); scene.add(shape);
} }

View File

@ -112,6 +112,82 @@ export const cell24 = () => {
} }
// face detection for the 120-cell
// NOTE: all of these return node ids, not nodes
// return all the links which connect to a node
function nodes_links(links, nodeid) {
return links.filter((l) => l.source === nodeid || l.target === nodeid);
}
// filter to remove a link to a given id from a set of links
function not_to_this(link, nodeid) {
return !(link.source === nodeid || link.target === nodeid);
}
// given nodes n1, n2, return all neighbours of n2 which are not n1
function unmutuals(links, n1id, n2id) {
const nlinks = nodes_links(links, n2id).filter((l) => not_to_this(l, n1id));
return nlinks.map((l) => {
if( l.source === n2id ) {
return l.target;
} else {
return l.source;
}
})
}
function fingerprint(ids) {
const sids = [...ids];
sids.sort();
return sids.join(',');
}
function auto_120cell_faces(links) {
const faces = [];
const seen = {};
let id = 1;
for( const edge of links ) {
const v1 = edge.source;
const v2 = edge.target;
const n1 = unmutuals(links, v2, v1);
const n2 = unmutuals(links, v1, v2);
const shared = [];
for( const a of n1 ) {
const an = unmutuals(links, v1, a);
for( const d of n2 ) {
const dn = unmutuals(links, v2, d);
for( const x of an ) {
for( const y of dn ) {
if( x == y ) {
shared.push([v1, a, x, d, v2])
}
}
}
}
}
if( shared.length !== 3 ) {
console.log(`Bad shared faces for ${edge.id} ${v1} ${v2}`);
}
for( const face of shared ) {
const fp = fingerprint(face);
if( !seen[fp] ) {
faces.push({ id: id, nodes: face });
id++;
seen[fp] = true;
}
}
}
return faces;
}
function make_120cell_vertices() { function make_120cell_vertices() {
@ -138,9 +214,11 @@ function make_120cell_vertices() {
export const cell120 = () => { export const cell120 = () => {
const nodes = make_120cell_vertices(); const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
const faces = auto_120cell_faces(links);
return { return {
nodes: nodes, nodes: nodes,
links: links links: links,
faces: faces
} }
} }