Skip to content

Commit

Permalink
Merge pull request #469 from ElDeveloper/correct-shape-size
Browse files Browse the repository at this point in the history
ENH: Correctly calculate the size of geometries
  • Loading branch information
antgonza committed May 10, 2016
2 parents ab5c050 + ffb5799 commit 7039245
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 43 deletions.
11 changes: 7 additions & 4 deletions emperor/support_files/js/shape-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ define([
var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(category);

// Reset all to shapes to default
var attributes = {}
var attributes = {};
for (var index in uniqueVals) {
attributes[uniqueVals[index]] = 'sphere';
attributes[uniqueVals[index]] = 'Sphere';
}
// fetch the slickgrid-formatted data
var data = decompViewDict.setCategory(attributes, scope.setPlottableAttributes, category);
Expand All @@ -72,7 +72,7 @@ define([
};

EmperorAttributeABC.call(this, container, title, helpmenu,
decompViewDict, options);
decompViewDict, options);
return this;
}

Expand All @@ -90,7 +90,10 @@ define([
*/
ShapeController.prototype.setPlottableAttributes = function(scope, shape, group) {
var idx;
var geometry = shapes.shapes[shape];

// get the appropriately sized geometry
var geometry = shapes.getGeometry(shape, scope.decomp.dimensionRanges);

if (geometry === undefined) {
throw new Error('Unknown shape ' + shape);
}
Expand Down
55 changes: 45 additions & 10 deletions emperor/support_files/js/shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,53 @@
// shapes.
define(['jquery', 'three'], function($, THREE) {

var shapes = {
'sphere': new THREE.SphereGeometry(0.1, 8, 8),
'cube': new THREE.CubeGeometry(0.2, 0.2, 0.2, 8, 8, 8),
'cone': new THREE.CylinderGeometry(0.1, 0, 0.1, 10),
'icosahedron': new THREE.IcosahedronGeometry(0.1, 0),
'cylinder': new THREE.CylinderGeometry(0.05, 0.05, 0.2, 10)
};
var SPHERE = 'Sphere', CUBE = 'Cube', CONE = 'Cone',
ICOSAHEDRON = 'Icosahedron', CYLINDER = 'Cylinder';

var shapes = [SPHERE, CUBE, CONE, ICOSAHEDRON, CYLINDER];

/*
*
* Return a correctly sized geometry that matches the plotting space
*
* @param {shapeName} string, one of 'Sphere', 'Cube', 'Cone', 'Icosahedron'
* or 'Cylinder'.
* @param {ranges} object, with two arrays of "max" and "min" values as
* generated by the DecompositionModel's dimensionRanges property;
*
* @return THREE.Geometry, returns the requested geometry object with a size
* appropriate for the data presented on screen.
*
**/
function getGeometry(shapeName, ranges){

// this is a heauristic tested on numerous plots since 2013, based off of
// the old implementation of emperor. We select the dimensions of all the
// geometries based on this factor.
var factor = (ranges.max[0] - ranges.min[0]) * 0.012;

switch(shapeName){
case SPHERE:
return new THREE.SphereGeometry(factor, 8, 8);
case CUBE:
return new THREE.CubeGeometry(factor, factor, factor, 8, 8, 8);
case CONE:
return new THREE.CylinderGeometry(factor * 0.4, 0, 1.5 * factor, 8);
case ICOSAHEDRON:
return new THREE.IcosahedronGeometry(factor, 0);
case CYLINDER:
return new THREE.CylinderGeometry(factor * 0.4, factor * 0.4,
1.5 * factor, 10);
default:
throw Error("Unknown geometry requested: " + shapeName);
}
}

var $shapesDropdown = $('<select>');
for (shape in shapes) {
_.each(shapes, function(shape){
$shapesDropdown.append(new Option(shape, shape));
}
});

return {shapes: shapes, $shapesDropdown: $shapesDropdown};
return {$shapesDropdown: $shapesDropdown, getGeometry: getGeometry,
shapes: shapes};
});
7 changes: 3 additions & 4 deletions emperor/support_files/js/view-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ define([
if (_.size(decompViewDict) <= 0){
throw Error('The decomposition view dictionary cannot be empty');
}
// Picks the first key in the dictionary as the active key
this.activeViewKey = Object.keys(decompViewDict)[0];

this.decompViewDict = decompViewDict;
this.$gridDiv = $('<div name="emperor-grid-div"></div>');
this.$gridDiv.css('margin', '0 auto');
Expand All @@ -250,10 +253,6 @@ define([
this.$body.append(this.$gridDiv);

this.metadataField = null;
this.activeViewKey = null;

// Picks the first key in the dictionary as the active key
this.activeViewKey = Object.keys(decompViewDict)[0];

var dm = decompViewDict[this.activeViewKey].decomp;
var scope = this;
Expand Down
9 changes: 6 additions & 3 deletions emperor/support_files/js/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ function DecompositionView(decomp) {
DecompositionView.prototype._initBaseView = function(){
var mesh, x = this.visibleDimensions[0], y = this.visibleDimensions[1],
z = this.visibleDimensions[2];
var scope = this;

// get the correctly sized geometry
var geometry = shapes.getGeometry('Sphere', this.decomp.dimensionRanges);

var dv = this;
this.decomp.apply(function(plottable) {
mesh = new THREE.Mesh(shapes.shapes.sphere, new THREE.MeshPhongMaterial());
mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial());
mesh.name = plottable.name;

mesh.material.color = new THREE.Color(0xff0000);
Expand All @@ -60,7 +63,7 @@ DecompositionView.prototype._initBaseView = function(){

mesh.updateMatrix();

dv.markers.push(mesh);
scope.markers.push(mesh);
});

// apply but to the adjacency list NOT IMPLEMENTED
Expand Down
63 changes: 41 additions & 22 deletions tests/javascript_tests/test_shape_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ requirejs([
module("Shape Controller", {
setup: function() {
// setup function
this.shapesAvailable = ['sphere', 'cube', 'cone', 'icosahedron', 'cylinder'];
this.shapesAvailable = ['Sphere', 'Cube', 'Cone', 'Icosahedron', 'Cylinder'];
this.sharedDecompositionViewDict = {};

// setup function
Expand Down Expand Up @@ -61,21 +61,6 @@ requirejs([
}
});

test("Shapes available list", function() {
var testShapes = [];
for (s in shapes.shapes) {
testShapes.push(s);
}
deepEqual(testShapes, this.shapesAvailable);

var testGeoms = [];
for (s in shapes.shapes) {
testGeoms.push(shapes.shapes[s].type);
}
deepEqual(testGeoms, ["SphereGeometry", "BoxGeometry", "CylinderGeometry",
"IcosahedronGeometry", "CylinderGeometry"])
});

test("Shapes dropdown", function() {
var values = [];
shapes.$shapesDropdown.find('option').each(function() {
Expand All @@ -96,19 +81,53 @@ requirejs([
equal(testColumn.field, 'value');
});

test("Test getGeometry", function(){
var geom, range;

range = {'min': [-2, -1, -3], 'max': [3, 8, 9]};

geom = shapes.getGeometry('Sphere', range);
equal(geom.parameters.radius, 0.06);

geom = shapes.getGeometry('Cube', range);
equal(geom.parameters.width, 0.06);
equal(geom.parameters.height, 0.06);
equal(geom.parameters.depth, 0.06);

geom = shapes.getGeometry('Cone', range);
equal(geom.parameters.radiusTop, 0.024);
equal(geom.parameters.radiusBottom, 0);
equal(geom.parameters.height, 0.09);

geom = shapes.getGeometry('Icosahedron', range);
equal(geom.parameters.radius, 0.06);

geom = shapes.getGeometry('Cylinder', range);
equal(geom.parameters.radiusTop, 0.024);
equal(geom.parameters.radiusBottom, 0.024);
equal(geom.parameters.height, 0.09);
});

test("Check getGeometry raises an exception with unknown shape", function(){
var range = {'min': [-2, -1, -3], 'max': [3, 8, 9]};
throws(function() {
shapes.getGeometry('Geometry McGeometryface', range);
}, Error, 'Throw error if unknown shape given');
});

test("Testing setPlottableAttributes helper function", function(assert) {
// testing with one plottable
var idx = 0;
plottables = [{idx:idx}];
equal(this.dv.markers[idx].geometry.type, 'SphereGeometry');
equal(this.dv.markers[idx+1].geometry.type, 'SphereGeometry');
ShapeController.prototype.setPlottableAttributes(this.dv, 'cube', plottables);
ShapeController.prototype.setPlottableAttributes(this.dv, 'Cube', plottables);
equal(this.dv.markers[idx].geometry.type, 'BoxGeometry');
equal(this.dv.markers[idx+1].geometry.type, 'SphereGeometry');

// testing with multiple plottable
plottables = [{idx:idx}, {idx:idx+1}];
ShapeController.prototype.setPlottableAttributes(this.dv, 'cylinder', plottables);
ShapeController.prototype.setPlottableAttributes(this.dv, 'Cylinder', plottables);
equal(this.dv.markers[idx].geometry.type, 'CylinderGeometry');
equal(this.dv.markers[idx+1].geometry.type, 'CylinderGeometry');
});
Expand All @@ -117,7 +136,7 @@ requirejs([
// testing with one plottable
plottables = [{idx:idx}];
throws(function() {
ShapeController.prototype.setPlottableAttributes(this.dv, 'WEIRD', plottables)
ShapeController.prototype.setPlottableAttributes(this.dv, 'WEIRD', plottables);
}, Error, 'Throw error if unknown shape given');

});
Expand All @@ -127,12 +146,12 @@ requirejs([
var controller = new ShapeController(container, this.sharedDecompositionViewDict);

var obs = controller.toJSON();
var exp = {category: 'SampleID', data: {'PC.636': 'sphere', 'PC.635': 'sphere'}};
var exp = {category: 'SampleID', data: {'PC.636': 'Sphere', 'PC.635': 'Sphere'}};
deepEqual(obs, exp);
});

test("Testing fromJSON", function() {
var json = {'category': 'SampleID', 'data': {'PC.636': 'cube', 'PC.635': 'sphere'}};
var json = {'category': 'SampleID', 'data': {'PC.636': 'Cube', 'PC.635': 'Sphere'}};

var container = $('<div id="does-not-exist" style="height:11px; width:12px"></div>');
var controller = new ShapeController(container, this.sharedDecompositionViewDict);
Expand All @@ -144,4 +163,4 @@ requirejs([
});

});
});
});

0 comments on commit 7039245

Please sign in to comment.