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(['./Tile', './HEALPixBase', './GeoBound', './CoordinateSystem', './Numeric', './AstroCoordTransform'], 
 21 	function(Tile, HEALPixBase, GeoBound, CoordinateSystem, Numeric, AstroCoordTransform) {
 22 
 23 /**************************************************************************************************************/
 24  
 25 /** @constructor
 26 	HEALPixTiling constructor
 27  */
 28 var HEALPixTiling = function(order, options)
 29 {
 30 	this.order = order;
 31 	this.nside = Math.pow(2,this.order);
 32 	this.coordSystem = options.coordSystem || "EQUATORIAL";
 33 }
 34 
 35 /**************************************************************************************************************/
 36 
 37 /** 
 38 	Generate the tiles for level zero
 39  */
 40 HEALPixTiling.prototype.generateLevelZeroTiles = function( config, tilePool )
 41 {	
 42 	config.skirt = false;
 43 	config.cullSign = -1;
 44 	config.tesselation = 5;
 45 	config.coordSystem = this.coordSystem;
 46 
 47 	var level0Tiles = [];
 48 	
 49 	var qpf = Math.pow(this.nside,2); // quad per face
 50 	var nFaces = 12;
 51 	var nQuads = nFaces * qpf;
 52 	
 53 	for (var i = 0; i < nQuads; i++){
 54 		var face = Math.floor(i/qpf);
 55 		var tile = new HEALPixTile(this.order, i, face);
 56 		tile.config = config;
 57 		level0Tiles.push( tile );
 58 		tile.generate(tilePool);
 59 		tile.state = Tile.State.NONE;
 60 	}
 61 
 62 	return level0Tiles;
 63 }
 64 
 65 /**************************************************************************************************************/
 66 
 67 /** 
 68 	Locate a level zero tile
 69  */
 70 HEALPixTiling.prototype.lonlat2LevelZeroIndex = function(lon,lat)
 71 {	
 72 	// var i = Math.floor( (lon + 180) * this.level0NumTilesX / 360 );
 73  	// var j = Math.floor( (lat + 90) * this.level0NumTilesY / 180 );
 74 	// return j * this.level0NumTilesX + i;
 75 	return 0;
 76 
 77 }
 78 
 79 /**************************************************************************************************************/
 80 
 81 /**
 82  	Return tile of given longitude/latitude from tiles array if exists, null otherwise
 83  */
 84 HEALPixTiling.prototype.findInsideTile = function(lon, lat, tiles)
 85 {
 86 	for ( var i=0; i<tiles.length; i++ )
 87 	{
 88 		var tile = tiles[i];
 89 		var index = HEALPixBase.lonLat2pix( tile.order, lon, lat );
 90 		if ( index == tile.pixelIndex )
 91 			return tile;
 92 	}
 93 	return null;
 94 }
 95 
 96 /**************************************************************************************************************/
 97 
 98 /** @constructor
 99 	Tile constructor
100 	
101 		Quadrilateral which composes one pixel of HEALPix sphere
102 		
103 		nside : 2^order
104 		order : log2(nside);
105 		pix : pixel index number
106 		face : face number = [0..11]
107  */
108 var HEALPixTile = function( order, pix, face )
109 {
110     // Call ancestor constructor
111     Tile.prototype.constructor.call(this);
112 	
113 	this.order = order;
114 	this.nside = Math.pow(2, this.order);
115 	this.pixelIndex = pix;
116 	this.face = face;
117 
118 	// Compute texture transform
119 	var width = 1728/64;
120 	var height = 1856/64;
121 	this.texTransform = [64/1728, 64/1856, ((this.pixelIndex % width))/width, ((Math.floor(this.pixelIndex/width))/height)];
122 
123 	this.geoBound = null;
124 }
125 
126 /**************************************************************************************************************/
127 
128 /** inherits from Tile */
129 HEALPixTile.prototype = new Tile;
130 
131 /**************************************************************************************************************/
132 
133 /**
134 	Create the children
135  */
136 HEALPixTile.prototype.createChildren = function()
137 {
138 	// Create the children
139 	
140 	var child00 = new HEALPixTile(this.order + 1, this.pixelIndex*4, this.face);
141 	var child10 = new HEALPixTile(this.order + 1, this.pixelIndex*4+2, this.face);
142 	var child01 = new HEALPixTile(this.order + 1, this.pixelIndex*4+1, this.face);
143 	var child11 = new HEALPixTile(this.order + 1, this.pixelIndex*4+3, this.face);
144 	
145 	child00.initFromParent( this, 0, 0 );
146 	child10.initFromParent( this, 1, 0 );
147 	child01.initFromParent( this, 0, 1 );
148 	child11.initFromParent( this, 1, 1 );
149 	
150 	this.children = [ child00, child10, child01, child11 ];
151 
152 }
153 
154 /**************************************************************************************************************/
155 
156 /**
157 	Compute the local matrix for the tile
158  */
159 HEALPixTile.prototype.computeLocalMatrix = function(vertices){
160 	var matrix = mat4.create();
161 	
162 	var east = vec3.create();
163 	var north = vec3.create();
164 	var up = vec3.create();
165 	
166 	var mx = 0;
167 	var my = 0;
168 	var mz = 0;
169 	for(var i=0; i<vertices.length; i++){
170 		mx+=vertices[i][0];
171 		my+=vertices[i][1];
172 		mz+=vertices[i][2];
173 	}
174 	var barycenter = vec3.create([mx/vertices.length,my/vertices.length,mz/vertices.length]);
175 	
176 	vec3.set(barycenter,up);
177 	vec3.normalize(up);
178 	
179 	vec3.subtract(vertices[0],vertices[3],north);
180 	
181 	vec3.cross(up, north, east);
182 	vec3.normalize(east);
183 	vec3.cross(up, east, north);
184 	vec3.normalize(north);
185 		
186 	matrix[0] = east[0];
187 	matrix[1] = east[1];
188 	matrix[2] = east[2];
189 	matrix[3] = 0.0;
190 	
191 	matrix[4] = north[0];
192 	matrix[5] = north[1];
193 	matrix[6] = north[2];
194 	matrix[7] = 0.0;
195 	
196 	matrix[8] = up[0];
197 	matrix[9] = up[1];
198 	matrix[10] = up[2];
199 	matrix[11] = 0.0;
200 	
201 	matrix[12] = barycenter[0];
202 	matrix[13] = barycenter[1];
203 	matrix[14] = barycenter[2];
204 	matrix[15] = 1.0;
205 	
206 	return matrix;
207 }
208 
209 /**************************************************************************************************************/
210 
211 /**
212 	Generate vertices for tile
213  */
214 HEALPixTile.prototype.generateVertices = function()
215 {
216 	// Build the vertices
217 	var size = this.config.tesselation;
218 	var worldSpaceVertices = new Array();
219 	var step = 1./(size - 1);
220 	
221 	// xyf calculation
222 	//var xyf = new healpixBase.Xyf(this.pixelIndex, this.order);
223 	var pix=this.pixelIndex&(this.nside*this.nside-1);
224 	var ix = HEALPixBase.compress_bits(pix);
225 	var iy = HEALPixBase.compress_bits(pix>>>1);
226 	
227 	// Compute array of worldspace coordinates
228 	for(var u = 0; u < size; u++){
229 		for(var v = 0; v < size; v++){
230 			if ( this.config.coordSystem == 'GALACTIC' )
231 			{
232 				var vertice = HEALPixBase.fxyf((ix+u*step)/this.nside, (iy+v*step)/this.nside, this.face);
233 				var geo = CoordinateSystem.from3DToGeo( vertice );
234 				var eq = AstroCoordTransform.transformInDeg( geo, AstroCoordTransform.Type.GAL2EQ );
235 				
236 				worldSpaceVertices[u*size + v] = CoordinateSystem.fromGeoTo3D( eq );
237 			}
238 			else
239 			{
240 				worldSpaceVertices[u*size + v] = HEALPixBase.fxyf((ix+u*step)/this.nside, (iy+v*step)/this.nside, this.face);
241 			}
242 		}
243 	}
244 	
245 	// Compute geoBound using corners of tile
246 	this.geoBound = new GeoBound();
247 
248 	var corners = [];
249 	corners.push( CoordinateSystem.from3DToGeo( worldSpaceVertices[0] ) );
250 	corners.push( CoordinateSystem.from3DToGeo( worldSpaceVertices[size-1] ) );
251 	corners.push( CoordinateSystem.from3DToGeo( worldSpaceVertices[size*(size-1)] ) );
252 	corners.push( CoordinateSystem.from3DToGeo( worldSpaceVertices[size*size-1] ) );
253 
254 	this.geoBound.computeFromCoordinates( corners );
255 
256 	// Compute tile matrix
257 	this.matrix = this.computeLocalMatrix(worldSpaceVertices);	
258 	var invMatrix = mat4.create();
259 	mat4.inverse( this.matrix, invMatrix );
260 	this.inverseMatrix = invMatrix;
261 	
262 	// Compute tile matrix
263 	/*var center = HEALPixBase.fxyf((ix+0.5)/this.nside, (iy+0.5)/this.nside, face);
264 	var geoCenter = CoordinateSystem.from3DToGeo(center);
265 	this.matrix = CoordinateSystem.getLHVTransform( geoCenter );
266 	var invMatrix = mat4.create();
267 	mat4.inverse( this.matrix, invMatrix );
268 	this.inverseMatrix = invMatrix;*/
269 	
270 	// Build the vertices
271 	var vertices = new Float32Array( 3*size*size );
272 	
273 	// Vertex coordinates in local space
274 	var vertexOffset = 0;
275 	for(var i=0;i<worldSpaceVertices.length;i++){
276 		vertices[vertexOffset] = invMatrix[0]*worldSpaceVertices[i][0] + invMatrix[4]*worldSpaceVertices[i][1] + invMatrix[8]*worldSpaceVertices[i][2] + invMatrix[12];
277 		vertices[vertexOffset+1] = invMatrix[1]*worldSpaceVertices[i][0] + invMatrix[5]*worldSpaceVertices[i][1] + invMatrix[9]*worldSpaceVertices[i][2] + invMatrix[13];
278 		vertices[vertexOffset+2] = invMatrix[2]*worldSpaceVertices[i][0] + invMatrix[6]*worldSpaceVertices[i][1] + invMatrix[10]*worldSpaceVertices[i][2] + invMatrix[14];
279 		vertexOffset += 3;
280 	}
281 	
282 	return vertices;
283 }
284 
285 /**************************************************************************************************************/
286 
287 return HEALPixTiling;
288 
289 });