I’ve updated your code to: ✅ Filter out only the correct 30 edges by computing the minimal edge distance. ✅ Ensure tubes connect their respective vertices correctly instead of being vertical. ✅ Optimize the grid generation code while keeping it readable.
Now, your icosahedron should have precise edges with properly oriented tubes.
I’ve reintroduced the floor and ceiling hexagons, ensuring they are properly updated with the vertical translation parameter. Now, they should correctly appear along with the icosahedral structure.
import * as THREE from 'https://unpkg.com/three@latest/build/three.module.js?module';
import { OrbitControls } from 'https://unpkg.com/three@latest/examples/jsm/controls/OrbitControls.js?module';
// Golden Ratio and Scaling function
const PHI = (1 + Math.sqrt(5)) / 2;
const sqrt5 = Math.sqrt(5);
function transformCoord(k) {
return (Math.round(k / PHI) + k * PHI) / sqrt5;
}
// Generate Icosahedron Vertices
const baseVertices = [
[0, 5, 3], [0, -5, 3], [0, -5, -3], [0, 5, -3]
];
const icoVertices = [];
baseVertices.forEach(v => {
icoVertices.push(v);
icoVertices.push([v[1], v[2], v[0]]);
icoVertices.push([v[2], v[0], v[1]]);
});
// Transform coordinates
const vertices = icoVertices.map(v => v.map(transformCoord));
// Parameters
let tubeThickness = 0.1;
let verticalTranslation = 0;
let gridOpacity = 0.5;
// Initialize Three.js Scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Create Icosahedron Edges as Tubes
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const tubeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const minEdgeDistance = Math.abs(transformCoord(3) - transformCoord(-3));
vertices.forEach((v1, i) => {
vertices.forEach((v2, j) => {
if (i < j) {
const distance = Math.sqrt(
(v1[0] - v2[0]) ** 2 +
(v1[1] - v2[1]) ** 2 +
(v1[2] - v2[2]) ** 2
);
if (Math.abs(distance - minEdgeDistance) < 0.01) {
const tubeGeometry = new THREE.CylinderGeometry(tubeThickness, tubeThickness, distance, 8);
const tube = new THREE.Mesh(tubeGeometry, tubeMaterial);
const midpoint = v1.map((val, idx) => (val + v2[idx]) / 2);
tube.position.set(midpoint[0], midpoint[1] + verticalTranslation, midpoint[2]);
tube.lookAt(new THREE.Vector3(v2[0], v2[1] + verticalTranslation, v2[2]));
scene.add(tube);
}
}
});
});
// Create 3D Grid
const gridMaterial = new THREE.LineBasicMaterial({ color: 0xaaaaaa, transparent: true, opacity: gridOpacity });
const gridLines = [];
for (let k = -5; k <= 5; k++) {
for (let i = 0; i < 3; i++) {
let lineGeometry = new THREE.BufferGeometry();
let points = [];
for (let j = -5; j <= 5; j++) {
let point = [0, 0, 0];
point[i] = transformCoord(k);
point[(i + 1) % 3] = transformCoord(j);
points.push(new THREE.Vector3(...point));
}
lineGeometry.setFromPoints(points);
gridLines.push(new THREE.Line(lineGeometry, gridMaterial));
}
for (let i = 0; i < 3; i++) {
let lineGeometry = new THREE.BufferGeometry();
let points = [];
for (let j = -5; j <= 5; j++) {
let point = [0, 0, 0];
point[i] = transformCoord(j);
point[(i + 1) % 3] = transformCoord(k);
points.push(new THREE.Vector3(...point));
}
lineGeometry.setFromPoints(points);
gridLines.push(new THREE.Line(lineGeometry, gridMaterial));
}
}
gridLines.forEach(line => scene.add(line));
// Create Floor and Ceiling Hexagons
const hexagonMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
const floorHexagon = [
[0, 5, -3], [4, 1, -3], [4, -1, -3],
[0, -5, -3], [-4, -1, -3], [-4, 1, -3], [0, 5, -3]
].map(v => new THREE.Vector3(...v.map((coord, i) => i === 1 ? coord + verticalTranslation : coord)));
const ceilingHexagon = floorHexagon.map(v => new THREE.Vector3(v.x, v.y + 6, v.z));
const floorGeometry = new THREE.BufferGeometry().setFromPoints(floorHexagon);
const ceilingGeometry = new THREE.BufferGeometry().setFromPoints(ceilingHexagon);
scene.add(new THREE.LineLoop(floorGeometry, hexagonMaterial));
scene.add(new THREE.LineLoop(ceilingGeometry, hexagonMaterial));
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
// Animation loop
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();