diff --git a/fourDShape.js b/fourDShape.js index 888ebd7..3ccc923 100644 --- a/fourDShape.js +++ b/fourDShape.js @@ -1,9 +1,12 @@ import * as THREE from 'three'; +import { TaperedLink } from './taperedLink.js'; + const HYPERPLANE = 2.0; const W_FORESHORTENING = 0.04; + class FourDShape extends THREE.Group { constructor(node_ms, link_ms, face_ms, structure) { @@ -42,7 +45,7 @@ class FourDShape extends THREE.Group { return sphere; } - makeLink(material, link) { + makeLink(basematerial, link) { const n1 = this.nodes3[link.source]; const n2 = this.nodes3[link.target]; const s1 = n1.scale; @@ -50,17 +53,11 @@ class FourDShape extends THREE.Group { const length = n1.v3.distanceTo(n2.v3); const centre = new THREE.Vector3(); centre.lerpVectors(n1.v3, n2.v3, 0.5); - const geometry = new THREE.CylinderGeometry( - this.link_scale * s2, this.link_scale * s1, 1, - 16, 1, true - ); - const cyl = new THREE.Mesh(geometry, material); - const edge = new THREE.Group(); - edge.add(cyl); + + const edge = new TaperedLink(basematerial); + edge.update(s1, s2, length); edge.position.copy(centre); - edge.scale.copy(new THREE.Vector3(1, 1, length)); edge.lookAt(n2.v3); - cyl.rotation.x = Math.PI / 2.0; this.add(edge); return edge; } @@ -73,14 +70,9 @@ class FourDShape extends THREE.Group { const length = n1.v3.distanceTo(n2.v3); const centre = new THREE.Vector3(); centre.lerpVectors(n1.v3, n2.v3, 0.5); - // take the average of the ends as the thickness - as a workaround, - // because I haven't worked out how to reshape tapered links without - // having to reassign a new geometry to every link - const link_mean = this.link_scale * (s1 + s2) * 0.5; - link.object.scale.copy(new THREE.Vector3(link_mean, link_mean, length)); - link.object.position.copy(centre); + link.object.update(s1, s2, length); + link.object.position.copy(n1.v3); link.object.lookAt(n2.v3); - link.object.children[0].rotation.x = Math.PI / 2.0; link.object.visible = (!links_show || link.label in links_show); } diff --git a/gui.js b/gui.js index baba2ea..57df9d4 100644 --- a/gui.js +++ b/gui.js @@ -7,7 +7,7 @@ const DEFAULTS = { linksize: 0.2, linkopacity: 0.75, link2opacity: 0.75, - shape: '120-cell', + shape: '16-cell', option: 'none', visibility: 5, inscribed: false, diff --git a/main.js b/main.js index 04d8497..b285ae2 100644 --- a/main.js +++ b/main.js @@ -31,6 +31,10 @@ camera.lookAt(0, 0, 0); const renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize( window.innerWidth, window.innerHeight ); + +renderer.localClippingEnabled = true; + + document.body.appendChild( renderer.domElement ); // set up colours and materials for gui callbacks diff --git a/taperedLink.js b/taperedLink.js new file mode 100644 index 0000000..0ccfcf7 --- /dev/null +++ b/taperedLink.js @@ -0,0 +1,36 @@ +import * as THREE from 'three'; + + +class TaperedLink extends THREE.Group { + + constructor(baseMaterial) { + super(); + const geometry = new THREE.ConeGeometry( 0.75, 1, 32, true ); + const cplane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0.5); + const material = baseMaterial.clone(); + material.clippingPlanes = [ cplane ]; + this.object = new THREE.Mesh( geometry, material ); + this.add( this.object ); + } + + update(r1, r2, l) { + const kraw = ( r1 - r2 ); + const k = ( kraw == 0 ) ? 0.001 : kraw; + if( k > 0 ) { + const h = l * r1 / k; + this.object.scale.copy(new THREE.Vector3(r1, h, r1)); + this.object.material.clippingPlanes[0].normal.y = -1; + this.object.material.clippingPlanes[0].constant = l / 2; + this.object.position.copy(new THREE.Vector3(0, h/2 - l/2, 0)); + } else { + const h = l * r2 / k; + this.object.scale.copy(new THREE.Vector3(r2, h, r2)); + this.object.material.clippingPlanes[0].normal.y = 1; + this.object.material.clippingPlanes[0].constant = l / 2; + this.object.position.copy(new THREE.Vector3(0, h / 2 + l / 2, 0)); + } + } + +} + +export { TaperedLink };