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','./VectorRendererManager','./TiledVectorRenderable','./TiledVectorRenderer','./Numeric'],
 21 	function(Utils,VectorRendererManager,TiledVectorRenderable,TiledVectorRenderer,Numeric) {
 22 
 23 /**************************************************************************************************************/
 24 
 25 
 26 /** @constructor
 27  *  @extends TiledVectorRenderable
 28  *	LineStringRenderable manages lineString data to be rendered on a tile.
 29  */
 30 var LineStringRenderable = function( bucket, gl )
 31 {
 32 	TiledVectorRenderable.prototype.constructor.call(this,bucket,gl);
 33 	this.glMode = gl.LINES;
 34 }
 35 
 36 /**************************************************************************************************************/
 37 
 38 // Inheritance
 39 Utils.inherits(TiledVectorRenderable,LineStringRenderable);
 40 
 41 /**************************************************************************************************************/
 42 
 43 /**
 44  * Build children indices.
 45  * Children indices are used to render a tile children when it is not completely loaded.
 46  */
 47 LineStringRenderable.prototype.buildChildrenIndices = function()
 48 {
 49 	this.childrenIndices = [ [], [], [], [] ];
 50 	this.childrenIndexBuffers = [ null, null, null, null ];
 51 		
 52 	for ( var n = 0;  n < this.indices.length/2; n++ )
 53 	{	
 54 		var vertexOffset1 = 3 * this.indices[2*n];
 55 		var vertexOffset2 = 3 * this.indices[2*n+1];
 56 		
 57 		var x1 = this.vertices[vertexOffset1];
 58 		var x2 = this.vertices[vertexOffset2];
 59 		
 60 		var i = 0;
 61 		if ( x1 > 0 ||  ( x1 == 0 && x2 > 0 ) )
 62 			i = 1;			
 63 		
 64 		var y1 = this.vertices[vertexOffset1+1];
 65 		var y2 = this.vertices[vertexOffset2+1];
 66 		
 67 		var j = 1;
 68 		if ( y1 > 0 ||  ( y1 == 0 && y2 > 0 ) )
 69 			j = 0;
 70 		
 71 		this.childrenIndices[ 2*j + i ].push( this.indices[2*n] )
 72 		this.childrenIndices[ 2*j + i ].push( this.indices[2*n+1] )
 73 	}
 74 }
 75 
 76 /**************************************************************************************************************/
 77 
 78 /**
 79  * Build vertices and indices from the coordinates.
 80  * Clamp a line string on a tile
 81  */
 82 LineStringRenderable.prototype.buildVerticesAndIndices = function( tile, coords )
 83 {
 84 	if ( coords.length == 0 )
 85 		return;
 86 
 87 	// Fix date line for coordinates first
 88 	var coordinates = this._fixDateLine( tile, coords );
 89 		
 90 	var size = tile.config.tesselation;
 91 	var vs = tile.config.vertexSize;
 92 	
 93 	// Convert lon/lat coordinates to tile coordinates (between [0,size-1] inside the tile)
 94 	var tileCoords = tile.lonlat2tile(coords);
 95 
 96 	for ( var i = 0; i < coordinates.length - 1; i++ )
 97 	{
 98 		var u1 = tileCoords[i][0];
 99 		var v1 = tileCoords[i][1];
100 		
101 		var u2 = tileCoords[i+1][0];
102 		var v2 = tileCoords[i+1][1];
103 		
104 		var intersections = [];
105 	
106 		// Intersect the segment with the tile grid
107 		
108 		// First intersect with columns
109 		// uStart, uEnd represent a range of the tile columns that the segement can intersect
110 		var uStart = Math.max( -1, Math.min( u1, u2 ) );
111 		var uEnd = Math.min( size-1, Math.max( u1, u2 ) );
112 		for ( var n = Math.floor(uStart)+1; n < Math.floor(uEnd)+1; n++)
113 		{
114 			var u = n;
115 			var res = Numeric.lineIntersection( u1, v1, u2, v2, u, 0.0, u, size-1 );
116 			if ( res[0] > 0.0 && res[0] < 1.0 && res[1] >= 0.0 && res[1] <= 1.0 )
117 			{
118 				var v = res[1] * (size-1);
119 				var vFloor = Math.floor( v );
120 				var vFrac = v - vFloor;
121 				var vertexOffset = vs*( vFloor*size + n );
122 				var x = (1.0 - vFrac) * tile.vertices[ vertexOffset ] + vFrac * tile.vertices[ vertexOffset + vs*size ];
123 				var y = (1.0 - vFrac) * tile.vertices[ vertexOffset + 1 ] + vFrac * tile.vertices[ vertexOffset + vs*size + 1 ];
124 				var z = (1.0 - vFrac) * tile.vertices[ vertexOffset + 2 ] + vFrac * tile.vertices[ vertexOffset + vs*size + 2 ];
125 				intersections.push( [ res[0], x, y, z ] );
126 			}
127 		}
128 	
129 		// Then intersect with rows
130 		// vStart, vEnd represent a range of the tile rows that the segement can intersect
131 		var vStart = Math.max( -1, Math.min( v1, v2 ) );
132 		var vEnd = Math.min( size-1, Math.max( v1, v2 ) );
133 		for ( var n = Math.floor(vStart)+1; n < Math.floor(vEnd)+1; n++)
134 		{
135 			var v = n;
136 			var res = Numeric.lineIntersection( u1, v1, u2, v2, 0.0, v, size-1, v );
137 			if ( res[0] > 0.0 && res[0] < 1.0 && res[1] >= 0.0 && res[1] <= 1.0 )
138 			{
139 				var u = res[1] * (size-1);
140 				var uFloor = Math.floor( u );
141 				var uFrac = u - uFloor;
142 				var vertexOffset = vs*( n*size + uFloor );
143 				var x = (1.0 - uFrac) * tile.vertices[ vertexOffset ] + uFrac * tile.vertices[ vertexOffset + vs ];
144 				var y = (1.0 - uFrac) * tile.vertices[ vertexOffset + 1 ] + uFrac * tile.vertices[ vertexOffset + vs+1 ];
145 				var z = (1.0 - uFrac) * tile.vertices[ vertexOffset + 2 ] + uFrac * tile.vertices[ vertexOffset + vs+2 ];
146 				intersections.push( [ res[0], x, y, z ] );
147 			}
148 		}
149 /*			for ( var n = 0; n < size; n++)
150 		{
151 			var u = n;
152 			var v = n;
153 			var res = lineIntersection( u1, v1, u2, v2, u, 0.0, 0.0, v );
154 			if ( res[0] > 0.0 && res[0] < 1.0 && res[1] > 0.0 && res[1] < 1.0 )
155 			{
156 				intersections.push( res[0] );
157 			}
158 			if ( n != size-1 )
159 			{
160 				var res = lineIntersection( u1, v1, u2, v2, u, size, size, v );
161 				if ( res[0] > 0.0 && res[0] < 1.0 && res[1] > 0.0 && res[1] < 1.0 )
162 				{
163 					intersections.push( res[0] );
164 				}
165 			}
166 		}*/
167 		
168 		// Sort intersections found on the segment
169 		intersections.sort( function(a,b) { return a[0] > b[0]; } );
170 		
171 		// Build the vertices from the intersections found
172 		var startIndex = this.vertices.length / 3;
173 		
174 		if ( u1 >= 0.0 && u1 <= size-1 &&  v1 >= 0.0 && v1 <= size-1 )
175 		{
176 			var vec = tile.computePosition(u1,v1);
177 			this.vertices.push( vec[0] );
178 			this.vertices.push( vec[1] );
179 			this.vertices.push( vec[2] );
180 		}
181 					
182 		for ( var n = 0; n < intersections.length; n++ )
183 		{
184 			this.vertices.push( intersections[n][1] );
185 			this.vertices.push( intersections[n][2] );
186 			this.vertices.push( intersections[n][3] );
187 		}
188 		
189 		if ( u2 >= 0.0 && u2 <= size-1 &&  v2 >= 0.0 && v2 <= size-1 )
190 		{
191 			var vec = tile.computePosition(u2,v2);
192 			this.vertices.push( vec[0] );
193 			this.vertices.push( vec[1] );
194 			this.vertices.push( vec[2] );
195 		}
196 		
197 		var endIndex = this.vertices.length / 3;
198 		
199 		for ( var n = startIndex; n < endIndex - 1; n++ )
200 		{
201 			this.indices.push( n );
202 			this.indices.push( n+1 );
203 		}
204 	}
205 }
206 
207 /**************************************************************************************************************/
208 
209 // Register the renderer
210 VectorRendererManager.registerRenderer({
211 					creator: function(globe) { 
212 						var lineStringRenderer = new TiledVectorRenderer(globe.tileManager);
213 						lineStringRenderer.id = "lineString";
214 						lineStringRenderer.styleEquals = function(s1,s2) {
215 							if (!s1.isEqualForLine)
216 								console.log(s1);
217 							return s1.isEqualForLine(s2);
218 						};
219 						lineStringRenderer.renderableConstuctor = LineStringRenderable;
220 						return lineStringRenderer;
221 					},
222 					canApply: function(type,style) {
223 						// LineStringRenderer supports line string (multi or not) and polygon (or multi) when not filled
224 
225 						return type == "LineString" || type == "MultiLineString"
226 							|| (!style.fill && (type == "Polygon" || type == "MultiPolygon")); 
227 					} 
228 				});
229 				
230 return LineStringRenderable;
231 
232 });
233 
234