-
Notifications
You must be signed in to change notification settings - Fork 939
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added cubic representation of agents in WebGL canvas.
- Loading branch information
1 parent
f1de9f4
commit 94c428d
Showing
6 changed files
with
46,165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from mesa.visualization.modules import CanvasGrid | ||
|
||
|
||
class CanvasGrid3D(CanvasGrid): | ||
""" A subclass of CanvasGrid that displays in 3D """ | ||
|
||
package_includes = ["three.min.js", "OrbitControls.js", "Canvas3DModule.js"] | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
# Override the initialization of js_code | ||
self.js_code = ( | ||
"elements.push ({});".format( | ||
"new Canvas3DModule({}, {}, {}, {})".format( | ||
self.canvas_width, self.canvas_height, self.grid_width, self.grid_height) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
var Canvas3DModule = function(canvas_width, canvas_height, grid_width, grid_height) { | ||
|
||
// TODO - determine how to allow grass patches to be grown in the base layer, instead of as cubes. | ||
// Perhaps allow it to be determined by the portrayal method, 'cube' vs 'plane'? | ||
|
||
// scene bounds | ||
this.width = grid_width; | ||
this.height = grid_height; | ||
this.right = grid_width / 2; | ||
this.left = grid_width / 2 * -1; | ||
this.bottom = grid_height / 2; | ||
this.top = grid_height / 2 * -1; | ||
this.offset = 0.1; | ||
|
||
var self = this; | ||
|
||
// Create the tag: | ||
var tag = "<canvas width='" + canvas_width + "' height='" + canvas_height + "' "; | ||
tag += "style='border:1px dotted'></canvas>"; | ||
// Append it to body: | ||
var canvas = $(tag)[0]; | ||
$("#elements").append(canvas); | ||
|
||
|
||
// First time setup | ||
var scene = new THREE.Scene(); | ||
var camera = new THREE.PerspectiveCamera( 75, canvas_width / canvas_height, 0.1, 1000 ); | ||
camera.up = new THREE.Vector3(0, 0, 1); | ||
var renderer = new THREE.WebGLRenderer({canvas: canvas}); | ||
var controls = new THREE.OrbitControls(camera, renderer.domElement); | ||
renderer.setSize(canvas_width, canvas_height); | ||
|
||
var colorPlane = new THREE.PlaneGeometry(grid_width, grid_height, grid_width, grid_height); | ||
var material = new THREE.MeshBasicMaterial({color: 'white', side: THREE.DoubleSide}); | ||
var mesh = new THREE.Mesh( colorPlane, material ); | ||
scene.add( mesh ); | ||
camera.position.z = 10; | ||
|
||
var animate = function () { | ||
requestAnimationFrame( animate ); | ||
controls.update(); | ||
renderer.render(scene, camera); | ||
}; | ||
|
||
var textureLoader = new THREE.TextureLoader(); | ||
|
||
animate(); // Start rendering as soon as we're ready | ||
|
||
var cubeLayers = { | ||
portrayals: [], | ||
materials: {} | ||
}; | ||
|
||
var planeLayers = {}; // Todo - portrayal method? | ||
|
||
var updateCubeLayer = function(layer, portrayalLayer, portrayalShape) { | ||
if (["rect", "circle", "arrowHead"].indexOf(portrayalShape) < 0) { | ||
textureLoader.load('local/'.concat(portrayalShape), function(texture) { | ||
cubeLayers.materials[layer] = new THREE.MeshBasicMaterial({map: texture}); | ||
makeCubes(layer, portrayalLayer); | ||
}) | ||
} | ||
else if (portrayalLayer[0].hasOwnProperty('Color')) { | ||
var color = portrayalLayer[0].Color; | ||
cubeLayers.materials[layer] = new THREE.MeshBasicMaterial({color: color}); | ||
makeCubes(layer, portrayalLayer); | ||
} else { | ||
console.log("Couldn't determine shape, skipping layer {}.".replace('{}', String(layer))); | ||
} | ||
}; | ||
|
||
var removeCubes = function(layer) { | ||
scene.remove(scene.getObjectByName(layer)); | ||
}; | ||
|
||
var makeCubes = function(layer, layerData) { | ||
|
||
// Time to make some cubes! | ||
var group = new THREE.Group(); | ||
group.name = layer; | ||
|
||
var makeOneCube = function(data) { | ||
var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), cubeLayers.materials[layer]); | ||
mesh.userData = data; | ||
group.add(mesh); | ||
mesh.position.copy( | ||
new THREE.Vector3( -self.width/2 + data.x + 0.5, -self.height / 2 + data.y + .5, 0.5 + self.offset) | ||
); | ||
mesh.updateMatrix(); | ||
}; | ||
|
||
// Grid starts in bottom left of scene | ||
for (var c in layerData) { | ||
var data = layerData[c]; | ||
makeOneCube(data); | ||
} | ||
|
||
scene.add(group); | ||
}; | ||
|
||
this.render = function(data) { | ||
|
||
// Go through each layer of the portrayal, decide if we've seen it before. | ||
// The number of unique portrays in a given instance may change | ||
for (var layer in data) { | ||
if (!cubeLayers.portrayals.includes(layer)) { | ||
cubeLayers.portrayals.push(layer); | ||
updateCubeLayer(layer, data[layer], data[layer][0].Shape, makeCubes); | ||
} | ||
else { | ||
removeCubes(layer); // need to remove cubes for a layer that currently exists. | ||
makeCubes(layer, data[layer]); | ||
} | ||
} | ||
}; | ||
|
||
this.reset = function() { | ||
// Do nothing, the render call that occurs will cleanup as necessary. | ||
} | ||
}; |
Oops, something went wrong.