var con = console; var maxIterations = 15000; var maxStartIterations = 1000; var iterations = 0; var runs = 0; var gridSize = 10; var cubeSize = 12; var maxPaths = 100; // maxPaths probably effects peformance more than anything else, but the bailout iterations above too. var cubesPerNode = 4; var px = 0; var py = 0; var py = 0; var direction = 2; var currentPath = -1; // var paths = []; var path; function tran(v) { return (v - (gridSize - 1) / 2) * cubeSize; } var grid = []; for (var i = 0; i < gridSize; i++) { grid[i] = []; for (var j = 0; j < gridSize; j++) { grid[i][j] = []; for (var k = 0; k < gridSize; k++) { grid[i][j][k] = 0; } } } function drawPath(path) { if (path.length == 1) return; // draw single dots??? var grey = 0x30 + Math.random() * 0x60; var colour = grey << 16 | grey << 8 | grey; if (Math.random() > 0.9) colour = 0x00ff40; // var colour = ~~(currentPath / maxPaths * 0xffffff); for ( var i = 1, il = path.length; i < il; i++) { var a = path[i - 1], ax = a[0], ay = a[1], az = a[2]; var b = path[i], bx = b[0], by = b[1], bz = b[2]; for( var j = 0; j < cubesPerNode; j++) { var x = ax + (bx - ax) * j / cubesPerNode; var y = ay + (by - ay) * j / cubesPerNode; var z = az + (bz - az) * j / cubesPerNode; addCube(x, y, z, colour, i, j); } // draws a keyline down the centre of a path // var material = new THREE.LineBasicMaterial({color: colour}); // var geometry = new THREE.Geometry(); // geometry.vertices.push( // new THREE.Vector3(tran(ax), tran(ay), tran(az)), // new THREE.Vector3(tran(bx), tran(by), tran(bz)) // ); // var line = new THREE.Line(geometry, material); // group.add( line ); } addCube(bx, by, bz, colour, i, 0); } function pointValid(x, y, z) { return grid[x] != undefined && grid[x][y] != undefined && grid[x][y][z] != undefined; } function pointFree(x, y, z) { return pointValid(x, y, z) && grid[x][y][z] != 1; } function getNextPoint() { var newX = px, newY = py, newZ = pz, newDir = Math.floor(Math.random() * 5) - 2; var dir = (6 + direction + newDir) % 6; // make sure dir is not backwards. // con.log("dir", dir) switch (dir) { case 0: newX--; break; // left case 1: newY--; break; // up case 2: newZ--; break; // forwards case 3: newX++; break; // right case 4: newY++; break; // down case 5: newZ++; break; // backwards } var valid = pointValid(newX, newY, newZ); if (valid) { direction = dir; // update new direction return { x: newX, y: newY, z: newZ, complete: !pointFree(newX, newY, newZ) // if it's not free, it's occupied. this line is over!!! } } else { return getNextPoint(); // try again, with original point. } } function calcSection() { var nextPoint = getNextPoint(); // con.log(nextPoint) if (nextPoint.complete === true) { drawPath(path); if (currentPath < maxPaths) { // newPath(); setTimeout( function() { newPath() }, 10 + Math.random() * 500); } else { con.log("maxPaths"); } } else { px = nextPoint.x; py = nextPoint.y; pz = nextPoint.z; // con.log('nextPoint', px, py, pz) grid[px][py][pz] = 1; path.push([px, py, pz]); // paths[currentPath] = path; iterations++; // drawPath(path); if (iterations < maxIterations ) { // setTimeout( function() { calcSection() }, 30); calcSection(); } else { // drawPath(path); con.log("iterations reached", iterations, maxIterations); } // if (iterations < 60 ) calcSection(); } } var startPositions = gridSize * 4; var start = []; for ( var i = 0; i < startPositions; i++ ) { start[i] = i; } function newStart() { px = ~~(Math.random() * gridSize); py = ~~(Math.random() * gridSize); pz = ~~(Math.random() * gridSize); var edge = Math.round(Math.random() * 6); switch (edge) { case 0: px = 0; break; // left case 1: py = 0; break; // top case 2: pz = 0; break; // front case 3: px = gridSize - 1; break; // right case 4: py = gridSize - 1; break; // bottom case 5: pz = gridSize - 1; break; // back } if (!pointFree(px, py, pz) && iterations < maxStartIterations) { iterations++; // con.log("finding new start!!!"); newStart(); } } function newPath() { currentPath++; newStart(); iterations = 0; path = []; path.push([px,py,pz]); grid[px][py][pz] = 1; calcSection(); } var stageWidth = 800; var stageHeight = 800; var cameraTarget = new THREE.Vector3(0,0,0) var camera = new THREE.PerspectiveCamera(55, stageWidth/stageHeight, 1, 20000); camera.position.x = 100; camera.position.y = cubeSize * gridSize / 1.8; // just outside bounding box. camera.position.z = 200; camera.lookAt(cameraTarget); var scene = new THREE.Scene(); // scene.fog = new THREE.Fog( 0x000000, 5000, 10000 ); var pointLight = new THREE.PointLight(0xffffff); pointLight.position.x = 5000; scene.add(pointLight); var pointLight = new THREE.PointLight(0xffffff); pointLight.position.y = 5000; scene.add(pointLight); var pointLight = new THREE.PointLight(0x404040); pointLight.position.z = 5000; scene.add(pointLight); var group = new THREE.Object3D(); scene.add( group ); // draw bounding box // var geometry = new THREE.BoxGeometry(cubeSize * gridSize, cubeSize * gridSize, cubeSize * gridSize); // var material = new THREE.MeshBasicMaterial({ wireframe: true, color: 0x303030 }); // var cube = new THREE.Mesh(geometry, material); // group.add( cube ); var renderer = new THREE.WebGLRenderer(); renderer.setSize(stageWidth, stageHeight); document.body.appendChild( renderer.domElement ); function render(t) { requestAnimationFrame( render ); group.rotation.z += 0.001; group.rotation.x += 0.001; camera.position.z -= 0.1; camera.lookAt(cameraTarget); renderer.render( scene, camera ); } function addCube(x, y, z, colour, ii, jj) { // scope really helpful here for passing in variables to a timeout function call. setTimeout( function() { var cubeGeometry = cubeSize / cubesPerNode * 0.9; var geometry = new THREE.BoxGeometry(cubeGeometry, cubeGeometry, cubeGeometry); var material = new THREE.MeshPhongMaterial( { color: colour, shininess: 100, shading: THREE.SmoothShading } ) var cube = new THREE.Mesh(geometry, material); cube.position.x = tran(x); cube.position.y = tran(y); cube.position.z = tran(z); group.add(cube); }, (ii * cubesPerNode + jj) * 50); } newPath(); render(0);