/**
* @fileOverview
* @author Jihoon Lee - jihoonlee.in@gmail.com
* @author Russell Toris - rctoris@wpi.edu
*/
/**
* A URDF can be used to load a ROSLIB.UrdfModel and its associated models into a 3D object.
*
* @constructor
* @param options - object with following keys:
*
* * urdfModel - the ROSLIB.UrdfModel to load
* * tfClient - the TF client handle to use
* * path (optional) - the base path to the associated Collada models that will be loaded
* * tfPrefix (optional) - the TF prefix to used for multi-robots
* * loader (optional) - the Collada loader to use (e.g., an instance of ROS3D.COLLADA_LOADER)
*/
ROS3D.Urdf = function(options) {
options = options || {};
var urdfModel = options.urdfModel;
var path = options.path || '/';
var tfClient = options.tfClient;
var tfPrefix = options.tfPrefix || '';
var loader = options.loader;
THREE.Object3D.call(this);
// load all models
var links = urdfModel.links;
for ( var l in links) {
var link = links[l];
for( var i=0; i<link.visuals.length; i++ ) {
var visual = link.visuals[i];
if (visual && visual.geometry) {
// Save frameID
var frameID = tfPrefix + '/' + link.name;
// Save color material
var colorMaterial = null;
if (visual.material && visual.material.color) {
var color = visual.material && visual.material.color;
colorMaterial = ROS3D.makeColorMaterial(color.r, color.g, color.b, color.a);
}
if (visual.geometry.type === ROSLIB.URDF_MESH) {
var uri = visual.geometry.filename;
// strips package://
var tmpIndex = uri.indexOf('package://');
if (tmpIndex !== -1) {
uri = uri.substr(tmpIndex + ('package://').length);
}
var fileType = uri.substr(-3).toLowerCase();
if (ROS3D.MeshLoader.loaders[fileType]) {
// create the model
var mesh = new ROS3D.MeshResource({
path : path,
resource : uri,
loader : loader,
material : colorMaterial
});
// check for a scale
if(link.visuals[i].geometry.scale) {
mesh.scale.copy(visual.geometry.scale);
}
// create a scene node with the model
var sceneNode = new ROS3D.SceneNode({
frameID : frameID,
pose : visual.origin,
tfClient : tfClient,
object : mesh
});
sceneNode.name = visual.name;
this.add(sceneNode);
} else {
console.warn('Could not load geometry mesh: '+uri);
}
} else {
var shapeMesh = this.createShapeMesh(visual, options);
// Create a scene node with the shape
var scene = new ROS3D.SceneNode({
frameID: frameID,
pose: visual.origin,
tfClient: tfClient,
object: shapeMesh
});
scene.name = visual.name;
this.add(scene);
}
}
}
}
};
ROS3D.Urdf.prototype.createShapeMesh = function(visual, options) {
var colorMaterial = null;
if (!colorMaterial) {
colorMaterial = ROS3D.makeColorMaterial(0, 0, 0, 1);
}
var shapeMesh;
// Create a shape
switch (visual.geometry.type) {
case ROSLIB.URDF_BOX:
var dimension = visual.geometry.dimension;
var cube = new THREE.BoxGeometry(dimension.x, dimension.y, dimension.z);
shapeMesh = new THREE.Mesh(cube, colorMaterial);
break;
case ROSLIB.URDF_CYLINDER:
var radius = visual.geometry.radius;
var length = visual.geometry.length;
var cylinder = new THREE.CylinderGeometry(radius, radius, length, 16, 1, false);
shapeMesh = new THREE.Mesh(cylinder, colorMaterial);
shapeMesh.quaternion.setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI * 0.5);
break;
case ROSLIB.URDF_SPHERE:
var sphere = new THREE.SphereGeometry(visual.geometry.radius, 16);
shapeMesh = new THREE.Mesh(sphere, colorMaterial);
break;
}
return shapeMesh;
};
ROS3D.Urdf.prototype.__proto__ = THREE.Object3D.prototype;
ROS3D.Urdf.prototype.unsubscribeTf = function () {
this.children.forEach(function(n) {
if (typeof n.unsubscribeTf === 'function') { n.unsubscribeTf(); }
});
};