1 /*************************************** 2 * Copyright 2011, 2012 GlobWeb contributors. 3 * 4 * This file is part of GlobWeb. 5 * 6 * GlobWeb is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * GlobWeb is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GlobWeb. If not, see <http://www.gnu.org/licenses/>. 18 ***************************************/ 19 20 define(['./Utils','./Animation','./CoordinateSystem','./Numeric'], function(Utils,Animation,CoordinateSystem,Numeric) { 21 22 /**************************************************************************************************************/ 23 24 /** @export 25 @constructor 26 PathAnimation is an animation defined with a path. 27 */ 28 var PathAnimation = function(coords,speed,valueSetter) 29 { 30 // Call ancestor constructor 31 Animation.prototype.constructor.call(this); 32 33 this.speed = speed * CoordinateSystem.heightScale / 1000; 34 this.nodes = []; 35 for ( var i = 0; i < coords.length; i++ ) 36 { 37 var node = { position: CoordinateSystem.fromGeoTo3D(coords[i]), 38 velocity: null, 39 distance: 0.0 }; 40 this.nodes.push( node ); 41 if ( i > 0 ) 42 { 43 var dx = this.nodes[i].position[0] - this.nodes[i-1].position[0]; 44 var dy = this.nodes[i].position[1] - this.nodes[i-1].position[1]; 45 var dz = this.nodes[i].position[2] - this.nodes[i-1].position[2]; 46 this.nodes[i-1].distance = Math.sqrt( dx*dx + dy*dy + dz*dz ); 47 } 48 } 49 50 for ( var i = 1; i < coords.length - 1; i++ ) 51 { 52 var vec1 = vec3.subtract( this.nodes[i+1].position, this.nodes[i].position, vec3.create() ); 53 var vec2 = vec3.subtract( this.nodes[i-1].position, this.nodes[i].position, vec3.create() ); 54 vec3.normalize(vec1); 55 vec3.normalize(vec2); 56 this.nodes[i].velocity = vec3.subtract( vec1, vec2, vec3.create() ); 57 vec3.normalize(this.nodes[i].velocity); 58 } 59 60 // Start velocity 61 var temp = vec3.subtract( this.nodes[1].position, this.nodes[0].position, vec3.create() ); 62 vec3.scale( temp, ( 3 / this.nodes[0].distance ) ); 63 this.nodes[0].velocity = vec3.subtract( temp, this.nodes[1].velocity, vec3.create() ); 64 vec3.scale( this.nodes[0].velocity, 0.5 ); 65 66 // End velocity 67 var i = coords.length - 1; 68 var temp = vec3.subtract( this.nodes[i].position, this.nodes[i-1].position, vec3.create() ); 69 vec3.scale( temp, ( 3 / this.nodes[i-1].distance ) ); 70 this.nodes[i].velocity = vec3.subtract( temp, this.nodes[i-1].velocity, vec3.create() ); 71 vec3.scale( this.nodes[i].velocity, 0.5 ); 72 73 this.index = 0; 74 this.currentDistance = 0; 75 this.previousTime = -1; 76 this.currentDirection = []; 77 this.centerOffset = -0.2; 78 this.altitudeOffset = 1000; 79 80 var that = this; 81 if ( valueSetter ) 82 { 83 this.valueSetter = valueSetter; 84 } 85 else 86 { 87 this.valueSetter = function(value,direction) 88 { 89 var up = vec3.normalize( value, vec3.create() ); 90 91 var geoEye = CoordinateSystem.from3DToGeo( value ); 92 geoEye[2] = that.globe.getElevation( geoEye[0], geoEye[1] ) + that.altitudeOffset; 93 var eye = CoordinateSystem.fromGeoTo3D( geoEye ); 94 95 //var eye = vec3.add( vec3.scale(up, (that.altitudeOffset+elevation) * CoordinateSystem.heightScale, vec3.create()), value ); 96 var dirn = vec3.normalize( direction, vec3.create() ); 97 var center = vec3.add( eye, dirn, vec3.create() ); 98 vec3.add( center, vec3.scale(up, that.centerOffset, vec3.create()) ); 99 mat4.lookAt( eye, center, up, that.globe.renderContext.viewMatrix ); 100 }; 101 } 102 } 103 104 /**************************************************************************************************************/ 105 106 Utils.inherits(Animation,PathAnimation); 107 108 /**************************************************************************************************************/ 109 110 /** 111 Set the speed 112 */ 113 PathAnimation.prototype.setSpeed = function(val) 114 { 115 this.speed = parseFloat(val) * CoordinateSystem.heightScale / 1000; 116 } 117 118 /**************************************************************************************************************/ 119 120 /** 121 Set the altitude offset 122 */ 123 PathAnimation.prototype.setAltitudeOffset = function(val) 124 { 125 this.altitudeOffset = parseFloat(val); 126 } 127 128 /**************************************************************************************************************/ 129 130 /** 131 Set the direction angle 132 */ 133 PathAnimation.prototype.setDirectionAngle = function(vertical) 134 { 135 this.centerOffset = Math.tan( parseFloat(vertical) * Math.PI / 180.0 ); 136 } 137 138 /**************************************************************************************************************/ 139 140 /** @export 141 Start the animation 142 */ 143 PathAnimation.prototype.start = function() 144 { 145 var previousStartTime = -1; 146 if ( this.pauseTime != -1 ) 147 { 148 previousStartTime = this.startTime; 149 } 150 151 Animation.prototype.start.call(this); 152 153 if ( previousStartTime != -1 ) 154 { 155 this.previousTime += this.startTime - previousStartTime; 156 } 157 else 158 { 159 this.previousTime = -1; 160 } 161 } 162 163 /**************************************************************************************************************/ 164 165 /* 166 Animation update method 167 */ 168 PathAnimation.prototype.update = function(now) 169 { 170 if ( this.previousTime == -1 ) 171 { 172 this.index = 0; 173 this.currentDistance = 0; 174 } 175 else 176 { 177 this.currentDistance += (now - this.previousTime) * this.speed; 178 } 179 this.previousTime = now; 180 181 while ( this.currentDistance >= this.nodes[this.index].distance && this.index < this.nodes.length - 1 ) 182 { 183 this.currentDistance -= this.nodes[this.index].distance; 184 this.index = this.index + 1; 185 } 186 187 if ( this.index < this.nodes.length - 1 ) 188 { 189 var t = this.currentDistance / this.nodes[this.index].distance; 190 var startPos = this.nodes[this.index].position; 191 var endPos = this.nodes[this.index+1].position; 192 var startVel = vec3.scale( this.nodes[this.index].velocity, this.nodes[this.index].distance, vec3.create() ); 193 var endVel = vec3.scale( this.nodes[this.index+1].velocity, this.nodes[this.index].distance, vec3.create() ); 194 var position = Numeric.cubicInterpolation( t, startPos, startVel, endPos, endVel ); 195 var direction = Numeric.cubicInterpolationDerivative( t, startPos, startVel, endPos, endVel ); 196 this.valueSetter( position, direction ); 197 } 198 else if ( this.index == this.nodes.length - 1 ) 199 { 200 this.valueSetter( this.nodes[this.index].position, this.nodes[this.index].velocity ); 201 } 202 else 203 { 204 this.stop(); 205 } 206 } 207 208 /**************************************************************************************************************/ 209 210 return PathAnimation; 211 212 }); 213