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', './Tile', './GeoBound', './CoordinateSystem'], function(Utils,Tile,GeoBound,CoordinateSystem) { 21 22 /**************************************************************************************************************/ 23 24 /** @constructor 25 MercatorTiling constructor 26 */ 27 var MercatorTiling = function(startLevel) 28 { 29 this.startLevel = startLevel; 30 } 31 32 /**************************************************************************************************************/ 33 34 /** 35 Generate the tiles for level zero 36 */ 37 MercatorTiling.prototype.generateLevelZeroTiles = function(config) 38 { 39 config.skirt = true; 40 config.cullSign = 1; 41 42 var level0Tiles = []; 43 44 var level0NumTilesX = Math.pow(2,this.startLevel); 45 var level0NumTilesY = Math.pow(2,this.startLevel); 46 47 for (var j = 0; j < level0NumTilesY; j++) 48 { 49 for (var i = 0; i < level0NumTilesX; i++) 50 { 51 var tile = new MercatorTile( this.startLevel, i, j ); 52 tile.config = config; 53 level0Tiles.push( tile ); 54 } 55 } 56 57 return level0Tiles; 58 } 59 60 /**************************************************************************************************************/ 61 62 /** 63 Locate a level zero tile 64 */ 65 MercatorTiling.prototype.lonlat2LevelZeroIndex = function(lon,lat) 66 { 67 // TODO 68 return 0; 69 } 70 71 /**************************************************************************************************************/ 72 73 MercatorTiling.tile2long = function(x,z) { 74 return ( x /Math.pow(2,z) * 360 - 180 ); 75 } 76 77 MercatorTiling.tile2lat = function(y,z) { 78 var n = Math.PI - 2 * Math.PI * y / Math.pow(2,z); 79 return ( 180 / Math.PI * Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); 80 } 81 82 /**************************************************************************************************************/ 83 84 /** @constructor 85 Tile constructor 86 */ 87 var MercatorTile = function( level, x, y ) 88 { 89 // Call ancestor constructor 90 Tile.prototype.constructor.call(this); 91 92 this.level = level; 93 this.x = x; 94 this.y = y; 95 96 this.geoBound = new GeoBound( MercatorTiling.tile2long(x,level), MercatorTiling.tile2lat(y+1,level), MercatorTiling.tile2long(x+1,level), MercatorTiling.tile2lat(y,level) ); 97 } 98 99 /**************************************************************************************************************/ 100 101 /** Inhertis from tile */ 102 MercatorTile.prototype = new Tile; 103 104 /**************************************************************************************************************/ 105 106 /** @export 107 Get elevation at a geo position 108 */ 109 MercatorTile.prototype.getElevation = function(lon,lat) 110 { 111 // TODO 112 return 0.0; 113 } 114 115 /**************************************************************************************************************/ 116 117 /** 118 Create the children 119 */ 120 MercatorTile.prototype.createChildren = function() 121 { 122 // Create the children 123 var tile00 = new MercatorTile( this.level+1, 2*this.x, 2*this.y ); 124 var tile10 = new MercatorTile( this.level+1, 2*this.x+1, 2*this.y ); 125 var tile01 = new MercatorTile( this.level+1, 2*this.x, 2*this.y+1 ); 126 var tile11 = new MercatorTile( this.level+1, 2*this.x+1, 2*this.y+1 ); 127 128 tile00.initFromParent( this, 0, 0 ); 129 tile10.initFromParent( this, 1, 0 ); 130 tile01.initFromParent( this, 0, 1 ); 131 tile11.initFromParent( this, 1, 1 ); 132 133 this.children = [ tile00, tile10, tile01, tile11 ]; 134 } 135 136 /**************************************************************************************************************/ 137 138 /** 139 Convert coordinates in longitude,latitude to coordinate in "tile space" 140 Tile space means coordinates are between [0,tesselation-1] if inside the tile 141 Used by renderers algorithm to clamp coordinates on the tile 142 */ 143 MercatorTile.prototype.lonlat2tile = function(coordinates) 144 { 145 var tpl = Math.pow(2,this.level); 146 var factor = this.config.tesselation-1; 147 148 var tileCoords = []; 149 for ( var i = 0; i < coordinates.length; i++ ) 150 { 151 var x = ( coordinates[i][0] + 180.) / 360.; 152 var sinLat = Math.sin(coordinates[i][1] * Math.PI / 180.); 153 var y = 0.5 - Math.log((1 + sinLat) / (1 - sinLat)) / (4. * Math.PI); 154 155 tileCoords.push( [ factor * (x * tpl - this.x), factor * (y * tpl - this.y) ] ); 156 } 157 158 return tileCoords; 159 } 160 161 /**************************************************************************************************************/ 162 163 /** 164 Generate vertices for tile 165 */ 166 MercatorTile.prototype.generateVertices = function(elevations) 167 { 168 // Compute tile matrix 169 this.matrix = CoordinateSystem.getLHVTransform( this.geoBound.getCenter() ); 170 var invMatrix = mat4.create(); 171 mat4.inverse( this.matrix, invMatrix ); 172 this.inverseMatrix = invMatrix; 173 174 // Build the vertices 175 var size = this.config.tesselation; 176 var vertices = new Float32Array( 3*size*(size+6) ); 177 var step = 1.0 / (size-1); 178 var radius = CoordinateSystem.radius; 179 var scale = CoordinateSystem.heightScale; 180 var offset = 0; 181 182 var twoPowLevel = Math.pow(2,this.level); 183 184 var v = this.y; 185 for ( var j=0; j < size; j++) 186 { 187 var n = Math.PI * (1.0 - 2.0 * v / twoPowLevel); 188 var lat = Math.atan( 0.5 * (Math.exp(n) - Math.exp(-n)) ); 189 190 var cosLat = Math.cos( lat ); 191 var sinLat = Math.sin( lat ); 192 193 var u = this.x; 194 195 for ( var i=0; i < size; i++) 196 { 197 var lon = Math.PI * ( 2.0 * u / twoPowLevel - 1.0 ); 198 var height = elevations ? scale * elevations[ offset ] : 0.0; 199 200 var x = (radius + height) * Math.cos( lon ) * cosLat; 201 var y = (radius + height) * Math.sin( lon ) * cosLat; 202 var z = (radius + height) * sinLat; 203 204 var vertexOffset = offset * 3; 205 vertices[vertexOffset] = invMatrix[0]*x + invMatrix[4]*y + invMatrix[8]*z + invMatrix[12]; 206 vertices[vertexOffset+1] = invMatrix[1]*x + invMatrix[5]*y + invMatrix[9]*z + invMatrix[13]; 207 vertices[vertexOffset+2] = invMatrix[2]*x + invMatrix[6]*y + invMatrix[10]*z + invMatrix[14]; 208 209 offset++; 210 u += step; 211 } 212 213 v += step; 214 } 215 216 return vertices; 217 } 218 219 220 /**************************************************************************************************************/ 221 222 /** 223 Override buildSkirtVertices for mercator. 224 Use skirt to "fill" the pole 225 */ 226 MercatorTile.prototype.buildSkirtVertices = function(center,srcOffset,srcStep,dstOffset) 227 { 228 var size = this.config.tesselation; 229 var vertexSize = this.config.vertexSize; 230 var numTilesY = Math.pow(2,this.level); 231 232 // Check if the tile is at the north (isTop) or south (isBottom) pole 233 var isTop = this.y == 0 && dstOffset == vertexSize * (size * size); 234 var isBottom = this.y == numTilesY-1 && dstOffset == vertexSize * ((size+1) * size); 235 236 if ( isTop || isBottom ) 237 { 238 var vertices = this.vertices; 239 240 var pt = CoordinateSystem.fromGeoTo3D( isTop ? [ 0.0, 90.0, 0.0 ] : [ 0.0, -90.0, 0.0 ] ); 241 mat4.multiplyVec3( this.inverseMatrix, pt ); 242 243 for ( var i = 0; i < size; i++) 244 { 245 vertices[ dstOffset ] = pt[0]; 246 vertices[ dstOffset+1 ] = pt[1]; 247 vertices[ dstOffset+2 ] = pt[2]; 248 249 for (var n = 3; n < vertexSize; n++) 250 { 251 vertices[ dstOffset+n ] = vertices[srcOffset+n]; 252 } 253 254 dstOffset += vertexSize; 255 } 256 257 // Recompute the bbox to have correct culling 258 //this.bbox.compute(this.vertices,dstOffset + vertexSize*size,vertexSize); 259 //this.radius = this.bbox.getRadius(); 260 } 261 else 262 { 263 Tile.prototype.buildSkirtVertices.call(this,center,srcOffset,srcStep,dstOffset); 264 } 265 } 266 267 /**************************************************************************************************************/ 268 269 return MercatorTiling; 270 271 }); 272