Select Git revision
grid.js 19.14 KiB
function threejs(GLOBALS,utils,containerName,container1Name){
this.camera;
this.scene;
this.renderer;
this.plane;
this.mouse;
this.raycaster;
this.isShiftDown = false;
this.rollOverMesh;
this.rollOverMaterial;
this.cubeGeo;
this.cubeMaterial;
this.sphereGeo;
this.helperMaterial;
this.helperPosition;
this.helperColor;
this.objects = [];
this.container = document.getElementById( containerName );
this.container1Name = container1Name;
this.controls;
this.voxelSpacing=GLOBALS.voxelSpacing;
this.occupancyHelper;
this.voxels=[];
this.color1=GLOBALS.color1;
this.color3=GLOBALS.color3;
this.color4=GLOBALS.color4;
this.gridSize=GLOBALS.gridSize;
this.utils=utils;
this.grid=GLOBALS.grid;
this.cubicGrid=GLOBALS.gridPresets.Cubic;
this.occupancy=GLOBALS.occupancy;
this.selectedNodeID;
this.menu;
this.highlight;
//TODO: REMOVE FROM HERE TO GLOBALS
var color1= "#ffffff"; //white
var color11= "#ffffff8c"; //white transparent
var color2= "#020227"; //dark blue
var color3= "#1c5c61"; //teal
var color33= "#1c5c618c"; //teal transparent
var color4= "#fa6e70"; //red/orange
var color44= "#fa6e708c"; //red/orange
var color5="#380152"; //purple
var color6="#696767"; //grey
this.cy = cytoscape({
container: document.getElementById(container1Name),
ready: function(){
},
style: [
],
autolock: true,
elements: {
nodes: [
],
edges: [
]
},
});
this.cxtdefaults = {
selector: 'core',//'node, edge',
menuRadius: 50,
fillColor: color11, // the background colour of the menu
activeFillColor: color44, // the colour used to indicate the selected command
// activePadding: 20, // additional size in pixels for the active command
indicatorSize: 20, // the size in pixels of the pointer to the active command
// separatorWidth: 3, // the empty spacing in pixels between successive commands
spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight
minSpotlightRadius: 15, // the minimum radius in pixels of the spotlight
maxSpotlightRadius: 10, // the maximum radius in pixels of the spotlight
// openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here
itemColor: color6, // the colour of text in the command's content
// itemTextShadowColor: 'transparent', // the text shadow colour of the command's content
zIndex: 9999, // the z-index of the ui div
// atMouse: false // draw menu at mouse position
commands: [
{
//RUN/PLAY NODE
content: '<span class="fa fa-play fa-1x"></span>',
select: function(){
// console.log( "play");//todo move to globals
GLOBALS.runNode(three.selectedNodeID.x,three.selectedNodeID.y,three.selectedNodeID.z);
}
},
{
content: '<span class="fa fa-trash fa-1x"></span>',
select: function(){
GLOBALS.selectNode(three.selectedNodeID.x,three.selectedNodeID.y,three.selectedNodeID.z);
GLOBALS.removeNode(three.selectedNodeID.x,three.selectedNodeID.y,three.selectedNodeID.z);
},
// enabled: true
},
{
// content: 'Select',
content: '<span class="fa fa-mouse-pointer fa-1x"></span>',
select: function(){
// console.log( "Select");//todo move to globals
GLOBALS.selectNode(three.selectedNodeID.x,three.selectedNodeID.y,three.selectedNodeID.z);
}
}
]
};
// this.init();
}
threejs.prototype.init=function() {
this.camera = new THREE.PerspectiveCamera( 45, this.getWidth()/ this.getHeight() , 1, 10000*this.voxelSpacing);
this.camera.position.set( -this.gridSize*this.voxelSpacing*1.0, this.gridSize*this.voxelSpacing, this.gridSize*this.voxelSpacing/2.0 );
this.camera.lookAt( this.gridSize/2, 0, this.gridSize/2 );
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color( 0xffffff );
this.cubeGeo = new THREE.BoxBufferGeometry( this.voxelSpacing, this.voxelSpacing, this.voxelSpacing );
this.sphereGeo = new THREE.SphereGeometry( this.voxelSpacing/2, 32, 32 );
this.cubeMaterial = new THREE.MeshPhongMaterial( { color: 0x1c5c61 } );
// grid
var gridHelper = new THREE.GridHelper( (this.gridSize)*this.voxelSpacing, this.gridSize );
gridHelper.position.x=this.gridSize/2.0*this.voxelSpacing-this.voxelSpacing/2.0;
gridHelper.position.z=this.gridSize/2.0*this.voxelSpacing-this.voxelSpacing/2.0;
gridHelper.position.y=-this.voxelSpacing/2.0*this.grid.voxelScaleZ;
gridHelper.scale.x=this.grid.xScale;
gridHelper.scale.z=this.grid.yScale;
gridHelper.scale.y=this.grid.zScale;
this.scene.add( gridHelper );
// roll-over helpers
var rollOverGeo = new THREE.BoxBufferGeometry( this.voxelSpacing, this.voxelSpacing, this.voxelSpacing );
this.rollOverMaterial = new THREE.MeshBasicMaterial( { color: this.color4, opacity: 0.8, transparent: true } );
this.rollOverMesh = new THREE.Mesh( rollOverGeo, this.rollOverMaterial );
this.rollOverMesh.scale.x=this.grid.voxelScaleX;
this.rollOverMesh.scale.z=this.grid.voxelScaleY;
this.rollOverMesh.scale.y=this.grid.voxelScaleZ;
var edges = new THREE.EdgesGeometry( rollOverGeo );
this.highlight = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: this.color4,linewidth: 4} ) );
this.highlight.scale.x=this.grid.voxelScaleX*1.1;
this.highlight.scale.z=this.grid.voxelScaleY*1.1;
this.highlight.scale.y=this.grid.voxelScaleZ*1.1;
this.scene.add(this.highlight);
this.scene.add( this.rollOverMesh );
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
this.helperPosition = new Float32Array( 1 * 3 );
var c = new THREE.Color( this.color1 );
this.helperColor = new Float32Array( 1 * 3 );
this.helperColor[0]=c.r;
this.helperColor[1]=c.g;
this.helperColor[2]=c.b;
this.helperMaterial = new THREE.PointsMaterial( { size: 5, vertexColors: THREE.VertexColors,color:this.color3 } );
this.buildGrid(this.gridSize);
this.createHelperMeshes(this.grid,this.gridSize);
// var axesHelper = new THREE.AxesHelper( 20 *grid.voxelSpacing);
// scene.add( axesHelper );
// lights
var ambientLight = new THREE.AmbientLight( 0x606060 );
this.scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 1, 0.75, 0.5 ).normalize();
this.scene.add( directionalLight );
this.renderer = new THREE.WebGLRenderer( { antialias: true } );
this.renderer.setPixelRatio( window.devicePixelRatio );
this.renderer.setSize( this.getWidth(), this.getHeight() );
this.renderer = new THREE.WebGLRenderer();
this.container.appendChild( this.renderer.domElement );
this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement );
this.controls.target=new THREE.Vector3( this.gridSize/2*this.voxelSpacing,0 ,this.gridSize/2*this.voxelSpacing );
this.controls.update();
// document.body.appendChild( renderer.domElement );
onWindowResizeThree();
this.container.addEventListener( 'mousemove', onDocumentMouseMoveThree, false );
this.container.addEventListener( 'mousedown', onDocumentMouseDownThree, false );
// window.addEventListener( 'keydown', onDocumentKeyDown, false );
window.addEventListener( 'mouseup', onDocumentKeyUpThree, false );
//
window.addEventListener( 'mouseup', onWindowResizeThree, false );
window.addEventListener( 'resize', onWindowResizeThree, false );
this.animate();
};
////////////////////////
threejs.prototype.animate=function() {
requestAnimationFrame(this.animate.bind(this));
this.render();
};
threejs.prototype.render=function() {
this.renderer.render( this.scene, this.camera );
this.controls.update();
};
////////////////////////////
threejs.prototype.buildGrid=function(gridSize){
this.occupancyHelper=[];
for (var i=0;i<gridSize;++i){
// occupancy.push([]);
this.occupancyHelper.push([]);
for (var j=0;j<gridSize;++j){
// occupancy[i].push([]);
this.occupancyHelper[i].push([]);
for (var k=0;k<gridSize;++k){
// occupancy[i][j].push(false);
this.occupancyHelper[i][j].push(false);
}
}
}
};
threejs.prototype.buildVoxelAt=function( grid,x, y,z){
var voxel = new THREE.Mesh( this.cubeGeo, this.cubeMaterial );
// var voxel = new THREE.Mesh( sphereGeo, cubeMaterial );
var p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y;
[p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y]=this.utils.getTransforms(grid,x, y,z);
voxel.scale.x=s_x;
voxel.scale.z=s_z;
voxel.scale.y=s_y;
voxel.position.x=0;
voxel.position.y=0;
voxel.position.z=0;
voxel.rotation.y=r_y;
voxel.position.x=p_x;
voxel.position.y=p_y;
voxel.position.z=p_z;
voxel.name="["+parseInt(x) +","+parseInt(y) +","+parseInt(z) +"]";
this.scene.add(voxel);
this.voxels.push(voxel);
};
threejs.prototype.createHelperMeshes=function(grid,gridSize){
for (var i=0;i<gridSize;++i){
for (var j=0;j<gridSize;++j){
this.buildHelperSnap(grid,i,j,0);
}
}
};
threejs.prototype.buildHelperSnap=function(grid,x,y,z){
this.occupancyHelper[x][y][z]=true;
var geometry = new THREE.PlaneBufferGeometry( grid.voxelSpacing*grid.xScale, grid.voxelSpacing*grid.yScale );
geometry.rotateX( - Math.PI / 2 );
this.plane = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { visible: false } ) );
// this.plane = new THREE.Mesh( geometry,this.helperMaterial );
[p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y]=this.utils.getTransforms(grid,x, y,z);
this.plane.scale.x=s_x;
this.plane.scale.z=s_z;
// rollOverMesh.scale.y=s_y;
this.plane.position.x=0;
this.plane.position.y=0;
this.plane.position.z=0;
this.plane.rotation.y=r_y;
this.plane.position.x=p_x;
this.plane.position.y=p_y;
this.plane.position.z=p_z;
this.plane.name="p["+parseInt(x) +","+parseInt(y) +","+parseInt(z) +"]";
this.helperPosition[0]=this.plane.position.x;
this.helperPosition[1]=this.plane.position.y;
this.helperPosition[2]=this.plane.position.z;
var helperGeometry = new THREE.BufferGeometry();
helperGeometry.setAttribute( 'position', new THREE.BufferAttribute( this.helperPosition.slice(), 3 ) );
helperGeometry.setAttribute( 'color', new THREE.BufferAttribute( this.helperColor.slice(), 3 ) );
this.helper = new THREE.Points( helperGeometry, this.helperMaterial );
this.helper.name="s["+parseInt(x) +","+parseInt(y) +","+parseInt(z) +"]";
this.scene.add( this.helper );
this.scene.add( this.plane );
this.objects.push( this.plane );
};
threejs.prototype.buildNeighborHelpers=function(grid, x, y,z){
var list=this.utils.getNeighborsList(grid,x,y,z);
for(var i=0;i<list.length;i++){
var x1,y1,z1;
[x1,y1,z1]=list[i];
if(this.helperAt(x1,y1,z1)){
this.buildHelperSnap(grid,x1,y1,z1);
}
}
//go through all neighbors
//if occupancy empty
//add helper meshes??
//how to rotate plane
};
threejs.prototype.helperAt=function(x,y,z){
if(x<0||y<0||z<0){
return false;
}
if(x>=this.gridSize||y>=this.gridSize||z>=this.gridSize){
return false;
}
if(this.occupancy[x][y][z]||this.occupancyHelper[x][y][z]){
return false;
}
return true;
};
threejs.prototype.updateHelperMeshesAfterRemove=function(grid,x,y,z){
// this.buildHelperSnap(grid,x,y,z);
this.occupancy[x][y][z]=false;
if(z<1){
this.buildHelperSnap(grid,x,y,z);
}
var list=this.utils.getNeighborsList(grid,x,y,z); //TODO ENCLOSE
for(var i=0;i<list.length;i++){
var x1,y1,z1;
[x1,y1,z1]=list[i];
if(!this.helperAt(x1,y1,z1)&&z1>0){
// buildHelperSnap(grid,x1,y1,z1);
var name='[' +x1+"," +y1+","+z1+']';
var object = this.scene.getObjectByName( 'p'+name );
if(object!==undefined){
this.scene.remove( object );
this.objects.splice( this.objects.indexOf( object ), 1 );
object = this.scene.getObjectByName( 's'+name );
this.scene.remove( object );
this.occupancyHelper[x1][y1][z1]=false;
}
}
}
list=this.utils.getNeighborsList(this.cubicGrid,x,y,z);
for(var i=0;i<list.length;i++){
var x1,y1,z1;
[x1,y1,z1]=list[i];
if(this.occupancy[x1][y1][z1]){
this.buildNeighborHelpers(grid, x1, y1,z1);
}
}
};
threejs.prototype.changeToGrid=function(newGrid){
};
threejs.prototype.getWidth=function(){
// return container.style.width;
return $('#'+this.container1Name).width() ;
};
threejs.prototype.getHeight=function(){
// return container.style.height;
return $('#'+this.container1Name).height() ;
};
//////////////////////////////////////////////////
function onWindowResizeThree( event ) {
three.camera.aspect = three.getWidth() / three.getHeight();
three.camera.updateProjectionMatrix();
three.renderer.setSize( three.getWidth(), three.getHeight() );
}
function onDocumentMouseMoveThree( event ) {
event.preventDefault();
three.mouse.set( ( event.clientX / three.getWidth() ) * 2 - 1, - ( event.clientY /three.getHeight() ) * 2 + 1 );
three.raycaster.setFromCamera(three.mouse, three.camera );
var intersects = three.raycaster.intersectObjects( three.objects );
if ( intersects.length > 0 ) {
var intersect = intersects[ 0 ];
var obj=utils.getXYZfromName(intersect.object.name);
[p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y]=utils.getTransforms(three.grid,obj.x, obj.y,obj.z);
// rollOverMesh.scale.x=s_x;
// rollOverMesh.scale.z=s_z;
// rollOverMesh.scale.y=s_y;
three.rollOverMesh.name="r["+parseInt(obj.x) +","+parseInt(obj.y) +","+parseInt(obj.z) +"]"
three.rollOverMesh.position.x=0;
three.rollOverMesh.position.y=0;
three.rollOverMesh.position.z=0;
three.rollOverMesh.rotation.y=r_y;
three.rollOverMesh.position.x=p_x;
three.rollOverMesh.position.y=p_y;
three.rollOverMesh.position.z=p_z;
// rollOverMesh.position.copy( intersect.object.position ).add(temp );
}
three.render();
}
function onDocumentMouseDownThree( event ) {
event.preventDefault();
three.mouse.set( ( event.clientX / three.getWidth() ) * 2 - 1, - ( event.clientY / three.getHeight() ) * 2 + 1 );
three.raycaster.setFromCamera( three.mouse, three.camera );
var intersects = three.raycaster.intersectObjects( three.objects );
var intersects1 = three.raycaster.intersectObjects( three.voxels );
if ( intersects.length > 0 ||intersects1.length>0){
if(event.which==1 && intersects.length > 0) { //left click
var intersect = intersects[ 0 ];
var obj=utils.getXYZfromName(intersect.object.name);
obj=utils.getXYZfromName(three.rollOverMesh.name);
GLOBALS.addNode (obj.x, obj.y,obj.z);
}
if ( intersects1.length > 0 && event.which==3){//right click
var intersect = intersects1[ 0 ];
var obj=utils.getXYZfromName(intersect.object.name);
three.selectedNodeID=obj;
three.menu=three.cy.cxtmenu( three.cxtdefaults );
[p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y]=utils.getTransforms(three.grid,obj.x, obj.y,obj.z);
three.highlight.name="h["+parseInt(obj.x) +","+parseInt(obj.y) +","+parseInt(obj.z) +"]";
three.highlight.position.x=0;
three.highlight.position.y=0;
three.highlight.position.z=0;
three.highlight.rotation.y=r_y;
three.highlight.position.x=p_x;
three.highlight.position.y=p_y;
three.highlight.position.z=p_z;
}
three.render();
}
}
function onDocumentKeyUpThree(event){
if(event.which==3){
if(three.menu!==undefined){
three.menu.destroy();
}
}
}
document.addEventListener('removeNode', function (e) {
var name='[' +e.detail.x +"," +e.detail.y+","+e.detail.z+']';
var object = three.scene.getObjectByName( name );
three.scene.remove( object );
three.voxels.splice( three.voxels.indexOf( object ), 1 );
three.updateHelperMeshesAfterRemove(three.grid,e.detail.x,e.detail.y,e.detail.z);
if(three.highlight.name=== 'h'+name) {
three.highlight.name="h["+0+","+0 +","+0 +"]";
three.highlight.position.x=0;
three.highlight.position.y=0;
three.highlight.position.z=0;
}
}, false);
document.addEventListener('addNode', function (e) {
three.buildVoxelAt( three.grid, e.detail.x, e.detail.y,e.detail.z);
//deleteHelper Meshes
var name='[' +e.detail.x +"," +e.detail.y+","+e.detail.z+']';
var object = three.scene.getObjectByName( 'p'+name );
three.scene.remove( object );
three.objects.splice( three.objects.indexOf( object ), 1 );
object = three.scene.getObjectByName( 's'+name );
three.scene.remove( object );
three.occupancyHelper[e.detail.x][e.detail.y][e.detail.z]=false;
three.buildNeighborHelpers(three.grid, e.detail.x, e.detail.y,e.detail.z);
}, false);
document.addEventListener('selectNode', function (e) {
var obj=e.detail;
[p_x ,p_y ,p_z ,s_x ,s_y,s_z,r_y]=utils.getTransforms(three.grid,obj.x, obj.y,obj.z);
three.highlight.name="h["+parseInt(obj.x) +","+parseInt(obj.y) +","+parseInt(obj.z) +"]";
three.highlight.position.x=0;
three.highlight.position.y=0;
three.highlight.position.z=0;
three.highlight.rotation.y=r_y;
three.highlight.position.x=p_x;
three.highlight.position.y=p_y;
three.highlight.position.z=p_z;
}, false);
/////////////////////