From 13b3d3514a7c11102e401ecb1ef8f7873088b42a Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Fri, 28 Jul 2023 17:39:57 +1000 Subject: [PATCH 01/14] broken --- main.js | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/main.js b/main.js index 31171d5..4f437b6 100644 --- a/main.js +++ b/main.js @@ -83,6 +83,43 @@ function rotXY(theta) { +function fallbackCopyTextToClipboard(text) { + var textArea = document.createElement("textarea"); + textArea.value = text; + + // Avoid scrolling to bottom + textArea.style.top = "0"; + textArea.style.left = "0"; + textArea.style.position = "fixed"; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + var successful = document.execCommand('copy'); + var msg = successful ? 'successful' : 'unsuccessful'; + console.log('Fallback: Copying text command was ' + msg); + } catch (err) { + console.error('Fallback: Oops, unable to copy', err); + } + + document.body.removeChild(textArea); +} + + +function copyTextToClipboard(text) { + if (!navigator.clipboard) { + fallbackCopyTextToClipboard(text); + return; + } + navigator.clipboard.writeText(text).then(function() { + console.log('Async: Copying to clipboard was successful!'); + }, function(err) { + console.error('Async: Could not copy text: ', err); + }); +} + @@ -162,9 +199,16 @@ function createShape(name) { } - - -createShape(DEFAULT_SHAPE); +function floatParam(linkUrl, param) { + const value = linkUrl.searchParams(param); + if( value ) { + const fl = parseFloat(value); + if( fl !== NaN ) { + return fl; + } + } + return 0; +} camera.position.z = 4; @@ -213,14 +257,32 @@ renderer.domElement.addEventListener("pointerup", (event) => { const gui = new GUI(); +const linkUrl = new URL(window.location.toLocaleString()); + +const linkparams = {}; + const gui_params = { shape: DEFAULT_SHAPE, hyperplane: 2, xRotate: 'YW', yRotate: 'XZ', - damping: false + damping: false, + copylink: function () { + const url = + } }; +for( const param in [ "shape", "hyperplane", "xRotate", "yRotate", "damping" ]) { + const value = linkUrl.searchParams(param); + if( value ) { + gui_params[param] = value; + } +} + +dpsi = floatParam(linkUrl, 'dpsi'); +dtheta = floatParam(linkUrl, 'dtheta'); + + gui.add(gui_params, 'shape', [ '5-cell', '16-cell', 'tesseract', '24-cell', '120-cell', '600-cell' ] ).onChange(createShape) @@ -229,6 +291,7 @@ gui.add(gui_params, 'hyperplane', 1.5, 4); gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); gui.add(gui_params, 'damping'); +gui.add() const ROTFN = { XY: rotXY, @@ -241,6 +304,9 @@ const ROTFN = { +createShape(gui_params["shape"]); + + const rotation = new THREE.Matrix4(); function animate() { From 7f7e79fc7c9dfbfc70f4a7526b072c2f397f26cb Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Fri, 28 Jul 2023 17:40:39 +1000 Subject: [PATCH 02/14] Made 120-cell the default --- main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index 31171d5..8018d42 100644 --- a/main.js +++ b/main.js @@ -7,7 +7,7 @@ import { FourDShape } from './fourDShape.js'; import { GUI } from 'lil-gui'; -const DEFAULT_SHAPE = '5-cell'; +const DEFAULT_SHAPE = '120-cell'; // hacky stuff for 4d rotations @@ -264,4 +264,4 @@ function animate() { renderer.render( scene, camera ); } -animate(); \ No newline at end of file +animate(); From fe5761aede72e7d1b72814bd3ff0c795206a2fdc Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 10:40:15 +1000 Subject: [PATCH 03/14] Link copying and param parsing works --- main.js | 52 ++++++++++++++++++++++++++++++++-------------------- polytopes.js | 2 -- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/main.js b/main.js index 4f437b6..cc590fc 100644 --- a/main.js +++ b/main.js @@ -199,8 +199,8 @@ function createShape(name) { } -function floatParam(linkUrl, param) { - const value = linkUrl.searchParams(param); +function floatParam(params, param) { + const value = params.get(param); if( value ) { const fl = parseFloat(value); if( fl !== NaN ) { @@ -259,28 +259,40 @@ const gui = new GUI(); const linkUrl = new URL(window.location.toLocaleString()); -const linkparams = {}; +const link_params = {}; -const gui_params = { - shape: DEFAULT_SHAPE, - hyperplane: 2, - xRotate: 'YW', - yRotate: 'XZ', - damping: false, - copylink: function () { - const url = - } -}; - -for( const param in [ "shape", "hyperplane", "xRotate", "yRotate", "damping" ]) { - const value = linkUrl.searchParams(param); +const urlParams = linkUrl.searchParams; +for( const param of [ "shape", "xRotate", "yRotate" ]) { + const value = urlParams.get(param); if( value ) { - gui_params[param] = value; + link_params[param] = value; } } -dpsi = floatParam(linkUrl, 'dpsi'); -dtheta = floatParam(linkUrl, 'dtheta'); +link_params['hyperplane'] = floatParam(urlParams, 'hyperplane'); + +dpsi = floatParam(urlParams, 'dpsi'); +dtheta = floatParam(urlParams, 'dtheta'); + + +const gui_params = { + shape: link_params['shape'] || DEFAULT_SHAPE, + hyperplane: link_params['hyperplane'] || 2, + xRotate: link_params['xRotate'] || 'YW', + yRotate: link_params['yRotate'] || 'XZ', + damping: false, + "copy link": function () { + const url = new URL(linkUrl.origin + linkUrl.pathname); + url.searchParams.append("shape", gui_params.shape); + url.searchParams.append("hyperplane", gui_params.hyperplane.toString()); + url.searchParams.append("xRotate", gui_params.xRotate); + url.searchParams.append("yRotate", gui_params.yRotate); + url.searchParams.append("dtheta", dtheta.toString()); + url.searchParams.append("dpsi", dpsi.toString()); + copyTextToClipboard(url); + } +}; + gui.add(gui_params, 'shape', @@ -291,7 +303,7 @@ gui.add(gui_params, 'hyperplane', 1.5, 4); gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); gui.add(gui_params, 'damping'); -gui.add() +gui.add(gui_params, 'copy link'); const ROTFN = { XY: rotXY, diff --git a/polytopes.js b/polytopes.js index d00b6ea..38309c0 100644 --- a/polytopes.js +++ b/polytopes.js @@ -76,8 +76,6 @@ export const cell16 = () => { let nodes = PERMUTE.coordinates([1, 1, 1, 1], 0); nodes = nodes.filter((n) => n.x * n.y * n.z * n.w > 0); scale_and_index(nodes, 0.75); - console.log('cell16 auto_detect_edges'); - console.log(nodes); const links = auto_detect_edges(nodes, 6); return { From f3e5a5b430a2fa5e01c7d228f1ef692197cb28d1 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 11:52:43 +1000 Subject: [PATCH 04/14] Adjustable colours and thickness, almost done --- main.js | 79 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/main.js b/main.js index c5f4e56..7666c8d 100644 --- a/main.js +++ b/main.js @@ -8,6 +8,12 @@ import { GUI } from 'lil-gui'; const DEFAULT_SHAPE = '120-cell'; +const DEFAULT_COLOR = 0x90ebff; +const DEFAULT_BG = 0xdddddd; + + + + // hacky stuff for 4d rotations @@ -139,7 +145,7 @@ scene.add(light); const amblight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(amblight); -scene.background = new THREE.Color(0xdddddd); +scene.background = new THREE.Color(DEFAULT_BG); const renderer = new THREE.WebGLRenderer({antialias: true}); @@ -147,35 +153,13 @@ renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); -const NODE_OPACITY = 1.0; -const LINK_OPACITY = 1.0; +const material = new THREE.MeshStandardMaterial( + { color: DEFAULT_COLOR } +); -const node_ms = [ - new THREE.MeshStandardMaterial( { color: 0x90ebff } ) -]; +const node_ms = [ material ]; -for( const node_m of node_ms ) { - node_m.roughness = 0.9; - - if( NODE_OPACITY < 1.0 ) { - node_m.transparent = true; - node_m.opacity = NODE_OPACITY; - } -} - -const link_ms = [ - new THREE.MeshStandardMaterial( { color: 0x90ebff } ) - ]; - -for( const link_m of link_ms ) { - link_m.metalness = 0.8; - link_m.roughness = 0.1; - - if( LINK_OPACITY < 1.0 ) { - link_m.transparent = true; - link_m.opacity = LINK_OPACITY; - } -} +const link_ms = [ material ]; const STRUCTURES = { '5-cell': POLYTOPES.cell5(), @@ -210,6 +194,26 @@ function floatParam(params, param) { return 0; } +function stringtoHex(cstr) { + return parseInt('0x' + cstr.substr(1)); +} + +function hexToString(hex) { + return '#' + hex.toString(16); +} + + +function colorParam(params, param, dft) { + const value = params.get(param); + if( value ) { + const hex = stringtoHex(value); + if( hex !== NaN ) { + return hex; + } + } + return dft; +} + camera.position.z = 4; @@ -270,6 +274,9 @@ for( const param of [ "shape", "xRotate", "yRotate" ]) { } link_params['hyperplane'] = floatParam(urlParams, 'hyperplane'); +link_params['thickness'] = floatParam(urlParams, 'thickness'); +link_params['color'] = colorParam(urlParams, 'color', DEFAULT_COLOR); +link_params['background'] = colorParam(urlParams, 'background', DEFAULT_BG); dpsi = floatParam(urlParams, 'dpsi'); dtheta = floatParam(urlParams, 'dtheta'); @@ -277,6 +284,9 @@ dtheta = floatParam(urlParams, 'dtheta'); const gui_params = { shape: link_params['shape'] || DEFAULT_SHAPE, + thickness: link_params['thickness'] || 1, + color: link_params['color'] || DEFAULT_COLOR, + background: link_params['background'] || DEFAULT_BG, hyperplane: link_params['hyperplane'] || 2, xRotate: link_params['xRotate'] || 'YW', yRotate: link_params['yRotate'] || 'XZ', @@ -284,6 +294,9 @@ const gui_params = { "copy link": function () { const url = new URL(linkUrl.origin + linkUrl.pathname); url.searchParams.append("shape", gui_params.shape); + url.searchParams.append("thickness", gui_params.thickness.toString()); + url.searchParams.append("color", hexToString(gui_params.color)); + url.searchParams.append("background", hexToString(gui_params.background)); url.searchParams.append("hyperplane", gui_params.hyperplane.toString()); url.searchParams.append("xRotate", gui_params.xRotate); url.searchParams.append("yRotate", gui_params.yRotate); @@ -300,6 +313,15 @@ gui.add(gui_params, 'shape', ).onChange(createShape) gui.add(gui_params, 'hyperplane', 1.5, 4); +gui.add(gui_params, 'thickness', 0.01, 4); +gui.addColor(gui_params, 'color').onChange((c) => { + console.log(`Setting material colour to ${c}`); + material.color = new THREE.Color(c); +}); +gui.addColor(gui_params, 'background').onChange((c) => { + console.log(`Setting background colour to ${c}`); + scene.background = new THREE.Color(c); +}); gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); gui.add(gui_params, 'damping'); @@ -338,6 +360,7 @@ function animate() { ROTFN[gui_params.yRotate](psi) ]; shape.hyperplane = gui_params.hyperplane; + shape.geom_scale = gui_params.thickness; shape.render3(rotations); renderer.render( scene, camera ); From de0f3dc8484a96a013f493c828609f7d57771bc9 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 12:06:34 +1000 Subject: [PATCH 05/14] Refactoring --- gui.js | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rotation.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 gui.js create mode 100644 rotation.js diff --git a/gui.js b/gui.js new file mode 100644 index 0000000..8396d88 --- /dev/null +++ b/gui.js @@ -0,0 +1,90 @@ +import { GUI } from 'lil-gui'; + + +const DEFAULT_SHAPE = '120-cell'; +const DEFAULT_COLOR = 0x90ebff; +const DEFAULT_BG = 0xdddddd; + + + + +// set up GUI + +const gui = new GUI(); + +const linkUrl = new URL(window.location.toLocaleString()); + +const link_params = {}; + +const urlParams = linkUrl.searchParams; +for( const param of [ "shape", "xRotate", "yRotate" ]) { + const value = urlParams.get(param); + if( value ) { + link_params[param] = value; + } +} + +link_params['hyperplane'] = floatParam(urlParams, 'hyperplane'); +link_params['thickness'] = floatParam(urlParams, 'thickness'); +link_params['color'] = colorParam(urlParams, 'color', DEFAULT_COLOR); +link_params['background'] = colorParam(urlParams, 'background', DEFAULT_BG); + +dpsi = floatParam(urlParams, 'dpsi'); +dtheta = floatParam(urlParams, 'dtheta'); + + +const gui_params = { + shape: link_params['shape'] || DEFAULT_SHAPE, + thickness: link_params['thickness'] || 1, + color: link_params['color'] || DEFAULT_COLOR, + background: link_params['background'] || DEFAULT_BG, + hyperplane: link_params['hyperplane'] || 2, + xRotate: link_params['xRotate'] || 'YW', + yRotate: link_params['yRotate'] || 'XZ', + damping: false, + "copy link": function () { + const url = new URL(linkUrl.origin + linkUrl.pathname); + url.searchParams.append("shape", gui_params.shape); + url.searchParams.append("thickness", gui_params.thickness.toString()); + url.searchParams.append("color", hexToString(gui_params.color)); + url.searchParams.append("background", hexToString(gui_params.background)); + url.searchParams.append("hyperplane", gui_params.hyperplane.toString()); + url.searchParams.append("xRotate", gui_params.xRotate); + url.searchParams.append("yRotate", gui_params.yRotate); + url.searchParams.append("dtheta", dtheta.toString()); + url.searchParams.append("dpsi", dpsi.toString()); + copyTextToClipboard(url); + } +}; + + + +gui.add(gui_params, 'shape', + [ '5-cell', '16-cell', 'tesseract', '24-cell', '120-cell', '600-cell' ] + ).onChange(createShape) + +gui.add(gui_params, 'hyperplane', 1.5, 4); +gui.add(gui_params, 'thickness', 0.01, 4); +gui.addColor(gui_params, 'color').onChange((c) => { + console.log(`Setting material colour to ${c}`); + material.color = new THREE.Color(c); +}); +gui.addColor(gui_params, 'background').onChange((c) => { + console.log(`Setting background colour to ${c}`); + scene.background = new THREE.Color(c); +}); +gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); +gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); +gui.add(gui_params, 'damping'); +gui.add(gui_params, 'copy link'); + +const ROTFN = { + XY: rotXY, + XZ: rotXZ, + XW: rotXW, + YZ: rotYZ, + YW: rotYW, + ZW: rotZW, +}; + + diff --git a/rotation.js b/rotation.js new file mode 100644 index 0000000..27b3fc7 --- /dev/null +++ b/rotation.js @@ -0,0 +1,85 @@ +// hacky stuff for 4d rotations + +// see https://math.stackexchange.com/questions/1402362/can-rotations-in-4d-be-given-an-explicit-matrix-form#1402376 + +import * as THREE from 'three'; + + +function rotZW(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + ctheta, -stheta, 0, 0, + stheta, ctheta, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); +} + +function rotYW(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + ctheta, 0, -stheta, 0, + 0, 1, 0, 0, + stheta, 0, ctheta, 0, + 0, 0, 0, 1, + ); +} + +function rotYZ(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + ctheta, 0, 0, -stheta, + 0, 1, 0, 0, + 0, 0, 1, 0, + stheta, 0, 0, ctheta, + ); +} + +function rotXW(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + 1, 0, 0, 0, + 0, ctheta, -stheta, 0, + 0, stheta, ctheta, 0, + 0, 0, 0, 1 + ); +} + +function rotXZ(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + 1, 0, 0, 0, + 0, ctheta, 0, -stheta, + 0, 0, 1, 0, + 0, stheta, 0, ctheta, + ); +} + +function rotXY(theta) { + const ctheta = Math.cos(theta); + const stheta = Math.sin(theta); + return new THREE.Matrix4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, ctheta, -stheta, + 0, 0, stheta, ctheta, + ); +} + + +export const rotfn = { + XY: rotXY, + XZ: rotXZ, + XW: rotXW, + YZ: rotYZ, + YW: rotYW, + ZW: rotZW, +}; + + + From d253a851e95ca2e2f1e76ff70917bcfe5f7982c5 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 16:23:08 +1000 Subject: [PATCH 06/14] almost through big refactor --- fourDShape.js | 16 +-- gui.js | 201 +++++++++++++++++++++------------- main.js | 294 +++++--------------------------------------------- polytopes.js | 37 +++++-- 4 files changed, 197 insertions(+), 351 deletions(-) diff --git a/fourDShape.js b/fourDShape.js index 03aa60b..bd88764 100644 --- a/fourDShape.js +++ b/fourDShape.js @@ -3,10 +3,6 @@ import * as THREE from 'three'; const HYPERPLANE = 2; -const NODE_SIZE = 0.01; -const LINK_SIZE = 0.01; - - class FourDShape extends THREE.Group { @@ -17,6 +13,9 @@ class FourDShape extends THREE.Group { this.nodes4 = structure.nodes; this.nodes3 = {}; this.links = structure.links; + this.node_size = structure.geometry.node_size; + this.link_size = structure.geometry.link_size; + this.geom_scale = 1; this.hyperplane = HYPERPLANE; this.initShapes(); } @@ -34,7 +33,7 @@ class FourDShape extends THREE.Group { } makeNode(material, v3) { - const geometry = new THREE.SphereGeometry(NODE_SIZE); + const geometry = new THREE.SphereGeometry(this.node_size); const sphere = new THREE.Mesh(geometry, material); sphere.position.copy(v3); this.add(sphere); @@ -47,7 +46,7 @@ class FourDShape extends THREE.Group { const length = n1.distanceTo(n2); const centre = new THREE.Vector3(); centre.lerpVectors(n1, n2, 0.5); - const geometry = new THREE.CylinderGeometry(LINK_SIZE, LINK_SIZE, 1); + const geometry = new THREE.CylinderGeometry(this.link_size, this.link_size, 1); const cyl = new THREE.Mesh(geometry, material); const edge = new THREE.Group(); edge.add(cyl); @@ -65,7 +64,7 @@ class FourDShape extends THREE.Group { const length = n1.distanceTo(n2); const centre = new THREE.Vector3(); centre.lerpVectors(n1, n2, 0.5); - link.object.scale.copy(new THREE.Vector3(1, 1, length)); + link.object.scale.copy(new THREE.Vector3(this.geom_scale, this.geom_scale, length)); link.object.position.copy(centre); link.object.lookAt(n2); link.object.children[0].rotation.x = Math.PI / 2.0; @@ -98,11 +97,12 @@ class FourDShape extends THREE.Group { render3(rotations) { + this.scalev3 = new THREE.Vector3(this.geom_scale, this.geom_scale, this.geom_scale); for( const n of this.nodes4 ) { const v3 = this.fourDtoV3(n.x, n.y, n.z, n.w, rotations); this.nodes3[n.id].v3 = v3; this.nodes3[n.id].object.position.copy(v3); - // could do scaling here + this.nodes3[n.id].object.scale.copy(this.scalev3); } for( const l of this.links ) { diff --git a/gui.js b/gui.js index 8396d88..054f8da 100644 --- a/gui.js +++ b/gui.js @@ -7,84 +7,141 @@ const DEFAULT_BG = 0xdddddd; +class FourDGUI { -// set up GUI + constructor(createShape, setColor, setBackground) { + this.gui = new GUI(); + this.parseLinkParams(); + this.params = { + shape: this.link['shape'] || DEFAULT_SHAPE, + thickness: this.link['thickness'] || 1, + color: this.link['color'] || DEFAULT_COLOR, + background: this.link['background'] || DEFAULT_BG, + hyperplane: this.link['hyperplane'] || 2, + xRotate: this.link['xRotate'] || 'YW', + yRotate: this.link['yRotate'] || 'XZ', + damping: false, + dtheta: this.link['dtheta'], + dpsi: this.link['dpsi'], + "copy link": function () { this.copyUrl() } + }; -const gui = new GUI(); + this.gui.add(this.params, 'shape', + [ '5-cell', '16-cell', 'tesseract', '24-cell', '120-cell', '600-cell' ] + ).onChange(createShape) -const linkUrl = new URL(window.location.toLocaleString()); + this.gui.add(this.params, 'hyperplane', 1.5, 4); + this.gui.add(this.params, 'thickness', 0.01, 4); + this.gui.addColor(this.params, 'color').onChange(setColor); + this.gui.addColor(this.params, 'background').onChange(setBackground); + this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); + this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); + this.gui.add(this.params, 'damping'); + this.gui.add(this.params, 'copy link'); + } -const link_params = {}; -const urlParams = linkUrl.searchParams; -for( const param of [ "shape", "xRotate", "yRotate" ]) { - const value = urlParams.get(param); - if( value ) { - link_params[param] = value; + numParam(param, parser, dft) { + const value = this.urlParams.get(param); + if( value ) { + const n = parser(value); + if( n !== NaN ) { + return n; + } + } + return dft; } + + stringtoHex(cstr) { + return parseInt('0x' + cstr.substr(1)); + } + + hexToString(hex) { + return '#' + hex.toString(16); + } + + + + parseLinkParams() { + this.linkUrl = new URL(window.location.toLocaleString()); + this.link = {}; + + this.urlParams = this.linkUrl.searchParams; + for( const param of [ "shape", "xRotate", "yRotate" ]) { + const value = this.urlParams.get(param); + if( value ) { + this.link[param] = value; + } + } + + this.link['hyperplane'] = this.numParam('hyperplane', parseFloat, 2); + this.link['thickness'] = this.numParam('thickness', parseFloat, 1); + this.link['color'] = this.numParam( + 'color', (s) => this.stringToHex(s), DEFAULT_COLOR + ); + this.link['background'] = this.numParam( + 'background', (s) => this.stringToHex(s), DEFAULT_BG + ); + + this.link['dpsi'] = this.numParam('dpsi', 0); + this.link['dtheta'] = this.numParam('dtheta', 0); + } + + + copyUrl() { + const url = new URL(linkUrl.origin + linkUrl.pathname); + url.searchParams.append("shape", this.params.shape); + url.searchParams.append("thickness", this.params.thickness.toString()); + url.searchParams.append("color", hexToString(this.params.color)); + url.searchParams.append("background", hexToString(this.params.background)); + url.searchParams.append("hyperplane", this.params.hyperplane.toString()); + url.searchParams.append("xRotate", this.params.xRotate); + url.searchParams.append("yRotate", this.params.yRotate); + url.searchParams.append("dtheta", this.dtheta.toString()); + url.searchParams.append("dpsi", this.dpsi.toString()); + this.copyTextToClipboard(url); + } + + + copyTextToClipboard(text) { + if (!navigator.clipboard) { + this.fallbackCopyTextToClipboard(text); + return; + } + navigator.clipboard.writeText(text).then(function() { + console.log('Async: Copying to clipboard was successful!'); + }, function(err) { + console.error('Async: Could not copy text: ', err); + }); + } + + + fallbackCopyTextToClipboard(text) { + var textArea = document.createElement("textarea"); + textArea.value = text; + + // Avoid scrolling to bottom + textArea.style.top = "0"; + textArea.style.left = "0"; + textArea.style.position = "fixed"; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + var successful = document.execCommand('copy'); + var msg = successful ? 'successful' : 'unsuccessful'; + console.log('Fallback: Copying text command was ' + msg); + } catch (err) { + console.error('Fallback: Oops, unable to copy', err); + } + + document.body.removeChild(textArea); + } + + } -link_params['hyperplane'] = floatParam(urlParams, 'hyperplane'); -link_params['thickness'] = floatParam(urlParams, 'thickness'); -link_params['color'] = colorParam(urlParams, 'color', DEFAULT_COLOR); -link_params['background'] = colorParam(urlParams, 'background', DEFAULT_BG); - -dpsi = floatParam(urlParams, 'dpsi'); -dtheta = floatParam(urlParams, 'dtheta'); - - -const gui_params = { - shape: link_params['shape'] || DEFAULT_SHAPE, - thickness: link_params['thickness'] || 1, - color: link_params['color'] || DEFAULT_COLOR, - background: link_params['background'] || DEFAULT_BG, - hyperplane: link_params['hyperplane'] || 2, - xRotate: link_params['xRotate'] || 'YW', - yRotate: link_params['yRotate'] || 'XZ', - damping: false, - "copy link": function () { - const url = new URL(linkUrl.origin + linkUrl.pathname); - url.searchParams.append("shape", gui_params.shape); - url.searchParams.append("thickness", gui_params.thickness.toString()); - url.searchParams.append("color", hexToString(gui_params.color)); - url.searchParams.append("background", hexToString(gui_params.background)); - url.searchParams.append("hyperplane", gui_params.hyperplane.toString()); - url.searchParams.append("xRotate", gui_params.xRotate); - url.searchParams.append("yRotate", gui_params.yRotate); - url.searchParams.append("dtheta", dtheta.toString()); - url.searchParams.append("dpsi", dpsi.toString()); - copyTextToClipboard(url); - } -}; - - - -gui.add(gui_params, 'shape', - [ '5-cell', '16-cell', 'tesseract', '24-cell', '120-cell', '600-cell' ] - ).onChange(createShape) - -gui.add(gui_params, 'hyperplane', 1.5, 4); -gui.add(gui_params, 'thickness', 0.01, 4); -gui.addColor(gui_params, 'color').onChange((c) => { - console.log(`Setting material colour to ${c}`); - material.color = new THREE.Color(c); -}); -gui.addColor(gui_params, 'background').onChange((c) => { - console.log(`Setting background colour to ${c}`); - scene.background = new THREE.Color(c); -}); -gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); -gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); -gui.add(gui_params, 'damping'); -gui.add(gui_params, 'copy link'); - -const ROTFN = { - XY: rotXY, - XZ: rotXZ, - XW: rotXW, - YZ: rotYZ, - YW: rotYW, - ZW: rotZW, -}; - +export { FourDGUI }; \ No newline at end of file diff --git a/main.js b/main.js index 7666c8d..b4d1009 100644 --- a/main.js +++ b/main.js @@ -1,161 +1,35 @@ import * as THREE from 'three'; -import * as POLYTOPES from './polytopes.js'; + +import * as POLYTOPES from './polytopes.js'; +import { rotfn } from './rotation.js'; +import { FourDGUI } from './gui.js'; import { FourDShape } from './fourDShape.js'; -import { GUI } from 'lil-gui'; - - -const DEFAULT_SHAPE = '120-cell'; -const DEFAULT_COLOR = 0x90ebff; -const DEFAULT_BG = 0xdddddd; - - - - - -// hacky stuff for 4d rotations - -// see https://math.stackexchange.com/questions/1402362/can-rotations-in-4d-be-given-an-explicit-matrix-form#1402376 - - - -function rotZW(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - ctheta, -stheta, 0, 0, - stheta, ctheta, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ); -} - -function rotYW(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - ctheta, 0, -stheta, 0, - 0, 1, 0, 0, - stheta, 0, ctheta, 0, - 0, 0, 0, 1, - ); -} - -function rotYZ(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - ctheta, 0, 0, -stheta, - 0, 1, 0, 0, - 0, 0, 1, 0, - stheta, 0, 0, ctheta, - ); -} - -function rotXW(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - 1, 0, 0, 0, - 0, ctheta, -stheta, 0, - 0, stheta, ctheta, 0, - 0, 0, 0, 1 - ); -} - -function rotXZ(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - 1, 0, 0, 0, - 0, ctheta, 0, -stheta, - 0, 0, 1, 0, - 0, stheta, 0, ctheta, - ); -} - -function rotXY(theta) { - const ctheta = Math.cos(theta); - const stheta = Math.sin(theta); - return new THREE.Matrix4( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, ctheta, -stheta, - 0, 0, stheta, ctheta, - ); -} - - - -function fallbackCopyTextToClipboard(text) { - var textArea = document.createElement("textarea"); - textArea.value = text; - - // Avoid scrolling to bottom - textArea.style.top = "0"; - textArea.style.left = "0"; - textArea.style.position = "fixed"; - - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - - try { - var successful = document.execCommand('copy'); - var msg = successful ? 'successful' : 'unsuccessful'; - console.log('Fallback: Copying text command was ' + msg); - } catch (err) { - console.error('Fallback: Oops, unable to copy', err); - } - - document.body.removeChild(textArea); -} - - -function copyTextToClipboard(text) { - if (!navigator.clipboard) { - fallbackCopyTextToClipboard(text); - return; - } - navigator.clipboard.writeText(text).then(function() { - console.log('Async: Copying to clipboard was successful!'); - }, function(err) { - console.error('Async: Could not copy text: ', err); - }); -} - - - - +// scene, lights and camera const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); - const light = new THREE.PointLight(0xffffff, 2); light.position.set(10, 10, 10); scene.add(light); - const light2 = new THREE.PointLight(0xffffff, 2); light2.position.set(-10, 5, 10); scene.add(light); - - const amblight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(amblight); -scene.background = new THREE.Color(DEFAULT_BG); - +camera.position.z = 4; const renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); +// set up colours and materials for gui callbacks -const material = new THREE.MeshStandardMaterial( - { color: DEFAULT_COLOR } -); +scene.background = new THREE.Color(0x000000); +const material = new THREE.MeshStandardMaterial({ color: 0xff0000 }); const node_ms = [ material ]; @@ -170,7 +44,6 @@ const STRUCTURES = { '600-cell': POLYTOPES.cell600() }; - let shape = false; function createShape(name) { @@ -182,40 +55,18 @@ function createShape(name) { } +// initialise gui and read params from URL -function floatParam(params, param) { - const value = params.get(param); - if( value ) { - const fl = parseFloat(value); - if( fl !== NaN ) { - return fl; - } - } - return 0; -} +// callbacks to do things which are triggered by controls: reset the shape, +// change the colors. Otherwise we just read stuff from gui.params. -function stringtoHex(cstr) { - return parseInt('0x' + cstr.substr(1)); -} - -function hexToString(hex) { - return '#' + hex.toString(16); -} +const gui = new FourDGUI( + createShape, + (c) => { material.color = new THREE.Color(c) }, + (c) => { scene.background = new THREE.Color(c) }, +); -function colorParam(params, param, dft) { - const value = params.get(param); - if( value ) { - const hex = stringtoHex(value); - if( hex !== NaN ) { - return hex; - } - } - return dft; -} - - -camera.position.z = 4; const dragK = 0.005; const damping = 0.99; @@ -226,8 +77,6 @@ let theta0 = 0; let psi0 = 0; let dragx0 = 0; let dragy0 = 0; -let dtheta = 0; -let dpsi = 0; let dragging = false; @@ -245,8 +94,8 @@ renderer.domElement.addEventListener("pointermove", (event) => { if( event.buttons === 1 ) { const theta1 = theta0 + (event.clientX - dragx0) * dragK; const psi1 = psi0 + (event.clientY - dragy0) * dragK; - dtheta = theta1 - theta; - dpsi = psi1 - psi; + gui.params.dtheta = theta1 - theta; + gui.params.dpsi = psi1 - psi; theta = theta1; psi = psi1; } @@ -256,111 +105,26 @@ renderer.domElement.addEventListener("pointerup", (event) => { dragging = false; }) - -// set up GUI - -const gui = new GUI(); - -const linkUrl = new URL(window.location.toLocaleString()); - -const link_params = {}; - -const urlParams = linkUrl.searchParams; -for( const param of [ "shape", "xRotate", "yRotate" ]) { - const value = urlParams.get(param); - if( value ) { - link_params[param] = value; - } -} - -link_params['hyperplane'] = floatParam(urlParams, 'hyperplane'); -link_params['thickness'] = floatParam(urlParams, 'thickness'); -link_params['color'] = colorParam(urlParams, 'color', DEFAULT_COLOR); -link_params['background'] = colorParam(urlParams, 'background', DEFAULT_BG); - -dpsi = floatParam(urlParams, 'dpsi'); -dtheta = floatParam(urlParams, 'dtheta'); - - -const gui_params = { - shape: link_params['shape'] || DEFAULT_SHAPE, - thickness: link_params['thickness'] || 1, - color: link_params['color'] || DEFAULT_COLOR, - background: link_params['background'] || DEFAULT_BG, - hyperplane: link_params['hyperplane'] || 2, - xRotate: link_params['xRotate'] || 'YW', - yRotate: link_params['yRotate'] || 'XZ', - damping: false, - "copy link": function () { - const url = new URL(linkUrl.origin + linkUrl.pathname); - url.searchParams.append("shape", gui_params.shape); - url.searchParams.append("thickness", gui_params.thickness.toString()); - url.searchParams.append("color", hexToString(gui_params.color)); - url.searchParams.append("background", hexToString(gui_params.background)); - url.searchParams.append("hyperplane", gui_params.hyperplane.toString()); - url.searchParams.append("xRotate", gui_params.xRotate); - url.searchParams.append("yRotate", gui_params.yRotate); - url.searchParams.append("dtheta", dtheta.toString()); - url.searchParams.append("dpsi", dpsi.toString()); - copyTextToClipboard(url); - } -}; - - - -gui.add(gui_params, 'shape', - [ '5-cell', '16-cell', 'tesseract', '24-cell', '120-cell', '600-cell' ] - ).onChange(createShape) - -gui.add(gui_params, 'hyperplane', 1.5, 4); -gui.add(gui_params, 'thickness', 0.01, 4); -gui.addColor(gui_params, 'color').onChange((c) => { - console.log(`Setting material colour to ${c}`); - material.color = new THREE.Color(c); -}); -gui.addColor(gui_params, 'background').onChange((c) => { - console.log(`Setting background colour to ${c}`); - scene.background = new THREE.Color(c); -}); -gui.add(gui_params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); -gui.add(gui_params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); -gui.add(gui_params, 'damping'); -gui.add(gui_params, 'copy link'); - -const ROTFN = { - XY: rotXY, - XZ: rotXZ, - XW: rotXW, - YZ: rotYZ, - YW: rotYW, - ZW: rotZW, -}; - - - -createShape(gui_params["shape"]); - - -const rotation = new THREE.Matrix4(); +createShape(gui.params.shape); function animate() { requestAnimationFrame( animate ); if( ! dragging ) { - theta += dtheta; - psi += dpsi; - if( gui_params.damping ) { - dtheta = dtheta * damping; - dpsi = dpsi * damping; + theta += gui.params.dtheta; + psi += gui.params.dpsi; + if( gui.params.damping ) { + gui.params.dtheta = gui.params.dtheta * damping; + gui.params.dpsi = gui.params.dpsi * damping; } } const rotations = [ - ROTFN[gui_params.xRotate](theta), - ROTFN[gui_params.yRotate](psi) + rotfn[gui.params.xRotate](theta), + rotfn[gui.params.yRotate](psi) ]; - shape.hyperplane = gui_params.hyperplane; - shape.geom_scale = gui_params.thickness; + shape.hyperplane = gui.params.hyperplane; + shape.geom_scale = gui.params.thickness; shape.render3(rotations); renderer.render( scene, camera ); diff --git a/polytopes.js b/polytopes.js index 38309c0..0266880 100644 --- a/polytopes.js +++ b/polytopes.js @@ -67,7 +67,11 @@ export const cell5 = () => { { id:8, source:3, target: 4}, { id:9, source:3, target: 5}, { id:10, source:4, target: 5}, - ] + ], + geometry: { + node_size: 0.05, + link_size: 0.05 + } }; }; @@ -80,7 +84,11 @@ export const cell16 = () => { return { nodes: nodes, - links: links + links: links, + geometry: { + node_size: 0.03, + link_size: 0.03 + } }; }; @@ -92,7 +100,11 @@ export const tesseract = () => { return { nodes: nodes, - links: links + links: links, + geometry: { + node_size: 0.03, + link_size: 0.03 + } }; } @@ -105,7 +117,11 @@ export const cell24 = () => { return { nodes: nodes, - links: links + links: links, + geometry: { + node_size: 0.02, + link_size: 0.02 + } }; } @@ -138,7 +154,12 @@ export const cell120 = () => { const links = auto_detect_edges(nodes, 4); return { nodes: nodes, - links: links + links: links, + geometry: { + node_size: 0.01, + link_size: 0.01 + } + } } @@ -161,7 +182,11 @@ export const cell600 = () => { const links = auto_detect_edges(nodes, 20); return { nodes: nodes, - links: links + links: links, + geometry: { + node_size: 0.003, + link_size: 0.003 + } } } From 0b78ea29392ae472cffc9a39c02373900e2adfe3 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 16:44:18 +1000 Subject: [PATCH 07/14] Everything's working except for default colours --- gui.js | 30 ++++++++++++++++-------------- main.js | 5 ++--- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/gui.js b/gui.js index 054f8da..bf04cf1 100644 --- a/gui.js +++ b/gui.js @@ -12,6 +12,7 @@ class FourDGUI { constructor(createShape, setColor, setBackground) { this.gui = new GUI(); this.parseLinkParams(); + const guiObj = this; this.params = { shape: this.link['shape'] || DEFAULT_SHAPE, thickness: this.link['thickness'] || 1, @@ -21,9 +22,9 @@ class FourDGUI { xRotate: this.link['xRotate'] || 'YW', yRotate: this.link['yRotate'] || 'XZ', damping: false, - dtheta: this.link['dtheta'], - dpsi: this.link['dpsi'], - "copy link": function () { this.copyUrl() } + dtheta: this.link['dtheta'] || 0, + dpsi: this.link['dpsi'] || 0, + "copy link": function () { guiObj.copyUrl() } }; this.gui.add(this.params, 'shape', @@ -52,7 +53,7 @@ class FourDGUI { return dft; } - stringtoHex(cstr) { + stringToHex(cstr) { return parseInt('0x' + cstr.substr(1)); } @@ -73,32 +74,33 @@ class FourDGUI { this.link[param] = value; } } - + const guiObj = this; + console.log(guiObj); this.link['hyperplane'] = this.numParam('hyperplane', parseFloat, 2); this.link['thickness'] = this.numParam('thickness', parseFloat, 1); this.link['color'] = this.numParam( - 'color', (s) => this.stringToHex(s), DEFAULT_COLOR + 'color', (s) => guiObj.stringToHex(s), DEFAULT_COLOR ); this.link['background'] = this.numParam( - 'background', (s) => this.stringToHex(s), DEFAULT_BG + 'background', (s) => guiObj.stringToHex(s), DEFAULT_BG ); - this.link['dpsi'] = this.numParam('dpsi', 0); - this.link['dtheta'] = this.numParam('dtheta', 0); + this.link['dpsi'] = this.numParam('dpsi', parseFloat, 0); + this.link['dtheta'] = this.numParam('dtheta', parseFloat, 0); } copyUrl() { - const url = new URL(linkUrl.origin + linkUrl.pathname); + const url = new URL(this.linkUrl.origin + this.linkUrl.pathname); url.searchParams.append("shape", this.params.shape); url.searchParams.append("thickness", this.params.thickness.toString()); - url.searchParams.append("color", hexToString(this.params.color)); - url.searchParams.append("background", hexToString(this.params.background)); + url.searchParams.append("color", this.hexToString(this.params.color)); + url.searchParams.append("background", this.hexToString(this.params.background)); url.searchParams.append("hyperplane", this.params.hyperplane.toString()); url.searchParams.append("xRotate", this.params.xRotate); url.searchParams.append("yRotate", this.params.yRotate); - url.searchParams.append("dtheta", this.dtheta.toString()); - url.searchParams.append("dpsi", this.dpsi.toString()); + url.searchParams.append("dtheta", this.params.dtheta.toString()); + url.searchParams.append("dpsi", this.params.dpsi.toString()); this.copyTextToClipboard(url); } diff --git a/main.js b/main.js index b4d1009..2d913e1 100644 --- a/main.js +++ b/main.js @@ -28,8 +28,8 @@ document.body.appendChild( renderer.domElement ); // set up colours and materials for gui callbacks -scene.background = new THREE.Color(0x000000); -const material = new THREE.MeshStandardMaterial({ color: 0xff0000 }); +scene.background = new THREE.Color(0xdddddd); +const material = new THREE.MeshStandardMaterial({ color: 0x90ebff }); const node_ms = [ material ]; @@ -52,7 +52,6 @@ function createShape(name) { } shape = new FourDShape(node_ms, link_ms, STRUCTURES[name]); scene.add(shape); - } // initialise gui and read params from URL From efb4cf76084106e1e8bcc1742311c6ee55b3a309 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 16:52:00 +1000 Subject: [PATCH 08/14] Refactored all the GUI and rotation stuff out, colour links are working --- gui.js | 1 + main.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gui.js b/gui.js index bf04cf1..d8e0f0f 100644 --- a/gui.js +++ b/gui.js @@ -39,6 +39,7 @@ class FourDGUI { this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); this.gui.add(this.params, 'damping'); this.gui.add(this.params, 'copy link'); + } diff --git a/main.js b/main.js index 2d913e1..2566ae8 100644 --- a/main.js +++ b/main.js @@ -65,7 +65,8 @@ const gui = new FourDGUI( (c) => { scene.background = new THREE.Color(c) }, ); - +material.color = new THREE.Color(gui.params.color); +scene.background = new THREE.Color(gui.params.background); const dragK = 0.005; const damping = 0.99; From 1bd838dd7406174595f0249ccc11ca4f21ec8601 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 29 Jul 2023 16:55:31 +1000 Subject: [PATCH 09/14] Improved default colours --- gui.js | 4 ++-- main.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gui.js b/gui.js index d8e0f0f..9b0c681 100644 --- a/gui.js +++ b/gui.js @@ -2,8 +2,8 @@ import { GUI } from 'lil-gui'; const DEFAULT_SHAPE = '120-cell'; -const DEFAULT_COLOR = 0x90ebff; -const DEFAULT_BG = 0xdddddd; +const DEFAULT_COLOR = 0x3293a9; +const DEFAULT_BG = 0x808080; diff --git a/main.js b/main.js index 2566ae8..892aa68 100644 --- a/main.js +++ b/main.js @@ -28,8 +28,8 @@ document.body.appendChild( renderer.domElement ); // set up colours and materials for gui callbacks -scene.background = new THREE.Color(0xdddddd); -const material = new THREE.MeshStandardMaterial({ color: 0x90ebff }); +scene.background = new THREE.Color(0x808080); +const material = new THREE.MeshStandardMaterial({ color: 0x3293a9 }); const node_ms = [ material ]; From 13510c1ac11bdcd4f98b855bb3456b407fbebcbd Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 30 Jul 2023 11:46:13 +1000 Subject: [PATCH 10/14] Fixed bug which gave 600-cell too many edges --- polytopes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polytopes.js b/polytopes.js index 0266880..7277e6f 100644 --- a/polytopes.js +++ b/polytopes.js @@ -179,7 +179,7 @@ function make_600cell_vertices() { export const cell600 = () => { const nodes = make_600cell_vertices(); - const links = auto_detect_edges(nodes, 20); + const links = auto_detect_edges(nodes, 12); return { nodes: nodes, links: links, From c2ac5d79282b3514beb1912572c89465d6489f1e Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 30 Jul 2023 11:46:34 +1000 Subject: [PATCH 11/14] removed debug stuff --- gui.js | 1 - 1 file changed, 1 deletion(-) diff --git a/gui.js b/gui.js index 9b0c681..1effd83 100644 --- a/gui.js +++ b/gui.js @@ -76,7 +76,6 @@ class FourDGUI { } } const guiObj = this; - console.log(guiObj); this.link['hyperplane'] = this.numParam('hyperplane', parseFloat, 2); this.link['thickness'] = this.numParam('thickness', parseFloat, 1); this.link['color'] = this.numParam( From f4ec6d403e31802761d10ad0cc7976cd476bf626 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 30 Jul 2023 17:56:01 +1000 Subject: [PATCH 12/14] Made all shapes have the same thickness --- gui.js | 2 +- polytopes.js | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gui.js b/gui.js index 1effd83..cb92458 100644 --- a/gui.js +++ b/gui.js @@ -32,7 +32,7 @@ class FourDGUI { ).onChange(createShape) this.gui.add(this.params, 'hyperplane', 1.5, 4); - this.gui.add(this.params, 'thickness', 0.01, 4); + this.gui.add(this.params, 'thickness', 0.1, 4); this.gui.addColor(this.params, 'color').onChange(setColor); this.gui.addColor(this.params, 'background').onChange(setBackground); this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); diff --git a/polytopes.js b/polytopes.js index 7277e6f..326445a 100644 --- a/polytopes.js +++ b/polytopes.js @@ -69,8 +69,8 @@ export const cell5 = () => { { id:10, source:4, target: 5}, ], geometry: { - node_size: 0.05, - link_size: 0.05 + node_size: 0.02, + link_size: 0.02 } }; }; @@ -86,8 +86,8 @@ export const cell16 = () => { nodes: nodes, links: links, geometry: { - node_size: 0.03, - link_size: 0.03 + node_size: 0.02, + link_size: 0.02 } }; }; @@ -102,8 +102,8 @@ export const tesseract = () => { nodes: nodes, links: links, geometry: { - node_size: 0.03, - link_size: 0.03 + node_size: 0.02, + link_size: 0.02 } }; } @@ -156,8 +156,8 @@ export const cell120 = () => { nodes: nodes, links: links, geometry: { - node_size: 0.01, - link_size: 0.01 + node_size: 0.02, + link_size: 0.02 } } @@ -184,8 +184,8 @@ export const cell600 = () => { nodes: nodes, links: links, geometry: { - node_size: 0.003, - link_size: 0.003 + node_size: 0.02, + link_size: 0.02 } } } From 2992f4ab66b66e8eb9c73e0107d40766216bc194 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Mon, 31 Jul 2023 17:23:57 +1000 Subject: [PATCH 13/14] Added debug flag to edge detector --- polytopes.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/polytopes.js b/polytopes.js index 326445a..8dbbfac 100644 --- a/polytopes.js +++ b/polytopes.js @@ -17,7 +17,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; } -function auto_detect_edges(nodes, neighbours) { +function auto_detect_edges(nodes, neighbours, debug=false) { const seen = {}; const nnodes = nodes.length; const links = []; @@ -29,6 +29,10 @@ function auto_detect_edges(nodes, neighbours) { } d2.sort((a, b) => a.d2 - b.d2); const closest = d2.slice(1, neighbours + 1); + if( debug ) { + console.log(`closest = ${closest.length}`); + console.log(closest); + } for( const e of closest ) { const ids = [ n1.id, e.id ]; ids.sort(); @@ -40,6 +44,9 @@ function auto_detect_edges(nodes, neighbours) { } } } + if( debug ) { + console.log(`Found ${links.length} edges`) + } return links; } @@ -179,7 +186,7 @@ function make_600cell_vertices() { export const cell600 = () => { const nodes = make_600cell_vertices(); - const links = auto_detect_edges(nodes, 12); + const links = auto_detect_edges(nodes, 12, true); return { nodes: nodes, links: links, From c50095760942abc62da220af6f88fda5cdb499db Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Mon, 31 Jul 2023 17:24:26 +1000 Subject: [PATCH 14/14] Turned off debug for 600-cell --- polytopes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polytopes.js b/polytopes.js index 8dbbfac..affc219 100644 --- a/polytopes.js +++ b/polytopes.js @@ -186,7 +186,7 @@ function make_600cell_vertices() { export const cell600 = () => { const nodes = make_600cell_vertices(); - const links = auto_detect_edges(nodes, 12, true); + const links = auto_detect_edges(nodes, 12); return { nodes: nodes, links: links,