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 GeoTiling constructor 26 */ 27 var GeoTiling = function(nx,ny) 28 { 29 this.level0NumTilesX = nx; 30 this.level0NumTilesY = ny; 31 } 32 33 /**************************************************************************************************************/ 34 35 /** 36 Generate the tiles for level zero 37 */ 38 GeoTiling.prototype.generateLevelZeroTiles = function(config) 39 { 40 config.skirt = 1; 41 config.cullSign = 1; 42 43 var level0Tiles = []; 44 45 var latStep = 180 / this.level0NumTilesY; 46 var lonStep = 360 / this.level0NumTilesX; 47 48 for (var j = 0; j < this.level0NumTilesY; j++) 49 { 50 for (var i = 0; i < this.level0NumTilesX; i++) 51 { 52 var geoBound = new GeoBound( -180 + i * lonStep, 90 - (j+1) * latStep, -180 + (i+1) * lonStep, 90 - j * latStep ); 53 var tile = new GeoTile(geoBound, 0, i, j) 54 tile.config = config; 55 level0Tiles.push( tile ); 56 } 57 } 58 59 return level0Tiles; 60 } 61 62 /**************************************************************************************************************/ 63 64 /** 65 Locate a level zero tile 66 */ 67 GeoTiling.prototype.lonlat2LevelZeroIndex = function(lon,lat) 68 { 69 var i = Math.floor( (lon + 180) * this.level0NumTilesX / 360 ); 70 var j = Math.floor( (90 - lat) * this.level0NumTilesY / 180 ); 71 return j * this.level0NumTilesX + i; 72 73 } 74 75 /**************************************************************************************************************/ 76 77 /** @constructor 78 Tile constructor 79 */ 80 var GeoTile = function( geoBound, level, x, y ) 81 { 82 // Call ancestor constructor 83 Tile.prototype.constructor.call(this); 84 85 this.geoBound = geoBound; 86 this.level = level; 87 this.x = x; 88 this.y = y; 89 } 90 91 /**************************************************************************************************************/ 92 93 /** inherits from Tile */ 94 GeoTile.prototype = new Tile; 95 96 /**************************************************************************************************************/ 97 98 /** @export 99 Get elevation at a geo position 100 */ 101 GeoTile.prototype.getElevation = function(lon,lat) 102 { 103 // Get the lon/lat in coordinates between [0,1] in the tile 104 var u = (lon - this.geoBound.west) / (this.geoBound.east - this.geoBound.west); 105 var v = (lat - this.geoBound.north) / (this.geoBound.south - this.geoBound.north); 106 107 // Quick fix when lat is on the border of the tile 108 var childIndex = (v >= 1 ? 1 : Math.floor(2*v) )*2 + Math.floor(2*u); 109 if ( this.children && this.children[childIndex].state == Tile.State.LOADED ) 110 return this.children[childIndex].getElevation(lon,lat); 111 112 var tess = this.config.tesselation; 113 var i = Math.floor( u * tess ); 114 var j = Math.floor( v * tess ); 115 116 var vo = this.config.vertexSize * (j * tess + i); 117 var vertex = [ this.vertices[vo], this.vertices[vo+1], this.vertices[vo+2] ]; 118 mat4.multiplyVec3( this.matrix, vertex ); 119 var geo = CoordinateSystem.from3DToGeo(vertex); 120 return geo[2]; 121 } 122 123 /**************************************************************************************************************/ 124 125 /** 126 Create the children 127 */ 128 GeoTile.prototype.createChildren = function() 129 { 130 // Create the children 131 var lonCenter = ( this.geoBound.east + this.geoBound.west ) * 0.5; 132 var latCenter = ( this.geoBound.north + this.geoBound.south ) * 0.5; 133 134 var level = this.level+1; 135 136 var tile00 = new GeoTile( new GeoBound( this.geoBound.west, latCenter, lonCenter, this.geoBound.north), level, 2*this.x, 2*this.y ); 137 var tile10 = new GeoTile( new GeoBound( lonCenter, latCenter, this.geoBound.east, this.geoBound.north), level, 2*this.x+1, 2*this.y ); 138 var tile01 = new GeoTile( new GeoBound( this.geoBound.west, this.geoBound.south, lonCenter, latCenter), level, 2*this.x, 2*this.y+1 ); 139 var tile11 = new GeoTile( new GeoBound( lonCenter, this.geoBound.south, this.geoBound.east, latCenter), level, 2*this.x+1, 2*this.y+1 ); 140 141 tile00.initFromParent( this, 0, 0 ); 142 tile10.initFromParent( this, 1, 0 ); 143 tile01.initFromParent( this, 0, 1 ); 144 tile11.initFromParent( this, 1, 1 ); 145 146 this.children = [ tile00, tile10, tile01, tile11 ]; 147 } 148 149 /**************************************************************************************************************/ 150 151 /** 152 Convert coordinates in longitude,latitude to coordinate in "tile space" 153 Tile space means coordinates are between [0,tesselation-1] if inside the tile 154 Used by renderers algorithm to clamp coordinates on the tile 155 */ 156 GeoTile.prototype.lonlat2tile = function(coordinates) 157 { 158 var ul = this.geoBound.east - this.geoBound.west; 159 var vl = this.geoBound.south - this.geoBound.north; 160 var factor = this.config.tesselation-1; 161 162 var tileCoords = []; 163 for ( var i = 0; i < coordinates.length; i++ ) 164 { 165 var u = factor * (coordinates[i][0] - this.geoBound.west) / ul; 166 var v = factor * (coordinates[i][1] - this.geoBound.north) / vl; 167 tileCoords.push( [ u, v ] ); 168 } 169 170 return tileCoords; 171 } 172 173 /**************************************************************************************************************/ 174 175 /** 176 Generate vertices for tile 177 */ 178 GeoTile.prototype.generateVertices = function(elevations) 179 { 180 // Compute tile matrix 181 this.matrix = CoordinateSystem.getLHVTransform( this.geoBound.getCenter() ); 182 var invMatrix = mat4.create(); 183 mat4.inverse( this.matrix, invMatrix ); 184 this.inverseMatrix = invMatrix; 185 186 // Build the vertices 187 var vertexSize = this.config.vertexSize; 188 var size = this.config.tesselation; 189 var vertices = new Float32Array( vertexSize*size*(size+6) ); 190 var lonStep = (this.geoBound.east - this.geoBound.west) / (size-1); 191 var latStep = (this.geoBound.south - this.geoBound.north) / (size-1); 192 var radius = CoordinateSystem.radius; 193 var scale = CoordinateSystem.heightScale; 194 var offset = 0; 195 196 var lat = this.geoBound.north * Math.PI / 180.0; 197 latStep = latStep * Math.PI / 180.0; 198 lonStep = lonStep * Math.PI / 180.0; 199 for ( var j=0; j < size; j++) 200 { 201 var cosLat = Math.cos( lat ); 202 var sinLat = Math.sin( lat ); 203 204 var lon = this.geoBound.west * Math.PI / 180.0; 205 206 for ( var i=0; i < size; i++) 207 { 208 var height = elevations ? scale * elevations[ offset ] : 0.0; 209 210 var x = (radius + height) * Math.cos( lon ) * cosLat; 211 var y = (radius + height) * Math.sin( lon ) * cosLat; 212 var z = (radius + height) * sinLat; 213 214 var vi = offset * vertexSize; 215 vertices[vi] = invMatrix[0]*x + invMatrix[4]*y + invMatrix[8]*z + invMatrix[12]; 216 vertices[vi+1] = invMatrix[1]*x + invMatrix[5]*y + invMatrix[9]*z + invMatrix[13]; 217 vertices[vi+2] = invMatrix[2]*x + invMatrix[6]*y + invMatrix[10]*z + invMatrix[14]; 218 219 offset++; 220 lon += lonStep; 221 } 222 223 lat += latStep; 224 } 225 226 return vertices; 227 } 228 229 /**************************************************************************************************************/ 230 231 return GeoTiling; 232 233 }); 234