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', './BaseLayer', './GeoBound', './GroundOverlayRenderer'], 
 21 	function(Utils, BaseLayer, GeoBound, GroundOverlayRenderer) {
 22 
 23 
 24 /**************************************************************************************************************/
 25 
 26 /** @constructor
 27 	@export
 28 	This layer draws an image overlay draped onto the terrain
 29 	Arg : options
 30 		image : the image to drape on the terrain, can be an Image element or a string (url of the image)
 31 		quad : An array of 4 points to define the area on the terrain to drape the image
 32 		opacity : opacity of the layer
 33 		flipY : flip or not the image
 34  */
 35 var GroundOverlayLayer = function( options )
 36 {
 37 	BaseLayer.prototype.constructor.call( this, options );
 38 	
 39 	this.quad = options.quad;
 40 	this.opacity = options.opacity || 1.0;
 41 	if ( typeof options.flipY === 'undefined' )
 42 	{
 43 		this.flipY = true;
 44 	}
 45 	else
 46 	{
 47 		this.flipY = options.flipY;
 48 	}
 49 	
 50 	// Compute the geo bound of the ground overlay
 51 	this.geoBound = new GeoBound();
 52 	this.geoBound.computeFromCoordinates( this.quad );
 53 	this.computeTransform();
 54 
 55 	if (typeof options.image == "string")
 56 	{
 57 		this.image = new Image();
 58 		this.image.crossOrigin = '';
 59 		this.image.src = options.image;
 60 	}
 61 	else if ( options.image instanceof HTMLImageElement )
 62 	{
 63 		this.image = options.image;
 64 	}
 65 	this.globe = null;
 66 }
 67 
 68 /**************************************************************************************************************/
 69 
 70 Utils.inherits( BaseLayer,GroundOverlayLayer );
 71 
 72 /**************************************************************************************************************/
 73 
 74 /**
 75 	Attach layer to the globe
 76  */
 77 GroundOverlayLayer.prototype._attach = function( globe )
 78 {
 79 	// Add layer to ground overlay renderer, create one if needed
 80 	var renderer = globe.groundOverlayRenderer;
 81 	if ( !renderer )
 82 	{
 83 		renderer = new GroundOverlayRenderer(globe.tileManager);
 84 		globe.tileManager.addPostRenderer( renderer );
 85 		globe.groundOverlayRenderer = renderer;
 86 	}
 87 	renderer.groundOverlays.push( this );
 88 	
 89 	this.globe = globe;
 90 }
 91 
 92 //*************************************************************************
 93 
 94 /**
 95 	Dtach layer from the globe
 96  */
 97 GroundOverlayLayer.prototype._detach = function( globe )
 98 {
 99 	// Remove layer from the globe renderer for ground overlay
100 	var prevRenderer = this.globe.groundOverlayRenderer;
101 	if ( prevRenderer )
102 	{
103 		var index = prevRenderer.groundOverlays.indexOf( this );
104 		if ( index != - 1 )
105 		{
106 			prevRenderer.groundOverlays.splice(index,1);
107 			
108 			if ( prevRenderer.groundOverlays.length == 0 )
109 			{
110 				this.globe.tileManager.removePostRenderer( prevRenderer );
111 				this.globe.groundOverlayRenderer = null;
112 			}
113 		}
114 	}
115 }
116 
117 //*************************************************************************
118 
119 /**
120 	Transform a geographic position into the unit square of the ground overlay
121  */
122 GroundOverlayLayer.prototype.transformFromSquare = function( point )
123 {
124 	var x = this.transform[0] * point[0] + this.transform[3] * point[1] + this.transform[6];
125 	var y = this.transform[1] * point[0] + this.transform[4] * point[1] + this.transform[7];
126 	var w = 1.0 / (this.transform[2] * point[0] + this.transform[5] * point[1] + this.transform[8]);
127 	x *= w;
128 	y *= w;
129 	return [ x, y ];
130 }
131 
132 //*************************************************************************
133 
134 /**
135 	Transform from the unit square of the ground overlay into a unit square
136  */
137 GroundOverlayLayer.prototype.transformToSquare = function( point )
138 {
139 	var x = this.inverseTransform[0] * point[0] + this.inverseTransform[3] * point[1] + this.inverseTransform[6];
140 	var y = this.inverseTransform[1] * point[0] + this.inverseTransform[4] * point[1] + this.inverseTransform[7];
141 	var w = 1.0 / (this.inverseTransform[2] * point[0] + this.inverseTransform[5] * point[1] + this.inverseTransform[8]);
142 	x *= w;
143 	y *= w;
144 	return [ x, y ];
145 }
146 
147 //*************************************************************************
148 
149 /**
150 	Compute the inverse transform from unit square to geo position
151 	Code taken from QTransform
152  */
153 GroundOverlayLayer.prototype.computeInverse = function()
154 {
155     var det =  this.transform[0] * (this.transform[8] * this.transform[4] - this.transform[5] * this.transform[7]) -
156         this.transform[3] * (this.transform[8] * this.transform[1] -  this.transform[7]) *  this.transform[3] 
157 			+  this.transform[6] * ( this.transform[5] * this.transform[1] - this.transform[4] * this.transform[2]);
158 
159     var h11, h12, h13,
160         h21, h22, h23,
161         h31, h32, h33;
162     h11 = this.transform[4]*this.transform[8] - this.transform[5]*this.transform[7];
163     h21 = this.transform[5]*this.transform[6] - this.transform[3]*this.transform[8];
164     h31 = this.transform[3]*this.transform[7] - this.transform[4]*this.transform[6];
165     h12 = this.transform[2]*this.transform[7] - this.transform[1]*this.transform[8];
166     h22 = this.transform[0]*this.transform[8] - this.transform[2]*this.transform[6];
167     h32 = this.transform[1]*this.transform[6] - this.transform[0]*this.transform[7];
168     h13 = this.transform[1]*this.transform[5] - this.transform[2]*this.transform[4];
169     h23 = this.transform[2]*this.transform[3] - this.transform[0]*this.transform[5];
170     h33 = this.transform[0]*this.transform[4] - this.transform[1]*this.transform[3];
171 
172     this.inverseTransform = [ h11 / det, h12 / det, h13 / det,
173 							 h21 / det, h22 / det, h23 / det,
174 							 h31 / det, h32 / det, h33 / det ];
175 }
176 
177 //*************************************************************************
178 
179 /**
180 	Compute the transform from geo position to unit square
181 	Code taken from QTransform
182  */
183 GroundOverlayLayer.prototype.computeTransform = function()
184 {
185     var dx0 = this.quad[0][0];
186     var dx1 = this.quad[1][0];
187     var dx2 = this.quad[2][0];
188     var dx3 = this.quad[3][0];
189 
190     var dy0 = this.quad[0][1];
191     var dy1 = this.quad[1][1];
192     var dy2 = this.quad[2][1];
193     var dy3 = this.quad[3][1];
194 
195     var ax  = dx0 - dx1 + dx2 - dx3;
196     var ay  = dy0 - dy1 + dy2 - dy3;
197 	
198     if (!ax && !ay) { //afine transform
199         this.transform = [ dx1 - dx0, dy1 - dy0,  0,
200 							dx2 - dx1, dy2 - dy1,  0,
201 							dx0,       dy0,  1 ];
202     }
203 	else
204 	{
205         var ax1 = dx1 - dx2;
206         var ax2 = dx3 - dx2;
207         var ay1 = dy1 - dy2;
208         var ay2 = dy3 - dy2;
209 
210         /*determinants */
211         var gtop    =  ax  * ay2 - ax2 * ay;
212         var htop    =  ax1 * ay  - ax  * ay1;
213         var bottom  =  ax1 * ay2 - ax2 * ay1;
214 
215         var a, b, c, d, e, f, g, h;  /*i is always 1*/
216 
217         if (!bottom)
218             return;
219 
220         g = gtop/bottom;
221         h = htop/bottom;
222 
223         a = dx1 - dx0 + g * dx1;
224         b = dx3 - dx0 + h * dx3;
225         c = dx0;
226         d = dy1 - dy0 + g * dy1;
227         e = dy3 - dy0 + h * dy3;
228         f = dy0;
229 
230         this.transform = [ a, d, g,
231                         b, e, h,
232                         c, f, 1.0 ];
233     }
234 	
235 	this.computeInverse();
236 }
237 
238 //*************************************************************************
239 
240 return GroundOverlayLayer;
241 
242 });