[29852] | 1 | // Array element swap code by Richard Scarrott
|
---|
| 2 | // http://jsperf.com/array-prototype-move
|
---|
| 3 | Array.prototype.move = function(pos1, pos2) {
|
---|
| 4 | // local variables
|
---|
| 5 | var i, tmp;
|
---|
| 6 | // cast input parameters to integers
|
---|
| 7 | pos1 = parseInt(pos1, 10);
|
---|
| 8 | pos2 = parseInt(pos2, 10);
|
---|
| 9 | // if positions are different and inside array
|
---|
| 10 | if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
|
---|
| 11 | // save element from position 1
|
---|
| 12 | tmp = this[pos1];
|
---|
| 13 | // move element down and shift other elements up
|
---|
| 14 | if (pos1 < pos2) {
|
---|
| 15 | for (i = pos1; i < pos2; i++) {
|
---|
| 16 | this[i] = this[i + 1];
|
---|
| 17 | }
|
---|
| 18 | }
|
---|
| 19 | // move element up and shift other elements down
|
---|
| 20 | else {
|
---|
| 21 | for (i = pos1; i > pos2; i--) {
|
---|
| 22 | this[i] = this[i - 1];
|
---|
| 23 | }
|
---|
| 24 | }
|
---|
| 25 | // put element from position 1 to destination
|
---|
| 26 | this[pos2] = tmp;
|
---|
| 27 | }
|
---|
| 28 | }
|
---|
| 29 |
|
---|
| 30 | var panoContainer, camera, scene, renderer, projector;
|
---|
| 31 |
|
---|
| 32 | var mouse = { x: 0, y: 0 };
|
---|
| 33 |
|
---|
| 34 | var fov = 70, maxFov = 90, minFov = 15,
|
---|
| 35 | width,height, aspect,
|
---|
| 36 | isUserInteracting = false,
|
---|
| 37 | onMouseDownMouseX = 0, onMouseDownMouseY = 0,
|
---|
| 38 | lon = 0, onMouseDownLon = 0,
|
---|
| 39 | lat = 0, onMouseDownLat = 0,
|
---|
| 40 | phi = 0, theta = 0,
|
---|
| 41 | mesh, sphereRadius = 500,
|
---|
| 42 | meshRotation = Math.PI / 2 * 3,
|
---|
| 43 | panoSelectionRadius = 40;
|
---|
| 44 |
|
---|
| 45 | var panoDocList = new Array();
|
---|
| 46 | panoDocList.ids = new Array();
|
---|
| 47 | panoDocList.getDocByIndex = function(index) {
|
---|
| 48 | return panoDocList[panoDocList.ids[index]];
|
---|
| 49 | };
|
---|
| 50 |
|
---|
| 51 | var nearbyPanoList = new Array();
|
---|
| 52 | nearbyPanoList.ids = new Array();
|
---|
| 53 |
|
---|
| 54 | function initPanoramaViewer() {
|
---|
| 55 | //Creating the document list to store data about the panoramams
|
---|
| 56 | var jsonNodeDiv = $("#jsonPanoNodes");
|
---|
| 57 | if(jsonNodeDiv.length) {
|
---|
| 58 | var jsonNodehtml = jsonNodeDiv.html();
|
---|
| 59 | var jsonNodes = eval(jsonNodehtml);
|
---|
| 60 | if(jsonNodes && jsonNodes.length > 0) {
|
---|
| 61 | for(var i = 0; i < jsonNodes.length; i++) {
|
---|
| 62 | panoDocList[jsonNodes[i].nodeID] = jsonNodes[i];
|
---|
| 63 | panoDocList.ids.push(jsonNodes[i].nodeID);
|
---|
| 64 | }
|
---|
| 65 | } else {
|
---|
| 66 | $("pano-container").css({visibility:"hidden", height:"0px"});
|
---|
| 67 | }
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | panoContainer = document.getElementById( 'pano-container' );
|
---|
| 71 | // Creating the camera
|
---|
| 72 | // Setting width and height variables as the container dimensions changes when fov is changed
|
---|
| 73 | if(panoContainer.className == "pano_canvas_fullscreen") {
|
---|
| 74 | width = window.innerWidth;
|
---|
| 75 | height = window.innerHeight;
|
---|
| 76 | aspect = width / height;
|
---|
| 77 | } else if(panoContainer.className == "pano_canvas_half") {
|
---|
| 78 | width = panoContainer.offsetWidth;
|
---|
| 79 | height = panoContainer.offsetHeight;
|
---|
| 80 | aspect = width / height;
|
---|
| 81 | }
|
---|
| 82 | camera = new THREE.PerspectiveCamera( fov, aspect, 1, 1100 );
|
---|
| 83 | camera.target = new THREE.Vector3(0, 0, 0 );
|
---|
| 84 |
|
---|
| 85 | // Creating the scene
|
---|
| 86 | scene = new THREE.Scene();
|
---|
| 87 |
|
---|
| 88 | projector = new THREE.Projector();
|
---|
| 89 |
|
---|
| 90 | var sourceFile = gs.documentMetadata[panoDocList.ids[0]].Image;
|
---|
| 91 | var assocfilepath = gs.documentMetadata[panoDocList.ids[0]].assocfilepath;
|
---|
| 92 | var httpPath = gs.collectionMetadata.httpPath;
|
---|
| 93 |
|
---|
| 94 | var fullPanoURL = httpPath + "/index/assoc/" + assocfilepath + "/" + sourceFile;
|
---|
| 95 |
|
---|
| 96 | // Creating a sphere with the panorama applied as a texture
|
---|
| 97 | if (Detector.webgl) {
|
---|
| 98 | mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 60, 40 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), wireframe: false, overdraw: true, opacity:0 } ) );
|
---|
| 99 | } else {
|
---|
| 100 | mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 30, 20 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), wireframe: false, overdraw: true, opacity:0 } ) );
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 | mesh.scale.x = -1;
|
---|
| 104 | // Adding the sphere to the scene
|
---|
| 105 | scene.add( mesh );
|
---|
| 106 |
|
---|
| 107 | switchPanorama(panoDocList.ids[0]);
|
---|
| 108 |
|
---|
| 109 | renderer = Detector.webgl? new THREE.WebGLRenderer(): new THREE.CanvasRenderer();
|
---|
| 110 | renderer.setSize(width,height);
|
---|
| 111 |
|
---|
| 112 | panoContainer.appendChild( renderer.domElement );
|
---|
| 113 |
|
---|
| 114 | // Adding in Mouse events
|
---|
| 115 | panoContainer.addEventListener( 'mousedown', onDocumentMouseDown, false );
|
---|
| 116 | document.addEventListener( 'mousemove', onDocumentMouseMove, false );
|
---|
| 117 | document.addEventListener( 'mouseup', onDocumentMouseUp, false );
|
---|
| 118 | panoContainer.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
|
---|
| 119 | panoContainer.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
|
---|
| 120 |
|
---|
| 121 | if(panoContainer.className == "pano_canvas_fullscreen")
|
---|
| 122 | window.addEventListener( 'resize', onWindowResize, false );
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | function degreesToCoords(degrees, radius) {
|
---|
| 126 | return new THREE.Vector3(Math.cos(degrees * Math.PI/180) * radius, 0, Math.sin(degrees * Math.PI/180) * radius);
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 |
|
---|
| 130 | function calculateBearing(from, to) {
|
---|
| 131 | // x is lat and y is long
|
---|
| 132 | var R = 6371; // km
|
---|
| 133 | var lat1 = from.x * Math.PI / 180;
|
---|
| 134 | var lat2 = to.x * Math.PI / 180;
|
---|
| 135 | var dLon = (to.y-from.y) * Math.PI / 180;
|
---|
| 136 | var y = Math.sin(dLon) * Math.cos(lat2);
|
---|
| 137 | var x = Math.cos(lat1)*Math.sin(lat2) -
|
---|
| 138 | Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
|
---|
| 139 | var brng = (Math.atan2(y, x)) * 180 / Math.PI;
|
---|
| 140 | return (brng + 360) % 360;
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | function calculateDistance(from, to) {
|
---|
| 144 | // x is lat and y is long
|
---|
| 145 | var R = 6371; // km
|
---|
| 146 | var dLat = (from.x-to.x) * Math.PI / 180;
|
---|
| 147 | var dLon = (from.y-to.y) * Math.PI / 180;
|
---|
| 148 | var lat1 = from.x * Math.PI / 180;
|
---|
| 149 | var lat2 = to.x * Math.PI / 180;
|
---|
| 150 |
|
---|
| 151 | var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
---|
| 152 | Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
|
---|
| 153 | var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
---|
| 154 | var d = R * c;
|
---|
| 155 | // return distance in metres
|
---|
| 156 | return d * 1000;
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | function switchPanorama( panoramaID, destMarker ) {
|
---|
| 160 | // Building the file path
|
---|
| 161 | var sourceFile = gs.documentMetadata[panoramaID].Image;
|
---|
| 162 | var assocfilepath = gs.documentMetadata[panoramaID].assocfilepath;
|
---|
| 163 | var httpPath = gs.collectionMetadata.httpPath;
|
---|
| 164 |
|
---|
| 165 | var fullPanoURL = httpPath + "/index/assoc/" + assocfilepath + "/" + sourceFile;
|
---|
| 166 |
|
---|
| 167 | // Creating the material
|
---|
| 168 | if (Detector.webgl) {
|
---|
| 169 | var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0 } );
|
---|
| 170 | } else {
|
---|
| 171 | var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0, wireframe: false, overdraw: true } );
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | if (destMarker) {
|
---|
| 175 | new TWEEN.Tween(mesh.position).to({x: -destMarker.position.x, y: -destMarker.position.y, z: -destMarker.position.z}, 500).onComplete(function () {
|
---|
| 176 | mesh.position = new THREE.Vector3(destMarker.position.x,destMarker.position.y,destMarker.position.z);
|
---|
| 177 | new TWEEN.Tween(mesh.position).to({x: 0, y: 0,z: 0},500).start();
|
---|
| 178 | }).start();
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | new TWEEN.Tween(mesh.materials[0]).to({opacity: 0}, 500).onComplete(function () {
|
---|
| 182 | // Rotation
|
---|
| 183 | if (gs.documentMetadata[panoramaID].Angle) {
|
---|
| 184 | var temp = 360 + parseFloat(gs.documentMetadata[panoramaID].Angle);
|
---|
| 185 | temp = temp % 360;
|
---|
| 186 | console.log(temp);
|
---|
| 187 | mesh.rotation.y = meshRotation + (gs.documentMetadata[panoramaID].Angle * Math.PI / 180);
|
---|
| 188 | } else if (gs.documentMetadata[panoramaID].cv_rotation)
|
---|
| 189 | mesh.rotation.y = meshRotation + (gs.documentMetadata[panoramaID].cv_rotation * Math.PI / 180);
|
---|
| 190 | else
|
---|
| 191 | mesh.rotation.y = meshRotation;
|
---|
| 192 |
|
---|
| 193 | mesh.materials[0] = texture;
|
---|
| 194 | new TWEEN.Tween(mesh.materials[0]).to({opacity: 1}, 500).start();
|
---|
| 195 | }).start();
|
---|
| 196 |
|
---|
| 197 |
|
---|
| 198 | // Checking if there are markers to remove
|
---|
| 199 | if (nearbyPanoList.length > 0) {
|
---|
| 200 | for(var i = 0; i < nearbyPanoList.length; i++) {
|
---|
| 201 | panoContainer.removeChild(nearbyPanoList[i]);
|
---|
| 202 | // document.body.appendChild(nearbyPanoList[i]);
|
---|
| 203 | nearbyPanoList[i].deactivate();
|
---|
| 204 | }
|
---|
| 205 | }
|
---|
| 206 |
|
---|
| 207 | // Clearing the array
|
---|
| 208 | nearbyPanoList = new Array();
|
---|
| 209 |
|
---|
| 210 | // Moving the selected pano to the front of the panolist array
|
---|
| 211 | panoDocList.move(panoDocList.ids.indexOf(panoramaID), 0);
|
---|
| 212 | panoDocList.ids.move(panoDocList.ids.indexOf(panoramaID), 0);
|
---|
| 213 |
|
---|
| 214 | var startPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoramaID].Latitude,gs.documentMetadata[panoramaID].Longitude);
|
---|
| 215 |
|
---|
| 216 | // going through the panolist checking the distance
|
---|
| 217 | for(var i = 1; i < panoDocList.ids.length; i++) {
|
---|
| 218 | var endPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoDocList.ids[i]].Latitude,gs.documentMetadata[panoDocList.ids[i]].Longitude);
|
---|
| 219 | if(calculateDistance(startPanoLonLat,endPanoLonLat) < panoSelectionRadius) {
|
---|
| 220 | var bearing = calculateBearing(startPanoLonLat,endPanoLonLat);
|
---|
| 221 | var pos = degreesToCoords(bearing, sphereRadius);
|
---|
| 222 | var navMarker = NavMarker.create(panoDocList.ids[i],pos);
|
---|
| 223 | nearbyPanoList.push(navMarker);
|
---|
| 224 | //navMarker.addEventListener('click', switchPanorama(hash), false);
|
---|
| 225 | navMarker.addEventListener('click', function(e) {
|
---|
| 226 | var sender = (e && e.target) || (window.event && window.event.srcElement);
|
---|
| 227 | switchPanorama(sender.hash, sender); }, false);
|
---|
| 228 | }
|
---|
| 229 | }
|
---|
| 230 |
|
---|
| 231 | // Going through the new nearbyPanoList and adding in the markers to the scene
|
---|
| 232 | for(var i = 0; i < nearbyPanoList.length; i++) {
|
---|
| 233 | panoContainer.appendChild(nearbyPanoList[i]);
|
---|
| 234 | nearbyPanoList[i].activate();
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | }
|
---|
| 238 |
|
---|
| 239 |
|
---|
| 240 | function onWindowResize() {
|
---|
| 241 | camera.aspect = window.innerWidth / window.innerHeight;
|
---|
| 242 | camera.updateProjectionMatrix();
|
---|
| 243 |
|
---|
| 244 | renderer.setSize( window.innerWidth, window.innerHeight );
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 |
|
---|
| 248 | function onDocumentMouseDown( event ) {
|
---|
| 249 | event.preventDefault();
|
---|
| 250 | isUserInteracting = true;
|
---|
| 251 | onPointerDownPointerX = event.clientX;
|
---|
| 252 | onPointerDownPointerY = event.clientY;
|
---|
| 253 | onPointerDownLon = lon;
|
---|
| 254 | onPointerDownLat = lat;
|
---|
| 255 |
|
---|
| 256 | }
|
---|
| 257 |
|
---|
| 258 | function onDocumentMouseMove( event ) {
|
---|
| 259 | if ( isUserInteracting ) {
|
---|
| 260 | lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
|
---|
| 261 | lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
|
---|
| 262 | }
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | function onDocumentMouseUp( event ) {
|
---|
| 266 | var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
|
---|
| 267 | projector.unprojectVector( vector, camera );
|
---|
| 268 | isUserInteracting = false;
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | function onDocumentMouseWheel( event ) {
|
---|
| 272 | if ( event.wheelDeltaY ) {
|
---|
| 273 | // WebKit
|
---|
| 274 | fov -= event.wheelDeltaY * 0.05;
|
---|
| 275 | } else if ( event.wheelDelta ) {
|
---|
| 276 | // Opera / Explorer 9
|
---|
| 277 | fov -= event.wheelDelta * 0.05;
|
---|
| 278 | } else if ( event.detail ) {
|
---|
| 279 | // Firefox
|
---|
| 280 | fov += event.detail * 1.0;
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | if ( fov > maxFov) {
|
---|
| 284 | fov = maxFov;
|
---|
| 285 | } else if (fov < minFov) {
|
---|
| 286 | fov = minFov;
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, aspect , 1, 1100 );
|
---|
| 290 | _render();
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 | function _animate() {
|
---|
| 294 | requestAnimationFrame( _animate );
|
---|
| 295 | _render();
|
---|
| 296 | TWEEN.update();
|
---|
| 297 |
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | function _render() {
|
---|
| 301 | lat = Math.max( - 85, Math.min( 85, lat ) );
|
---|
| 302 | phi = ( 90 - lat ) * Math.PI / 180;
|
---|
| 303 | theta = lon * Math.PI / 180;
|
---|
| 304 |
|
---|
| 305 | camera.target.x = sphereRadius * Math.sin( phi ) * Math.cos( theta );
|
---|
| 306 | camera.target.y = sphereRadius * Math.cos( phi );
|
---|
| 307 | camera.target.z = sphereRadius * Math.sin( phi ) * Math.sin( theta );
|
---|
| 308 |
|
---|
| 309 | camera.lookAt( camera.target );
|
---|
| 310 |
|
---|
| 311 | /*
|
---|
| 312 | // distortion
|
---|
| 313 | camera.position.x = - camera.target.x;
|
---|
| 314 | camera.position.y = - camera.target.y;
|
---|
| 315 | camera.position.z = - camera.target.z;
|
---|
| 316 | */
|
---|
| 317 |
|
---|
| 318 | var camUnitVector = camera.target.clone().normalize();
|
---|
| 319 | var i, angle, sameSide, p2D, marker;
|
---|
| 320 |
|
---|
| 321 | // Snippet of code from Thanh Tran from in2ideas
|
---|
| 322 | // [email protected]
|
---|
| 323 | for (i = 0; i < nearbyPanoList.length; ++i) {
|
---|
| 324 | marker = nearbyPanoList[i];
|
---|
| 325 | p2D = projector.projectVector(marker.position.clone(), camera);
|
---|
| 326 |
|
---|
| 327 | p2D.x = (p2D.x + 1)/2 * width;
|
---|
| 328 | p2D.y = - (p2D.y - 1)/2 * height;
|
---|
| 329 |
|
---|
| 330 | angle = Math.acos(camUnitVector.dot(marker.unitVector)) * 180 / 3.14;
|
---|
| 331 | sameSide = (angle < 90);
|
---|
| 332 |
|
---|
| 333 | if(!sameSide || p2D.x < 0 || p2D.x > width ||
|
---|
| 334 | p2D.y < 0 || p2D.y > height) {
|
---|
| 335 | marker.visible(false);
|
---|
| 336 | } else {
|
---|
| 337 | marker.visible(true);
|
---|
| 338 | marker.setPosition(p2D.x, p2D.y);
|
---|
| 339 | }
|
---|
| 340 | }
|
---|
| 341 | renderer.render( scene, camera );
|
---|
| 342 | } |
---|