diff --git a/build/ros3d.js b/build/ros3d.js index 9e8edf50..7832dcaf 100644 --- a/build/ros3d.js +++ b/build/ros3d.js @@ -166,6 +166,3508 @@ ROS3D.closestAxisPoint = function(axisRay, camera, mousePos) { return ROS3D.findClosestPoint(axisRay, mpRay); }; +/* jshint ignore:start */ + +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + * + * + * @Modified by Jihoon Lee from ColladerLoader.js@r88 + * To support rviz compatible collada viewing. + * See: #202 why it is forked. + * + * It is a fork from ColladerLoader.js in three.js. It follows three.js license: + * + * The MIT License + * + * Copyright © 2010-2017 three.js authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +THREE.ColladaLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ColladaLoader.prototype = { + + constructor: THREE.ColladaLoader, + + crossOrigin: 'Anonymous', + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var path = THREE.Loader.prototype.extractUrlBase( url ); + + var loader = new THREE.FileLoader( scope.manager ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( text, path ) ); + + }, onProgress, onError ); + + }, + + options: { + + set convertUpAxis( value ) { + + console.warn( 'THREE.ColladaLoader: options.convertUpAxis() has been removed. Up axis is converted automatically.' ); + + } + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( text, path ) { + + function getElementsByTagName( xml, name ) { + + // Non recursive xml.getElementsByTagName() ... + + var array = []; + var childNodes = xml.childNodes; + + for ( var i = 0, l = childNodes.length; i < l; i ++ ) { + + var child = childNodes[ i ]; + + if ( child.nodeName === name ) { + + array.push( child ); + + } + + } + + return array; + + } + + function parseStrings( text ) { + + if ( text.length === 0 ) return []; + + var parts = text.trim().split( /\s+/ ); + var array = new Array( parts.length ); + + for ( var i = 0, l = parts.length; i < l; i ++ ) { + + array[ i ] = parts[ i ]; + + } + + return array; + + } + + function parseFloats( text ) { + + if ( text.length === 0 ) return []; + + var parts = text.trim().split( /\s+/ ); + var array = new Array( parts.length ); + + for ( var i = 0, l = parts.length; i < l; i ++ ) { + + array[ i ] = parseFloat( parts[ i ] ); + + } + + return array; + + } + + function parseInts( text ) { + + if ( text.length === 0 ) return []; + + var parts = text.trim().split( /\s+/ ); + var array = new Array( parts.length ); + + for ( var i = 0, l = parts.length; i < l; i ++ ) { + + array[ i ] = parseInt( parts[ i ] ); + + } + + return array; + + } + + function parseId( text ) { + + return text.substring( 1 ); + + } + + function generateId() { + + return 'three_default_' + ( count ++ ); + + } + + function isEmpty( object ) { + + return Object.keys( object ).length === 0; + + } + + // asset + + function parseAsset( xml ) { + + return { + unit: parseAssetUnit( getElementsByTagName( xml, 'unit' )[ 0 ] ), + upAxis: parseAssetUpAxis( getElementsByTagName( xml, 'up_axis' )[ 0 ] ) + }; + + } + + function parseAssetUnit( xml ) { + + return xml !== undefined ? parseFloat( xml.getAttribute( 'meter' ) ) : 1; + + } + + function parseAssetUpAxis( xml ) { + + return xml !== undefined ? xml.textContent : 'Y_UP'; + + } + + // library + + function parseLibrary( xml, libraryName, nodeName, parser ) { + + var library = getElementsByTagName( xml, libraryName )[ 0 ]; + + if ( library !== undefined ) { + + var elements = getElementsByTagName( library, nodeName ); + + for ( var i = 0; i < elements.length; i ++ ) { + + parser( elements[ i ] ); + + } + + } + + } + + function buildLibrary( data, builder ) { + + for ( var name in data ) { + + var object = data[ name ]; + object.build = builder( data[ name ] ); + + } + + } + + // get + + function getBuild( data, builder ) { + + if ( data.build !== undefined ) return data.build; + + data.build = builder( data ); + + return data.build; + + } + + // animation + + function parseAnimation( xml ) { + + var data = { + sources: {}, + samplers: {}, + channels: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + var id; + + switch ( child.nodeName ) { + + case 'source': + id = child.getAttribute( 'id' ); + data.sources[ id ] = parseSource( child ); + break; + + case 'sampler': + id = child.getAttribute( 'id' ); + data.samplers[ id ] = parseAnimationSampler( child ); + break; + + case 'channel': + id = child.getAttribute( 'target' ); + data.channels[ id ] = parseAnimationChannel( child ); + break; + + default: + console.log( child ); + + } + + } + + library.animations[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseAnimationSampler( xml ) { + + var data = { + inputs: {}, + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'input': + var id = parseId( child.getAttribute( 'source' ) ); + var semantic = child.getAttribute( 'semantic' ); + data.inputs[ semantic ] = id; + break; + + } + + } + + return data; + + } + + function parseAnimationChannel( xml ) { + + var data = {}; + + var target = xml.getAttribute( 'target' ); + + // parsing SID Addressing Syntax + + var parts = target.split( '/' ); + + var id = parts.shift(); + var sid = parts.shift(); + + // check selection syntax + + var arraySyntax = ( sid.indexOf( '(' ) !== - 1 ); + var memberSyntax = ( sid.indexOf( '.' ) !== - 1 ); + + if ( memberSyntax ) { + + // member selection access + + parts = sid.split( '.' ); + sid = parts.shift(); + data.member = parts.shift(); + + } else if ( arraySyntax ) { + + // array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices. + + var indices = sid.split( '(' ); + sid = indices.shift(); + + for ( var i = 0; i < indices.length; i ++ ) { + + indices[ i ] = parseInt( indices[ i ].replace( /\)/, '' ) ); + + } + + data.indices = indices; + + } + + data.id = id; + data.sid = sid; + + data.arraySyntax = arraySyntax; + data.memberSyntax = memberSyntax; + + data.sampler = parseId( xml.getAttribute( 'source' ) ); + + return data; + + } + + function buildAnimation( data ) { + + var tracks = []; + + var channels = data.channels; + var samplers = data.samplers; + var sources = data.sources; + + for ( var target in channels ) { + + if ( channels.hasOwnProperty( target ) ) { + + var channel = channels[ target ]; + var sampler = samplers[ channel.sampler ]; + + var inputId = sampler.inputs.INPUT; + var outputId = sampler.inputs.OUTPUT; + + var inputSource = sources[ inputId ]; + var outputSource = sources[ outputId ]; + + var animation = buildAnimationChannel( channel, inputSource, outputSource ); + + createKeyframeTracks( animation, tracks ); + + } + + } + + return tracks; + + } + + function getAnimation( id ) { + + return getBuild( library.animations[ id ], buildAnimation ); + + } + + function buildAnimationChannel( channel, inputSource, outputSource ) { + + var node = library.nodes[ channel.id ]; + var object3D = getNode( node.id ); + + var transform = node.transforms[ channel.sid ]; + var defaultMatrix = node.matrix.clone().transpose(); + + var time, stride; + var i, il, j, jl; + + var data = {}; + + // the collada spec allows the animation of data in various ways. + // depending on the transform type (matrix, translate, rotate, scale), we execute different logic + + switch ( transform ) { + + case 'matrix': + + for ( i = 0, il = inputSource.array.length; i < il; i ++ ) { + + time = inputSource.array[ i ]; + stride = i * outputSource.stride; + + if ( data[ time ] === undefined ) data[ time ] = {}; + + if ( channel.arraySyntax === true ) { + + var value = outputSource.array[ stride ]; + var index = channel.indices[ 0 ] + 4 * channel.indices[ 1 ]; + + data[ time ][ index ] = value; + + } else { + + for ( j = 0, jl = outputSource.stride; j < jl; j ++ ) { + + data[ time ][ j ] = outputSource.array[ stride + j ]; + + } + + } + + } + + break; + + case 'translate': + console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform ); + break; + + case 'rotate': + console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform ); + break; + + case 'scale': + console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform ); + break; + + } + + var keyframes = prepareAnimationData( data, defaultMatrix ); + + var animation = { + name: object3D.uuid, + keyframes: keyframes + }; + + return animation; + + } + + function prepareAnimationData( data, defaultMatrix ) { + + var keyframes = []; + + // transfer data into a sortable array + + for ( var time in data ) { + + keyframes.push( { time: parseFloat( time ), value: data[ time ] } ); + + } + + // ensure keyframes are sorted by time + + keyframes.sort( ascending ); + + // now we clean up all animation data, so we can use them for keyframe tracks + + for ( var i = 0; i < 16; i ++ ) { + + transformAnimationData( keyframes, i, defaultMatrix.elements[ i ] ); + + } + + return keyframes; + + // array sort function + + function ascending( a, b ) { + + return a.time - b.time; + + } + + } + + var position = new THREE.Vector3(); + var scale = new THREE.Vector3(); + var quaternion = new THREE.Quaternion(); + + function createKeyframeTracks( animation, tracks ) { + + var keyframes = animation.keyframes; + var name = animation.name; + + var times = []; + var positionData = []; + var quaternionData = []; + var scaleData = []; + + for ( var i = 0, l = keyframes.length; i < l; i ++ ) { + + var keyframe = keyframes[ i ]; + + var time = keyframe.time; + var value = keyframe.value; + + matrix.fromArray( value ).transpose(); + matrix.decompose( position, quaternion, scale ); + + times.push( time ); + positionData.push( position.x, position.y, position.z ); + quaternionData.push( quaternion.x, quaternion.y, quaternion.z, quaternion.w ); + scaleData.push( scale.x, scale.y, scale.z ); + + } + + if ( positionData.length > 0 ) tracks.push( new THREE.VectorKeyframeTrack( name + '.position', times, positionData ) ); + if ( quaternionData.length > 0 ) tracks.push( new THREE.QuaternionKeyframeTrack( name + '.quaternion', times, quaternionData ) ); + if ( scaleData.length > 0 ) tracks.push( new THREE.VectorKeyframeTrack( name + '.scale', times, scaleData ) ); + + return tracks; + + } + + function transformAnimationData( keyframes, property, defaultValue ) { + + var keyframe; + + var empty = true; + var i, l; + + // check, if values of a property are missing in our keyframes + + for ( i = 0, l = keyframes.length; i < l; i ++ ) { + + keyframe = keyframes[ i ]; + + if ( keyframe.value[ property ] === undefined ) { + + keyframe.value[ property ] = null; // mark as missing + + } else { + + empty = false; + + } + + } + + if ( empty === true ) { + + // no values at all, so we set a default value + + for ( i = 0, l = keyframes.length; i < l; i ++ ) { + + keyframe = keyframes[ i ]; + + keyframe.value[ property ] = defaultValue; + + } + + } else { + + // filling gaps + + createMissingKeyframes( keyframes, property ); + + } + + } + + function createMissingKeyframes( keyframes, property ) { + + var prev, next; + + for ( var i = 0, l = keyframes.length; i < l; i ++ ) { + + var keyframe = keyframes[ i ]; + + if ( keyframe.value[ property ] === null ) { + + prev = getPrev( keyframes, i, property ); + next = getNext( keyframes, i, property ); + + if ( prev === null ) { + + keyframe.value[ property ] = next.value[ property ]; + continue; + + } + + if ( next === null ) { + + keyframe.value[ property ] = prev.value[ property ]; + continue; + + } + + interpolate( keyframe, prev, next, property ); + + } + + } + + } + + function getPrev( keyframes, i, property ) { + + while ( i >= 0 ) { + + var keyframe = keyframes[ i ]; + + if ( keyframe.value[ property ] !== null ) return keyframe; + + i --; + + } + + return null; + + } + + function getNext( keyframes, i, property ) { + + while ( i < keyframes.length ) { + + var keyframe = keyframes[ i ]; + + if ( keyframe.value[ property ] !== null ) return keyframe; + + i ++; + + } + + return null; + + } + + function interpolate( key, prev, next, property ) { + + if ( ( next.time - prev.time ) === 0 ) { + + key.value[ property ] = prev.value[ property ]; + return; + + } + + key.value[ property ] = ( ( key.time - prev.time ) * ( next.value[ property ] - prev.value[ property ] ) / ( next.time - prev.time ) ) + prev.value[ property ]; + + } + + // animation clips + + function parseAnimationClip( xml ) { + + var data = { + name: xml.getAttribute( 'id' ) || 'default', + start: parseFloat( xml.getAttribute( 'start' ) || 0 ), + end: parseFloat( xml.getAttribute( 'end' ) || 0 ), + animations: [] + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'instance_animation': + data.animations.push( parseId( child.getAttribute( 'url' ) ) ); + break; + + } + + } + + library.clips[ xml.getAttribute( 'id' ) ] = data; + + } + + function buildAnimationClip( data ) { + + var tracks = []; + + var name = data.name; + var duration = ( data.end - data.start ) || - 1; + var animations = data.animations; + + for ( var i = 0, il = animations.length; i < il; i ++ ) { + + var animationTracks = getAnimation( animations[ i ] ); + + for ( var j = 0, jl = animationTracks.length; j < jl; j ++ ) { + + tracks.push( animationTracks[ j ] ); + + } + + } + + return new THREE.AnimationClip( name, duration, tracks ); + + } + + function getAnimationClip( id ) { + + return getBuild( library.clips[ id ], buildAnimationClip ); + + } + + // controller + + function parseController( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'skin': + // there is exactly one skin per controller + data.id = parseId( child.getAttribute( 'source' ) ); + data.skin = parseSkin( child ); + break; + + case 'morph': + data.id = parseId( child.getAttribute( 'source' ) ); + console.warn( 'THREE.ColladaLoader: Morph target animation not supported yet.' ); + break; + + } + + } + + library.controllers[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseSkin( xml ) { + + var data = { + sources: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'bind_shape_matrix': + data.bindShapeMatrix = parseFloats( child.textContent ); + break; + + case 'source': + var id = child.getAttribute( 'id' ); + data.sources[ id ] = parseSource( child ); + break; + + case 'joints': + data.joints = parseJoints( child ); + break; + + case 'vertex_weights': + data.vertexWeights = parseVertexWeights( child ); + break; + + } + + } + + return data; + + } + + function parseJoints( xml ) { + + var data = { + inputs: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'input': + var semantic = child.getAttribute( 'semantic' ); + var id = parseId( child.getAttribute( 'source' ) ); + data.inputs[ semantic ] = id; + break; + + } + + } + + return data; + + } + + function parseVertexWeights( xml ) { + + var data = { + inputs: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'input': + var semantic = child.getAttribute( 'semantic' ); + var id = parseId( child.getAttribute( 'source' ) ); + var offset = parseInt( child.getAttribute( 'offset' ) ); + data.inputs[ semantic ] = { id: id, offset: offset }; + break; + + case 'vcount': + data.vcount = parseInts( child.textContent ); + break; + + case 'v': + data.v = parseInts( child.textContent ); + break; + + } + + } + + return data; + + } + + function buildController( data ) { + + var build = { + id: data.id + }; + + var geometry = library.geometries[ build.id ]; + + if ( data.skin !== undefined ) { + + build.skin = buildSkin( data.skin ); + + // we enhance the 'sources' property of the corresponding geometry with our skin data + + geometry.sources.skinIndices = build.skin.indices; + geometry.sources.skinWeights = build.skin.weights; + + } + + return build; + + } + + function buildSkin( data ) { + + var BONE_LIMIT = 4; + + var build = { + joints: [], // this must be an array to preserve the joint order + indices: { + array: [], + stride: BONE_LIMIT + }, + weights: { + array: [], + stride: BONE_LIMIT + } + }; + + var sources = data.sources; + var vertexWeights = data.vertexWeights; + + var vcount = vertexWeights.vcount; + var v = vertexWeights.v; + var jointOffset = vertexWeights.inputs.JOINT.offset; + var weightOffset = vertexWeights.inputs.WEIGHT.offset; + + var jointSource = data.sources[ data.joints.inputs.JOINT ]; + var inverseSource = data.sources[ data.joints.inputs.INV_BIND_MATRIX ]; + + var weights = sources[ vertexWeights.inputs.WEIGHT.id ].array; + var stride = 0; + + var i, j, l; + + // procces skin data for each vertex + + for ( i = 0, l = vcount.length; i < l; i ++ ) { + + var jointCount = vcount[ i ]; // this is the amount of joints that affect a single vertex + var vertexSkinData = []; + + for ( j = 0; j < jointCount; j ++ ) { + + var skinIndex = v[ stride + jointOffset ]; + var weightId = v[ stride + weightOffset ]; + var skinWeight = weights[ weightId ]; + + vertexSkinData.push( { index: skinIndex, weight: skinWeight } ); + + stride += 2; + + } + + // we sort the joints in descending order based on the weights. + // this ensures, we only procced the most important joints of the vertex + + vertexSkinData.sort( descending ); + + // now we provide for each vertex a set of four index and weight values. + // the order of the skin data matches the order of vertices + + for ( j = 0; j < BONE_LIMIT; j ++ ) { + + var d = vertexSkinData[ j ]; + + if ( d !== undefined ) { + + build.indices.array.push( d.index ); + build.weights.array.push( d.weight ); + + } else { + + build.indices.array.push( 0 ); + build.weights.array.push( 0 ); + + } + + } + + } + + // setup bind matrix + + build.bindMatrix = new THREE.Matrix4().fromArray( data.bindShapeMatrix ).transpose(); + + // process bones and inverse bind matrix data + + for ( i = 0, l = jointSource.array.length; i < l; i ++ ) { + + var name = jointSource.array[ i ]; + var boneInverse = new THREE.Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose(); + + build.joints.push( { name: name, boneInverse: boneInverse } ); + + } + + return build; + + // array sort function + + function descending( a, b ) { + + return b.weight - a.weight; + + } + + } + + function getController( id ) { + + return getBuild( library.controllers[ id ], buildController ); + + } + + // image + + function parseImage( xml ) { + + var data = { + init_from: getElementsByTagName( xml, 'init_from' )[ 0 ].textContent + }; + + library.images[ xml.getAttribute( 'id' ) ] = data; + + } + + function buildImage( data ) { + + if ( data.build !== undefined ) return data.build; + + return data.init_from; + + } + + function getImage( id ) { + + return getBuild( library.images[ id ], buildImage ); + + } + + // effect + + function parseEffect( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'profile_COMMON': + data.profile = parseEffectProfileCOMMON( child ); + break; + + } + + } + + library.effects[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseEffectProfileCOMMON( xml ) { + + var data = { + surfaces: {}, + samplers: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'newparam': + parseEffectNewparam( child, data ); + break; + + case 'technique': + data.technique = parseEffectTechnique( child ); + break; + + } + + } + + return data; + + } + + function parseEffectNewparam( xml, data ) { + + var sid = xml.getAttribute( 'sid' ); + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'surface': + data.surfaces[ sid ] = parseEffectSurface( child ); + break; + + case 'sampler2D': + data.samplers[ sid ] = parseEffectSampler( child ); + break; + + } + + } + + } + + function parseEffectSurface( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'init_from': + data.init_from = child.textContent; + break; + + } + + } + + return data; + + } + + function parseEffectSampler( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'source': + data.source = child.textContent; + break; + + } + + } + + return data; + + } + + function parseEffectTechnique( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'constant': + case 'lambert': + case 'blinn': + case 'phong': + data.type = child.nodeName; + data.parameters = parseEffectParameters( child ); + break; + + } + + } + + return data; + + } + + function parseEffectParameters( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'emission': + case 'diffuse': + case 'specular': + case 'shininess': + case 'transparent': + case 'transparency': + data[ child.nodeName ] = parseEffectParameter( child ); + break; + + } + + } + + return data; + + } + + function parseEffectParameter( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'color': + data[ child.nodeName ] = parseFloats( child.textContent ); + break; + + case 'float': + data[ child.nodeName ] = parseFloat( child.textContent ); + break; + + case 'texture': + data[ child.nodeName ] = { id: child.getAttribute( 'texture' ), extra: parseEffectParameterTexture( child ) }; + break; + + } + + } + + return data; + + } + + function parseEffectParameterTexture( xml ) { + + var data = { + technique: {} + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'extra': + parseEffectParameterTextureExtra( child, data ); + break; + + } + + } + + return data; + + } + + function parseEffectParameterTextureExtra( xml, data ) { + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'technique': + parseEffectParameterTextureExtraTechnique( child, data ); + break; + + } + + } + + } + + function parseEffectParameterTextureExtraTechnique( xml, data ) { + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'repeatU': + case 'repeatV': + case 'offsetU': + case 'offsetV': + data.technique[ child.nodeName ] = parseFloat( child.textContent ); + break; + + case 'wrapU': + case 'wrapV': + + // some files have values for wrapU/wrapV which become NaN via parseInt + + if ( child.textContent.toUpperCase() === 'TRUE' ) { + + data.technique[ child.nodeName ] = 1; + + } else if ( child.textContent.toUpperCase() === 'FALSE' ) { + + data.technique[ child.nodeName ] = 0; + + } else { + + data.technique[ child.nodeName ] = parseInt( child.textContent ); + + } + + break; + + } + + } + + } + + function buildEffect( data ) { + + return data; + + } + + function getEffect( id ) { + + return getBuild( library.effects[ id ], buildEffect ); + + } + + // material + + function parseMaterial( xml ) { + + var data = { + name: xml.getAttribute( 'name' ) + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'instance_effect': + data.url = parseId( child.getAttribute( 'url' ) ); + break; + + } + + } + + library.materials[ xml.getAttribute( 'id' ) ] = data; + + } + + function buildMaterial( data ) { + + var effect = getEffect( data.url ); + var technique = effect.profile.technique; + + var material; + + switch ( technique.type ) { + + case 'phong': + case 'blinn': + material = new THREE.MeshPhongMaterial(); + break; + + case 'lambert': + material = new THREE.MeshLambertMaterial(); + break; + + default: + material = new THREE.MeshBasicMaterial(); + break; + + } + + material.name = data.name; + + function getTexture( textureObject ) { + + var sampler = effect.profile.samplers[ textureObject.id ]; + + if ( sampler !== undefined ) { + + var surface = effect.profile.surfaces[ sampler.source ]; + + var texture = textureLoader.load( getImage( surface.init_from ) ); + + var extra = textureObject.extra; + + if ( extra !== undefined && extra.technique !== undefined && isEmpty( extra.technique ) === false ) { + + var technique = extra.technique; + + texture.wrapS = technique.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + texture.wrapT = technique.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping; + + texture.offset.set( technique.offsetU || 0, technique.offsetV || 0 ); + texture.repeat.set( technique.repeatU || 1, technique.repeatV || 1 ); + + } else { + + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + + } + + return texture; + + } + + console.error( 'THREE.ColladaLoader: Undefined sampler', textureObject.id ); + + return null; + + } + + var parameters = technique.parameters; + + for ( var key in parameters ) { + + var parameter = parameters[ key ]; + + switch ( key ) { + + case 'diffuse': + if ( parameter.color ) material.color.fromArray( parameter.color ); + if ( parameter.texture ) material.map = getTexture( parameter.texture ); + break; + case 'specular': + if ( parameter.color && material.specular ) material.specular.fromArray( parameter.color ); + if ( parameter.texture ) material.specularMap = getTexture( parameter.texture ); + break; + case 'shininess': + if ( parameter.float && material.shininess ) + material.shininess = parameter.float; + break; + case 'emission': + if ( parameter.color && material.emissive ) + material.emissive.fromArray( parameter.color ); + break; + case 'transparent': + // if ( parameter.texture ) material.alphaMap = getTexture( parameter.texture ); + material.transparent = true; + break; + case 'transparency': + if ( parameter.float !== undefined ) material.opacity = parameter.float; + material.transparent = true; + break; + + } + + } + + return material; + + } + + function getMaterial( id ) { + + return getBuild( library.materials[ id ], buildMaterial ); + + } + + // camera + + function parseCamera( xml ) { + + var data = { + name: xml.getAttribute( 'name' ) + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'optics': + data.optics = parseCameraOptics( child ); + break; + + } + + } + + library.cameras[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseCameraOptics( xml ) { + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + switch ( child.nodeName ) { + + case 'technique_common': + return parseCameraTechnique( child ); + + } + + } + + return {}; + + } + + function parseCameraTechnique( xml ) { + + var data = {}; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + switch ( child.nodeName ) { + + case 'perspective': + case 'orthographic': + + data.technique = child.nodeName; + data.parameters = parseCameraParameters( child ); + + break; + + } + + } + + return data; + + } + + function parseCameraParameters( xml ) { + + var data = {}; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + switch ( child.nodeName ) { + + case 'xfov': + case 'yfov': + case 'xmag': + case 'ymag': + case 'znear': + case 'zfar': + case 'aspect_ratio': + data[ child.nodeName ] = parseFloat( child.textContent ); + break; + + } + + } + + return data; + + } + + function buildCamera( data ) { + + var camera; + + switch ( data.optics.technique ) { + + case 'perspective': + camera = new THREE.PerspectiveCamera( + data.optics.parameters.yfov, + data.optics.parameters.aspect_ratio, + data.optics.parameters.znear, + data.optics.parameters.zfar + ); + break; + + case 'orthographic': + var ymag = data.optics.parameters.ymag; + var xmag = data.optics.parameters.xmag; + var aspectRatio = data.optics.parameters.aspect_ratio; + + xmag = ( xmag === undefined ) ? ( ymag * aspectRatio ) : xmag; + ymag = ( ymag === undefined ) ? ( xmag / aspectRatio ) : ymag; + + xmag *= 0.5; + ymag *= 0.5; + + camera = new THREE.OrthographicCamera( + - xmag, xmag, ymag, - ymag, // left, right, top, bottom + data.optics.parameters.znear, + data.optics.parameters.zfar + ); + break; + + default: + camera = new THREE.PerspectiveCamera(); + break; + + } + + camera.name = data.name; + + return camera; + + } + + function getCamera( id ) { + var data = library.cameras[ id ]; + if ( data !== undefined ) { + return getBuild( data, buildCamera ); + } + return null; + } + + // light + + function parseLight( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'technique_common': + data = parseLightTechnique( child ); + break; + + } + + } + + library.lights[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseLightTechnique( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'directional': + case 'point': + case 'spot': + case 'ambient': + + data.technique = child.nodeName; + data.parameters = parseLightParameters( child ); + + } + + } + + return data; + + } + + function parseLightParameters( xml ) { + + var data = {}; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'color': + var array = parseFloats( child.textContent ); + data.color = new THREE.Color().fromArray( array ); + break; + + case 'falloff_angle': + data.falloffAngle = parseFloat( child.textContent ); + break; + + case 'quadratic_attenuation': + var f = parseFloat( child.textContent ); + data.distance = f ? Math.sqrt( 1 / f ) : 0; + break; + + } + + } + + return data; + + } + + function buildLight( data ) { + + var light; + + switch ( data.technique ) { + + case 'directional': + light = new THREE.DirectionalLight(); + break; + + case 'point': + light = new THREE.PointLight(); + break; + + case 'spot': + light = new THREE.SpotLight(); + break; + + case 'ambient': + light = new THREE.AmbientLight(); + break; + + } + + if ( data.parameters.color ) light.color.copy( data.parameters.color ); + if ( data.parameters.distance ) light.distance = data.parameters.distance; + + return light; + + } + + function getLight( id ) { + var data = library.lights[ id ]; + + if ( data !== undefined ) { + + return getBuild( data, buildLight ); + + } + + return null; + } + + // geometry + + function parseGeometry( xml ) { + + var data = { + name: xml.getAttribute( 'name' ), + sources: {}, + vertices: {}, + primitives: [] + }; + + var mesh = getElementsByTagName( xml, 'mesh' )[ 0 ]; + + for ( var i = 0; i < mesh.childNodes.length; i ++ ) { + + var child = mesh.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + var id = child.getAttribute( 'id' ); + + switch ( child.nodeName ) { + + case 'source': + data.sources[ id ] = parseSource( child ); + break; + + case 'vertices': + // data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ]; + data.vertices = parseGeometryVertices( child ); + break; + + case 'polygons': + console.warn( 'THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName ); + break; + + case 'lines': + case 'linestrips': + case 'polylist': + case 'triangles': + data.primitives.push( parseGeometryPrimitive( child ) ); + break; + + default: + console.log( child ); + + } + + } + + library.geometries[ xml.getAttribute( 'id' ) ] = data; + + } + + function parseSource( xml ) { + + var data = { + array: [], + stride: 3 + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'float_array': + data.array = parseFloats( child.textContent ); + break; + + case 'Name_array': + data.array = parseStrings( child.textContent ); + break; + + case 'technique_common': + var accessor = getElementsByTagName( child, 'accessor' )[ 0 ]; + + if ( accessor !== undefined ) { + + data.stride = parseInt( accessor.getAttribute( 'stride' ) ); + + } + break; + + } + + } + + return data; + + } + + function parseGeometryVertices( xml ) { + + var data = {}; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + data[ child.getAttribute( 'semantic' ) ] = parseId( child.getAttribute( 'source' ) ); + + } + + return data; + + } + + function parseGeometryPrimitive( xml ) { + + var primitive = { + type: xml.nodeName, + material: xml.getAttribute( 'material' ), + count: parseInt( xml.getAttribute( 'count' ) ), + inputs: {}, + stride: 0 + }; + + for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'input': + var id = parseId( child.getAttribute( 'source' ) ); + var semantic = child.getAttribute( 'semantic' ); + var offset = parseInt( child.getAttribute( 'offset' ) ); + primitive.inputs[ semantic ] = { id: id, offset: offset }; + primitive.stride = Math.max( primitive.stride, offset + 1 ); + break; + + case 'vcount': + primitive.vcount = parseInts( child.textContent ); + break; + + case 'p': + primitive.p = parseInts( child.textContent ); + break; + + } + + } + + return primitive; + + } + + function groupPrimitives( primitives ) { + + var build = {}; + + for ( var i = 0; i < primitives.length; i ++ ) { + + var primitive = primitives[ i ]; + + if ( build[ primitive.type ] === undefined ) build[ primitive.type ] = []; + + build[ primitive.type ].push( primitive ); + + } + + return build; + + } + + function buildGeometry( data ) { + + var build = {}; + + var sources = data.sources; + var vertices = data.vertices; + var primitives = data.primitives; + + if ( primitives.length === 0 ) return {}; + + // our goal is to create one buffer geoemtry for a single type of primitives + // first, we group all primitives by their type + + var groupedPrimitives = groupPrimitives( primitives ); + + for ( var type in groupedPrimitives ) { + + // second, we create for each type of primitives (polylist,triangles or lines) a buffer geometry + + build[ type ] = buildGeometryType( groupedPrimitives[ type ], sources, vertices ); + + } + + return build; + + } + + function buildGeometryType( primitives, sources, vertices ) { + + var build = {}; + + var position = { array: [], stride: 0 }; + var normal = { array: [], stride: 0 }; + var uv = { array: [], stride: 0 }; + var color = { array: [], stride: 0 }; + + var skinIndex = { array: [], stride: 4 }; + var skinWeight = { array: [], stride: 4 }; + + var geometry = new THREE.BufferGeometry(); + + var materialKeys = []; + + var start = 0, count = 0; + + for ( var p = 0; p < primitives.length; p ++ ) { + + var primitive = primitives[ p ]; + var inputs = primitive.inputs; + var triangleCount = 1; + + if ( primitive.vcount && primitive.vcount[ 0 ] === 4 ) { + + triangleCount = 2; // one quad -> two triangles + + } + + // groups + + if ( primitive.type === 'lines' || primitive.type === 'linestrips' ) { + + count = primitive.count * 2; + + } else { + + count = primitive.count * 3 * triangleCount; + + } + + geometry.addGroup( start, count, p ); + start += count; + + // material + + if ( primitive.material ) { + + materialKeys.push( primitive.material ); + + } + + // geometry data + + for ( var name in inputs ) { + + var input = inputs[ name ]; + + switch ( name ) { + + case 'VERTEX': + for ( var key in vertices ) { + + var id = vertices[ key ]; + + switch ( key ) { + + case 'POSITION': + buildGeometryData( primitive, sources[ id ], input.offset, position.array ); + position.stride = sources[ id ].stride; + + if ( sources.skinWeights && sources.skinIndices ) { + + buildGeometryData( primitive, sources.skinIndices, input.offset, skinIndex.array ); + buildGeometryData( primitive, sources.skinWeights, input.offset, skinWeight.array ); + + } + break; + + case 'NORMAL': + buildGeometryData( primitive, sources[ id ], input.offset, normal.array ); + normal.stride = sources[ id ].stride; + break; + + case 'COLOR': + buildGeometryData( primitive, sources[ id ], input.offset, color.array ); + color.stride = sources[ id ].stride; + break; + + case 'TEXCOORD': + buildGeometryData( primitive, sources[ id ], input.offset, uv.array ); + uv.stride = sources[ id ].stride; + break; + + default: + console.warn( 'THREE.ColladaLoader: Semantic "%s" not handled in geometry build process.', key ); + + } + + } + break; + + case 'NORMAL': + buildGeometryData( primitive, sources[ input.id ], input.offset, normal.array ); + normal.stride = sources[ input.id ].stride; + break; + + case 'COLOR': + buildGeometryData( primitive, sources[ input.id ], input.offset, color.array ); + color.stride = sources[ input.id ].stride; + break; + + case 'TEXCOORD': + buildGeometryData( primitive, sources[ input.id ], input.offset, uv.array ); + uv.stride = sources[ input.id ].stride; + break; + + } + + } + + } + + // build geometry + + if ( position.array.length > 0 ) geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( position.array, position.stride ) ); + if ( normal.array.length > 0 ) geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normal.array, normal.stride ) ); + if ( color.array.length > 0 ) geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( color.array, color.stride ) ); + if ( uv.array.length > 0 ) geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv.array, uv.stride ) ); + + if ( skinIndex.array.length > 0 ) geometry.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( skinIndex.array, skinIndex.stride ) ); + if ( skinWeight.array.length > 0 ) geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeight.array, skinWeight.stride ) ); + + build.data = geometry; + build.type = primitives[ 0 ].type; + build.materialKeys = materialKeys; + + return build; + + } + + function buildGeometryData( primitive, source, offset, array ) { + + var indices = primitive.p; + var stride = primitive.stride; + var vcount = primitive.vcount; + + function pushVector( i ) { + + var index = indices[ i + offset ] * sourceStride; + var length = index + sourceStride; + + for ( ; index < length; index ++ ) { + + array.push( sourceArray[ index ] ); + + } + + } + + var maxcount = 0; + + var sourceArray = source.array; + var sourceStride = source.stride; + + if ( primitive.vcount !== undefined ) { + + var index = 0; + + for ( var i = 0, l = vcount.length; i < l; i ++ ) { + + var count = vcount[ i ]; + + if ( count === 4 ) { + + var a = index + stride * 0; + var b = index + stride * 1; + var c = index + stride * 2; + var d = index + stride * 3; + + pushVector( a ); pushVector( b ); pushVector( d ); + pushVector( b ); pushVector( c ); pushVector( d ); + + } else if ( count === 3 ) { + + var a = index + stride * 0; + var b = index + stride * 1; + var c = index + stride * 2; + + pushVector( a ); pushVector( b ); pushVector( c ); + + } else { + + maxcount = Math.max( maxcount, count ); + + } + + index += stride * count; + + } + + if ( maxcount > 0 ) { + + console.log( 'THREE.ColladaLoader: Geometry has faces with more than 4 vertices.' ); + + } + + } else { + + for ( var i = 0, l = indices.length; i < l; i += stride ) { + + pushVector( i ); + + } + + } + + } + + function getGeometry( id ) { + + return getBuild( library.geometries[ id ], buildGeometry ); + + } + + // kinematics + + function parseKinematicsModel( xml ) { + + var data = { + name: xml.getAttribute( 'name' ) || '', + joints: {}, + links: [] + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'technique_common': + parseKinematicsTechniqueCommon( child, data ); + break; + + } + + } + + library.kinematicsModels[ xml.getAttribute( 'id' ) ] = data; + + } + + function buildKinematicsModel( data ) { + + if ( data.build !== undefined ) return data.build; + + return data; + + } + + function getKinematicsModel( id ) { + + return getBuild( library.kinematicsModels[ id ], buildKinematicsModel ); + + } + + function parseKinematicsTechniqueCommon( xml, data ) { + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'joint': + data.joints[ child.getAttribute( 'sid' ) ] = parseKinematicsJoint( child ); + break; + + case 'link': + data.links.push( parseKinematicsLink( child ) ); + break; + + } + + } + + } + + function parseKinematicsJoint( xml ) { + + var data; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'prismatic': + case 'revolute': + data = parseKinematicsJointParameter( child ); + break; + + } + + } + + return data; + + } + + function parseKinematicsJointParameter( xml, data ) { + + var data = { + sid: xml.getAttribute( 'sid' ), + name: xml.getAttribute( 'name' ) || '', + axis: new THREE.Vector3(), + limits: { + min: 0, + max: 0 + }, + type: xml.nodeName, + static: false, + zeroPosition: 0, + middlePosition: 0 + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'axis': + var array = parseFloats( child.textContent ); + data.axis.fromArray( array ); + break; + case 'limits': + var max = child.getElementsByTagName( 'max' )[ 0 ]; + var min = child.getElementsByTagName( 'min' )[ 0 ]; + + data.limits.max = parseFloat( max.textContent ); + data.limits.min = parseFloat( min.textContent ); + break; + + } + + } + + // if min is equal to or greater than max, consider the joint static + + if ( data.limits.min >= data.limits.max ) { + + data.static = true; + + } + + // calculate middle position + + data.middlePosition = ( data.limits.min + data.limits.max ) / 2.0; + + return data; + + } + + function parseKinematicsLink( xml ) { + + var data = { + sid: xml.getAttribute( 'sid' ), + name: xml.getAttribute( 'name' ) || '', + attachments: [], + transforms: [] + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'attachment_full': + data.attachments.push( parseKinematicsAttachment( child ) ); + break; + + case 'matrix': + case 'translate': + case 'rotate': + data.transforms.push( parseKinematicsTransform( child ) ); + break; + + } + + } + + return data; + + } + + function parseKinematicsAttachment( xml ) { + + var data = { + joint: xml.getAttribute( 'joint' ).split( '/' ).pop(), + transforms: [], + links: [] + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'link': + data.links.push( parseKinematicsLink( child ) ); + break; + + case 'matrix': + case 'translate': + case 'rotate': + data.transforms.push( parseKinematicsTransform( child ) ); + break; + + } + + } + + return data; + + } + + function parseKinematicsTransform( xml ) { + + var data = { + type: xml.nodeName + }; + + var array = parseFloats( xml.textContent ); + + switch ( data.type ) { + + case 'matrix': + data.obj = new THREE.Matrix4(); + data.obj.fromArray( array ).transpose(); + break; + + case 'translate': + data.obj = new THREE.Vector3(); + data.obj.fromArray( array ); + break; + + case 'rotate': + data.obj = new THREE.Vector3(); + data.obj.fromArray( array ); + data.angle = THREE.Math.degToRad( array[ 3 ] ); + break; + + } + + return data; + + } + + function parseKinematicsScene( xml ) { + + var data = { + bindJointAxis: [] + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'bind_joint_axis': + data.bindJointAxis.push( parseKinematicsBindJointAxis( child ) ); + break; + + } + + } + + library.kinematicsScenes[ parseId( xml.getAttribute( 'url' ) ) ] = data; + + } + + function parseKinematicsBindJointAxis( xml ) { + + var data = { + target: xml.getAttribute( 'target' ).split( '/' ).pop() + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'axis': + var param = child.getElementsByTagName( 'param' )[ 0 ]; + data.axis = param.textContent; + var tmpJointIndex = data.axis.split( 'inst_' ).pop().split( 'axis' )[ 0 ]; + data.jointIndex = tmpJointIndex.substr( 0, tmpJointIndex.length - 1 ); + break; + + } + + } + + return data; + + } + + function buildKinematicsScene( data ) { + + if ( data.build !== undefined ) return data.build; + + return data; + + } + + function getKinematicsScene( id ) { + + return getBuild( library.kinematicsScenes[ id ], buildKinematicsScene ); + + } + + function setupKinematics() { + + var kinematicsModelId = Object.keys( library.kinematicsModels )[ 0 ]; + var kinematicsSceneId = Object.keys( library.kinematicsScenes )[ 0 ]; + var visualSceneId = Object.keys( library.visualScenes )[ 0 ]; + + if ( kinematicsModelId === undefined || kinematicsSceneId === undefined ) return; + + var kinematicsModel = getKinematicsModel( kinematicsModelId ); + var kinematicsScene = getKinematicsScene( kinematicsSceneId ); + var visualScene = getVisualScene( visualSceneId ); + + var bindJointAxis = kinematicsScene.bindJointAxis; + var jointMap = {}; + + for ( var i = 0, l = bindJointAxis.length; i < l; i ++ ) { + + var axis = bindJointAxis[ i ]; + + // the result of the following query is an element of type 'translate', 'rotate','scale' or 'matrix' + + var targetElement = collada.querySelector( '[sid="' + axis.target + '"]' ); + + if ( targetElement ) { + + // get the parent of the transfrom element + + var parentVisualElement = targetElement.parentElement; + + // connect the joint of the kinematics model with the element in the visual scene + + connect( axis.jointIndex, parentVisualElement ); + + } + + } + + function connect( jointIndex, visualElement ) { + + var visualElementName = visualElement.getAttribute( 'name' ); + var joint = kinematicsModel.joints[ jointIndex ]; + + visualScene.traverse( function ( object ) { + + if ( object.name === visualElementName ) { + + jointMap[ jointIndex ] = { + object: object, + transforms: buildTransformList( visualElement ), + joint: joint, + position: joint.zeroPosition + }; + + } + + } ); + + } + + var m0 = new THREE.Matrix4(); + + kinematics = { + + joints: kinematicsModel && kinematicsModel.joints, + + getJointValue: function ( jointIndex ) { + + var jointData = jointMap[ jointIndex ]; + + if ( jointData ) { + + return jointData.position; + + } else { + + console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' doesn\'t exist.' ); + + } + + }, + + setJointValue: function ( jointIndex, value ) { + + var jointData = jointMap[ jointIndex ]; + + if ( jointData ) { + + var joint = jointData.joint; + + if ( value > joint.limits.max || value < joint.limits.min ) { + + console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ').' ); + + } else if ( joint.static ) { + + console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' is static.' ); + + } else { + + var object = jointData.object; + var axis = joint.axis; + var transforms = jointData.transforms; + + matrix.identity(); + + // each update, we have to apply all transforms in the correct order + + for ( var i = 0; i < transforms.length; i ++ ) { + + var transform = transforms[ i ]; + + // if there is a connection of the transform node with a joint, apply the joint value + + if ( transform.sid && transform.sid.indexOf( jointIndex ) !== - 1 ) { + + switch ( joint.type ) { + + case 'revolute': + matrix.multiply( m0.makeRotationAxis( axis, THREE.Math.degToRad( value ) ) ); + break; + + case 'prismatic': + matrix.multiply( m0.makeTranslation( axis.x * value, axis.y * value, axis.z * value ) ); + break; + + default: + console.warn( 'THREE.ColladaLoader: Unknown joint type: ' + joint.type ); + break; + + } + + } else { + + switch ( transform.type ) { + + case 'matrix': + matrix.multiply( transform.obj ); + break; + + case 'translate': + matrix.multiply( m0.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) ); + break; + + case 'scale': + matrix.scale( transform.obj ); + break; + + case 'rotate': + matrix.multiply( m0.makeRotationAxis( transform.obj, transform.angle ) ); + break; + + } + + } + + } + + object.matrix.copy( matrix ); + object.matrix.decompose( object.position, object.quaternion, object.scale ); + + jointMap[ jointIndex ].position = value; + + } + + } else { + + console.log( 'THREE.ColladaLoader: ' + jointIndex + ' does not exist.' ); + + } + + } + + }; + + } + + function buildTransformList( node ) { + + var transforms = []; + + var xml = collada.querySelector( '[id="' + node.id + '"]' ); + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'matrix': + var array = parseFloats( child.textContent ); + var matrix = new THREE.Matrix4().fromArray( array ).transpose(); + transforms.push( { + sid: child.getAttribute( 'sid' ), + type: child.nodeName, + obj: matrix + } ); + break; + + case 'translate': + case 'scale': + var array = parseFloats( child.textContent ); + var vector = new THREE.Vector3().fromArray( array ); + transforms.push( { + sid: child.getAttribute( 'sid' ), + type: child.nodeName, + obj: vector + } ); + break; + + case 'rotate': + var array = parseFloats( child.textContent ); + var vector = new THREE.Vector3().fromArray( array ); + var angle = THREE.Math.degToRad( array[ 3 ] ); + transforms.push( { + sid: child.getAttribute( 'sid' ), + type: child.nodeName, + obj: vector, + angle: angle + } ); + break; + + } + + } + + return transforms; + + } + + // nodes + + function prepareNodes( xml ) { + + var elements = xml.getElementsByTagName( 'node' ); + + // ensure all node elements have id attributes + + for ( var i = 0; i < elements.length; i ++ ) { + + var element = elements[ i ]; + + if ( element.hasAttribute( 'id' ) === false ) { + + element.setAttribute( 'id', generateId() ); + + } + + } + + } + + var matrix = new THREE.Matrix4(); + var vector = new THREE.Vector3(); + + function parseNode( xml ) { + + var data = { + name: xml.getAttribute( 'name' ) || '', + type: xml.getAttribute( 'type' ), + id: xml.getAttribute( 'id' ), + sid: xml.getAttribute( 'sid' ), + matrix: new THREE.Matrix4(), + nodes: [], + instanceCameras: [], + instanceControllers: [], + instanceLights: [], + instanceGeometries: [], + instanceNodes: [], + transforms: {} + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + if ( child.nodeType !== 1 ) continue; + + switch ( child.nodeName ) { + + case 'node': + data.nodes.push( child.getAttribute( 'id' ) ); + parseNode( child ); + break; + + case 'instance_camera': + data.instanceCameras.push( parseId( child.getAttribute( 'url' ) ) ); + break; + + case 'instance_controller': + data.instanceControllers.push( parseNodeInstance( child ) ); + break; + + case 'instance_light': + data.instanceLights.push( parseId( child.getAttribute( 'url' ) ) ); + break; + + case 'instance_geometry': + data.instanceGeometries.push( parseNodeInstance( child ) ); + break; + + case 'instance_node': + data.instanceNodes.push( parseId( child.getAttribute( 'url' ) ) ); + break; + + case 'matrix': + var array = parseFloats( child.textContent ); + data.matrix.multiply( matrix.fromArray( array ).transpose() ); + data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName; + break; + + case 'translate': + var array = parseFloats( child.textContent ); + vector.fromArray( array ); + data.matrix.multiply( matrix.makeTranslation( vector.x, vector.y, vector.z ) ); + data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName; + break; + + case 'rotate': + var array = parseFloats( child.textContent ); + var angle = THREE.Math.degToRad( array[ 3 ] ); + data.matrix.multiply( matrix.makeRotationAxis( vector.fromArray( array ), angle ) ); + data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName; + break; + + case 'scale': + var array = parseFloats( child.textContent ); + data.matrix.scale( vector.fromArray( array ) ); + data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName; + break; + + case 'extra': + break; + + default: + console.log( child ); + + } + + } + + library.nodes[ data.id ] = data; + + return data; + + } + + function parseNodeInstance( xml ) { + + var data = { + id: parseId( xml.getAttribute( 'url' ) ), + materials: {}, + skeletons: [] + }; + + for ( var i = 0; i < xml.childNodes.length; i ++ ) { + + var child = xml.childNodes[ i ]; + + switch ( child.nodeName ) { + + case 'bind_material': + var instances = child.getElementsByTagName( 'instance_material' ); + + for ( var j = 0; j < instances.length; j ++ ) { + + var instance = instances[ j ]; + var symbol = instance.getAttribute( 'symbol' ); + var target = instance.getAttribute( 'target' ); + + data.materials[ symbol ] = parseId( target ); + + } + + break; + + case 'skeleton': + data.skeletons.push( parseId( child.textContent ) ); + break; + + default: + break; + + } + + } + + return data; + + } + + function buildSkeleton( skeletons, joints ) { + + var boneData = []; + var sortedBoneData = []; + + var i, j, data; + + // a skeleton can have multiple root bones. collada expresses this + // situtation with multiple "skeleton" tags per controller instance + + for ( i = 0; i < skeletons.length; i ++ ) { + + var skeleton = skeletons[ i ]; + var root = getNode( skeleton ); + + // setup bone data for a single bone hierarchy + + buildBoneHierarchy( root, joints, boneData ); + + } + + // sort bone data (the order is defined in the corresponding controller) + + for ( i = 0; i < joints.length; i ++ ) { + + for ( j = 0; j < boneData.length; j ++ ) { + + data = boneData[ j ]; + + if ( data.bone.name === joints[ i ].name ) { + + sortedBoneData[ i ] = data; + data.processed = true; + break; + + } + + } + + } + + // add unprocessed bone data at the end of the list + + for ( i = 0; i < boneData.length; i ++ ) { + + data = boneData[ i ]; + + if ( data.processed === false ) { + + sortedBoneData.push( data ); + data.processed = true; + + } + + } + + // setup arrays for skeleton creation + + var bones = []; + var boneInverses = []; + + for ( i = 0; i < sortedBoneData.length; i ++ ) { + + data = sortedBoneData[ i ]; + + bones.push( data.bone ); + boneInverses.push( data.boneInverse ); + + } + + return new THREE.Skeleton( bones, boneInverses ); + + } + + function buildBoneHierarchy( root, joints, boneData ) { + + // setup bone data from visual scene + + root.traverse( function ( object ) { + + if ( object.isBone === true ) { + + var boneInverse; + + // retrieve the boneInverse from the controller data + + for ( var i = 0; i < joints.length; i ++ ) { + + var joint = joints[ i ]; + + if ( joint.name === object.name ) { + + boneInverse = joint.boneInverse; + break; + + } + + } + + if ( boneInverse === undefined ) { + + // Unfortunately, there can be joints in the visual scene that are not part of the + // corresponding controller. In this case, we have to create a dummy boneInverse matrix + // for the respective bone. This bone won't affect any vertices, because there are no skin indices + // and weights defined for it. But we still have to add the bone to the sorted bone list in order to + // ensure a correct animation of the model. + + boneInverse = new THREE.Matrix4(); + + } + + boneData.push( { bone: object, boneInverse: boneInverse, processed: false } ); + + } + + } ); + + } + + function buildNode( data ) { + + var objects = []; + + var matrix = data.matrix; + var nodes = data.nodes; + var type = data.type; + var instanceCameras = data.instanceCameras; + var instanceControllers = data.instanceControllers; + var instanceLights = data.instanceLights; + var instanceGeometries = data.instanceGeometries; + var instanceNodes = data.instanceNodes; + + // nodes + + for ( var i = 0, l = nodes.length; i < l; i ++ ) { + + objects.push( getNode( nodes[ i ] ) ); + + } + + // instance cameras + + for ( var i = 0, l = instanceCameras.length; i < l; i ++ ) { + + var instanceCamera = getCamera( instanceCameras[ i ] ); + + if ( instanceCamera !== null ) { + + objects.push( instanceCamera.clone() ); + + } + + + } + + // instance controllers + + for ( var i = 0, l = instanceControllers.length; i < l; i ++ ) { + + var instance = instanceControllers[ i ]; + var controller = getController( instance.id ); + var geometries = getGeometry( controller.id ); + var newObjects = buildObjects( geometries, instance.materials ); + + var skeletons = instance.skeletons; + var joints = controller.skin.joints; + + var skeleton = buildSkeleton( skeletons, joints ); + + for ( var j = 0, jl = newObjects.length; j < jl; j ++ ) { + + var object = newObjects[ j ]; + + if ( object.isSkinnedMesh ) { + + object.bind( skeleton, controller.skin.bindMatrix ); + object.normalizeSkinWeights(); + + } + + objects.push( object ); + + } + + } + + // instance lights + + for ( var i = 0, l = instanceLights.length; i < l; i ++ ) { + var instanceCamera = getCamera( instanceCameras[ i ] ); + + if ( instanceCamera !== null ) { + + objects.push( instanceCamera.clone() ); + + } + + } + + // instance geometries + + for ( var i = 0, l = instanceGeometries.length; i < l; i ++ ) { + + var instance = instanceGeometries[ i ]; + + // a single geometry instance in collada can lead to multiple object3Ds. + // this is the case when primitives are combined like triangles and lines + + var geometries = getGeometry( instance.id ); + var newObjects = buildObjects( geometries, instance.materials ); + + for ( var j = 0, jl = newObjects.length; j < jl; j ++ ) { + + objects.push( newObjects[ j ] ); + + } + + } + + // instance nodes + + for ( var i = 0, l = instanceNodes.length; i < l; i ++ ) { + + objects.push( getNode( instanceNodes[ i ] ).clone() ); + + } + + var object; + + if ( nodes.length === 0 && objects.length === 1 ) { + + object = objects[ 0 ]; + + } else { + + object = ( type === 'JOINT' ) ? new THREE.Bone() : new THREE.Group(); + + for ( var i = 0; i < objects.length; i ++ ) { + + object.add( objects[ i ] ); + + } + + } + + object.name = ( type === 'JOINT' ) ? data.sid : data.name; + object.matrix.copy( matrix ); + object.matrix.decompose( object.position, object.quaternion, object.scale ); + + return object; + + } + + function resolveMaterialBinding( keys, instanceMaterials ) { + + var materials = []; + + for ( var i = 0, l = keys.length; i < l; i ++ ) { + + var id = instanceMaterials[ keys[ i ] ]; + materials.push( getMaterial( id ) ); + + } + + return materials; + + } + + function buildObjects( geometries, instanceMaterials ) { + + var objects = []; + + for ( var type in geometries ) { + + var geometry = geometries[ type ]; + + var materials = resolveMaterialBinding( geometry.materialKeys, instanceMaterials ); + + // handle case if no materials are defined + + if ( materials.length === 0 ) { + + if ( type === 'lines' || type === 'linestrips' ) { + + materials.push( new THREE.LineBasicMaterial() ); + + } else { + + materials.push( new THREE.MeshPhongMaterial() ); + + } + + } + + // regard skinning + + var skinning = ( geometry.data.attributes.skinIndex !== undefined ); + + if ( skinning ) { + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + materials[ i ].skinning = true; + + } + + } + + // choose between a single or multi materials (material array) + + var material = ( materials.length === 1 ) ? materials[ 0 ] : materials; + + // now create a specific 3D object + + var object; + + switch ( type ) { + + case 'lines': + object = new THREE.LineSegments( geometry.data, material ); + break; + + case 'linestrips': + object = new THREE.Line( geometry.data, material ); + break; + + case 'triangles': + case 'polylist': + if ( skinning ) { + + object = new THREE.SkinnedMesh( geometry.data, material ); + + } else { + + object = new THREE.Mesh( geometry.data, material ); + + } + break; + + } + + objects.push( object ); + + } + + return objects; + + } + + function getNode( id ) { + + return getBuild( library.nodes[ id ], buildNode ); + + } + + // visual scenes + + function parseVisualScene( xml ) { + + var data = { + name: xml.getAttribute( 'name' ), + children: [] + }; + + prepareNodes( xml ); + + var elements = getElementsByTagName( xml, 'node' ); + + for ( var i = 0; i < elements.length; i ++ ) { + + data.children.push( parseNode( elements[ i ] ) ); + + } + + library.visualScenes[ xml.getAttribute( 'id' ) ] = data; + + } + + function buildVisualScene( data ) { + + var group = new THREE.Group(); + group.name = data.name; + + var children = data.children; + + for ( var i = 0; i < children.length; i ++ ) { + + var child = children[ i ]; + + if ( child.id === null ) { + + group.add( buildNode( child ) ); + + } else { + + // if there is an ID, let's try to get the finished build (e.g. joints are already build) + + group.add( getNode( child.id ) ); + + } + + } + + return group; + + } + + function getVisualScene( id ) { + + return getBuild( library.visualScenes[ id ], buildVisualScene ); + + } + + // scenes + + function parseScene( xml ) { + + var instance = getElementsByTagName( xml, 'instance_visual_scene' )[ 0 ]; + return getVisualScene( parseId( instance.getAttribute( 'url' ) ) ); + + } + + function setupAnimations() { + + var clips = library.clips; + + if ( isEmpty( clips ) === true ) { + + if ( isEmpty( library.animations ) === false ) { + + // if there are animations but no clips, we create a default clip for playback + + var tracks = []; + + for ( var id in library.animations ) { + + var animationTracks = getAnimation( id ); + + for ( var i = 0, l = animationTracks.length; i < l; i ++ ) { + + tracks.push( animationTracks[ i ] ); + + } + + } + + animations.push( new THREE.AnimationClip( 'default', - 1, tracks ) ); + + } + + } else { + + for ( var id in clips ) { + + animations.push( getAnimationClip( id ) ); + + } + + } + + } + + console.time( 'THREE.ColladaLoader' ); + + if ( text.length === 0 ) { + + return { scene: new THREE.Scene() }; + + } + + console.time( 'THREE.ColladaLoader: DOMParser' ); + + var xml = new DOMParser().parseFromString( text, 'application/xml' ); + + console.timeEnd( 'THREE.ColladaLoader: DOMParser' ); + + var collada = getElementsByTagName( xml, 'COLLADA' )[ 0 ]; + + // metadata + + var version = collada.getAttribute( 'version' ); + console.log( 'THREE.ColladaLoader: File version', version ); + + var asset = parseAsset( getElementsByTagName( collada, 'asset' )[ 0 ] ); + var textureLoader = new THREE.TextureLoader( this.manager ); + textureLoader.setPath( path ).setCrossOrigin( this.crossOrigin ); + + // + + var animations = []; + var kinematics = {}; + var count = 0; + + // + + var library = { + animations: {}, + clips: {}, + controllers: {}, + images: {}, + effects: {}, + materials: {}, + cameras: {}, + lights: {}, + geometries: {}, + nodes: {}, + visualScenes: {}, + kinematicsModels: {}, + kinematicsScenes: {} + }; + + console.time( 'THREE.ColladaLoader: Parse' ); + + parseLibrary( collada, 'library_animations', 'animation', parseAnimation ); + parseLibrary( collada, 'library_animation_clips', 'animation_clip', parseAnimationClip ); + parseLibrary( collada, 'library_controllers', 'controller', parseController ); + parseLibrary( collada, 'library_images', 'image', parseImage ); + parseLibrary( collada, 'library_effects', 'effect', parseEffect ); + parseLibrary( collada, 'library_materials', 'material', parseMaterial ); + parseLibrary( collada, 'library_cameras', 'camera', parseCamera ); + parseLibrary( collada, 'library_lights', 'light', parseLight ); + parseLibrary( collada, 'library_geometries', 'geometry', parseGeometry ); + parseLibrary( collada, 'library_nodes', 'node', parseNode ); + parseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene ); + parseLibrary( collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel ); + parseLibrary( collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene ); + + console.timeEnd( 'THREE.ColladaLoader: Parse' ); + + console.time( 'THREE.ColladaLoader: Build' ); + + buildLibrary( library.animations, buildAnimation ); + buildLibrary( library.clips, buildAnimationClip ); + buildLibrary( library.controllers, buildController ); + buildLibrary( library.images, buildImage ); + buildLibrary( library.effects, buildEffect ); + buildLibrary( library.materials, buildMaterial ); + buildLibrary( library.cameras, buildCamera ); + buildLibrary( library.lights, buildLight ); + buildLibrary( library.geometries, buildGeometry ); + buildLibrary( library.visualScenes, buildVisualScene ); + + console.timeEnd( 'THREE.ColladaLoader: Build' ); + + setupAnimations(); + setupKinematics(); + + var scene = parseScene( getElementsByTagName( collada, 'scene' )[ 0 ] ); + + /* + * up_axis of some robot models in ROS world aren't properly set because + * rviz ignores this field. Thus, ignores Z_UP to show urdfs just like rviz. + * See https://github.com/ros-visualization/rviz/issues/1045 for the detail + if ( asset.upAxis === 'Z_UP' ) { + + scene.rotation.x = - Math.PI / 2; + + } + */ + + scene.scale.multiplyScalar( asset.unit ); + + console.timeEnd( 'THREE.ColladaLoader' ); + + return { + animations: animations, + kinematics: kinematics, + library: library, + scene: scene + }; + + } + +}; + +/* jshint ignore:end */ + /** * @author Julius Kammerl - jkammerl@willowgarage.com */ @@ -2623,34 +6125,46 @@ ROS3D.MeshResource = function(options) { console.warn(message); } }; - loader.load(uri, function colladaReady(collada) { - // check for a scale factor in ColladaLoader2 - // add a texture to anything that is missing one - if(material !== null) { - collada.scene.traverse(function(child) { - if(child instanceof THREE.Mesh) { - if(child.material === undefined) { - child.material = material; + loader.load( + uri, + function colladaReady(collada) { + // check for a scale factor in ColladaLoader2 + // add a texture to anything that is missing one + if(material !== null) { + collada.scene.traverse(function(child) { + if(child instanceof THREE.Mesh) { + if(child.material === undefined) { + child.material = material; + } } - } - }); - } + }); + } - that.add(collada.scene); - }); + that.add(collada.scene); + }, + /*onProgress=*/null, + function onLoadError(error) { + console.error(error); + }); } else if (fileType === '.stl') { loader = new THREE.STLLoader(); { - loader.load(uri, function ( geometry ) { - geometry.computeFaceNormals(); - var mesh; - if(material !== null) { - mesh = new THREE.Mesh( geometry, material ); - } else { - mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x999999 } ) ); - } - that.add(mesh); - } ); + loader.load(uri, + function ( geometry ) { + geometry.computeFaceNormals(); + var mesh; + if(material !== null) { + mesh = new THREE.Mesh( geometry, material ); + } else { + mesh = new THREE.Mesh( geometry, + new THREE.MeshBasicMaterial( { color: 0x999999 } ) ); + } + that.add(mesh); + }, + /*onProgress=*/null, + function onLoadError(error) { + console.error(error); + }); } } }; diff --git a/build/ros3d.min.js b/build/ros3d.min.js index cc983fae..5f7a5ce9 100644 --- a/build/ros3d.min.js +++ b/build/ros3d.min.js @@ -1,3 +1,4 @@ -function setFrame(a,b){null===a.sn&&(a.sn=new ROS3D.SceneNode({frameID:b,tfClient:a.tfClient,object:a.ps}),a.rootObject.add(a.sn))}function finishedUpdate(a,b){null===a.first_size&&(a.first_size=b,a.max_pts=Math.max(a.max_pts,b));for(var c=b;ca.max_pts&&console.error("Attempted to draw more points than max_pts allows")}function read_point(a,b,c){for(var d=[],e=a.point_step*b,f=0;f=8&&(d-=8,b.push(c>>d),c&=Math.pow(2,d)-1),c<<=6;return b}var ROS3D=ROS3D||{REVISION:"0.18.0"};ROS3D.MARKER_ARROW=0,ROS3D.MARKER_CUBE=1,ROS3D.MARKER_SPHERE=2,ROS3D.MARKER_CYLINDER=3,ROS3D.MARKER_LINE_STRIP=4,ROS3D.MARKER_LINE_LIST=5,ROS3D.MARKER_CUBE_LIST=6,ROS3D.MARKER_SPHERE_LIST=7,ROS3D.MARKER_POINTS=8,ROS3D.MARKER_TEXT_VIEW_FACING=9,ROS3D.MARKER_MESH_RESOURCE=10,ROS3D.MARKER_TRIANGLE_LIST=11,ROS3D.INTERACTIVE_MARKER_KEEP_ALIVE=0,ROS3D.INTERACTIVE_MARKER_POSE_UPDATE=1,ROS3D.INTERACTIVE_MARKER_MENU_SELECT=2,ROS3D.INTERACTIVE_MARKER_BUTTON_CLICK=3,ROS3D.INTERACTIVE_MARKER_MOUSE_DOWN=4,ROS3D.INTERACTIVE_MARKER_MOUSE_UP=5,ROS3D.INTERACTIVE_MARKER_NONE=0,ROS3D.INTERACTIVE_MARKER_MENU=1,ROS3D.INTERACTIVE_MARKER_BUTTON=2,ROS3D.INTERACTIVE_MARKER_MOVE_AXIS=3,ROS3D.INTERACTIVE_MARKER_MOVE_PLANE=4,ROS3D.INTERACTIVE_MARKER_ROTATE_AXIS=5,ROS3D.INTERACTIVE_MARKER_MOVE_ROTATE=6,ROS3D.INTERACTIVE_MARKER_INHERIT=0,ROS3D.INTERACTIVE_MARKER_FIXED=1,ROS3D.INTERACTIVE_MARKER_VIEW_FACING=2,ROS3D.makeColorMaterial=function(a,b,c,d){var e=new THREE.Color;return e.setRGB(a,b,c),d<=.99?new THREE.MeshBasicMaterial({color:e.getHex(),opacity:d+.1,transparent:!0,depthWrite:!0,blendSrc:THREE.SrcAlphaFactor,blendDst:THREE.OneMinusSrcAlphaFactor,blendEquation:THREE.ReverseSubtractEquation,blending:THREE.NormalBlending}):new THREE.MeshPhongMaterial({color:e.getHex(),opacity:d,blending:THREE.NormalBlending})},ROS3D.intersectPlane=function(a,b,c){var d=new THREE.Vector3,e=new THREE.Vector3;d.subVectors(b,a.origin);var f=a.direction.dot(c);if(!(Math.abs(f)0.99)"," {"," vec4 depthColor2 = texture2D( map, vUv2 );"," float depth2 = ( depthColor2.r + depthColor2.g + depthColor2.b ) / 3.0 ;"," depth = 0.99+depth2;"," }"," "," return depth;"," }","","float median(float a, float b, float c)"," {"," float r=a;"," "," if ( (a0.5) || (vUvP.y<0.5) || (vUvP.y>0.0))"," {"," vec2 smp = decodeDepth(vec2(position.x, position.y));"," float depth = smp.x;"," depthVariance = smp.y;"," "," float z = -depth;"," "," pos = vec4("," ( position.x / width - 0.5 ) * z * (1000.0/focallength) * -1.0,"," ( position.y / height - 0.5 ) * z * (1000.0/focallength),"," (- z + zOffset / 1000.0) * 2.0,"," 1.0);"," "," vec2 maskP = vec2( position.x / (width*2.0), position.y / (height*2.0) );"," vec4 maskColor = texture2D( map, maskP );"," maskVal = ( maskColor.r + maskColor.g + maskColor.b ) / 3.0 ;"," }"," "," gl_PointSize = pointSize;"," gl_Position = projectionMatrix * modelViewMatrix * pos;"," ","}"].join("\n"),this.fragment_shader=["uniform sampler2D map;","uniform float varianceThreshold;","uniform float whiteness;","","varying vec2 vUvP;","varying vec2 colorP;","","varying float depthVariance;","varying float maskVal;","","","void main() {"," "," vec4 color;"," "," if ( (depthVariance>varianceThreshold) || (maskVal>0.5) ||(vUvP.x<0.0)|| (vUvP.x>0.5) || (vUvP.y<0.5) || (vUvP.y>1.0))"," { "," discard;"," }"," else "," {"," color = texture2D( map, colorP );"," "," float fader = whiteness /100.0;"," "," color.r = color.r * (1.0-fader)+ fader;"," "," color.g = color.g * (1.0-fader)+ fader;"," "," color.b = color.b * (1.0-fader)+ fader;"," "," color.a = 1.0;//smoothstep( 20000.0, -20000.0, gl_FragCoord.z / gl_FragCoord.w );"," }"," "," gl_FragColor = vec4( color.r, color.g, color.b, color.a );"," ","}"].join("\n")},ROS3D.DepthCloud.prototype.__proto__=THREE.Object3D.prototype,ROS3D.DepthCloud.prototype.metaLoaded=function(){this.metaLoaded=!0,this.initStreamer()},ROS3D.DepthCloud.prototype.initStreamer=function(){if(this.metaLoaded){this.texture=new THREE.Texture(this.video),this.geometry=new THREE.Geometry;for(var a=0,b=this.width*this.height;a0&&(this.menu=new ROS3D.InteractiveMarkerMenu({menuEntries:c.menuEntries,menuFontSize:c.menuFontSize}),this.menu.addEventListener("menu-select",function(a){b.dispatchEvent(a)}))},ROS3D.InteractiveMarker.prototype.__proto__=THREE.Object3D.prototype,ROS3D.InteractiveMarker.prototype.showMenu=function(a,b){this.menu&&this.menu.show(a,b)},ROS3D.InteractiveMarker.prototype.moveAxis=function(a,b,c){if(this.dragging){var d=a.currentControlOri,e=b.clone().applyQuaternion(d),f=this.dragStart.event3d.intersection.point,g=e.clone().applyQuaternion(this.dragStart.orientationWorld.clone()),h=new THREE.Ray(f,g),i=ROS3D.closestAxisPoint(h,c.camera,c.mousePos),j=new THREE.Vector3;j.addVectors(this.dragStart.position,e.clone().applyQuaternion(this.dragStart.orientation).multiplyScalar(i)),this.setPosition(a,j),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.movePlane=function(a,b,c){if(this.dragging){var d=a.currentControlOri,e=b.clone().applyQuaternion(d),f=this.dragStart.event3d.intersection.point,g=e.clone().applyQuaternion(this.dragStart.orientationWorld),h=ROS3D.intersectPlane(c.mouseRay,f,g),i=new THREE.Vector3;i.subVectors(h,f),i.add(this.dragStart.positionWorld),this.setPosition(a,i),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.rotateAxis=function(a,b,c){if(this.dragging){a.updateMatrixWorld();var d=a.currentControlOri,e=d.clone().multiply(b.clone()),f=new THREE.Vector3(1,0,0).applyQuaternion(e),g=this.dragStart.event3d.intersection.point,h=f.applyQuaternion(this.dragStart.orientationWorld),i=ROS3D.intersectPlane(c.mouseRay,g,h),j=new THREE.Ray(this.dragStart.positionWorld,h),k=ROS3D.intersectPlane(j,g,h),l=this.dragStart.orientationWorld.clone().multiply(e),m=l.clone().inverse();i.sub(k),i.applyQuaternion(m);var n=this.dragStart.event3d.intersection.point.clone();n.sub(k),n.applyQuaternion(m);var o=Math.atan2(i.y,i.z),p=Math.atan2(n.y,n.z),q=p-o,r=new THREE.Quaternion;r.setFromAxisAngle(f,q),this.setOrientation(a,r.multiply(this.dragStart.orientationWorld)),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.feedbackEvent=function(a,b){this.dispatchEvent({type:a,position:this.position.clone(),orientation:this.quaternion.clone(),controlName:b.name})},ROS3D.InteractiveMarker.prototype.startDrag=function(a,b){if(0===b.domEvent.button){b.stopPropagation(),this.dragging=!0,this.updateMatrixWorld(!0);var c=new THREE.Vector3;this.matrixWorld.decompose(this.dragStart.positionWorld,this.dragStart.orientationWorld,c),this.dragStart.position=this.position.clone(),this.dragStart.orientation=this.quaternion.clone(),this.dragStart.event3d=b,this.feedbackEvent("user-mousedown",a)}},ROS3D.InteractiveMarker.prototype.stopDrag=function(a,b){0===b.domEvent.button&&(b.stopPropagation(),this.dragging=!1,this.dragStart.event3d={},this.onServerSetPose(this.bufferedPoseEvent),this.bufferedPoseEvent=void 0,this.feedbackEvent("user-mouseup",a))},ROS3D.InteractiveMarker.prototype.buttonClick=function(a,b){b.stopPropagation(),this.feedbackEvent("user-button-click",a)},ROS3D.InteractiveMarker.prototype.setPosition=function(a,b){this.position.copy(b),this.feedbackEvent("user-pose-change",a)},ROS3D.InteractiveMarker.prototype.setOrientation=function(a,b){b.normalize(),this.quaternion.copy(b),this.feedbackEvent("user-pose-change",a)},ROS3D.InteractiveMarker.prototype.onServerSetPose=function(a){if(void 0!==a)if(this.dragging)this.bufferedPoseEvent=a;else{var b=a.pose;this.position.copy(b.position),this.quaternion.copy(b.orientation),this.updateMatrixWorld(!0)}},ROS3D.InteractiveMarker.prototype.dispose=function(){var a=this;this.children.forEach(function(b){b.children.forEach(function(a){a.dispose(),b.remove(a)}),a.remove(b)})},Object.assign(ROS3D.InteractiveMarker.prototype,THREE.EventDispatcher.prototype),ROS3D.InteractiveMarkerClient=function(a){a=a||{},this.ros=a.ros,this.tfClient=a.tfClient,this.topicName=a.topic,this.path=a.path||"/",this.camera=a.camera,this.rootObject=a.rootObject||new THREE.Object3D,this.loader=a.loader||ROS3D.COLLADA_LOADER_2,this.menuFontSize=a.menuFontSize||"0.8em",this.interactiveMarkers={},this.updateTopic=null,this.feedbackTopic=null,this.topicName&&this.subscribe(this.topicName)},ROS3D.InteractiveMarkerClient.prototype.subscribe=function(a){this.unsubscribe(),this.updateTopic=new ROSLIB.Topic({ros:this.ros,name:a+"/tunneled/update",messageType:"visualization_msgs/InteractiveMarkerUpdate",compression:"png"}),this.updateTopic.subscribe(this.processUpdate.bind(this)),this.feedbackTopic=new ROSLIB.Topic({ros:this.ros,name:a+"/feedback",messageType:"visualization_msgs/InteractiveMarkerFeedback",compression:"png"}),this.feedbackTopic.advertise(),this.initService=new ROSLIB.Service({ros:this.ros,name:a+"/tunneled/get_init",serviceType:"demo_interactive_markers/GetInit"});var b=new ROSLIB.ServiceRequest({});this.initService.callService(b,this.processInit.bind(this))},ROS3D.InteractiveMarkerClient.prototype.unsubscribe=function(){this.updateTopic&&this.updateTopic.unsubscribe(),this.feedbackTopic&&this.feedbackTopic.unadvertise();for(var a in this.interactiveMarkers)this.eraseIntMarker(a);this.interactiveMarkers={}},ROS3D.InteractiveMarkerClient.prototype.processInit=function(a){var b=a.msg;b.erases=[];for(var c in this.interactiveMarkers)b.erases.push(c);b.poses=[],this.processUpdate(b)},ROS3D.InteractiveMarkerClient.prototype.processUpdate=function(a){var b=this;a.erases.forEach(function(a){b.eraseIntMarker(a)}),a.poses.forEach(function(a){var c=b.interactiveMarkers[a.name];c&&c.setPoseFromServer(a.pose)}),a.markers.forEach(function(a){var c=b.interactiveMarkers[a.name];c&&b.eraseIntMarker(c.name);var d=new ROS3D.InteractiveMarkerHandle({message:a,feedbackTopic:b.feedbackTopic,tfClient:b.tfClient,menuFontSize:b.menuFontSize});b.interactiveMarkers[a.name]=d;var e=new ROS3D.InteractiveMarker({handle:d,camera:b.camera,path:b.path,loader:b.loader});e.name=a.name,b.rootObject.add(e),d.on("pose",function(a){e.onServerSetPose({pose:a})}),e.addEventListener("user-pose-change",d.setPoseFromClientBound),e.addEventListener("user-mousedown",d.onMouseDownBound),e.addEventListener("user-mouseup",d.onMouseUpBound),e.addEventListener("user-button-click",d.onButtonClickBound),e.addEventListener("menu-select",d.onMenuSelectBound),d.subscribeTf()})},ROS3D.InteractiveMarkerClient.prototype.eraseIntMarker=function(a){if(this.interactiveMarkers[a]){var b=this.rootObject.getObjectByName(a);this.rootObject.remove(b);var c=this.interactiveMarkers[a];c.unsubscribeTf(),b.removeEventListener("user-pose-change",c.setPoseFromClientBound),b.removeEventListener("user-mousedown",c.onMouseDownBound),b.removeEventListener("user-mouseup",c.onMouseUpBound),b.removeEventListener("user-button-click",c.onButtonClickBound),b.removeEventListener("menu-select",c.onMenuSelectBound),delete this.interactiveMarkers[a],b.dispose()}},ROS3D.InteractiveMarkerControl=function(a){function b(a){a.stopPropagation()}var c=this;THREE.Object3D.call(this),a=a||{},this.parent=a.parent;var d=a.handle,e=a.message;this.name=e.name,this.camera=a.camera,this.path=a.path||"/",this.loader=a.loader||ROS3D.COLLADA_LOADER_2,this.dragging=!1,this.startMousePos=new THREE.Vector2;var f=new THREE.Quaternion(e.orientation.x,e.orientation.y,e.orientation.z,e.orientation.w);f.normalize();var g=new THREE.Vector3(1,0,0);switch(g.applyQuaternion(f),this.currentControlOri=new THREE.Quaternion,e.interaction_mode){case ROS3D.INTERACTIVE_MARKER_MOVE_AXIS:this.addEventListener("mousemove",this.parent.moveAxis.bind(this.parent,this,g)),this.addEventListener("touchmove",this.parent.moveAxis.bind(this.parent,this,g));break;case ROS3D.INTERACTIVE_MARKER_ROTATE_AXIS:this.addEventListener("mousemove",this.parent.rotateAxis.bind(this.parent,this,f));break;case ROS3D.INTERACTIVE_MARKER_MOVE_PLANE:this.addEventListener("mousemove",this.parent.movePlane.bind(this.parent,this,g));break;case ROS3D.INTERACTIVE_MARKER_BUTTON:this.addEventListener("click",this.parent.buttonClick.bind(this.parent,this))}e.interaction_mode!==ROS3D.INTERACTIVE_MARKER_NONE&&(this.addEventListener("mousedown",this.parent.startDrag.bind(this.parent,this)),this.addEventListener("mouseup",this.parent.stopDrag.bind(this.parent,this)),this.addEventListener("contextmenu",this.parent.showMenu.bind(this.parent,this)),this.addEventListener("mouseup",function(a){0===c.startMousePos.distanceToSquared(a.mousePos)&&(a.type="contextmenu",c.dispatchEvent(a))}),this.addEventListener("mouseover",b),this.addEventListener("mouseout",b),this.addEventListener("click",b),this.addEventListener("mousedown",function(a){c.startMousePos=a.mousePos}),this.addEventListener("touchstart",function(a){1===a.domEvent.touches.length&&(a.type="mousedown",a.domEvent.button=0,c.dispatchEvent(a))}),this.addEventListener("touchmove",function(a){1===a.domEvent.touches.length&&(a.type="mousemove",a.domEvent.button=0,c.dispatchEvent(a))}),this.addEventListener("touchend",function(a){0===a.domEvent.touches.length&&(a.domEvent.button=0,a.type="mouseup",c.dispatchEvent(a),a.type="click",c.dispatchEvent(a))}));var h=new THREE.Quaternion,i=this.parent.position.clone().multiplyScalar(-1);switch(e.orientation_mode){case ROS3D.INTERACTIVE_MARKER_INHERIT:h=this.parent.quaternion.clone().inverse(),this.updateMatrixWorld=function(a){ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a),c.currentControlOri.copy(c.quaternion),c.currentControlOri.normalize()};break;case ROS3D.INTERACTIVE_MARKER_FIXED:this.updateMatrixWorld=function(a){c.quaternion.copy(c.parent.quaternion.clone().inverse()),c.updateMatrix(),c.matrixWorldNeedsUpdate=!0,ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a),c.currentControlOri.copy(c.quaternion)};break;case ROS3D.INTERACTIVE_MARKER_VIEW_FACING:var j=e.independent_marker_orientation;this.updateMatrixWorld=function(a){c.camera.updateMatrixWorld();var b=(new THREE.Matrix4).extractRotation(c.camera.matrixWorld),d=new THREE.Matrix4,e=.5*Math.PI,f=new THREE.Euler(-e,0,e);d.makeRotationFromEuler(f);var g=new THREE.Matrix4;g.getInverse(c.parent.matrixWorld),b.multiplyMatrices(b,d),b.multiplyMatrices(g,b),c.currentControlOri.setFromRotationMatrix(b),j||(c.quaternion.copy(c.currentControlOri),c.updateMatrix(),c.matrixWorldNeedsUpdate=!0),ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a)};break;default:console.error("Unkown orientation mode: "+e.orientation_mode)}var k=new ROSLIB.TFClient({ros:d.tfClient.ros,fixedFrame:d.message.header.frame_id,serverName:d.tfClient.serverName});e.markers.forEach(function(a){var b=function(b){var d=new ROS3D.Marker({message:a,path:c.path,loader:c.loader});if(null!==b){var e=new ROSLIB.Pose({position:d.position,orientation:d.quaternion});e.applyTransform(new ROSLIB.Transform(b));var f=new ROS3D.Marker({message:a,path:c.path,loader:c.loader});f.position.add(i),f.position.applyQuaternion(h),f.quaternion.multiplyQuaternions(h,f.quaternion);var g=new THREE.Vector3(f.position.x,f.position.y,f.position.z),j=new ROSLIB.Transform({translation:g,orientation:f.quaternion});e.applyTransform(j),d.setPose(e),d.updateMatrixWorld(),k.unsubscribe(a.header.frame_id)}c.add(d)};""!==a.header.frame_id?k.subscribe(a.header.frame_id,b):b(null)})},ROS3D.InteractiveMarkerControl.prototype.__proto__=THREE.Object3D.prototype,ROS3D.InteractiveMarkerHandle=function(a){a=a||{},this.message=a.message,this.feedbackTopic=a.feedbackTopic,this.tfClient=a.tfClient,this.menuFontSize=a.menuFontSize||"0.8em",this.name=this.message.name,this.header=this.message.header,this.controls=this.message.controls,this.menuEntries=this.message.menu_entries,this.dragging=!1,this.timeoutHandle=null,this.tfTransform=new ROSLIB.Transform,this.pose=new ROSLIB.Pose,this.setPoseFromClientBound=this.setPoseFromClient.bind(this),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onButtonClickBound=this.onButtonClick.bind(this),this.onMenuSelectBound=this.onMenuSelect.bind(this),this.setPoseFromServer(this.message.pose),this.tfUpdateBound=this.tfUpdate.bind(this)},ROS3D.InteractiveMarkerHandle.prototype.__proto__=EventEmitter2.prototype,ROS3D.InteractiveMarkerHandle.prototype.subscribeTf=function(){0===this.message.header.stamp.secs&&0===this.message.header.stamp.nsecs&&this.tfClient.subscribe(this.message.header.frame_id,this.tfUpdateBound)},ROS3D.InteractiveMarkerHandle.prototype.unsubscribeTf=function(){this.tfClient.unsubscribe(this.message.header.frame_id,this.tfUpdateBound)},ROS3D.InteractiveMarkerHandle.prototype.emitServerPoseUpdate=function(){var a=new ROSLIB.Pose(this.pose);a.applyTransform(this.tfTransform),this.emit("pose",a)},ROS3D.InteractiveMarkerHandle.prototype.setPoseFromServer=function(a){this.pose=new ROSLIB.Pose(a),this.emitServerPoseUpdate()},ROS3D.InteractiveMarkerHandle.prototype.tfUpdate=function(a){this.tfTransform=new ROSLIB.Transform(a),this.emitServerPoseUpdate()},ROS3D.InteractiveMarkerHandle.prototype.setPoseFromClient=function(a){this.pose=new ROSLIB.Pose(a);var b=this.tfTransform.clone();b.rotation.invert(),b.translation.multiplyQuaternion(b.rotation),b.translation.x*=-1,b.translation.y*=-1,b.translation.z*=-1,this.pose.applyTransform(b),this.sendFeedback(ROS3D.INTERACTIVE_MARKER_POSE_UPDATE,void 0,0,a.controlName),this.dragging&&(this.timeoutHandle&&clearTimeout(this.timeoutHandle),this.timeoutHandle=setTimeout(this.setPoseFromClient.bind(this,a),250))},ROS3D.InteractiveMarkerHandle.prototype.onButtonClick=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_BUTTON_CLICK,a.clickPosition,0,a.controlName)},ROS3D.InteractiveMarkerHandle.prototype.onMouseDown=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MOUSE_DOWN,a.clickPosition,0,a.controlName),this.dragging=!0},ROS3D.InteractiveMarkerHandle.prototype.onMouseUp=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MOUSE_UP,a.clickPosition,0,a.controlName),this.dragging=!1,this.timeoutHandle&&clearTimeout(this.timeoutHandle)},ROS3D.InteractiveMarkerHandle.prototype.onMenuSelect=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MENU_SELECT,void 0,a.id,a.controlName)},ROS3D.InteractiveMarkerHandle.prototype.sendFeedback=function(a,b,c,d){var e=void 0!==b;b=b||{x:0,y:0,z:0};var f={header:this.header,client_id:this.clientID,marker_name:this.name,control_name:d,event_type:a,pose:this.pose,mouse_point:b,mouse_point_valid:e,menu_entry_id:c};this.feedbackTopic.publish(f)},ROS3D.InteractiveMarkerMenu=function(a){function b(a,b){this.dispatchEvent({type:"menu-select",domEvent:b,id:a.id,controlName:this.controlName}),this.hide(b)}function c(a,e){var f=document.createElement("ul");a.appendChild(f);for(var g=e.children,h=0;h0?(c(i,g[h]),j.addEventListener("click",d.hide.bind(d)),j.addEventListener("touchstart",d.hide.bind(d))):(j.addEventListener("click",b.bind(d,g[h])),j.addEventListener("touchstart",b.bind(d,g[h])),j.className="default-interactive-marker-menu-entry")}}var d=this;a=a||{};var e=a.menuEntries,f=a.className||"default-interactive-marker-menu",g=(a.entryClassName,a.overlayClassName||"default-interactive-marker-overlay"),h=a.menuFontSize||"0.8em",i=[];if(i[0]={children:[]},THREE.EventDispatcher.call(this),null===document.getElementById("default-interactive-marker-menu-css")){var j=document.createElement("style");j.id="default-interactive-marker-menu-css",j.type="text/css",j.innerHTML=".default-interactive-marker-menu {background-color: #444444;border: 1px solid #888888;border: 1px solid #888888;padding: 0px 0px 0px 0px;color: #FFFFFF;font-family: sans-serif;font-size: "+h+";z-index: 1002;}.default-interactive-marker-menu ul {padding: 0px 0px 5px 0px;margin: 0px;list-style-type: none;}.default-interactive-marker-menu ul li div {-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;cursor: default;padding: 3px 10px 3px 10px;}.default-interactive-marker-menu-entry:hover { background-color: #666666; cursor: pointer;}.default-interactive-marker-menu ul ul { font-style: italic; padding-left: 10px;}.default-interactive-marker-overlay { position: absolute; top: 0%; left: 0%; width: 100%; height: 100%; background-color: black; z-index: 1001; -moz-opacity: 0.0; opacity: .0; filter: alpha(opacity = 0);}",document.getElementsByTagName("head")[0].appendChild(j)}this.menuDomElem=document.createElement("div"),this.menuDomElem.style.position="absolute",this.menuDomElem.className=f,this.menuDomElem.addEventListener("contextmenu",function(a){a.preventDefault()}),this.overlayDomElem=document.createElement("div"),this.overlayDomElem.className=g,this.hideListener=this.hide.bind(this),this.overlayDomElem.addEventListener("contextmenu",this.hideListener),this.overlayDomElem.addEventListener("click",this.hideListener),this.overlayDomElem.addEventListener("touchstart",this.hideListener);var k,l,m;for(k=0;k0){var V=this.msgColor,W=document.createElement("canvas"),X=W.getContext("2d") -;X.font="normal 100px sans-serif";var Y=X.measureText(c.text),Z=Y.width;W.width=Z,W.height=150,X.font="normal 100px sans-serif",X.fillStyle="rgba("+Math.round(255*V.r)+", "+Math.round(255*V.g)+", "+Math.round(255*V.b)+", "+V.a+")",X.textAlign="left",X.textBaseline="middle",X.fillText(c.text,0,W.height/2);var $=new THREE.Texture(W);$.needsUpdate=!0;var _=new THREE.SpriteMaterial({map:$,useScreenCoordinates:!1}),aa=new THREE.Sprite(_),ba=c.scale.x;aa.scale.set(Z/W.height*ba,ba,1),this.add(aa)}break;case ROS3D.MARKER_MESH_RESOURCE:var ca=null;0===c.color.r&&0===c.color.g&&0===c.color.b&&0===c.color.a||(ca=d),this.msgMesh=c.mesh_resource.substr(10);var da=new ROS3D.MeshResource({path:b,resource:this.msgMesh,material:ca});this.add(da);break;case ROS3D.MARKER_TRIANGLE_LIST:var ea=new ROS3D.TriangleList({material:d,vertices:c.points,colors:c.colors});ea.scale.set(c.scale.x,c.scale.y,c.scale.z),this.add(ea);break;default:console.error("Currently unsupported marker type: "+c.type)}},ROS3D.Marker.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Marker.prototype.setPose=function(a){this.position.x=a.position.x,this.position.y=a.position.y,this.position.z=a.position.z,this.quaternion.set(a.orientation.x,a.orientation.y,a.orientation.z,a.orientation.w),this.quaternion.normalize(),this.updateMatrixWorld()},ROS3D.Marker.prototype.update=function(a){if(this.setPose(a.pose),a.color.r!==this.msgColor.r||a.color.g!==this.msgColor.g||a.color.b!==this.msgColor.b||a.color.a!==this.msgColor.a){var b=ROS3D.makeColorMaterial(a.color.r,a.color.g,a.color.b,a.color.a);switch(a.type){case ROS3D.MARKER_LINE_STRIP:case ROS3D.MARKER_LINE_LIST:case ROS3D.MARKER_POINTS:break;case ROS3D.MARKER_ARROW:case ROS3D.MARKER_CUBE:case ROS3D.MARKER_SPHERE:case ROS3D.MARKER_CYLINDER:case ROS3D.MARKER_TRIANGLE_LIST:case ROS3D.MARKER_TEXT_VIEW_FACING:this.traverse(function(a){a instanceof THREE.Mesh&&(a.material=b)});break;case ROS3D.MARKER_MESH_RESOURCE:var c=null;0===a.color.r&&0===a.color.g&&0===a.color.b&&0===a.color.a||(c=this.colorMaterial),this.traverse(function(a){a instanceof THREE.Mesh&&(a.material=c)});break;case ROS3D.MARKER_CUBE_LIST:case ROS3D.MARKER_SPHERE_LIST:default:return!1}this.msgColor=a.color}var d=Math.abs(this.msgScale[0]-a.scale.x)>1e-6||Math.abs(this.msgScale[1]-a.scale.y)>1e-6||Math.abs(this.msgScale[2]-a.scale.z)>1e-6;switch(this.msgScale=[a.scale.x,a.scale.y,a.scale.z],a.type){case ROS3D.MARKER_CUBE:case ROS3D.MARKER_SPHERE:case ROS3D.MARKER_CYLINDER:if(d)return!1;break;case ROS3D.MARKER_TEXT_VIEW_FACING:if(d||this.text!==a.text)return!1;break;case ROS3D.MARKER_MESH_RESOURCE:if(a.mesh_resource.substr(10)!==this.msgMesh)return!1;if(d)return!1;break;case ROS3D.MARKER_ARROW:case ROS3D.MARKER_LINE_STRIP:case ROS3D.MARKER_LINE_LIST:case ROS3D.MARKER_CUBE_LIST:case ROS3D.MARKER_SPHERE_LIST:case ROS3D.MARKER_POINTS:case ROS3D.MARKER_TRIANGLE_LIST:return!1}return!0},ROS3D.Marker.prototype.dispose=function(){this.children.forEach(function(a){a instanceof ROS3D.MeshResource?a.children.forEach(function(b){void 0!==b.material&&b.material.dispose(),b.children.forEach(function(a){void 0!==a.geometry&&a.geometry.dispose(),void 0!==a.material&&a.material.dispose(),b.remove(a)}),a.remove(b)}):(void 0!==a.geometry&&a.geometry.dispose(),void 0!==a.material&&a.material.dispose()),a.parent.remove(a)})},ROS3D.MarkerArrayClient=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic,this.tfClient=a.tfClient,this.rootObject=a.rootObject||new THREE.Object3D,this.path=a.path||"/",this.markers={},this.rosTopic=void 0,this.subscribe()},ROS3D.MarkerArrayClient.prototype.__proto__=EventEmitter2.prototype,ROS3D.MarkerArrayClient.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"visualization_msgs/MarkerArray",compression:"png"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.MarkerArrayClient.prototype.processMessage=function(a){a.markers.forEach(function(a){if(0===a.action){var b=!1;if(a.ns+a.id in this.markers&&((b=this.markers[a.ns+a.id].children[0].update(a))||(this.markers[a.ns+a.id].unsubscribeTf(),this.rootObject.remove(this.markers[a.ns+a.id]))),!b){var c=new ROS3D.Marker({message:a,path:this.path});this.markers[a.ns+a.id]=new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:c}),this.rootObject.add(this.markers[a.ns+a.id])}}else if(1===a.action)console.warn('Received marker message with deprecated action identifier "1"');else if(2===a.action)this.markers[a.ns+a.id].unsubscribeTf(),this.rootObject.remove(this.markers[a.ns+a.id]),delete this.markers[a.ns+a.id];else if(3===a.action){for(var d in this.markers)this.markers[d].unsubscribeTf(),this.rootObject.remove(this.markers[d]);this.markers={}}else console.warn('Received marker message with unknown action identifier "'+a.action+'"')}.bind(this)),this.emit("change")},ROS3D.MarkerArrayClient.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.MarkerClient=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic,this.tfClient=a.tfClient,this.rootObject=a.rootObject||new THREE.Object3D,this.path=a.path||"/",this.markers={},this.rosTopic=void 0,this.subscribe()},ROS3D.MarkerClient.prototype.__proto__=EventEmitter2.prototype,ROS3D.MarkerClient.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.MarkerClient.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"visualization_msgs/Marker",compression:"png"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.MarkerClient.prototype.processMessage=function(a){var b=new ROS3D.Marker({message:a,path:this.path}),c=this.markers[a.ns+a.id];c&&(c.unsubscribeTf(),this.rootObject.remove(c)),this.markers[a.ns+a.id]=new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:b}),this.rootObject.add(this.markers[a.ns+a.id]),this.emit("change")},ROS3D.Arrow=function(a){a=a||{};var b=a.origin||new THREE.Vector3(0,0,0),c=a.direction||new THREE.Vector3(1,0,0),d=a.length||1,e=a.headLength||.2,f=a.shaftDiameter||.05,g=a.headDiameter||.1,h=a.material||new THREE.MeshBasicMaterial,i=d-e,j=new THREE.CylinderGeometry(.5*f,.5*f,i,12,1),k=new THREE.Matrix4;k.setPosition(new THREE.Vector3(0,.5*i,0)),j.applyMatrix(k);var l=new THREE.CylinderGeometry(0,.5*g,e,12,1);k.setPosition(new THREE.Vector3(0,i+.5*e,0)),l.applyMatrix(k),j.merge(l),THREE.Mesh.call(this,j,h),this.position.copy(b),this.setDirection(c)},ROS3D.Arrow.prototype.__proto__=THREE.Mesh.prototype,ROS3D.Arrow.prototype.setDirection=function(a){var b=new THREE.Vector3(0,1,0).cross(a),c=Math.acos(new THREE.Vector3(0,1,0).dot(a.clone().normalize()));this.matrix=(new THREE.Matrix4).makeRotationAxis(b.normalize(),c),this.rotation.setFromRotationMatrix(this.matrix,this.rotation.order)},ROS3D.Arrow.prototype.setLength=function(a){this.scale.set(a,a,a)},ROS3D.Arrow.prototype.setColor=function(a){this.material.color.setHex(a)},ROS3D.Arrow.prototype.dispose=function(){void 0!==this.geometry&&this.geometry.dispose(),void 0!==this.material&&this.material.dispose()},ROS3D.Arrow2=function(a){a=a||{};var b=a.origin||new THREE.Vector3(0,0,0),c=a.direction||new THREE.Vector3(1,0,0),d=a.length||1;a.headLength,a.shaftDiameter,a.headDiameter,a.material||new THREE.MeshBasicMaterial;THREE.ArrowHelper.call(this,c,b,d,16711680)},ROS3D.Arrow2.prototype.__proto__=THREE.ArrowHelper.prototype,ROS3D.Arrow2.prototype.dispose=function(){void 0!==this.line&&(this.line.material.dispose(),this.line.geometry.dispose()),void 0!==this.cone&&(this.cone.material.dispose(),this.cone.geometry.dispose())},ROS3D.Axes=function(a){function b(a){var b=new THREE.Color;b.setRGB(a.x,a.y,a.z);var d=new THREE.MeshBasicMaterial({color:b.getHex()}),e=new THREE.Vector3;e.crossVectors(a,new THREE.Vector3(0,-1,0));var f=new THREE.Quaternion;f.setFromAxisAngle(e,.5*Math.PI);var g=new THREE.Mesh(c.headGeom,d);g.position.copy(a),g.position.multiplyScalar(.95),g.quaternion.copy(f),g.updateMatrix(),c.add(g);var h=new THREE.Mesh(c.lineGeom,d);h.position.copy(a),h.position.multiplyScalar(.45),h.quaternion.copy(f),h.updateMatrix(),c.add(h)}var c=this;a=a||{};var d=a.shaftRadius||.008,e=a.headRadius||.023,f=a.headLength||.1;THREE.Object3D.call(this),this.lineGeom=new THREE.CylinderGeometry(d,d,1-f),this.headGeom=new THREE.CylinderGeometry(0,e,f),b(new THREE.Vector3(1,0,0)),b(new THREE.Vector3(0,1,0)),b(new THREE.Vector3(0,0,1))},ROS3D.Axes.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Grid=function(a){a=a||{};var b=a.num_cells||10,c=a.color||"#cccccc",d=a.lineWidth||1,e=a.cellSize||1;THREE.Object3D.call(this);for(var f=new THREE.LineBasicMaterial({color:c,linewidth:d}),g=0;g<=b;++g){var h=e*b/2,i=h-g*e,j=new THREE.Geometry;j.vertices.push(new THREE.Vector3(-h,i,0),new THREE.Vector3(h,i,0));var k=new THREE.Geometry;k.vertices.push(new THREE.Vector3(i,-h,0),new THREE.Vector3(i,h,0)),this.add(new THREE.Line(j,f)),this.add(new THREE.Line(k,f))}},ROS3D.Grid.prototype.__proto__=THREE.Object3D.prototype,ROS3D.MeshResource=function(a){var b=this;a=a||{};var c=a.path||"/",d=a.resource,e=a.material||null;this.warnings=a.warnings,THREE.Object3D.call(this),"/"!==c.substr(c.length-1)&&(c+="/");var f,g=c+d,h=g.substr(-4).toLowerCase();".dae"===h?(f=new THREE.ColladaLoader,f.log=function(a){b.warnings&&console.warn(a)},f.load(g,function(a){null!==e&&a.scene.traverse(function(a){a instanceof THREE.Mesh&&void 0===a.material&&(a.material=e)}),b.add(a.scene)})):".stl"===h&&(f=new THREE.STLLoader,f.load(g,function(a){a.computeFaceNormals();var c;c=null!==e?new THREE.Mesh(a,e):new THREE.Mesh(a,new THREE.MeshBasicMaterial({color:10066329})),b.add(c)}))},ROS3D.MeshResource.prototype.__proto__=THREE.Object3D.prototype,ROS3D.TriangleList=function(a){a=a||{};var b=a.material||new THREE.MeshBasicMaterial,c=a.vertices,d=a.colors;THREE.Object3D.call(this),b.side=THREE.DoubleSide;var e=new THREE.Geometry;for(f=0;f=this.keep&&(this.sns[0].unsubscribeTf(),this.rootObject.remove(this.sns[0]),this.sns.shift()),this.options.origin=new THREE.Vector3(a.pose.pose.position.x,a.pose.pose.position.y,a.pose.pose.position.z);var b=new THREE.Quaternion(a.pose.pose.orientation.x,a.pose.pose.orientation.y,a.pose.pose.orientation.z,a.pose.pose.orientation.w);this.options.direction=new THREE.Vector3(1,0,0),this.options.direction.applyQuaternion(b),this.options.material=new THREE.MeshBasicMaterial({color:this.color});var c=new ROS3D.Arrow(this.options);this.sns.push(new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:c})),this.rootObject.add(this.sns[this.sns.length-1])},ROS3D.Path=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic||"/path",this.tfClient=a.tfClient,this.color=a.color||13369599,this.rootObject=a.rootObject||new THREE.Object3D,THREE.Object3D.call(this),this.sn=null,this.line=null,this.rosTopic=void 0,this.subscribe()},ROS3D.Path.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Path.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.Path.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"nav_msgs/Path"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.Path.prototype.processMessage=function(a){null!==this.sn&&(this.sn.unsubscribeTf(),this.rootObject.remove(this.sn));for(var b=new THREE.Geometry,c=0;ca.range_max)this.particles.alpha[c]=0;else{var e=a.angle_min+c*a.angle_increment;this.particles.points[c]=new THREE.Vector3(d*Math.cos(e),d*Math.sin(e),0),this.particles.alpha[c]=1}this.particles.colors[c]=new THREE.Color(this.color)}finishedUpdate(this.particles,b)},ROS3D.Particles=function(a){a=a||{},this.tfClient=a.tfClient;var b=a.texture||"https://upload.wikimedia.org/wikipedia/commons/a/a2/Pixel-white.png",c=a.size||.05;this.max_pts=a.max_pts||1e4,this.first_size=null,this.prev_pts=0,this.rootObject=a.rootObject||new THREE.Object3D;THREE.Object3D.call(this),this.vertex_shader=["attribute vec3 customColor;","attribute float alpha;","varying vec3 vColor;","varying float falpha;","void main() ","{"," vColor = customColor; // set color associated to vertex; use later in fragment shader"," vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );"," falpha = alpha; ",""," // option (1): draw particles at constant size on screen"," // gl_PointSize = size;"," // option (2): scale particles as objects in 3D space"," gl_PointSize = ",c,"* ( 300.0 / length( mvPosition.xyz ) );"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),this.fragment_shader=["uniform sampler2D texture;","varying vec3 vColor; // colors associated to vertices; assigned by vertex shader","varying float falpha;","void main() ","{"," // THREE.Material.alphaTest is not evaluated for ShaderMaterial, so we"," // have to take care of this ourselves."," if (falpha < 0.5) discard;"," // calculates a color for the particle"," gl_FragColor = vec4( vColor, falpha );"," // sets particle texture to desired color"," gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );","}"].join("\n"),this.geom=new THREE.Geometry;for(var d=0;d0?(d=o[0].object,n.intersection=this.lastIntersection=o[0]):d=this.fallbackTarget,d!==this.lastTarget&&a.type.match(/mouse/)){var p=this.notify(d,"mouseover",n);0===p?this.notify(this.lastTarget,"mouseout",n):1===p&&(d=this.fallbackTarget)!==this.lastTarget&&(this.notify(d,"mouseover",n),this.notify(this.lastTarget,"mouseout",n))}if(d!==this.lastTarget&&a.type.match(/touch/)){this.notify(d,a.type,n)?(this.notify(this.lastTarget,"touchleave",n),this.notify(this.lastTarget,"touchend",n)):(d=this.fallbackTarget)!==this.lastTarget&&(this.notify(this.lastTarget,"touchmove",n),this.notify(this.lastTarget,"touchend",n))}this.notify(d,a.type,n),"mousedown"!==a.type&&"touchstart"!==a.type&&"touchmove"!==a.type||(this.dragging=!0),this.lastTarget=d},ROS3D.MouseHandler.prototype.notify=function(a,b,c){for(c.type=b,c.cancelBubble=!1,c.continueBubble=!1,c.stopPropagation=function(){c.cancelBubble=!0},c.continuePropagation=function(){c.continueBubble=!0},c.currentTarget=a;c.currentTarget;){if(c.currentTarget.dispatchEvent&&c.currentTarget.dispatchEvent instanceof Function){if(c.currentTarget.dispatchEvent(c),c.cancelBubble)return this.dispatchEvent(c),0;if(c.continueBubble)return 2}c.currentTarget=c.currentTarget.parent}return 1},Object.assign(ROS3D.MouseHandler.prototype,THREE.EventDispatcher.prototype),ROS3D.OrbitControls=function(a){function b(a){var b=a.domEvent;switch(b.preventDefault(),b.button){case 0:A=z.ROTATE,n.set(b.clientX,b.clientY);break;case 1:A=z.MOVE,u=new THREE.Vector3(0,0,1);var c=(new THREE.Matrix4).extractRotation(this.camera.matrix);u.applyMatrix4(c),t=j.center.clone(),v=j.camera.position.clone(),w=d(a.mouseRay,t,u);break;case 2:A=z.ZOOM,q.set(b.clientX,b.clientY)}this.showAxes()}function c(a){var b=a.domEvent;if(A===z.ROTATE)o.set(b.clientX,b.clientY),p.subVectors(o,n),j.rotateLeft(2*Math.PI*p.x/l*j.userRotateSpeed),j.rotateUp(2*Math.PI*p.y/l*j.userRotateSpeed),n.copy(o),this.showAxes();else if(A===z.ZOOM)r.set(b.clientX,b.clientY),s.subVectors(r,q),s.y>0?j.zoomIn():j.zoomOut(),q.copy(r),this.showAxes();else if(A===z.MOVE){var c=d(a.mouseRay,j.center,u);if(!c)return;var e=(new THREE.Vector3).subVectors(w.clone(),c.clone());j.center.addVectors(t.clone(),e.clone()),j.camera.position.addVectors(v.clone(),e.clone()),j.update(),j.camera.updateMatrixWorld(),this.showAxes()}}function d(a,b,c){var d=new THREE.Vector3;new THREE.Vector3;d.subVectors(b,a.origin);var e=a.direction.dot(c);if(Math.abs(e)0?j.zoomIn():j.zoomOut(),this.showAxes()}}function g(a){var b=a.domEvent;switch(b.touches.length){case 1:A=z.ROTATE,n.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY);break;case 2:A=z.NONE,u=new THREE.Vector3(0,0,1);var c=(new THREE.Matrix4).extractRotation(this.camera.matrix);u.applyMatrix4(c),t=j.center.clone(),v=j.camera.position.clone(),w=d(a.mouseRay,t,u),x[0]=new THREE.Vector2(b.touches[0].pageX,b.touches[0].pageY),x[1]=new THREE.Vector2(b.touches[1].pageX,b.touches[1].pageY),y[0]=new THREE.Vector2(0,0),y[1]=new THREE.Vector2(0,0)}this.showAxes(),b.preventDefault()}function h(a){var b=a.domEvent;if(A===z.ROTATE)o.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY),p.subVectors(o,n),j.rotateLeft(2*Math.PI*p.x/l*j.userRotateSpeed),j.rotateUp(2*Math.PI*p.y/l*j.userRotateSpeed),n.copy(o),this.showAxes();else{if(y[0].set(x[0].x-b.touches[0].pageX,x[0].y-b.touches[0].pageY),y[1].set(x[1].x-b.touches[1].pageX,x[1].y-b.touches[1].pageY),y[0].lengthSq()>m&&y[1].lengthSq()>m&&(x[0].set(b.touches[0].pageX,b.touches[0].pageY),x[1].set(b.touches[1].pageX,b.touches[1].pageY),y[0].dot(y[1])>0&&A!==z.ZOOM?A=z.MOVE:y[0].dot(y[1])<0&&A!==z.MOVE&&(A=z.ZOOM),A===z.ZOOM)){var c=new THREE.Vector2;c.subVectors(x[0],x[1]),y[0].dot(c)<0&&y[1].dot(c)>0?j.zoomOut():y[0].dot(c)>0&&y[1].dot(c)<0&&j.zoomIn()}if(A===z.MOVE){var e=d(a.mouseRay,j.center,u);if(!e)return;var f=(new THREE.Vector3).subVectors(w.clone(),e.clone());j.center.addVectors(t.clone(),f.clone()),j.camera.position.addVectors(v.clone(),f.clone()),j.update(),j.camera.updateMatrixWorld()}this.showAxes(),b.preventDefault()}}function i(a){var b=a.domEvent;1===b.touches.length&&A!==z.ROTATE?(A=z.ROTATE,n.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY)):A=z.NONE}THREE.EventDispatcher.call(this);var j=this;a=a||{};var k=a.scene;this.camera=a.camera,this.center=new THREE.Vector3,this.userZoom=!0,this.userZoomSpeed=a.userZoomSpeed||1,this.userRotate=!0,this.userRotateSpeed=a.userRotateSpeed||1,this.autoRotate=a.autoRotate,this.autoRotateSpeed=a.autoRotateSpeed||2,this.camera.up=new THREE.Vector3(0,0,1);var l=1800,m=10,n=new THREE.Vector2,o=new THREE.Vector2,p=new THREE.Vector2,q=new THREE.Vector2,r=new THREE.Vector2,s=new THREE.Vector2,t=new THREE.Vector3,u=new THREE.Vector3,v=new THREE.Vector3,w=new THREE.Vector3,x=new Array(2),y=new Array(2);this.phiDelta=0,this.thetaDelta=0,this.scale=1,this.lastPosition=new THREE.Vector3;var z={NONE:-1,ROTATE:0,ZOOM:1,MOVE:2},A=z.NONE;this.axes=new ROS3D.Axes({shaftRadius:.025,headRadius:.07,headLength:.2}),k.add(this.axes),this.axes.traverse(function(a){a.visible=!1}),this.addEventListener("mousedown",b),this.addEventListener("mouseup",e),this.addEventListener("mousemove",c),this.addEventListener("touchstart",g),this.addEventListener("touchmove",h),this.addEventListener("touchend",i),this.addEventListener("mousewheel",f),this.addEventListener("DOMMouseScroll",f)},ROS3D.OrbitControls.prototype.showAxes=function(){var a=this;this.axes.traverse(function(a){a.visible=!0}),this.hideTimeout&&clearTimeout(this.hideTimeout),this.hideTimeout=setTimeout(function(){a.axes.traverse(function(a){a.visible=!1}),a.hideTimeout=!1},1e3)},ROS3D.OrbitControls.prototype.rotateLeft=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.thetaDelta-=a},ROS3D.OrbitControls.prototype.rotateRight=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.thetaDelta+=a},ROS3D.OrbitControls.prototype.rotateUp=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.phiDelta-=a},ROS3D.OrbitControls.prototype.rotateDown=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.phiDelta+=a},ROS3D.OrbitControls.prototype.zoomIn=function(a){void 0===a&&(a=Math.pow(.95,this.userZoomSpeed)),this.scale/=a},ROS3D.OrbitControls.prototype.zoomOut=function(a){void 0===a&&(a=Math.pow(.95,this.userZoomSpeed)),this.scale*=a},ROS3D.OrbitControls.prototype.update=function(){var a=this.camera.position,b=a.clone().sub(this.center),c=Math.atan2(b.y,b.x),d=Math.atan2(Math.sqrt(b.y*b.y+b.x*b.x),b.z);this.autoRotate&&this.rotateLeft(2*Math.PI/60/60*this.autoRotateSpeed),c+=this.thetaDelta,d+=this.phiDelta;d=Math.max(1e-6,Math.min(Math.PI-1e-6,d));var e=b.length();b.set(e*Math.sin(d)*Math.cos(c),e*Math.sin(d)*Math.sin(c),e*Math.cos(d)),b.multiplyScalar(this.scale),a.copy(this.center).add(b),this.camera.lookAt(this.center),e=b.length(),this.axes.position.copy(this.center),this.axes.scale.set(.05*e,.05*e,.05*e),this.axes.updateMatrixWorld(!0),this.thetaDelta=0,this.phiDelta=0,this.scale=1,this.lastPosition.distanceTo(this.camera.position)>0&&(this.dispatchEvent({type:"change"}),this.lastPosition.copy(this.camera.position))},Object.assign(ROS3D.OrbitControls.prototype,THREE.EventDispatcher.prototype),ROS3D.SceneNode=function(a){a=a||{};var b=this;this.tfClient=a.tfClient,this.frameID=a.frameID;var c=a.object;this.pose=a.pose||new ROSLIB.Pose,THREE.Object3D.call(this),this.visible=!1,this.add(c),this.updatePose(this.pose),this.tfUpdate=function(a){var c=new ROSLIB.Transform(a),d=new ROSLIB.Pose(b.pose);d.applyTransform(c),b.updatePose(d),b.visible=!0},this.tfClient.subscribe(this.frameID,this.tfUpdate)},ROS3D.SceneNode.prototype.__proto__=THREE.Object3D.prototype,ROS3D.SceneNode.prototype.updatePose=function(a){this.position.set(a.position.x,a.position.y,a.position.z),this.quaternion.set(a.orientation.x,a.orientation.y,a.orientation.z,a.orientation.w),this.updateMatrixWorld(!0)},ROS3D.SceneNode.prototype.unsubscribeTf=function(){this.tfClient.unsubscribe(this.frameID,this.tfUpdate)},ROS3D.Viewer=function(a){a=a||{};var b=a.divID,c=a.width,d=a.height,e=a.background||"#111111",f=a.antialias,g=a.intensity||.66,h=a.near||.01,i=a.far||1e3,j=a.alpha||1,k=a.cameraPose||{x:3,y:3,z:3},l=a.cameraZoomSpeed||.5;this.renderer=new THREE.WebGLRenderer({antialias:f,alpha:!0}),this.renderer.setClearColor(parseInt(e.replace("#","0x"),16),j),this.renderer.sortObjects=!1,this.renderer.setSize(c,d),this.renderer.shadowMap.enabled=!1,this.renderer.autoClear=!1,this.scene=new THREE.Scene,this.camera=new THREE.PerspectiveCamera(40,c/d,h,i),this.camera.position.x=k.x,this.camera.position.y=k.y,this.camera.position.z=k.z,this.cameraControls=new ROS3D.OrbitControls({scene:this.scene,camera:this.camera}),this.cameraControls.userZoomSpeed=l,this.scene.add(new THREE.AmbientLight(5592405)),this.directionalLight=new THREE.DirectionalLight(16777215,g),this.scene.add(this.directionalLight),this.selectableObjects=new THREE.Object3D,this.scene.add(this.selectableObjects);var m=new ROS3D.MouseHandler({renderer:this.renderer,camera:this.camera,rootObject:this.selectableObjects,fallbackTarget:this.cameraControls});this.highlighter=new ROS3D.Highlighter({mouseHandler:m}),this.stopped=!0,this.animationRequestId=void 0,document.getElementById(b).appendChild(this.renderer.domElement),this.start()},ROS3D.Viewer.prototype.start=function(){this.stopped=!1,this.draw()},ROS3D.Viewer.prototype.draw=function(){this.stopped||(this.cameraControls.update(),this.directionalLight.position=this.camera.localToWorld(new THREE.Vector3(-1,1,0)),this.directionalLight.position.normalize(),this.renderer.clear(!0,!0,!0),this.renderer.render(this.scene,this.camera),this.highlighter.renderHighlights(this.scene,this.renderer,this.camera),this.animationRequestId=requestAnimationFrame(this.draw.bind(this)))},ROS3D.Viewer.prototype.stop=function(){this.stopped||cancelAnimationFrame(this.animationRequestId),this.stopped=!0},ROS3D.Viewer.prototype.addObject=function(a,b){b?this.selectableObjects.add(a):this.scene.add(a)},ROS3D.Viewer.prototype.resize=function(a,b){this.camera.aspect=a/b,this.camera.updateProjectionMatrix(),this.renderer.setSize(a,b)}; \ No newline at end of file +function setFrame(a,b){null===a.sn&&(a.sn=new ROS3D.SceneNode({frameID:b,tfClient:a.tfClient,object:a.ps}),a.rootObject.add(a.sn))}function finishedUpdate(a,b){null===a.first_size&&(a.first_size=b,a.max_pts=Math.max(a.max_pts,b));for(var c=b;ca.max_pts&&console.error("Attempted to draw more points than max_pts allows")}function read_point(a,b,c){for(var d=[],e=a.point_step*b,f=0;f=8&&(d-=8,b.push(c>>d),c&=Math.pow(2,d)-1),c<<=6;return b}var ROS3D=ROS3D||{REVISION:"0.18.0"};ROS3D.MARKER_ARROW=0,ROS3D.MARKER_CUBE=1,ROS3D.MARKER_SPHERE=2,ROS3D.MARKER_CYLINDER=3,ROS3D.MARKER_LINE_STRIP=4,ROS3D.MARKER_LINE_LIST=5,ROS3D.MARKER_CUBE_LIST=6,ROS3D.MARKER_SPHERE_LIST=7,ROS3D.MARKER_POINTS=8,ROS3D.MARKER_TEXT_VIEW_FACING=9,ROS3D.MARKER_MESH_RESOURCE=10,ROS3D.MARKER_TRIANGLE_LIST=11,ROS3D.INTERACTIVE_MARKER_KEEP_ALIVE=0,ROS3D.INTERACTIVE_MARKER_POSE_UPDATE=1,ROS3D.INTERACTIVE_MARKER_MENU_SELECT=2,ROS3D.INTERACTIVE_MARKER_BUTTON_CLICK=3,ROS3D.INTERACTIVE_MARKER_MOUSE_DOWN=4,ROS3D.INTERACTIVE_MARKER_MOUSE_UP=5,ROS3D.INTERACTIVE_MARKER_NONE=0,ROS3D.INTERACTIVE_MARKER_MENU=1,ROS3D.INTERACTIVE_MARKER_BUTTON=2,ROS3D.INTERACTIVE_MARKER_MOVE_AXIS=3,ROS3D.INTERACTIVE_MARKER_MOVE_PLANE=4,ROS3D.INTERACTIVE_MARKER_ROTATE_AXIS=5,ROS3D.INTERACTIVE_MARKER_MOVE_ROTATE=6,ROS3D.INTERACTIVE_MARKER_INHERIT=0,ROS3D.INTERACTIVE_MARKER_FIXED=1,ROS3D.INTERACTIVE_MARKER_VIEW_FACING=2,ROS3D.makeColorMaterial=function(a,b,c,d){var e=new THREE.Color;return e.setRGB(a,b,c),d<=.99?new THREE.MeshBasicMaterial({color:e.getHex(),opacity:d+.1,transparent:!0,depthWrite:!0,blendSrc:THREE.SrcAlphaFactor,blendDst:THREE.OneMinusSrcAlphaFactor,blendEquation:THREE.ReverseSubtractEquation,blending:THREE.NormalBlending}):new THREE.MeshPhongMaterial({color:e.getHex(),opacity:d,blending:THREE.NormalBlending})},ROS3D.intersectPlane=function(a,b,c){var d=new THREE.Vector3,e=new THREE.Vector3;d.subVectors(b,a.origin);var f=a.direction.dot(c);if(!(Math.abs(f)0&&b.push(new THREE.VectorKeyframeTrack(d+".position",e,f)),g.length>0&&b.push(new THREE.QuaternionKeyframeTrack(d+".quaternion",e,g)),h.length>0&&b.push(new THREE.VectorKeyframeTrack(d+".scale",e,h)),b}function w(a,b,c){var d,e,f,g=!0;for(e=0,f=a.length;e=0;){var d=a[b];if(null!==d.value[c])return d;b--}return null}function z(a,b,c){for(;b0&&k.addAttribute("position",new THREE.Float32BufferAttribute(e.array,e.stride)),f.array.length>0&&k.addAttribute("normal",new THREE.Float32BufferAttribute(f.array,f.stride)),h.array.length>0&&k.addAttribute("color",new THREE.Float32BufferAttribute(h.array,h.stride)),g.array.length>0&&k.addAttribute("uv",new THREE.Float32BufferAttribute(g.array,g.stride)),i.array.length>0&&k.addAttribute("skinIndex",new THREE.Float32BufferAttribute(i.array,i.stride)),j.array.length>0&&k.addAttribute("skinWeight",new THREE.Float32BufferAttribute(j.array,j.stride)),d.data=k,d.type=a[0].type,d.materialKeys=l,d}function ta(a,b,c,d){function e(a){for(var b=f[a+c]*k,e=b+k;b0&&console.log("THREE.ColladaLoader: Geometry has faces with more than 4 vertices.")}else for(var m=0,n=f.length;m=b.limits.max&&(b.static=!0),b.middlePosition=(b.limits.min+b.limits.max)/2,b}function Ba(a){for(var b={sid:a.getAttribute("sid"),name:a.getAttribute("name")||"",attachments:[],transforms:[]},c=0;cd.limits.max||b0.99)"," {"," vec4 depthColor2 = texture2D( map, vUv2 );"," float depth2 = ( depthColor2.r + depthColor2.g + depthColor2.b ) / 3.0 ;"," depth = 0.99+depth2;"," }"," "," return depth;"," }","","float median(float a, float b, float c)"," {"," float r=a;"," "," if ( (a0.5) || (vUvP.y<0.5) || (vUvP.y>0.0))"," {"," vec2 smp = decodeDepth(vec2(position.x, position.y));"," float depth = smp.x;"," depthVariance = smp.y;"," "," float z = -depth;"," "," pos = vec4("," ( position.x / width - 0.5 ) * z * (1000.0/focallength) * -1.0,"," ( position.y / height - 0.5 ) * z * (1000.0/focallength),"," (- z + zOffset / 1000.0) * 2.0,"," 1.0);"," "," vec2 maskP = vec2( position.x / (width*2.0), position.y / (height*2.0) );"," vec4 maskColor = texture2D( map, maskP );"," maskVal = ( maskColor.r + maskColor.g + maskColor.b ) / 3.0 ;"," }"," "," gl_PointSize = pointSize;"," gl_Position = projectionMatrix * modelViewMatrix * pos;"," ","}"].join("\n"),this.fragment_shader=["uniform sampler2D map;","uniform float varianceThreshold;","uniform float whiteness;","","varying vec2 vUvP;","varying vec2 colorP;","","varying float depthVariance;","varying float maskVal;","","","void main() {"," "," vec4 color;"," "," if ( (depthVariance>varianceThreshold) || (maskVal>0.5) ||(vUvP.x<0.0)|| (vUvP.x>0.5) || (vUvP.y<0.5) || (vUvP.y>1.0))"," { "," discard;"," }"," else "," {"," color = texture2D( map, colorP );"," "," float fader = whiteness /100.0;"," "," color.r = color.r * (1.0-fader)+ fader;"," "," color.g = color.g * (1.0-fader)+ fader;"," "," color.b = color.b * (1.0-fader)+ fader;"," "," color.a = 1.0;//smoothstep( 20000.0, -20000.0, gl_FragCoord.z / gl_FragCoord.w );"," }"," "," gl_FragColor = vec4( color.r, color.g, color.b, color.a );"," ","}"].join("\n")},ROS3D.DepthCloud.prototype.__proto__=THREE.Object3D.prototype,ROS3D.DepthCloud.prototype.metaLoaded=function(){this.metaLoaded=!0,this.initStreamer()},ROS3D.DepthCloud.prototype.initStreamer=function(){if(this.metaLoaded){this.texture=new THREE.Texture(this.video),this.geometry=new THREE.Geometry;for(var a=0,b=this.width*this.height;a0&&(this.menu=new ROS3D.InteractiveMarkerMenu({menuEntries:c.menuEntries,menuFontSize:c.menuFontSize}),this.menu.addEventListener("menu-select",function(a){b.dispatchEvent(a)}))},ROS3D.InteractiveMarker.prototype.__proto__=THREE.Object3D.prototype,ROS3D.InteractiveMarker.prototype.showMenu=function(a,b){this.menu&&this.menu.show(a,b)},ROS3D.InteractiveMarker.prototype.moveAxis=function(a,b,c){if(this.dragging){var d=a.currentControlOri,e=b.clone().applyQuaternion(d),f=this.dragStart.event3d.intersection.point,g=e.clone().applyQuaternion(this.dragStart.orientationWorld.clone()),h=new THREE.Ray(f,g),i=ROS3D.closestAxisPoint(h,c.camera,c.mousePos),j=new THREE.Vector3;j.addVectors(this.dragStart.position,e.clone().applyQuaternion(this.dragStart.orientation).multiplyScalar(i)),this.setPosition(a,j),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.movePlane=function(a,b,c){if(this.dragging){var d=a.currentControlOri,e=b.clone().applyQuaternion(d),f=this.dragStart.event3d.intersection.point,g=e.clone().applyQuaternion(this.dragStart.orientationWorld),h=ROS3D.intersectPlane(c.mouseRay,f,g),i=new THREE.Vector3;i.subVectors(h,f),i.add(this.dragStart.positionWorld),this.setPosition(a,i),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.rotateAxis=function(a,b,c){if(this.dragging){a.updateMatrixWorld();var d=a.currentControlOri,e=d.clone().multiply(b.clone()),f=new THREE.Vector3(1,0,0).applyQuaternion(e),g=this.dragStart.event3d.intersection.point,h=f.applyQuaternion(this.dragStart.orientationWorld),i=ROS3D.intersectPlane(c.mouseRay,g,h),j=new THREE.Ray(this.dragStart.positionWorld,h),k=ROS3D.intersectPlane(j,g,h),l=this.dragStart.orientationWorld.clone().multiply(e),m=l.clone().inverse();i.sub(k),i.applyQuaternion(m);var n=this.dragStart.event3d.intersection.point.clone();n.sub(k),n.applyQuaternion(m);var o=Math.atan2(i.y,i.z),p=Math.atan2(n.y,n.z),q=p-o,r=new THREE.Quaternion;r.setFromAxisAngle(f,q),this.setOrientation(a,r.multiply(this.dragStart.orientationWorld)),c.stopPropagation()}},ROS3D.InteractiveMarker.prototype.feedbackEvent=function(a,b){this.dispatchEvent({type:a,position:this.position.clone(),orientation:this.quaternion.clone(),controlName:b.name})},ROS3D.InteractiveMarker.prototype.startDrag=function(a,b){if(0===b.domEvent.button){b.stopPropagation(),this.dragging=!0,this.updateMatrixWorld(!0);var c=new THREE.Vector3;this.matrixWorld.decompose(this.dragStart.positionWorld,this.dragStart.orientationWorld,c),this.dragStart.position=this.position.clone(),this.dragStart.orientation=this.quaternion.clone(),this.dragStart.event3d=b,this.feedbackEvent("user-mousedown",a)}},ROS3D.InteractiveMarker.prototype.stopDrag=function(a,b){0===b.domEvent.button&&(b.stopPropagation(),this.dragging=!1,this.dragStart.event3d={},this.onServerSetPose(this.bufferedPoseEvent),this.bufferedPoseEvent=void 0,this.feedbackEvent("user-mouseup",a))},ROS3D.InteractiveMarker.prototype.buttonClick=function(a,b){b.stopPropagation(),this.feedbackEvent("user-button-click",a)},ROS3D.InteractiveMarker.prototype.setPosition=function(a,b){this.position.copy(b),this.feedbackEvent("user-pose-change",a)},ROS3D.InteractiveMarker.prototype.setOrientation=function(a,b){b.normalize(),this.quaternion.copy(b),this.feedbackEvent("user-pose-change",a)},ROS3D.InteractiveMarker.prototype.onServerSetPose=function(a){if(void 0!==a)if(this.dragging)this.bufferedPoseEvent=a;else{var b=a.pose;this.position.copy(b.position),this.quaternion.copy(b.orientation),this.updateMatrixWorld(!0)}},ROS3D.InteractiveMarker.prototype.dispose=function(){var a=this;this.children.forEach(function(b){b.children.forEach(function(a){a.dispose(),b.remove(a)}),a.remove(b)})},Object.assign(ROS3D.InteractiveMarker.prototype,THREE.EventDispatcher.prototype),ROS3D.InteractiveMarkerClient=function(a){a=a||{},this.ros=a.ros,this.tfClient=a.tfClient,this.topicName=a.topic,this.path=a.path||"/",this.camera=a.camera,this.rootObject=a.rootObject||new THREE.Object3D,this.loader=a.loader||ROS3D.COLLADA_LOADER_2,this.menuFontSize=a.menuFontSize||"0.8em",this.interactiveMarkers={},this.updateTopic=null,this.feedbackTopic=null,this.topicName&&this.subscribe(this.topicName)},ROS3D.InteractiveMarkerClient.prototype.subscribe=function(a){this.unsubscribe(),this.updateTopic=new ROSLIB.Topic({ros:this.ros,name:a+"/tunneled/update",messageType:"visualization_msgs/InteractiveMarkerUpdate",compression:"png"}),this.updateTopic.subscribe(this.processUpdate.bind(this)),this.feedbackTopic=new ROSLIB.Topic({ros:this.ros,name:a+"/feedback",messageType:"visualization_msgs/InteractiveMarkerFeedback",compression:"png"}),this.feedbackTopic.advertise(),this.initService=new ROSLIB.Service({ros:this.ros,name:a+"/tunneled/get_init",serviceType:"demo_interactive_markers/GetInit"});var b=new ROSLIB.ServiceRequest({});this.initService.callService(b,this.processInit.bind(this))},ROS3D.InteractiveMarkerClient.prototype.unsubscribe=function(){this.updateTopic&&this.updateTopic.unsubscribe(),this.feedbackTopic&&this.feedbackTopic.unadvertise();for(var a in this.interactiveMarkers)this.eraseIntMarker(a);this.interactiveMarkers={}},ROS3D.InteractiveMarkerClient.prototype.processInit=function(a){var b=a.msg;b.erases=[];for(var c in this.interactiveMarkers)b.erases.push(c);b.poses=[],this.processUpdate(b)},ROS3D.InteractiveMarkerClient.prototype.processUpdate=function(a){var b=this;a.erases.forEach(function(a){b.eraseIntMarker(a)}),a.poses.forEach(function(a){var c=b.interactiveMarkers[a.name];c&&c.setPoseFromServer(a.pose)}),a.markers.forEach(function(a){var c=b.interactiveMarkers[a.name];c&&b.eraseIntMarker(c.name);var d=new ROS3D.InteractiveMarkerHandle({message:a,feedbackTopic:b.feedbackTopic,tfClient:b.tfClient,menuFontSize:b.menuFontSize});b.interactiveMarkers[a.name]=d;var e=new ROS3D.InteractiveMarker({handle:d,camera:b.camera,path:b.path,loader:b.loader});e.name=a.name,b.rootObject.add(e),d.on("pose",function(a){e.onServerSetPose({pose:a})}),e.addEventListener("user-pose-change",d.setPoseFromClientBound),e.addEventListener("user-mousedown",d.onMouseDownBound),e.addEventListener("user-mouseup",d.onMouseUpBound),e.addEventListener("user-button-click",d.onButtonClickBound),e.addEventListener("menu-select",d.onMenuSelectBound),d.subscribeTf()})},ROS3D.InteractiveMarkerClient.prototype.eraseIntMarker=function(a){if(this.interactiveMarkers[a]){var b=this.rootObject.getObjectByName(a);this.rootObject.remove(b);var c=this.interactiveMarkers[a];c.unsubscribeTf(),b.removeEventListener("user-pose-change",c.setPoseFromClientBound),b.removeEventListener("user-mousedown",c.onMouseDownBound),b.removeEventListener("user-mouseup",c.onMouseUpBound),b.removeEventListener("user-button-click",c.onButtonClickBound),b.removeEventListener("menu-select",c.onMenuSelectBound),delete this.interactiveMarkers[a],b.dispose()}},ROS3D.InteractiveMarkerControl=function(a){function b(a){a.stopPropagation()}var c=this;THREE.Object3D.call(this),a=a||{},this.parent=a.parent;var d=a.handle,e=a.message;this.name=e.name,this.camera=a.camera,this.path=a.path||"/",this.loader=a.loader||ROS3D.COLLADA_LOADER_2,this.dragging=!1,this.startMousePos=new THREE.Vector2;var f=new THREE.Quaternion(e.orientation.x,e.orientation.y,e.orientation.z,e.orientation.w);f.normalize();var g=new THREE.Vector3(1,0,0);switch(g.applyQuaternion(f),this.currentControlOri=new THREE.Quaternion,e.interaction_mode){case ROS3D.INTERACTIVE_MARKER_MOVE_AXIS:this.addEventListener("mousemove",this.parent.moveAxis.bind(this.parent,this,g)),this.addEventListener("touchmove",this.parent.moveAxis.bind(this.parent,this,g));break;case ROS3D.INTERACTIVE_MARKER_ROTATE_AXIS:this.addEventListener("mousemove",this.parent.rotateAxis.bind(this.parent,this,f));break;case ROS3D.INTERACTIVE_MARKER_MOVE_PLANE:this.addEventListener("mousemove",this.parent.movePlane.bind(this.parent,this,g));break;case ROS3D.INTERACTIVE_MARKER_BUTTON:this.addEventListener("click",this.parent.buttonClick.bind(this.parent,this))}e.interaction_mode!==ROS3D.INTERACTIVE_MARKER_NONE&&(this.addEventListener("mousedown",this.parent.startDrag.bind(this.parent,this)),this.addEventListener("mouseup",this.parent.stopDrag.bind(this.parent,this)),this.addEventListener("contextmenu",this.parent.showMenu.bind(this.parent,this)),this.addEventListener("mouseup",function(a){0===c.startMousePos.distanceToSquared(a.mousePos)&&(a.type="contextmenu",c.dispatchEvent(a))}),this.addEventListener("mouseover",b),this.addEventListener("mouseout",b),this.addEventListener("click",b),this.addEventListener("mousedown",function(a){c.startMousePos=a.mousePos}),this.addEventListener("touchstart",function(a){1===a.domEvent.touches.length&&(a.type="mousedown",a.domEvent.button=0,c.dispatchEvent(a))}),this.addEventListener("touchmove",function(a){1===a.domEvent.touches.length&&(a.type="mousemove",a.domEvent.button=0,c.dispatchEvent(a))}),this.addEventListener("touchend",function(a){0===a.domEvent.touches.length&&(a.domEvent.button=0,a.type="mouseup",c.dispatchEvent(a),a.type="click",c.dispatchEvent(a))}));var h=new THREE.Quaternion,i=this.parent.position.clone().multiplyScalar(-1);switch(e.orientation_mode){case ROS3D.INTERACTIVE_MARKER_INHERIT:h=this.parent.quaternion.clone().inverse(),this.updateMatrixWorld=function(a){ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a),c.currentControlOri.copy(c.quaternion),c.currentControlOri.normalize()};break;case ROS3D.INTERACTIVE_MARKER_FIXED:this.updateMatrixWorld=function(a){c.quaternion.copy(c.parent.quaternion.clone().inverse()),c.updateMatrix(),c.matrixWorldNeedsUpdate=!0,ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a),c.currentControlOri.copy(c.quaternion)};break;case ROS3D.INTERACTIVE_MARKER_VIEW_FACING:var j=e.independent_marker_orientation;this.updateMatrixWorld=function(a){c.camera.updateMatrixWorld();var b=(new THREE.Matrix4).extractRotation(c.camera.matrixWorld),d=new THREE.Matrix4,e=.5*Math.PI,f=new THREE.Euler(-e,0,e);d.makeRotationFromEuler(f);var g=new THREE.Matrix4;g.getInverse(c.parent.matrixWorld),b.multiplyMatrices(b,d),b.multiplyMatrices(g,b),c.currentControlOri.setFromRotationMatrix(b),j||(c.quaternion.copy(c.currentControlOri),c.updateMatrix(),c.matrixWorldNeedsUpdate=!0),ROS3D.InteractiveMarkerControl.prototype.updateMatrixWorld.call(c,a)};break;default:console.error("Unkown orientation mode: "+e.orientation_mode)}var k=new ROSLIB.TFClient({ros:d.tfClient.ros,fixedFrame:d.message.header.frame_id,serverName:d.tfClient.serverName});e.markers.forEach(function(a){var b=function(b){var d=new ROS3D.Marker({message:a,path:c.path,loader:c.loader});if(null!==b){var e=new ROSLIB.Pose({position:d.position,orientation:d.quaternion});e.applyTransform(new ROSLIB.Transform(b));var f=new ROS3D.Marker({message:a,path:c.path,loader:c.loader});f.position.add(i),f.position.applyQuaternion(h),f.quaternion.multiplyQuaternions(h,f.quaternion);var g=new THREE.Vector3(f.position.x,f.position.y,f.position.z),j=new ROSLIB.Transform({translation:g,orientation:f.quaternion});e.applyTransform(j),d.setPose(e),d.updateMatrixWorld(),k.unsubscribe(a.header.frame_id)}c.add(d)};""!==a.header.frame_id?k.subscribe(a.header.frame_id,b):b(null)})},ROS3D.InteractiveMarkerControl.prototype.__proto__=THREE.Object3D.prototype,ROS3D.InteractiveMarkerHandle=function(a){a=a||{},this.message=a.message,this.feedbackTopic=a.feedbackTopic,this.tfClient=a.tfClient,this.menuFontSize=a.menuFontSize||"0.8em",this.name=this.message.name,this.header=this.message.header,this.controls=this.message.controls,this.menuEntries=this.message.menu_entries,this.dragging=!1,this.timeoutHandle=null,this.tfTransform=new ROSLIB.Transform,this.pose=new ROSLIB.Pose,this.setPoseFromClientBound=this.setPoseFromClient.bind(this),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onButtonClickBound=this.onButtonClick.bind(this),this.onMenuSelectBound=this.onMenuSelect.bind(this),this.setPoseFromServer(this.message.pose),this.tfUpdateBound=this.tfUpdate.bind(this)},ROS3D.InteractiveMarkerHandle.prototype.__proto__=EventEmitter2.prototype,ROS3D.InteractiveMarkerHandle.prototype.subscribeTf=function(){0===this.message.header.stamp.secs&&0===this.message.header.stamp.nsecs&&this.tfClient.subscribe(this.message.header.frame_id,this.tfUpdateBound)},ROS3D.InteractiveMarkerHandle.prototype.unsubscribeTf=function(){this.tfClient.unsubscribe(this.message.header.frame_id,this.tfUpdateBound)},ROS3D.InteractiveMarkerHandle.prototype.emitServerPoseUpdate=function(){var a=new ROSLIB.Pose(this.pose);a.applyTransform(this.tfTransform),this.emit("pose",a)},ROS3D.InteractiveMarkerHandle.prototype.setPoseFromServer=function(a){this.pose=new ROSLIB.Pose(a),this.emitServerPoseUpdate()},ROS3D.InteractiveMarkerHandle.prototype.tfUpdate=function(a){this.tfTransform=new ROSLIB.Transform(a),this.emitServerPoseUpdate()},ROS3D.InteractiveMarkerHandle.prototype.setPoseFromClient=function(a){this.pose=new ROSLIB.Pose(a);var b=this.tfTransform.clone();b.rotation.invert(),b.translation.multiplyQuaternion(b.rotation),b.translation.x*=-1,b.translation.y*=-1,b.translation.z*=-1,this.pose.applyTransform(b),this.sendFeedback(ROS3D.INTERACTIVE_MARKER_POSE_UPDATE,void 0,0,a.controlName),this.dragging&&(this.timeoutHandle&&clearTimeout(this.timeoutHandle),this.timeoutHandle=setTimeout(this.setPoseFromClient.bind(this,a),250))},ROS3D.InteractiveMarkerHandle.prototype.onButtonClick=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_BUTTON_CLICK,a.clickPosition,0,a.controlName)},ROS3D.InteractiveMarkerHandle.prototype.onMouseDown=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MOUSE_DOWN,a.clickPosition,0,a.controlName),this.dragging=!0},ROS3D.InteractiveMarkerHandle.prototype.onMouseUp=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MOUSE_UP,a.clickPosition,0,a.controlName),this.dragging=!1,this.timeoutHandle&&clearTimeout(this.timeoutHandle)},ROS3D.InteractiveMarkerHandle.prototype.onMenuSelect=function(a){this.sendFeedback(ROS3D.INTERACTIVE_MARKER_MENU_SELECT,void 0,a.id,a.controlName)},ROS3D.InteractiveMarkerHandle.prototype.sendFeedback=function(a,b,c,d){var e=void 0!==b;b=b||{x:0,y:0,z:0};var f={header:this.header,client_id:this.clientID,marker_name:this.name,control_name:d,event_type:a,pose:this.pose,mouse_point:b,mouse_point_valid:e,menu_entry_id:c};this.feedbackTopic.publish(f)},ROS3D.InteractiveMarkerMenu=function(a){function b(a,b){this.dispatchEvent({type:"menu-select",domEvent:b,id:a.id,controlName:this.controlName}),this.hide(b)}function c(a,e){var f=document.createElement("ul");a.appendChild(f);for(var g=e.children,h=0;h0?(c(i,g[h]),j.addEventListener("click",d.hide.bind(d)),j.addEventListener("touchstart",d.hide.bind(d))):(j.addEventListener("click",b.bind(d,g[h])),j.addEventListener("touchstart",b.bind(d,g[h])),j.className="default-interactive-marker-menu-entry")}}var d=this;a=a||{};var e=a.menuEntries,f=a.className||"default-interactive-marker-menu",g=(a.entryClassName,a.overlayClassName||"default-interactive-marker-overlay"),h=a.menuFontSize||"0.8em",i=[];if(i[0]={children:[]},THREE.EventDispatcher.call(this),null===document.getElementById("default-interactive-marker-menu-css")){var j=document.createElement("style");j.id="default-interactive-marker-menu-css",j.type="text/css",j.innerHTML=".default-interactive-marker-menu {background-color: #444444;border: 1px solid #888888;border: 1px solid #888888;padding: 0px 0px 0px 0px;color: #FFFFFF;font-family: sans-serif;font-size: "+h+";z-index: 1002;}.default-interactive-marker-menu ul {padding: 0px 0px 5px 0px;margin: 0px;list-style-type: none;}.default-interactive-marker-menu ul li div {-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;cursor: default;padding: 3px 10px 3px 10px;}.default-interactive-marker-menu-entry:hover { background-color: #666666; cursor: pointer;}.default-interactive-marker-menu ul ul { font-style: italic; padding-left: 10px;}.default-interactive-marker-overlay { position: absolute; top: 0%; left: 0%; width: 100%; height: 100%; background-color: black; z-index: 1001; -moz-opacity: 0.0; opacity: .0; filter: alpha(opacity = 0);}",document.getElementsByTagName("head")[0].appendChild(j)}this.menuDomElem=document.createElement("div"),this.menuDomElem.style.position="absolute",this.menuDomElem.className=f,this.menuDomElem.addEventListener("contextmenu",function(a){a.preventDefault()}),this.overlayDomElem=document.createElement("div"),this.overlayDomElem.className=g,this.hideListener=this.hide.bind(this),this.overlayDomElem.addEventListener("contextmenu",this.hideListener),this.overlayDomElem.addEventListener("click",this.hideListener),this.overlayDomElem.addEventListener("touchstart",this.hideListener);var k,l,m;for(k=0;k0){var V=this.msgColor,W=document.createElement("canvas"),X=W.getContext("2d");X.font="normal 100px sans-serif";var Y=X.measureText(c.text),Z=Y.width;W.width=Z,W.height=150,X.font="normal 100px sans-serif",X.fillStyle="rgba("+Math.round(255*V.r)+", "+Math.round(255*V.g)+", "+Math.round(255*V.b)+", "+V.a+")",X.textAlign="left",X.textBaseline="middle",X.fillText(c.text,0,W.height/2);var $=new THREE.Texture(W);$.needsUpdate=!0;var _=new THREE.SpriteMaterial({map:$,useScreenCoordinates:!1}),aa=new THREE.Sprite(_),ba=c.scale.x;aa.scale.set(Z/W.height*ba,ba,1),this.add(aa)}break;case ROS3D.MARKER_MESH_RESOURCE:var ca=null;0===c.color.r&&0===c.color.g&&0===c.color.b&&0===c.color.a||(ca=d),this.msgMesh=c.mesh_resource.substr(10);var da=new ROS3D.MeshResource({path:b,resource:this.msgMesh,material:ca});this.add(da);break;case ROS3D.MARKER_TRIANGLE_LIST:var ea=new ROS3D.TriangleList({material:d,vertices:c.points,colors:c.colors});ea.scale.set(c.scale.x,c.scale.y,c.scale.z),this.add(ea);break;default:console.error("Currently unsupported marker type: "+c.type)}},ROS3D.Marker.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Marker.prototype.setPose=function(a){this.position.x=a.position.x, +this.position.y=a.position.y,this.position.z=a.position.z,this.quaternion.set(a.orientation.x,a.orientation.y,a.orientation.z,a.orientation.w),this.quaternion.normalize(),this.updateMatrixWorld()},ROS3D.Marker.prototype.update=function(a){if(this.setPose(a.pose),a.color.r!==this.msgColor.r||a.color.g!==this.msgColor.g||a.color.b!==this.msgColor.b||a.color.a!==this.msgColor.a){var b=ROS3D.makeColorMaterial(a.color.r,a.color.g,a.color.b,a.color.a);switch(a.type){case ROS3D.MARKER_LINE_STRIP:case ROS3D.MARKER_LINE_LIST:case ROS3D.MARKER_POINTS:break;case ROS3D.MARKER_ARROW:case ROS3D.MARKER_CUBE:case ROS3D.MARKER_SPHERE:case ROS3D.MARKER_CYLINDER:case ROS3D.MARKER_TRIANGLE_LIST:case ROS3D.MARKER_TEXT_VIEW_FACING:this.traverse(function(a){a instanceof THREE.Mesh&&(a.material=b)});break;case ROS3D.MARKER_MESH_RESOURCE:var c=null;0===a.color.r&&0===a.color.g&&0===a.color.b&&0===a.color.a||(c=this.colorMaterial),this.traverse(function(a){a instanceof THREE.Mesh&&(a.material=c)});break;case ROS3D.MARKER_CUBE_LIST:case ROS3D.MARKER_SPHERE_LIST:default:return!1}this.msgColor=a.color}var d=Math.abs(this.msgScale[0]-a.scale.x)>1e-6||Math.abs(this.msgScale[1]-a.scale.y)>1e-6||Math.abs(this.msgScale[2]-a.scale.z)>1e-6;switch(this.msgScale=[a.scale.x,a.scale.y,a.scale.z],a.type){case ROS3D.MARKER_CUBE:case ROS3D.MARKER_SPHERE:case ROS3D.MARKER_CYLINDER:if(d)return!1;break;case ROS3D.MARKER_TEXT_VIEW_FACING:if(d||this.text!==a.text)return!1;break;case ROS3D.MARKER_MESH_RESOURCE:if(a.mesh_resource.substr(10)!==this.msgMesh)return!1;if(d)return!1;break;case ROS3D.MARKER_ARROW:case ROS3D.MARKER_LINE_STRIP:case ROS3D.MARKER_LINE_LIST:case ROS3D.MARKER_CUBE_LIST:case ROS3D.MARKER_SPHERE_LIST:case ROS3D.MARKER_POINTS:case ROS3D.MARKER_TRIANGLE_LIST:return!1}return!0},ROS3D.Marker.prototype.dispose=function(){this.children.forEach(function(a){a instanceof ROS3D.MeshResource?a.children.forEach(function(b){void 0!==b.material&&b.material.dispose(),b.children.forEach(function(a){void 0!==a.geometry&&a.geometry.dispose(),void 0!==a.material&&a.material.dispose(),b.remove(a)}),a.remove(b)}):(void 0!==a.geometry&&a.geometry.dispose(),void 0!==a.material&&a.material.dispose()),a.parent.remove(a)})},ROS3D.MarkerArrayClient=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic,this.tfClient=a.tfClient,this.rootObject=a.rootObject||new THREE.Object3D,this.path=a.path||"/",this.markers={},this.rosTopic=void 0,this.subscribe()},ROS3D.MarkerArrayClient.prototype.__proto__=EventEmitter2.prototype,ROS3D.MarkerArrayClient.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"visualization_msgs/MarkerArray",compression:"png"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.MarkerArrayClient.prototype.processMessage=function(a){a.markers.forEach(function(a){if(0===a.action){var b=!1;if(a.ns+a.id in this.markers&&((b=this.markers[a.ns+a.id].children[0].update(a))||(this.markers[a.ns+a.id].unsubscribeTf(),this.rootObject.remove(this.markers[a.ns+a.id]))),!b){var c=new ROS3D.Marker({message:a,path:this.path});this.markers[a.ns+a.id]=new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:c}),this.rootObject.add(this.markers[a.ns+a.id])}}else if(1===a.action)console.warn('Received marker message with deprecated action identifier "1"');else if(2===a.action)this.markers[a.ns+a.id].unsubscribeTf(),this.rootObject.remove(this.markers[a.ns+a.id]),delete this.markers[a.ns+a.id];else if(3===a.action){for(var d in this.markers)this.markers[d].unsubscribeTf(),this.rootObject.remove(this.markers[d]);this.markers={}}else console.warn('Received marker message with unknown action identifier "'+a.action+'"')}.bind(this)),this.emit("change")},ROS3D.MarkerArrayClient.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.MarkerClient=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic,this.tfClient=a.tfClient,this.rootObject=a.rootObject||new THREE.Object3D,this.path=a.path||"/",this.markers={},this.rosTopic=void 0,this.subscribe()},ROS3D.MarkerClient.prototype.__proto__=EventEmitter2.prototype,ROS3D.MarkerClient.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.MarkerClient.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"visualization_msgs/Marker",compression:"png"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.MarkerClient.prototype.processMessage=function(a){var b=new ROS3D.Marker({message:a,path:this.path}),c=this.markers[a.ns+a.id];c&&(c.unsubscribeTf(),this.rootObject.remove(c)),this.markers[a.ns+a.id]=new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:b}),this.rootObject.add(this.markers[a.ns+a.id]),this.emit("change")},ROS3D.Arrow=function(a){a=a||{};var b=a.origin||new THREE.Vector3(0,0,0),c=a.direction||new THREE.Vector3(1,0,0),d=a.length||1,e=a.headLength||.2,f=a.shaftDiameter||.05,g=a.headDiameter||.1,h=a.material||new THREE.MeshBasicMaterial,i=d-e,j=new THREE.CylinderGeometry(.5*f,.5*f,i,12,1),k=new THREE.Matrix4;k.setPosition(new THREE.Vector3(0,.5*i,0)),j.applyMatrix(k);var l=new THREE.CylinderGeometry(0,.5*g,e,12,1);k.setPosition(new THREE.Vector3(0,i+.5*e,0)),l.applyMatrix(k),j.merge(l),THREE.Mesh.call(this,j,h),this.position.copy(b),this.setDirection(c)},ROS3D.Arrow.prototype.__proto__=THREE.Mesh.prototype,ROS3D.Arrow.prototype.setDirection=function(a){var b=new THREE.Vector3(0,1,0).cross(a),c=Math.acos(new THREE.Vector3(0,1,0).dot(a.clone().normalize()));this.matrix=(new THREE.Matrix4).makeRotationAxis(b.normalize(),c),this.rotation.setFromRotationMatrix(this.matrix,this.rotation.order)},ROS3D.Arrow.prototype.setLength=function(a){this.scale.set(a,a,a)},ROS3D.Arrow.prototype.setColor=function(a){this.material.color.setHex(a)},ROS3D.Arrow.prototype.dispose=function(){void 0!==this.geometry&&this.geometry.dispose(),void 0!==this.material&&this.material.dispose()},ROS3D.Arrow2=function(a){a=a||{};var b=a.origin||new THREE.Vector3(0,0,0),c=a.direction||new THREE.Vector3(1,0,0),d=a.length||1;a.headLength,a.shaftDiameter,a.headDiameter,a.material||new THREE.MeshBasicMaterial;THREE.ArrowHelper.call(this,c,b,d,16711680)},ROS3D.Arrow2.prototype.__proto__=THREE.ArrowHelper.prototype,ROS3D.Arrow2.prototype.dispose=function(){void 0!==this.line&&(this.line.material.dispose(),this.line.geometry.dispose()),void 0!==this.cone&&(this.cone.material.dispose(),this.cone.geometry.dispose())},ROS3D.Axes=function(a){function b(a){var b=new THREE.Color;b.setRGB(a.x,a.y,a.z);var d=new THREE.MeshBasicMaterial({color:b.getHex()}),e=new THREE.Vector3;e.crossVectors(a,new THREE.Vector3(0,-1,0));var f=new THREE.Quaternion;f.setFromAxisAngle(e,.5*Math.PI);var g=new THREE.Mesh(c.headGeom,d);g.position.copy(a),g.position.multiplyScalar(.95),g.quaternion.copy(f),g.updateMatrix(),c.add(g);var h=new THREE.Mesh(c.lineGeom,d);h.position.copy(a),h.position.multiplyScalar(.45),h.quaternion.copy(f),h.updateMatrix(),c.add(h)}var c=this;a=a||{};var d=a.shaftRadius||.008,e=a.headRadius||.023,f=a.headLength||.1;THREE.Object3D.call(this),this.lineGeom=new THREE.CylinderGeometry(d,d,1-f),this.headGeom=new THREE.CylinderGeometry(0,e,f),b(new THREE.Vector3(1,0,0)),b(new THREE.Vector3(0,1,0)),b(new THREE.Vector3(0,0,1))},ROS3D.Axes.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Grid=function(a){a=a||{};var b=a.num_cells||10,c=a.color||"#cccccc",d=a.lineWidth||1,e=a.cellSize||1;THREE.Object3D.call(this);for(var f=new THREE.LineBasicMaterial({color:c,linewidth:d}),g=0;g<=b;++g){var h=e*b/2,i=h-g*e,j=new THREE.Geometry;j.vertices.push(new THREE.Vector3(-h,i,0),new THREE.Vector3(h,i,0));var k=new THREE.Geometry;k.vertices.push(new THREE.Vector3(i,-h,0),new THREE.Vector3(i,h,0)),this.add(new THREE.Line(j,f)),this.add(new THREE.Line(k,f))}},ROS3D.Grid.prototype.__proto__=THREE.Object3D.prototype,ROS3D.MeshResource=function(a){var b=this;a=a||{};var c=a.path||"/",d=a.resource,e=a.material||null;this.warnings=a.warnings,THREE.Object3D.call(this),"/"!==c.substr(c.length-1)&&(c+="/");var f,g=c+d,h=g.substr(-4).toLowerCase();".dae"===h?(f=new THREE.ColladaLoader,f.log=function(a){b.warnings&&console.warn(a)},f.load(g,function(a){null!==e&&a.scene.traverse(function(a){a instanceof THREE.Mesh&&void 0===a.material&&(a.material=e)}),b.add(a.scene)},null,function(a){console.error(a)})):".stl"===h&&(f=new THREE.STLLoader,f.load(g,function(a){a.computeFaceNormals();var c;c=null!==e?new THREE.Mesh(a,e):new THREE.Mesh(a,new THREE.MeshBasicMaterial({color:10066329})),b.add(c)},null,function(a){console.error(a)}))},ROS3D.MeshResource.prototype.__proto__=THREE.Object3D.prototype,ROS3D.TriangleList=function(a){a=a||{};var b=a.material||new THREE.MeshBasicMaterial,c=a.vertices,d=a.colors;THREE.Object3D.call(this),b.side=THREE.DoubleSide;var e=new THREE.Geometry;for(f=0;f=this.keep&&(this.sns[0].unsubscribeTf(),this.rootObject.remove(this.sns[0]),this.sns.shift()),this.options.origin=new THREE.Vector3(a.pose.pose.position.x,a.pose.pose.position.y,a.pose.pose.position.z);var b=new THREE.Quaternion(a.pose.pose.orientation.x,a.pose.pose.orientation.y,a.pose.pose.orientation.z,a.pose.pose.orientation.w);this.options.direction=new THREE.Vector3(1,0,0),this.options.direction.applyQuaternion(b),this.options.material=new THREE.MeshBasicMaterial({color:this.color});var c=new ROS3D.Arrow(this.options);this.sns.push(new ROS3D.SceneNode({frameID:a.header.frame_id,tfClient:this.tfClient,object:c})),this.rootObject.add(this.sns[this.sns.length-1])},ROS3D.Path=function(a){a=a||{},this.ros=a.ros,this.topicName=a.topic||"/path",this.tfClient=a.tfClient,this.color=a.color||13369599,this.rootObject=a.rootObject||new THREE.Object3D,THREE.Object3D.call(this),this.sn=null,this.line=null,this.rosTopic=void 0,this.subscribe()},ROS3D.Path.prototype.__proto__=THREE.Object3D.prototype,ROS3D.Path.prototype.unsubscribe=function(){this.rosTopic&&this.rosTopic.unsubscribe()},ROS3D.Path.prototype.subscribe=function(){this.unsubscribe(),this.rosTopic=new ROSLIB.Topic({ros:this.ros,name:this.topicName,messageType:"nav_msgs/Path"}),this.rosTopic.subscribe(this.processMessage.bind(this))},ROS3D.Path.prototype.processMessage=function(a){null!==this.sn&&(this.sn.unsubscribeTf(),this.rootObject.remove(this.sn));for(var b=new THREE.Geometry,c=0;ca.range_max)this.particles.alpha[c]=0;else{var e=a.angle_min+c*a.angle_increment;this.particles.points[c]=new THREE.Vector3(d*Math.cos(e),d*Math.sin(e),0),this.particles.alpha[c]=1}this.particles.colors[c]=new THREE.Color(this.color)}finishedUpdate(this.particles,b)},ROS3D.Particles=function(a){a=a||{},this.tfClient=a.tfClient;var b=a.texture||"https://upload.wikimedia.org/wikipedia/commons/a/a2/Pixel-white.png",c=a.size||.05;this.max_pts=a.max_pts||1e4,this.first_size=null,this.prev_pts=0,this.rootObject=a.rootObject||new THREE.Object3D;THREE.Object3D.call(this),this.vertex_shader=["attribute vec3 customColor;","attribute float alpha;","varying vec3 vColor;","varying float falpha;","void main() ","{"," vColor = customColor; // set color associated to vertex; use later in fragment shader"," vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );"," falpha = alpha; ",""," // option (1): draw particles at constant size on screen"," // gl_PointSize = size;"," // option (2): scale particles as objects in 3D space"," gl_PointSize = ",c,"* ( 300.0 / length( mvPosition.xyz ) );"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),this.fragment_shader=["uniform sampler2D texture;","varying vec3 vColor; // colors associated to vertices; assigned by vertex shader","varying float falpha;","void main() ","{"," // THREE.Material.alphaTest is not evaluated for ShaderMaterial, so we"," // have to take care of this ourselves."," if (falpha < 0.5) discard;"," // calculates a color for the particle"," gl_FragColor = vec4( vColor, falpha );"," // sets particle texture to desired color"," gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );","}"].join("\n"),this.geom=new THREE.Geometry;for(var d=0;d0?(d=o[0].object,n.intersection=this.lastIntersection=o[0]):d=this.fallbackTarget,d!==this.lastTarget&&a.type.match(/mouse/)){var p=this.notify(d,"mouseover",n);0===p?this.notify(this.lastTarget,"mouseout",n):1===p&&(d=this.fallbackTarget)!==this.lastTarget&&(this.notify(d,"mouseover",n),this.notify(this.lastTarget,"mouseout",n))}if(d!==this.lastTarget&&a.type.match(/touch/)){this.notify(d,a.type,n)?(this.notify(this.lastTarget,"touchleave",n),this.notify(this.lastTarget,"touchend",n)):(d=this.fallbackTarget)!==this.lastTarget&&(this.notify(this.lastTarget,"touchmove",n),this.notify(this.lastTarget,"touchend",n))}this.notify(d,a.type,n),"mousedown"!==a.type&&"touchstart"!==a.type&&"touchmove"!==a.type||(this.dragging=!0), +this.lastTarget=d},ROS3D.MouseHandler.prototype.notify=function(a,b,c){for(c.type=b,c.cancelBubble=!1,c.continueBubble=!1,c.stopPropagation=function(){c.cancelBubble=!0},c.continuePropagation=function(){c.continueBubble=!0},c.currentTarget=a;c.currentTarget;){if(c.currentTarget.dispatchEvent&&c.currentTarget.dispatchEvent instanceof Function){if(c.currentTarget.dispatchEvent(c),c.cancelBubble)return this.dispatchEvent(c),0;if(c.continueBubble)return 2}c.currentTarget=c.currentTarget.parent}return 1},Object.assign(ROS3D.MouseHandler.prototype,THREE.EventDispatcher.prototype),ROS3D.OrbitControls=function(a){function b(a){var b=a.domEvent;switch(b.preventDefault(),b.button){case 0:A=z.ROTATE,n.set(b.clientX,b.clientY);break;case 1:A=z.MOVE,u=new THREE.Vector3(0,0,1);var c=(new THREE.Matrix4).extractRotation(this.camera.matrix);u.applyMatrix4(c),t=j.center.clone(),v=j.camera.position.clone(),w=d(a.mouseRay,t,u);break;case 2:A=z.ZOOM,q.set(b.clientX,b.clientY)}this.showAxes()}function c(a){var b=a.domEvent;if(A===z.ROTATE)o.set(b.clientX,b.clientY),p.subVectors(o,n),j.rotateLeft(2*Math.PI*p.x/l*j.userRotateSpeed),j.rotateUp(2*Math.PI*p.y/l*j.userRotateSpeed),n.copy(o),this.showAxes();else if(A===z.ZOOM)r.set(b.clientX,b.clientY),s.subVectors(r,q),s.y>0?j.zoomIn():j.zoomOut(),q.copy(r),this.showAxes();else if(A===z.MOVE){var c=d(a.mouseRay,j.center,u);if(!c)return;var e=(new THREE.Vector3).subVectors(w.clone(),c.clone());j.center.addVectors(t.clone(),e.clone()),j.camera.position.addVectors(v.clone(),e.clone()),j.update(),j.camera.updateMatrixWorld(),this.showAxes()}}function d(a,b,c){var d=new THREE.Vector3;new THREE.Vector3;d.subVectors(b,a.origin);var e=a.direction.dot(c);if(Math.abs(e)0?j.zoomIn():j.zoomOut(),this.showAxes()}}function g(a){var b=a.domEvent;switch(b.touches.length){case 1:A=z.ROTATE,n.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY);break;case 2:A=z.NONE,u=new THREE.Vector3(0,0,1);var c=(new THREE.Matrix4).extractRotation(this.camera.matrix);u.applyMatrix4(c),t=j.center.clone(),v=j.camera.position.clone(),w=d(a.mouseRay,t,u),x[0]=new THREE.Vector2(b.touches[0].pageX,b.touches[0].pageY),x[1]=new THREE.Vector2(b.touches[1].pageX,b.touches[1].pageY),y[0]=new THREE.Vector2(0,0),y[1]=new THREE.Vector2(0,0)}this.showAxes(),b.preventDefault()}function h(a){var b=a.domEvent;if(A===z.ROTATE)o.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY),p.subVectors(o,n),j.rotateLeft(2*Math.PI*p.x/l*j.userRotateSpeed),j.rotateUp(2*Math.PI*p.y/l*j.userRotateSpeed),n.copy(o),this.showAxes();else{if(y[0].set(x[0].x-b.touches[0].pageX,x[0].y-b.touches[0].pageY),y[1].set(x[1].x-b.touches[1].pageX,x[1].y-b.touches[1].pageY),y[0].lengthSq()>m&&y[1].lengthSq()>m&&(x[0].set(b.touches[0].pageX,b.touches[0].pageY),x[1].set(b.touches[1].pageX,b.touches[1].pageY),y[0].dot(y[1])>0&&A!==z.ZOOM?A=z.MOVE:y[0].dot(y[1])<0&&A!==z.MOVE&&(A=z.ZOOM),A===z.ZOOM)){var c=new THREE.Vector2;c.subVectors(x[0],x[1]),y[0].dot(c)<0&&y[1].dot(c)>0?j.zoomOut():y[0].dot(c)>0&&y[1].dot(c)<0&&j.zoomIn()}if(A===z.MOVE){var e=d(a.mouseRay,j.center,u);if(!e)return;var f=(new THREE.Vector3).subVectors(w.clone(),e.clone());j.center.addVectors(t.clone(),f.clone()),j.camera.position.addVectors(v.clone(),f.clone()),j.update(),j.camera.updateMatrixWorld()}this.showAxes(),b.preventDefault()}}function i(a){var b=a.domEvent;1===b.touches.length&&A!==z.ROTATE?(A=z.ROTATE,n.set(b.touches[0].pageX-window.scrollX,b.touches[0].pageY-window.scrollY)):A=z.NONE}THREE.EventDispatcher.call(this);var j=this;a=a||{};var k=a.scene;this.camera=a.camera,this.center=new THREE.Vector3,this.userZoom=!0,this.userZoomSpeed=a.userZoomSpeed||1,this.userRotate=!0,this.userRotateSpeed=a.userRotateSpeed||1,this.autoRotate=a.autoRotate,this.autoRotateSpeed=a.autoRotateSpeed||2,this.camera.up=new THREE.Vector3(0,0,1);var l=1800,m=10,n=new THREE.Vector2,o=new THREE.Vector2,p=new THREE.Vector2,q=new THREE.Vector2,r=new THREE.Vector2,s=new THREE.Vector2,t=new THREE.Vector3,u=new THREE.Vector3,v=new THREE.Vector3,w=new THREE.Vector3,x=new Array(2),y=new Array(2);this.phiDelta=0,this.thetaDelta=0,this.scale=1,this.lastPosition=new THREE.Vector3;var z={NONE:-1,ROTATE:0,ZOOM:1,MOVE:2},A=z.NONE;this.axes=new ROS3D.Axes({shaftRadius:.025,headRadius:.07,headLength:.2}),k.add(this.axes),this.axes.traverse(function(a){a.visible=!1}),this.addEventListener("mousedown",b),this.addEventListener("mouseup",e),this.addEventListener("mousemove",c),this.addEventListener("touchstart",g),this.addEventListener("touchmove",h),this.addEventListener("touchend",i),this.addEventListener("mousewheel",f),this.addEventListener("DOMMouseScroll",f)},ROS3D.OrbitControls.prototype.showAxes=function(){var a=this;this.axes.traverse(function(a){a.visible=!0}),this.hideTimeout&&clearTimeout(this.hideTimeout),this.hideTimeout=setTimeout(function(){a.axes.traverse(function(a){a.visible=!1}),a.hideTimeout=!1},1e3)},ROS3D.OrbitControls.prototype.rotateLeft=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.thetaDelta-=a},ROS3D.OrbitControls.prototype.rotateRight=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.thetaDelta+=a},ROS3D.OrbitControls.prototype.rotateUp=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.phiDelta-=a},ROS3D.OrbitControls.prototype.rotateDown=function(a){void 0===a&&(a=2*Math.PI/60/60*this.autoRotateSpeed),this.phiDelta+=a},ROS3D.OrbitControls.prototype.zoomIn=function(a){void 0===a&&(a=Math.pow(.95,this.userZoomSpeed)),this.scale/=a},ROS3D.OrbitControls.prototype.zoomOut=function(a){void 0===a&&(a=Math.pow(.95,this.userZoomSpeed)),this.scale*=a},ROS3D.OrbitControls.prototype.update=function(){var a=this.camera.position,b=a.clone().sub(this.center),c=Math.atan2(b.y,b.x),d=Math.atan2(Math.sqrt(b.y*b.y+b.x*b.x),b.z);this.autoRotate&&this.rotateLeft(2*Math.PI/60/60*this.autoRotateSpeed),c+=this.thetaDelta,d+=this.phiDelta;d=Math.max(1e-6,Math.min(Math.PI-1e-6,d));var e=b.length();b.set(e*Math.sin(d)*Math.cos(c),e*Math.sin(d)*Math.sin(c),e*Math.cos(d)),b.multiplyScalar(this.scale),a.copy(this.center).add(b),this.camera.lookAt(this.center),e=b.length(),this.axes.position.copy(this.center),this.axes.scale.set(.05*e,.05*e,.05*e),this.axes.updateMatrixWorld(!0),this.thetaDelta=0,this.phiDelta=0,this.scale=1,this.lastPosition.distanceTo(this.camera.position)>0&&(this.dispatchEvent({type:"change"}),this.lastPosition.copy(this.camera.position))},Object.assign(ROS3D.OrbitControls.prototype,THREE.EventDispatcher.prototype),ROS3D.SceneNode=function(a){a=a||{};var b=this;this.tfClient=a.tfClient,this.frameID=a.frameID;var c=a.object;this.pose=a.pose||new ROSLIB.Pose,THREE.Object3D.call(this),this.visible=!1,this.add(c),this.updatePose(this.pose),this.tfUpdate=function(a){var c=new ROSLIB.Transform(a),d=new ROSLIB.Pose(b.pose);d.applyTransform(c),b.updatePose(d),b.visible=!0},this.tfClient.subscribe(this.frameID,this.tfUpdate)},ROS3D.SceneNode.prototype.__proto__=THREE.Object3D.prototype,ROS3D.SceneNode.prototype.updatePose=function(a){this.position.set(a.position.x,a.position.y,a.position.z),this.quaternion.set(a.orientation.x,a.orientation.y,a.orientation.z,a.orientation.w),this.updateMatrixWorld(!0)},ROS3D.SceneNode.prototype.unsubscribeTf=function(){this.tfClient.unsubscribe(this.frameID,this.tfUpdate)},ROS3D.Viewer=function(a){a=a||{};var b=a.divID,c=a.width,d=a.height,e=a.background||"#111111",f=a.antialias,g=a.intensity||.66,h=a.near||.01,i=a.far||1e3,j=a.alpha||1,k=a.cameraPose||{x:3,y:3,z:3},l=a.cameraZoomSpeed||.5;this.renderer=new THREE.WebGLRenderer({antialias:f,alpha:!0}),this.renderer.setClearColor(parseInt(e.replace("#","0x"),16),j),this.renderer.sortObjects=!1,this.renderer.setSize(c,d),this.renderer.shadowMap.enabled=!1,this.renderer.autoClear=!1,this.scene=new THREE.Scene,this.camera=new THREE.PerspectiveCamera(40,c/d,h,i),this.camera.position.x=k.x,this.camera.position.y=k.y,this.camera.position.z=k.z,this.cameraControls=new ROS3D.OrbitControls({scene:this.scene,camera:this.camera}),this.cameraControls.userZoomSpeed=l,this.scene.add(new THREE.AmbientLight(5592405)),this.directionalLight=new THREE.DirectionalLight(16777215,g),this.scene.add(this.directionalLight),this.selectableObjects=new THREE.Object3D,this.scene.add(this.selectableObjects);var m=new ROS3D.MouseHandler({renderer:this.renderer,camera:this.camera,rootObject:this.selectableObjects,fallbackTarget:this.cameraControls});this.highlighter=new ROS3D.Highlighter({mouseHandler:m}),this.stopped=!0,this.animationRequestId=void 0,document.getElementById(b).appendChild(this.renderer.domElement),this.start()},ROS3D.Viewer.prototype.start=function(){this.stopped=!1,this.draw()},ROS3D.Viewer.prototype.draw=function(){this.stopped||(this.cameraControls.update(),this.directionalLight.position=this.camera.localToWorld(new THREE.Vector3(-1,1,0)),this.directionalLight.position.normalize(),this.renderer.clear(!0,!0,!0),this.renderer.render(this.scene,this.camera),this.highlighter.renderHighlights(this.scene,this.renderer,this.camera),this.animationRequestId=requestAnimationFrame(this.draw.bind(this)))},ROS3D.Viewer.prototype.stop=function(){this.stopped||cancelAnimationFrame(this.animationRequestId),this.stopped=!0},ROS3D.Viewer.prototype.addObject=function(a,b){b?this.selectableObjects.add(a):this.scene.add(a)},ROS3D.Viewer.prototype.resize=function(a,b){this.camera.aspect=a/b,this.camera.updateProjectionMatrix(),this.renderer.setSize(a,b)}; \ No newline at end of file diff --git a/src/models/MeshResource.js b/src/models/MeshResource.js index 3c804d0e..b45732a1 100644 --- a/src/models/MeshResource.js +++ b/src/models/MeshResource.js @@ -42,34 +42,46 @@ ROS3D.MeshResource = function(options) { console.warn(message); } }; - loader.load(uri, function colladaReady(collada) { - // check for a scale factor in ColladaLoader2 - // add a texture to anything that is missing one - if(material !== null) { - collada.scene.traverse(function(child) { - if(child instanceof THREE.Mesh) { - if(child.material === undefined) { - child.material = material; + loader.load( + uri, + function colladaReady(collada) { + // check for a scale factor in ColladaLoader2 + // add a texture to anything that is missing one + if(material !== null) { + collada.scene.traverse(function(child) { + if(child instanceof THREE.Mesh) { + if(child.material === undefined) { + child.material = material; + } } - } - }); - } + }); + } - that.add(collada.scene); - }); + that.add(collada.scene); + }, + /*onProgress=*/null, + function onLoadError(error) { + console.error(error); + }); } else if (fileType === '.stl') { loader = new THREE.STLLoader(); { - loader.load(uri, function ( geometry ) { - geometry.computeFaceNormals(); - var mesh; - if(material !== null) { - mesh = new THREE.Mesh( geometry, material ); - } else { - mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x999999 } ) ); - } - that.add(mesh); - } ); + loader.load(uri, + function ( geometry ) { + geometry.computeFaceNormals(); + var mesh; + if(material !== null) { + mesh = new THREE.Mesh( geometry, material ); + } else { + mesh = new THREE.Mesh( geometry, + new THREE.MeshBasicMaterial( { color: 0x999999 } ) ); + } + that.add(mesh); + }, + /*onProgress=*/null, + function onLoadError(error) { + console.error(error); + }); } } };