Changeset 342 for trunk/zoo-project/zoo-api
- Timestamp:
- Oct 12, 2011, 1:13:15 PM (13 years ago)
- Location:
- trunk/zoo-project/zoo-api/js
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/zoo-project/zoo-api/js/ZOO-api.js
r278 r342 331 331 return ZOO.String.isNumeric(value) ? parseFloat(value) : value; 332 332 } 333 }; 334 335 /** 336 * Class: ZOO.Class 337 * Object for creating CLASS 338 */ 339 ZOO.Class = function() { 340 var len = arguments.length; 341 var P = arguments[0]; 342 var F = arguments[len-1]; 343 var C = typeof F.initialize == "function" ? 344 F.initialize : 345 function(){ P.prototype.initialize.apply(this, arguments); }; 346 347 if (len > 1) { 348 var newArgs = [C, P].concat( 349 Array.prototype.slice.call(arguments).slice(1, len-1), F); 350 ZOO.inherit.apply(null, newArgs); 351 } else { 352 C.prototype = F; 353 } 354 return C; 355 }; 356 /** 357 * Function: create 358 * Function for creating CLASS 359 */ 360 ZOO.Class.create = function() { 361 return function() { 362 if (arguments && arguments[0] != ZOO.Class.isPrototype) { 363 this.initialize.apply(this, arguments); 364 } 365 }; 366 }; 367 /** 368 * Function: inherit 369 * Function for inheriting CLASS 370 */ 371 ZOO.Class.inherit = function (P) { 372 var C = function() { 373 P.call(this); 374 }; 375 var newArgs = [C].concat(Array.prototype.slice.call(arguments)); 376 ZOO.inherit.apply(null, newArgs); 377 return C.prototype; 378 }; 379 /** 380 * Function: inherit 381 * Function for inheriting CLASS 382 */ 383 ZOO.inherit = function(C, P) { 384 var F = function() {}; 385 F.prototype = P.prototype; 386 C.prototype = new F; 387 var i, l, o; 388 for(i=2, l=arguments.length; i<l; i++) { 389 o = arguments[i]; 390 if(typeof o === "function") { 391 o = o.prototype; 392 } 393 ZOO.Util.extend(C.prototype, o); 394 } 395 }; 396 /** 397 * Class: ZOO.Util 398 * Object for utilities 399 */ 400 ZOO.Util = ZOO.Util || {}; 401 /** 402 * Function: extend 403 * Function for extending object 404 */ 405 ZOO.Util.extend = function(destination, source) { 406 destination = destination || {}; 407 if (source) { 408 for (var property in source) { 409 var value = source[property]; 410 if (value !== undefined) { 411 destination[property] = value; 412 } 413 } 414 } 415 return destination; 333 416 }; 334 417 … … 6124 6207 */ 6125 6208 'complex': function(identifier,data) { 6126 var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:ComplexData><![CDATA['+data.value+']]></wps:ComplexData></wps:Data></wps:Input>'); 6127 input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'application/json'; 6209 var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier>'+(data.value?'<wps:Data><wps:ComplexData><![CDATA['+data.value+']]></wps:ComplexData></wps:Data>':(data.xlink?'<wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.xlink+'" mimeType="'+data.mimeType+'" />':''))+'</wps:Input>'); 6210 if(data.xlink) 6211 input.*::Reference.@mimeType = data.mimetype ? data.mimetype : 'application/json'; 6212 else 6213 input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'application/json'; 6128 6214 if (data.encoding) 6129 6215 input.*::Data.*::ComplexData.@encoding = data.encoding; -
trunk/zoo-project/zoo-api/js/ZOO-proj4js.js
r144 r342 23 23 */ 24 24 25 /** 26 * Author: Mike Adair madairATdmsolutions.ca 27 * Richard Greenwood rich@greenwoodmap.com 28 * License: LGPL as per: http://www.gnu.org/copyleft/lesser.html 29 * $Id: Proj.js 2956 2007-07-09 12:17:52Z steven $ 30 */ 25 /* 26 proj4js.js -- Javascript reprojection library. 27 28 Authors: Mike Adair madairATdmsolutions.ca 29 Richard Greenwood richATgreenwoodmap.com 30 Didier Richard didier.richardATign.fr 31 Stephen Irons 32 License: LGPL as per: http://www.gnu.org/copyleft/lesser.html 33 Note: This program is an almost direct port of the C library 34 Proj4. 35 */ 31 36 32 /** 33 * Class: ZOO 34 */ 35 ZOO = { 36 /** 37 * Constant: SERVICE_ACCEPTED 38 * {Integer} used for 39 */ 40 SERVICE_ACCEPTED: 0, 41 /** 42 * Constant: SERVICE_STARTED 43 * {Integer} used for 44 */ 45 SERVICE_STARTED: 1, 46 /** 47 * Constant: SERVICE_PAUSED 48 * {Integer} used for 49 */ 50 SERVICE_PAUSED: 2, 51 /** 52 * Constant: SERVICE_SUCCEEDED 53 * {Integer} used for 54 */ 55 SERVICE_SUCCEEDED: 3, 56 /** 57 * Constant: SERVICE_FAILED 58 * {Integer} used for 59 */ 60 SERVICE_FAILED: 4, 61 /** 62 * Function: removeItem 63 * Remove an object from an array. Iterates through the array 64 * to find the item, then removes it. 65 * 66 * Parameters: 67 * array - {Array} 68 * item - {Object} 69 * 70 * Return 71 * {Array} A reference to the array 72 */ 73 removeItem: function(array, item) { 74 for(var i = array.length - 1; i >= 0; i--) { 75 if(array[i] == item) { 76 array.splice(i,1); 77 } 78 } 79 return array; 37 Proj4js={defaultDatum:'WGS84',transform:function(source,dest,point){if(!source.readyToUse||!dest.readyToUse){this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete");return point;} 38 if((source.srsProjNumber=="900913"&&dest.datumCode!="WGS84")||(dest.srsProjNumber=="900913"&&source.datumCode!="WGS84")){var wgs84=Proj4js.WGS84;this.transform(source,wgs84,point);source=wgs84;} 39 if(source.projName=="longlat"){point.x*=Proj4js.common.D2R;point.y*=Proj4js.common.D2R;}else{if(source.to_meter){point.x*=source.to_meter;point.y*=source.to_meter;} 40 source.inverse(point);} 41 if(source.from_greenwich){point.x+=source.from_greenwich;} 42 point=this.datum_transform(source.datum,dest.datum,point);if(dest.from_greenwich){point.x-=dest.from_greenwich;} 43 if(dest.projName=="longlat"){point.x*=Proj4js.common.R2D;point.y*=Proj4js.common.R2D;}else{dest.forward(point);if(dest.to_meter){point.x/=dest.to_meter;point.y/=dest.to_meter;}} 44 return point;},datum_transform:function(source,dest,point){if(source.compare_datums(dest)){return point;} 45 if(source.datum_type==Proj4js.common.PJD_NODATUM||dest.datum_type==Proj4js.common.PJD_NODATUM){return point;} 46 if(source.datum_type==Proj4js.common.PJD_GRIDSHIFT) 47 {alert("ERROR: Grid shift transformations are not implemented yet.");} 48 if(dest.datum_type==Proj4js.common.PJD_GRIDSHIFT) 49 {alert("ERROR: Grid shift transformations are not implemented yet.");} 50 if(source.es!=dest.es||source.a!=dest.a||source.datum_type==Proj4js.common.PJD_3PARAM||source.datum_type==Proj4js.common.PJD_7PARAM||dest.datum_type==Proj4js.common.PJD_3PARAM||dest.datum_type==Proj4js.common.PJD_7PARAM) 51 {source.geodetic_to_geocentric(point);if(source.datum_type==Proj4js.common.PJD_3PARAM||source.datum_type==Proj4js.common.PJD_7PARAM){source.geocentric_to_wgs84(point);} 52 if(dest.datum_type==Proj4js.common.PJD_3PARAM||dest.datum_type==Proj4js.common.PJD_7PARAM){dest.geocentric_from_wgs84(point);} 53 dest.geocentric_to_geodetic(point);} 54 if(dest.datum_type==Proj4js.common.PJD_GRIDSHIFT) 55 {alert("ERROR: Grid shift transformations are not implemented yet.");} 56 return point;},reportError:function(msg){},extend:function(destination,source){destination=destination||{};if(source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}} 57 return destination;},Class:function(){var Class=function(){this.initialize.apply(this,arguments);};var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];} 58 Proj4js.extend(extended,parent);} 59 Class.prototype=extended;return Class;},bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},scriptName:"proj4js-compressed.js",defsLookupService:'http://spatialreference.org/ref',libPath:null,getScriptLocation:function(){if(this.libPath)return this.libPath;var scriptName=this.scriptName;var scriptNameLen=scriptName.length;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptNameLen==src.length)){this.libPath=src.slice(0,-scriptNameLen);break;}}} 60 return this.libPath||"";}, 61 loadScript:function(url,onload,onfail,loadCheck){ 62 var script = []; 63 var script = ZOORequest('GET',url); 64 try { 65 eval(script); 66 onload(); 67 } catch (e) { 68 onfail(); 69 } 70 /* 71 var script=document.createElement('script'); 72 script.defer=false; 73 script.type="text/javascript"; 74 script.id=url; 75 script.src=url; 76 script.onload=onload; 77 script.onerror=onfail; 78 script.loadCheck=loadCheck; 79 if(/MSIE/.test(navigator.userAgent)){script.onreadystatechange=this.checkReadyState;} 80 document.getElementsByTagName('head')[0].appendChild(script); 81 */ 80 82 }, 81 /** 82 * Function: indexOf 83 * 84 * Parameters: 85 * array - {Array} 86 * obj - {Object} 87 * 88 * Returns: 89 * {Integer} The index at, which the first object was found in the array. 90 * If not found, returns -1. 91 */ 92 indexOf: function(array, obj) { 93 for(var i=0, len=array.length; i<len; i++) { 94 if (array[i] == obj) 95 return i; 96 } 97 return -1; 83 checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,initialize:function(srsCode){this.srsCodeInput=srsCode;if(srsCode.indexOf('urn:')==0){var urn=srsCode.split(':');if((urn[1]=='ogc'||urn[1]=='x-ogc')&&(urn[2]=='def')&&(urn[3]=='crs')){srsCode=urn[4]+':'+urn[urn.length-1];}}else if(srsCode.indexOf('http://')==0){var url=srsCode.split('#');if(url[0].match(/epsg.org/)){srsCode='EPSG:'+url[1];}else if(url[0].match(/RIG.xml/)){srsCode='IGNF:'+url[1];}} 84 this.srsCode=srsCode.toUpperCase();if(this.srsCode.indexOf("EPSG")==0){this.srsCode=this.srsCode;this.srsAuth='epsg';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("IGNF")==0){this.srsCode=this.srsCode;this.srsAuth='IGNF';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("CRS")==0){this.srsCode=this.srsCode;this.srsAuth='CRS';this.srsProjNumber=this.srsCode.substring(4);}else{this.srsAuth='';this.srsProjNumber=this.srsCode;} 85 this.loadProjDefinition();}, 86 loadProjDefinition:function(){ 87 if(Proj4js.defs[this.srsCode]){this.defsLoaded();return;} 88 this.loadFromService(); 89 /* 90 var url=Proj4js.getScriptLocation()+'defs/'+this.srsAuth.toUpperCase()+this.srsProjNumber+'.js'; 91 Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.loadFromService,this),Proj4js.bind(this.checkDefsLoaded,this)); 92 */ 98 93 }, 99 /** 100 * Function: extend 101 * Copy all properties of a source object to a destination object. Modifies 102 * the passed in destination object. Any properties on the source object 103 * that are set to undefined will not be (re)set on the destination object. 104 * 105 * Parameters: 106 * destination - {Object} The object that will be modified 107 * source - {Object} The object with properties to be set on the destination 108 * 109 * Returns: 110 * {Object} The destination object. 111 */ 112 extend: function(destination, source) { 113 destination = destination || {}; 114 if(source) { 115 for(var property in source) { 116 var value = source[property]; 117 if(value !== undefined) 118 destination[property] = value; 119 } 120 } 121 return destination; 94 loadFromService:function(){var url=Proj4js.defsLookupService+'/'+this.srsAuth+'/'+this.srsProjNumber+'/proj4js/';Proj4js.loadScript(url,Proj4js.bind(this.defsLoaded,this),Proj4js.bind(this.defsFailed,this),Proj4js.bind(this.checkDefsLoaded,this));},defsLoaded:function(){this.parseDefs();this.loadProjCode(this.projName);},checkDefsLoaded:function(){if(Proj4js.defs[this.srsCode]){return true;}else{return false;}},defsFailed:function(){Proj4js.reportError('failed to load projection definition for: '+this.srsCode);Proj4js.defs[this.srsCode]=Proj4js.defs['WGS84'];this.defsLoaded();}, 95 loadProjCode:function(projName){ 96 if(Proj4js.Proj[projName]){this.initTransforms();return;} 97 var url=Proj4js.getScriptLocation()+'projCode/'+projName+'.js'; 98 Proj4js.loadScript(url,Proj4js.bind(this.loadProjCodeSuccess,this,projName),Proj4js.bind(this.loadProjCodeFailure,this,projName),Proj4js.bind(this.checkCodeLoaded,this,projName)); 122 99 }, 123 /** 124 * Function: rad 125 * 126 * Parameters: 127 * x - {Float} 128 * 129 * Returns: 130 * {Float} 131 */ 132 rad: function(x) {return x*Math.PI/180;}, 133 /** 134 * Function: distVincenty 135 * Given two objects representing points with geographic coordinates, this 136 * calculates the distance between those points on the surface of an 137 * ellipsoid. 138 * 139 * Parameters: 140 * p1 - {<ZOO.Geometry.Point>} (or any object with both .x, .y properties) 141 * p2 - {<ZOO.Geometry.Point>} (or any object with both .x, .y properties) 142 * 143 * Returns: 144 * {Float} The distance (in km) between the two input points as measured on an 145 * ellipsoid. Note that the input point objects must be in geographic 146 * coordinates (decimal degrees) and the return distance is in kilometers. 147 */ 148 distVincenty: function(p1, p2) { 149 var a = 6378137, b = 6356752.3142, f = 1/298.257223563; 150 var L = ZOO.rad(p2.x - p1.y); 151 var U1 = Math.atan((1-f) * Math.tan(ZOO.rad(p1.y))); 152 var U2 = Math.atan((1-f) * Math.tan(ZOO.rad(p2.y))); 153 var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); 154 var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); 155 var lambda = L, lambdaP = 2*Math.PI; 156 var iterLimit = 20; 157 while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) { 158 var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); 159 var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + 160 (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); 161 if (sinSigma==0) { 162 return 0; // co-incident points 163 } 164 var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; 165 var sigma = Math.atan2(sinSigma, cosSigma); 166 var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma); 167 var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha); 168 var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; 169 var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); 170 lambdaP = lambda; 171 lambda = L + (1-C) * f * Math.sin(alpha) * 172 (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); 173 } 174 if (iterLimit==0) { 175 return NaN; // formula failed to converge 176 } 177 var uSq = cosSqAlpha * (a*a - b*b) / (b*b); 178 var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); 179 var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); 180 var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- 181 B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); 182 var s = b*A*(sigma-deltaSigma); 183 var d = s.toFixed(3)/1000; // round to 1mm precision 184 return d; 185 }, 186 /** 187 * Function: Class 188 * Method used to create ZOO classes. Includes support for 189 * multiple inheritance. 190 */ 191 Class: function() { 192 var Class = function() { 193 this.initialize.apply(this, arguments); 194 }; 195 var extended = {}; 196 var parent; 197 for(var i=0; i<arguments.length; ++i) { 198 if(typeof arguments[i] == "function") { 199 // get the prototype of the superclass 200 parent = arguments[i].prototype; 201 } else { 202 // in this case we're extending with the prototype 203 parent = arguments[i]; 204 } 205 ZOO.extend(extended, parent); 206 } 207 Class.prototype = extended; 208 209 return Class; 210 }, 211 /** 212 * Function: UpdateStatus 213 * Method used to update the status of the process 214 * 215 * Parameters: 216 * env - {Object} The environment object 217 * value - {Float} the status value between 0 to 100 218 */ 219 UpdateStatus: function(env,value) { 220 return ZOOUpdateStatus(env,value); 221 } 222 }; 223 224 /** 225 * Class: ZOO.String 226 * Contains convenience methods for string manipulation 227 */ 228 ZOO.String = { 229 /** 230 * Function: startsWith 231 * Test whether a string starts with another string. 232 * 233 * Parameters: 234 * str - {String} The string to test. 235 * sub - {Sring} The substring to look for. 236 * 237 * Returns: 238 * {Boolean} The first string starts with the second. 239 */ 240 startsWith: function(str, sub) { 241 return (str.indexOf(sub) == 0); 242 }, 243 /** 244 * Function: contains 245 * Test whether a string contains another string. 246 * 247 * Parameters: 248 * str - {String} The string to test. 249 * sub - {String} The substring to look for. 250 * 251 * Returns: 252 * {Boolean} The first string contains the second. 253 */ 254 contains: function(str, sub) { 255 return (str.indexOf(sub) != -1); 256 }, 257 /** 258 * Function: trim 259 * Removes leading and trailing whitespace characters from a string. 260 * 261 * Parameters: 262 * str - {String} The (potentially) space padded string. This string is not 263 * modified. 264 * 265 * Returns: 266 * {String} A trimmed version of the string with all leading and 267 * trailing spaces removed. 268 */ 269 trim: function(str) { 270 return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 271 }, 272 /** 273 * Function: camelize 274 * Camel-case a hyphenated string. 275 * Ex. "chicken-head" becomes "chickenHead", and 276 * "-chicken-head" becomes "ChickenHead". 277 * 278 * Parameters: 279 * str - {String} The string to be camelized. The original is not modified. 280 * 281 * Returns: 282 * {String} The string, camelized 283 * 284 */ 285 camelize: function(str) { 286 var oStringList = str.split('-'); 287 var camelizedString = oStringList[0]; 288 for (var i=1, len=oStringList.length; i<len; i++) { 289 var s = oStringList[i]; 290 camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 291 } 292 return camelizedString; 293 }, 294 /** 295 * Property: tokenRegEx 296 * Used to find tokens in a string. 297 * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} 298 */ 299 tokenRegEx: /\$\{([\w.]+?)\}/g, 300 /** 301 * Property: numberRegEx 302 * Used to test strings as numbers. 303 */ 304 numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, 305 /** 306 * Function: isNumeric 307 * Determine whether a string contains only a numeric value. 308 * 309 * Examples: 310 * (code) 311 * ZOO.String.isNumeric("6.02e23") // true 312 * ZOO.String.isNumeric("12 dozen") // false 313 * ZOO.String.isNumeric("4") // true 314 * ZOO.String.isNumeric(" 4 ") // false 315 * (end) 316 * 317 * Returns: 318 * {Boolean} String contains only a number. 319 */ 320 isNumeric: function(value) { 321 return ZOO.String.numberRegEx.test(value); 322 }, 323 /** 324 * Function: numericIf 325 * Converts a string that appears to be a numeric value into a number. 326 * 327 * Returns 328 * {Number|String} a Number if the passed value is a number, a String 329 * otherwise. 330 */ 331 numericIf: function(value) { 332 return ZOO.String.isNumeric(value) ? parseFloat(value) : value; 333 } 334 }; 335 336 /** 337 * Class: ZOO.Request 338 * Contains convenience methods for working with ZOORequest which 339 * replace XMLHttpRequest. Because of we are not in a browser 340 * JavaScript environment, ZOO Project provides a method to 341 * query servers which is based on curl : ZOORequest. 342 */ 343 ZOO.Request = { 344 /** 345 * Function: GET 346 * Send an HTTP GET request. 347 * 348 * Parameters: 349 * url - {String} The URL to request. 350 * params - {Object} Params to add to the url 351 * 352 * Returns: 353 * {String} Request result. 354 */ 355 Get: function(url,params) { 356 var paramsArray = []; 357 for (var key in params) { 358 var value = params[key]; 359 if ((value != null) && (typeof value != 'function')) { 360 var encodedValue; 361 if (typeof value == 'object' && value.constructor == Array) { 362 /* value is an array; encode items and separate with "," */ 363 var encodedItemArray = []; 364 for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) { 365 encodedItemArray.push(encodeURIComponent(value[itemIndex])); 366 } 367 encodedValue = encodedItemArray.join(","); 368 } 369 else { 370 /* value is a string; simply encode */ 371 encodedValue = encodeURIComponent(value); 372 } 373 paramsArray.push(encodeURIComponent(key) + "=" + encodedValue); 374 } 375 } 376 var paramString = paramsArray.join("&"); 377 if(paramString.length > 0) { 378 var separator = (url.indexOf('?') > -1) ? '&' : '?'; 379 url += separator + paramString; 380 } 381 return ZOORequest('GET',url); 382 }, 383 /** 384 * Function: POST 385 * Send an HTTP POST request. 386 * 387 * Parameters: 388 * url - {String} The URL to request. 389 * body - {String} The request's body to send. 390 * headers - {Object} A key-value object of headers to push to 391 * the request's head 392 * 393 * Returns: 394 * {String} Request result. 395 */ 396 Post: function(url,body,headers) { 397 if(!(headers instanceof Array)) { 398 var headersArray = []; 399 for (var name in headers) { 400 headersArray.push(name+': '+headers[name]); 401 } 402 headers = headersArray; 403 } 404 return ZOORequest('POST',url,body,headers); 405 } 406 }; 407 408 /** 409 * Class: ZOO.Bounds 410 * Instances of this class represent bounding boxes. Data stored as left, 411 * bottom, right, top floats. All values are initialized to null, 412 * however, you should make sure you set them before using the bounds 413 * for anything. 414 */ 415 ZOO.Bounds = ZOO.Class({ 416 /** 417 * Property: left 418 * {Number} Minimum horizontal coordinate. 419 */ 420 left: null, 421 /** 422 * Property: bottom 423 * {Number} Minimum vertical coordinate. 424 */ 425 bottom: null, 426 /** 427 * Property: right 428 * {Number} Maximum horizontal coordinate. 429 */ 430 right: null, 431 /** 432 * Property: top 433 * {Number} Maximum vertical coordinate. 434 */ 435 top: null, 436 /** 437 * Constructor: ZOO.Bounds 438 * Construct a new bounds object. 439 * 440 * Parameters: 441 * left - {Number} The left bounds of the box. Note that for width 442 * calculations, this is assumed to be less than the right value. 443 * bottom - {Number} The bottom bounds of the box. Note that for height 444 * calculations, this is assumed to be more than the top value. 445 * right - {Number} The right bounds. 446 * top - {Number} The top bounds. 447 */ 448 initialize: function(left, bottom, right, top) { 449 if (left != null) 450 this.left = parseFloat(left); 451 if (bottom != null) 452 this.bottom = parseFloat(bottom); 453 if (right != null) 454 this.right = parseFloat(right); 455 if (top != null) 456 this.top = parseFloat(top); 457 }, 458 /** 459 * Method: clone 460 * Create a cloned instance of this bounds. 461 * 462 * Returns: 463 * {<ZOO.Bounds>} A fresh copy of the bounds 464 */ 465 clone:function() { 466 return new ZOO.Bounds(this.left, this.bottom, 467 this.right, this.top); 468 }, 469 /** 470 * Method: equals 471 * Test a two bounds for equivalence. 472 * 473 * Parameters: 474 * bounds - {<ZOO.Bounds>} 475 * 476 * Returns: 477 * {Boolean} The passed-in bounds object has the same left, 478 * right, top, bottom components as this. Note that if bounds 479 * passed in is null, returns false. 480 */ 481 equals:function(bounds) { 482 var equals = false; 483 if (bounds != null) 484 equals = ((this.left == bounds.left) && 485 (this.right == bounds.right) && 486 (this.top == bounds.top) && 487 (this.bottom == bounds.bottom)); 488 return equals; 489 }, 490 /** 491 * Method: toString 492 * 493 * Returns: 494 * {String} String representation of bounds object. 495 * (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>) 496 */ 497 toString:function() { 498 return ( "left-bottom=(" + this.left + "," + this.bottom + ")" 499 + " right-top=(" + this.right + "," + this.top + ")" ); 500 }, 501 /** 502 * APIMethod: toArray 503 * 504 * Returns: 505 * {Array} array of left, bottom, right, top 506 */ 507 toArray: function() { 508 return [this.left, this.bottom, this.right, this.top]; 509 }, 510 /** 511 * Method: toBBOX 512 * 513 * Parameters: 514 * decimal - {Integer} How many significant digits in the bbox coords? 515 * Default is 6 516 * 517 * Returns: 518 * {String} Simple String representation of bounds object. 519 * (ex. <i>"5,42,10,45"</i>) 520 */ 521 toBBOX:function(decimal) { 522 if (decimal== null) 523 decimal = 6; 524 var mult = Math.pow(10, decimal); 525 var bbox = Math.round(this.left * mult) / mult + "," + 526 Math.round(this.bottom * mult) / mult + "," + 527 Math.round(this.right * mult) / mult + "," + 528 Math.round(this.top * mult) / mult; 529 return bbox; 530 }, 531 /** 532 * Method: toGeometry 533 * Create a new polygon geometry based on this bounds. 534 * 535 * Returns: 536 * {<ZOO.Geometry.Polygon>} A new polygon with the coordinates 537 * of this bounds. 538 */ 539 toGeometry: function() { 540 return new ZOO.Geometry.Polygon([ 541 new ZOO.Geometry.LinearRing([ 542 new ZOO.Geometry.Point(this.left, this.bottom), 543 new ZOO.Geometry.Point(this.right, this.bottom), 544 new ZOO.Geometry.Point(this.right, this.top), 545 new ZOO.Geometry.Point(this.left, this.top) 546 ]) 547 ]); 548 }, 549 /** 550 * Method: getWidth 551 * 552 * Returns: 553 * {Float} The width of the bounds 554 */ 555 getWidth:function() { 556 return (this.right - this.left); 557 }, 558 /** 559 * Method: getHeight 560 * 561 * Returns: 562 * {Float} The height of the bounds (top minus bottom). 563 */ 564 getHeight:function() { 565 return (this.top - this.bottom); 566 }, 567 /** 568 * Method: add 569 * 570 * Parameters: 571 * x - {Float} 572 * y - {Float} 573 * 574 * Returns: 575 * {<ZOO.Bounds>} A new bounds whose coordinates are the same as 576 * this, but shifted by the passed-in x and y values. 577 */ 578 add:function(x, y) { 579 if ( (x == null) || (y == null) ) 580 return null; 581 return new ZOO.Bounds(this.left + x, this.bottom + y, 582 this.right + x, this.top + y); 583 }, 584 /** 585 * Method: extend 586 * Extend the bounds to include the point, lonlat, or bounds specified. 587 * Note, this function assumes that left < right and bottom < top. 588 * 589 * Parameters: 590 * object - {Object} Can be Point, or Bounds 591 */ 592 extend:function(object) { 593 var bounds = null; 594 if (object) { 595 // clear cached center location 596 switch(object.CLASS_NAME) { 597 case "ZOO.Geometry.Point": 598 bounds = new ZOO.Bounds(object.x, object.y, 599 object.x, object.y); 600 break; 601 case "ZOO.Bounds": 602 bounds = object; 603 break; 604 } 605 if (bounds) { 606 if ( (this.left == null) || (bounds.left < this.left)) 607 this.left = bounds.left; 608 if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) 609 this.bottom = bounds.bottom; 610 if ( (this.right == null) || (bounds.right > this.right) ) 611 this.right = bounds.right; 612 if ( (this.top == null) || (bounds.top > this.top) ) 613 this.top = bounds.top; 614 } 615 } 616 }, 617 /** 618 * APIMethod: contains 619 * 620 * Parameters: 621 * x - {Float} 622 * y - {Float} 623 * inclusive - {Boolean} Whether or not to include the border. 624 * Default is true. 625 * 626 * Returns: 627 * {Boolean} Whether or not the passed-in coordinates are within this 628 * bounds. 629 */ 630 contains:function(x, y, inclusive) { 631 //set default 632 if (inclusive == null) 633 inclusive = true; 634 if (x == null || y == null) 635 return false; 636 x = parseFloat(x); 637 y = parseFloat(y); 638 639 var contains = false; 640 if (inclusive) 641 contains = ((x >= this.left) && (x <= this.right) && 642 (y >= this.bottom) && (y <= this.top)); 643 else 644 contains = ((x > this.left) && (x < this.right) && 645 (y > this.bottom) && (y < this.top)); 646 return contains; 647 }, 648 /** 649 * Method: intersectsBounds 650 * Determine whether the target bounds intersects this bounds. Bounds are 651 * considered intersecting if any of their edges intersect or if one 652 * bounds contains the other. 653 * 654 * Parameters: 655 * bounds - {<ZOO.Bounds>} The target bounds. 656 * inclusive - {Boolean} Treat coincident borders as intersecting. Default 657 * is true. If false, bounds that do not overlap but only touch at the 658 * border will not be considered as intersecting. 659 * 660 * Returns: 661 * {Boolean} The passed-in bounds object intersects this bounds. 662 */ 663 intersectsBounds:function(bounds, inclusive) { 664 if (inclusive == null) 665 inclusive = true; 666 var intersects = false; 667 var mightTouch = ( 668 this.left == bounds.right || 669 this.right == bounds.left || 670 this.top == bounds.bottom || 671 this.bottom == bounds.top 672 ); 673 if (inclusive || !mightTouch) { 674 var inBottom = ( 675 ((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) || 676 ((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top)) 677 ); 678 var inTop = ( 679 ((bounds.top >= this.bottom) && (bounds.top <= this.top)) || 680 ((this.top > bounds.bottom) && (this.top < bounds.top)) 681 ); 682 var inLeft = ( 683 ((bounds.left >= this.left) && (bounds.left <= this.right)) || 684 ((this.left >= bounds.left) && (this.left <= bounds.right)) 685 ); 686 var inRight = ( 687 ((bounds.right >= this.left) && (bounds.right <= this.right)) || 688 ((this.right >= bounds.left) && (this.right <= bounds.right)) 689 ); 690 intersects = ((inBottom || inTop) && (inLeft || inRight)); 691 } 692 return intersects; 693 }, 694 /** 695 * Method: containsBounds 696 * Determine whether the target bounds is contained within this bounds. 697 * 698 * bounds - {<ZOO.Bounds>} The target bounds. 699 * partial - {Boolean} If any of the target corners is within this bounds 700 * consider the bounds contained. Default is false. If true, the 701 * entire target bounds must be contained within this bounds. 702 * inclusive - {Boolean} Treat shared edges as contained. Default is 703 * true. 704 * 705 * Returns: 706 * {Boolean} The passed-in bounds object is contained within this bounds. 707 */ 708 containsBounds:function(bounds, partial, inclusive) { 709 if (partial == null) 710 partial = false; 711 if (inclusive == null) 712 inclusive = true; 713 var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive); 714 var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive); 715 var topLeft = this.contains(bounds.left, bounds.top, inclusive); 716 var topRight = this.contains(bounds.right, bounds.top, inclusive); 717 return (partial) ? (bottomLeft || bottomRight || topLeft || topRight) 718 : (bottomLeft && bottomRight && topLeft && topRight); 719 }, 720 CLASS_NAME: 'ZOO.Bounds' 721 }); 722 723 /** 724 * Class: ZOO.Projection 725 * Class for coordinate transforms between coordinate systems. 726 * Depends on the zoo-proj4js library. zoo-proj4js library 727 * is loaded by the ZOO Kernel with zoo-api. 728 */ 729 ZOO.Projection = ZOO.Class({ 730 /** 731 * Property: proj 732 * {Object} Proj4js.Proj instance. 733 */ 734 proj: null, 735 /** 736 * Property: projCode 737 * {String} 738 */ 739 projCode: null, 740 /** 741 * Constructor: ZOO.Projection 742 * This class offers several methods for interacting with a wrapped 743 * zoo-pro4js projection object. 744 * 745 * Parameters: 746 * projCode - {String} A string identifying the Well Known Identifier for 747 * the projection. 748 * options - {Object} An optional object to set additional properties. 749 * 750 * Returns: 751 * {<ZOO.Projection>} A projection object. 752 */ 753 initialize: function(projCode, options) { 754 ZOO.extend(this, options); 755 this.projCode = projCode; 756 if (Proj4js) { 757 this.proj = new Proj4js.Proj(projCode); 758 } 759 }, 760 /** 761 * Method: getCode 762 * Get the string SRS code. 763 * 764 * Returns: 765 * {String} The SRS code. 766 */ 767 getCode: function() { 768 return this.proj ? this.proj.srsCode : this.projCode; 769 }, 770 /** 771 * Method: getUnits 772 * Get the units string for the projection -- returns null if 773 * zoo-proj4js is not available. 774 * 775 * Returns: 776 * {String} The units abbreviation. 777 */ 778 getUnits: function() { 779 return this.proj ? this.proj.units : null; 780 }, 781 /** 782 * Method: toString 783 * Convert projection to string (getCode wrapper). 784 * 785 * Returns: 786 * {String} The projection code. 787 */ 788 toString: function() { 789 return this.getCode(); 790 }, 791 /** 792 * Method: equals 793 * Test equality of two projection instances. Determines equality based 794 * soley on the projection code. 795 * 796 * Returns: 797 * {Boolean} The two projections are equivalent. 798 */ 799 equals: function(projection) { 800 if (projection && projection.getCode) 801 return this.getCode() == projection.getCode(); 802 else 803 return false; 804 }, 805 /* Method: destroy 806 * Destroy projection object. 807 */ 808 destroy: function() { 809 this.proj = null; 810 this.projCode = null; 811 }, 812 CLASS_NAME: 'ZOO.Projection' 813 }); 814 /** 815 * Method: transform 816 * Transform a point coordinate from one projection to another. Note that 817 * the input point is transformed in place. 818 * 819 * Parameters: 820 * point - {{ZOO.Geometry.Point> | Object} An object with x and y 821 * properties representing coordinates in those dimensions. 822 * sourceProj - {ZOO.Projection} Source map coordinate system 823 * destProj - {ZOO.Projection} Destination map coordinate system 824 * 825 * Returns: 826 * point - {object} A transformed coordinate. The original point is modified. 827 */ 828 ZOO.Projection.transform = function(point, source, dest) { 829 if (source.proj && dest.proj) 830 point = Proj4js.transform(source.proj, dest.proj, point); 831 return point; 832 }; 833 834 /** 835 * Class: ZOO.Format 836 * Base class for format reading/writing a variety of formats. Subclasses 837 * of ZOO.Format are expected to have read and write methods. 838 */ 839 ZOO.Format = ZOO.Class({ 840 /** 841 * Property: options 842 * {Object} A reference to options passed to the constructor. 843 */ 844 options:null, 845 /** 846 * Property: externalProjection 847 * {<ZOO.Projection>} When passed a externalProjection and 848 * internalProjection, the format will reproject the geometries it 849 * reads or writes. The externalProjection is the projection used by 850 * the content which is passed into read or which comes out of write. 851 * In order to reproject, a projection transformation function for the 852 * specified projections must be available. This support is provided 853 * via zoo-proj4js. 854 */ 855 externalProjection: null, 856 /** 857 * Property: internalProjection 858 * {<ZOO.Projection>} When passed a externalProjection and 859 * internalProjection, the format will reproject the geometries it 860 * reads or writes. The internalProjection is the projection used by 861 * the geometries which are returned by read or which are passed into 862 * write. In order to reproject, a projection transformation function 863 * for the specified projections must be available. This support is 864 * provided via zoo-proj4js. 865 */ 866 internalProjection: null, 867 /** 868 * Property: data 869 * {Object} When <keepData> is true, this is the parsed string sent to 870 * <read>. 871 */ 872 data: null, 873 /** 874 * Property: keepData 875 * {Object} Maintain a reference (<data>) to the most recently read data. 876 * Default is false. 877 */ 878 keepData: false, 879 /** 880 * Constructor: ZOO.Format 881 * Instances of this class are not useful. See one of the subclasses. 882 * 883 * Parameters: 884 * options - {Object} An optional object with properties to set on the 885 * format 886 * 887 * Valid options: 888 * keepData - {Boolean} If true, upon <read>, the data property will be 889 * set to the parsed object (e.g. the json or xml object). 890 * 891 * Returns: 892 * An instance of ZOO.Format 893 */ 894 initialize: function(options) { 895 ZOO.extend(this, options); 896 this.options = options; 897 }, 898 /** 899 * Method: destroy 900 * Clean up. 901 */ 902 destroy: function() { 903 }, 904 /** 905 * Method: read 906 * Read data from a string, and return an object whose type depends on the 907 * subclass. 908 * 909 * Parameters: 910 * data - {string} Data to read/parse. 911 * 912 * Returns: 913 * Depends on the subclass 914 */ 915 read: function(data) { 916 }, 917 /** 918 * Method: write 919 * Accept an object, and return a string. 920 * 921 * Parameters: 922 * object - {Object} Object to be serialized 923 * 924 * Returns: 925 * {String} A string representation of the object. 926 */ 927 write: function(data) { 928 }, 929 CLASS_NAME: 'ZOO.Format' 930 }); 931 /** 932 * Class: ZOO.Format.WKT 933 * Class for reading and writing Well-Known Text. Create a new instance 934 * with the <ZOO.Format.WKT> constructor. 935 * 936 * Inherits from: 937 * - <ZOO.Format> 938 */ 939 ZOO.Format.WKT = ZOO.Class(ZOO.Format, { 940 /** 941 * Constructor: ZOO.Format.WKT 942 * Create a new parser for WKT 943 * 944 * Parameters: 945 * options - {Object} An optional object whose properties will be set on 946 * this instance 947 * 948 * Returns: 949 * {<ZOO.Format.WKT>} A new WKT parser. 950 */ 951 initialize: function(options) { 952 this.regExes = { 953 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/, 954 'spaces': /\s+/, 955 'parenComma': /\)\s*,\s*\(/, 956 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here 957 'trimParens': /^\s*\(?(.*?)\)?\s*$/ 958 }; 959 ZOO.Format.prototype.initialize.apply(this, [options]); 960 }, 961 /** 962 * Method: read 963 * Deserialize a WKT string and return a vector feature or an 964 * array of vector features. Supports WKT for POINT, 965 * MULTIPOINT, LINESTRING, MULTILINESTRING, POLYGON, 966 * MULTIPOLYGON, and GEOMETRYCOLLECTION. 967 * 968 * Parameters: 969 * wkt - {String} A WKT string 970 * 971 * Returns: 972 * {<ZOO.Feature.Vector>|Array} A feature or array of features for 973 * GEOMETRYCOLLECTION WKT. 974 */ 975 read: function(wkt) { 976 var features, type, str; 977 var matches = this.regExes.typeStr.exec(wkt); 978 if(matches) { 979 type = matches[1].toLowerCase(); 980 str = matches[2]; 981 if(this.parse[type]) { 982 features = this.parse[type].apply(this, [str]); 983 } 984 if (this.internalProjection && this.externalProjection) { 985 if (features && 986 features.CLASS_NAME == "ZOO.Feature") { 987 features.geometry.transform(this.externalProjection, 988 this.internalProjection); 989 } else if (features && 990 type != "geometrycollection" && 991 typeof features == "object") { 992 for (var i=0, len=features.length; i<len; i++) { 993 var component = features[i]; 994 component.geometry.transform(this.externalProjection, 995 this.internalProjection); 996 } 997 } 998 } 999 } 1000 return features; 1001 }, 1002 /** 1003 * Method: write 1004 * Serialize a feature or array of features into a WKT string. 1005 * 1006 * Parameters: 1007 * features - {<ZOO.Feature.Vector>|Array} A feature or array of 1008 * features 1009 * 1010 * Returns: 1011 * {String} The WKT string representation of the input geometries 1012 */ 1013 write: function(features) { 1014 var collection, geometry, type, data, isCollection; 1015 if(features.constructor == Array) { 1016 collection = features; 1017 isCollection = true; 1018 } else { 1019 collection = [features]; 1020 isCollection = false; 1021 } 1022 var pieces = []; 1023 if(isCollection) 1024 pieces.push('GEOMETRYCOLLECTION('); 1025 for(var i=0, len=collection.length; i<len; ++i) { 1026 if(isCollection && i>0) 1027 pieces.push(','); 1028 geometry = collection[i].geometry; 1029 type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); 1030 if(!this.extract[type]) 1031 return null; 1032 if (this.internalProjection && this.externalProjection) { 1033 geometry = geometry.clone(); 1034 geometry.transform(this.internalProjection, 1035 this.externalProjection); 1036 } 1037 data = this.extract[type].apply(this, [geometry]); 1038 pieces.push(type.toUpperCase() + '(' + data + ')'); 1039 } 1040 if(isCollection) 1041 pieces.push(')'); 1042 return pieces.join(''); 1043 }, 1044 /** 1045 * Property: extract 1046 * Object with properties corresponding to the geometry types. 1047 * Property values are functions that do the actual data extraction. 1048 */ 1049 extract: { 1050 /** 1051 * Return a space delimited string of point coordinates. 1052 * @param {<ZOO.Geometry.Point>} point 1053 * @returns {String} A string of coordinates representing the point 1054 */ 1055 'point': function(point) { 1056 return point.x + ' ' + point.y; 1057 }, 1058 /** 1059 * Return a comma delimited string of point coordinates from a multipoint. 1060 * @param {<ZOO.Geometry.MultiPoint>} multipoint 1061 * @returns {String} A string of point coordinate strings representing 1062 * the multipoint 1063 */ 1064 'multipoint': function(multipoint) { 1065 var array = []; 1066 for(var i=0, len=multipoint.components.length; i<len; ++i) { 1067 array.push(this.extract.point.apply(this, [multipoint.components[i]])); 1068 } 1069 return array.join(','); 1070 }, 1071 /** 1072 * Return a comma delimited string of point coordinates from a line. 1073 * @param {<ZOO.Geometry.LineString>} linestring 1074 * @returns {String} A string of point coordinate strings representing 1075 * the linestring 1076 */ 1077 'linestring': function(linestring) { 1078 var array = []; 1079 for(var i=0, len=linestring.components.length; i<len; ++i) { 1080 array.push(this.extract.point.apply(this, [linestring.components[i]])); 1081 } 1082 return array.join(','); 1083 }, 1084 /** 1085 * Return a comma delimited string of linestring strings from a multilinestring. 1086 * @param {<ZOO.Geometry.MultiLineString>} multilinestring 1087 * @returns {String} A string of of linestring strings representing 1088 * the multilinestring 1089 */ 1090 'multilinestring': function(multilinestring) { 1091 var array = []; 1092 for(var i=0, len=multilinestring.components.length; i<len; ++i) { 1093 array.push('(' + 1094 this.extract.linestring.apply(this, [multilinestring.components[i]]) + 1095 ')'); 1096 } 1097 return array.join(','); 1098 }, 1099 /** 1100 * Return a comma delimited string of linear ring arrays from a polygon. 1101 * @param {<ZOO.Geometry.Polygon>} polygon 1102 * @returns {String} An array of linear ring arrays representing the polygon 1103 */ 1104 'polygon': function(polygon) { 1105 var array = []; 1106 for(var i=0, len=polygon.components.length; i<len; ++i) { 1107 array.push('(' + 1108 this.extract.linestring.apply(this, [polygon.components[i]]) + 1109 ')'); 1110 } 1111 return array.join(','); 1112 }, 1113 /** 1114 * Return an array of polygon arrays from a multipolygon. 1115 * @param {<ZOO.Geometry.MultiPolygon>} multipolygon 1116 * @returns {Array} An array of polygon arrays representing 1117 * the multipolygon 1118 */ 1119 'multipolygon': function(multipolygon) { 1120 var array = []; 1121 for(var i=0, len=multipolygon.components.length; i<len; ++i) { 1122 array.push('(' + 1123 this.extract.polygon.apply(this, [multipolygon.components[i]]) + 1124 ')'); 1125 } 1126 return array.join(','); 1127 } 1128 }, 1129 /** 1130 * Property: parse 1131 * Object with properties corresponding to the geometry types. 1132 * Property values are functions that do the actual parsing. 1133 */ 1134 parse: { 1135 /** 1136 * Method: parse.point 1137 * Return point feature given a point WKT fragment. 1138 * 1139 * Parameters: 1140 * str - {String} A WKT fragment representing the point 1141 * Returns: 1142 * {<ZOO.Feature>} A point feature 1143 */ 1144 'point': function(str) { 1145 var coords = ZOO.String.trim(str).split(this.regExes.spaces); 1146 return new ZOO.Feature( 1147 new ZOO.Geometry.Point(coords[0], coords[1]) 1148 ); 1149 }, 1150 /** 1151 * Method: parse.multipoint 1152 * Return a multipoint feature given a multipoint WKT fragment. 1153 * 1154 * Parameters: 1155 * str - {String} A WKT fragment representing the multipoint 1156 * 1157 * Returns: 1158 * {<ZOO.Feature>} A multipoint feature 1159 */ 1160 'multipoint': function(str) { 1161 var points = ZOO.String.trim(str).split(','); 1162 var components = []; 1163 for(var i=0, len=points.length; i<len; ++i) { 1164 components.push(this.parse.point.apply(this, [points[i]]).geometry); 1165 } 1166 return new ZOO.Feature( 1167 new ZOO.Geometry.MultiPoint(components) 1168 ); 1169 }, 1170 /** 1171 * Method: parse.linestring 1172 * Return a linestring feature given a linestring WKT fragment. 1173 * 1174 * Parameters: 1175 * str - {String} A WKT fragment representing the linestring 1176 * 1177 * Returns: 1178 * {<ZOO.Feature>} A linestring feature 1179 */ 1180 'linestring': function(str) { 1181 var points = ZOO.String.trim(str).split(','); 1182 var components = []; 1183 for(var i=0, len=points.length; i<len; ++i) { 1184 components.push(this.parse.point.apply(this, [points[i]]).geometry); 1185 } 1186 return new ZOO.Feature( 1187 new ZOO.Geometry.LineString(components) 1188 ); 1189 }, 1190 /** 1191 * Method: parse.multilinestring 1192 * Return a multilinestring feature given a multilinestring WKT fragment. 1193 * 1194 * Parameters: 1195 * str - {String} A WKT fragment representing the multilinestring 1196 * 1197 * Returns: 1198 * {<ZOO.Feature>} A multilinestring feature 1199 */ 1200 'multilinestring': function(str) { 1201 var line; 1202 var lines = ZOO.String.trim(str).split(this.regExes.parenComma); 1203 var components = []; 1204 for(var i=0, len=lines.length; i<len; ++i) { 1205 line = lines[i].replace(this.regExes.trimParens, '$1'); 1206 components.push(this.parse.linestring.apply(this, [line]).geometry); 1207 } 1208 return new ZOO.Feature( 1209 new ZOO.Geometry.MultiLineString(components) 1210 ); 1211 }, 1212 /** 1213 * Method: parse.polygon 1214 * Return a polygon feature given a polygon WKT fragment. 1215 * 1216 * Parameters: 1217 * str - {String} A WKT fragment representing the polygon 1218 * 1219 * Returns: 1220 * {<ZOO.Feature>} A polygon feature 1221 */ 1222 'polygon': function(str) { 1223 var ring, linestring, linearring; 1224 var rings = ZOO.String.trim(str).split(this.regExes.parenComma); 1225 var components = []; 1226 for(var i=0, len=rings.length; i<len; ++i) { 1227 ring = rings[i].replace(this.regExes.trimParens, '$1'); 1228 linestring = this.parse.linestring.apply(this, [ring]).geometry; 1229 linearring = new ZOO.Geometry.LinearRing(linestring.components); 1230 components.push(linearring); 1231 } 1232 return new ZOO.Feature( 1233 new ZOO.Geometry.Polygon(components) 1234 ); 1235 }, 1236 /** 1237 * Method: parse.multipolygon 1238 * Return a multipolygon feature given a multipolygon WKT fragment. 1239 * 1240 * Parameters: 1241 * str - {String} A WKT fragment representing the multipolygon 1242 * 1243 * Returns: 1244 * {<ZOO.Feature>} A multipolygon feature 1245 */ 1246 'multipolygon': function(str) { 1247 var polygon; 1248 var polygons = ZOO.String.trim(str).split(this.regExes.doubleParenComma); 1249 var components = []; 1250 for(var i=0, len=polygons.length; i<len; ++i) { 1251 polygon = polygons[i].replace(this.regExes.trimParens, '$1'); 1252 components.push(this.parse.polygon.apply(this, [polygon]).geometry); 1253 } 1254 return new ZOO.Feature( 1255 new ZOO.Geometry.MultiPolygon(components) 1256 ); 1257 }, 1258 /** 1259 * Method: parse.geometrycollection 1260 * Return an array of features given a geometrycollection WKT fragment. 1261 * 1262 * Parameters: 1263 * str - {String} A WKT fragment representing the geometrycollection 1264 * 1265 * Returns: 1266 * {Array} An array of ZOO.Feature 1267 */ 1268 'geometrycollection': function(str) { 1269 // separate components of the collection with | 1270 str = str.replace(/,\s*([A-Za-z])/g, '|$1'); 1271 var wktArray = ZOO.String.trim(str).split('|'); 1272 var components = []; 1273 for(var i=0, len=wktArray.length; i<len; ++i) { 1274 components.push(ZOO.Format.WKT.prototype.read.apply(this,[wktArray[i]])); 1275 } 1276 return components; 1277 } 1278 }, 1279 CLASS_NAME: 'ZOO.Format.WKT' 1280 }); 1281 /** 1282 * Class: ZOO.Format.JSON 1283 * A parser to read/write JSON safely. Create a new instance with the 1284 * <ZOO.Format.JSON> constructor. 1285 * 1286 * Inherits from: 1287 * - <ZOO.Format> 1288 */ 1289 ZOO.Format.JSON = ZOO.Class(ZOO.Format, { 1290 /** 1291 * Property: indent 1292 * {String} For "pretty" printing, the indent string will be used once for 1293 * each indentation level. 1294 */ 1295 indent: " ", 1296 /** 1297 * Property: space 1298 * {String} For "pretty" printing, the space string will be used after 1299 * the ":" separating a name/value pair. 1300 */ 1301 space: " ", 1302 /** 1303 * Property: newline 1304 * {String} For "pretty" printing, the newline string will be used at the 1305 * end of each name/value pair or array item. 1306 */ 1307 newline: "\n", 1308 /** 1309 * Property: level 1310 * {Integer} For "pretty" printing, this is incremented/decremented during 1311 * serialization. 1312 */ 1313 level: 0, 1314 /** 1315 * Property: pretty 1316 * {Boolean} Serialize with extra whitespace for structure. This is set 1317 * by the <write> method. 1318 */ 1319 pretty: false, 1320 /** 1321 * Constructor: ZOO.Format.JSON 1322 * Create a new parser for JSON. 1323 * 1324 * Parameters: 1325 * options - {Object} An optional object whose properties will be set on 1326 * this instance. 1327 */ 1328 initialize: function(options) { 1329 ZOO.Format.prototype.initialize.apply(this, [options]); 1330 }, 1331 /** 1332 * Method: read 1333 * Deserialize a json string. 1334 * 1335 * Parameters: 1336 * json - {String} A JSON string 1337 * filter - {Function} A function which will be called for every key and 1338 * value at every level of the final result. Each value will be 1339 * replaced by the result of the filter function. This can be used to 1340 * reform generic objects into instances of classes, or to transform 1341 * date strings into Date objects. 1342 * 1343 * Returns: 1344 * {Object} An object, array, string, or number . 1345 */ 1346 read: function(json, filter) { 1347 /** 1348 * Parsing happens in three stages. In the first stage, we run the text 1349 * against a regular expression which looks for non-JSON 1350 * characters. We are especially concerned with '()' and 'new' 1351 * because they can cause invocation, and '=' because it can cause 1352 * mutation. But just to be safe, we will reject all unexpected 1353 * characters. 1354 */ 1355 try { 1356 if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, '@'). 1357 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). 1358 replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 1359 /** 1360 * In the second stage we use the eval function to compile the 1361 * text into a JavaScript structure. The '{' operator is 1362 * subject to a syntactic ambiguity in JavaScript - it can 1363 * begin a block or an object literal. We wrap the text in 1364 * parens to eliminate the ambiguity. 1365 */ 1366 var object = eval('(' + json + ')'); 1367 /** 1368 * In the optional third stage, we recursively walk the new 1369 * structure, passing each name/value pair to a filter 1370 * function for possible transformation. 1371 */ 1372 if(typeof filter === 'function') { 1373 function walk(k, v) { 1374 if(v && typeof v === 'object') { 1375 for(var i in v) { 1376 if(v.hasOwnProperty(i)) { 1377 v[i] = walk(i, v[i]); 1378 } 1379 } 1380 } 1381 return filter(k, v); 1382 } 1383 object = walk('', object); 1384 } 1385 if(this.keepData) { 1386 this.data = object; 1387 } 1388 return object; 1389 } 1390 } catch(e) { 1391 // Fall through if the regexp test fails. 1392 } 1393 return null; 1394 }, 1395 /** 1396 * Method: write 1397 * Serialize an object into a JSON string. 1398 * 1399 * Parameters: 1400 * value - {String} The object, array, string, number, boolean or date 1401 * to be serialized. 1402 * pretty - {Boolean} Structure the output with newlines and indentation. 1403 * Default is false. 1404 * 1405 * Returns: 1406 * {String} The JSON string representation of the input value. 1407 */ 1408 write: function(value, pretty) { 1409 this.pretty = !!pretty; 1410 var json = null; 1411 var type = typeof value; 1412 if(this.serialize[type]) { 1413 try { 1414 json = this.serialize[type].apply(this, [value]); 1415 } catch(err) { 1416 //OpenLayers.Console.error("Trouble serializing: " + err); 1417 } 1418 } 1419 return json; 1420 }, 1421 /** 1422 * Method: writeIndent 1423 * Output an indentation string depending on the indentation level. 1424 * 1425 * Returns: 1426 * {String} An appropriate indentation string. 1427 */ 1428 writeIndent: function() { 1429 var pieces = []; 1430 if(this.pretty) { 1431 for(var i=0; i<this.level; ++i) { 1432 pieces.push(this.indent); 1433 } 1434 } 1435 return pieces.join(''); 1436 }, 1437 /** 1438 * Method: writeNewline 1439 * Output a string representing a newline if in pretty printing mode. 1440 * 1441 * Returns: 1442 * {String} A string representing a new line. 1443 */ 1444 writeNewline: function() { 1445 return (this.pretty) ? this.newline : ''; 1446 }, 1447 /** 1448 * Method: writeSpace 1449 * Output a string representing a space if in pretty printing mode. 1450 * 1451 * Returns: 1452 * {String} A space. 1453 */ 1454 writeSpace: function() { 1455 return (this.pretty) ? this.space : ''; 1456 }, 1457 /** 1458 * Property: serialize 1459 * Object with properties corresponding to the serializable data types. 1460 * Property values are functions that do the actual serializing. 1461 */ 1462 serialize: { 1463 /** 1464 * Method: serialize.object 1465 * Transform an object into a JSON string. 1466 * 1467 * Parameters: 1468 * object - {Object} The object to be serialized. 1469 * 1470 * Returns: 1471 * {String} A JSON string representing the object. 1472 */ 1473 'object': function(object) { 1474 // three special objects that we want to treat differently 1475 if(object == null) 1476 return "null"; 1477 if(object.constructor == Date) 1478 return this.serialize.date.apply(this, [object]); 1479 if(object.constructor == Array) 1480 return this.serialize.array.apply(this, [object]); 1481 var pieces = ['{']; 1482 this.level += 1; 1483 var key, keyJSON, valueJSON; 1484 1485 var addComma = false; 1486 for(key in object) { 1487 if(object.hasOwnProperty(key)) { 1488 // recursive calls need to allow for sub-classing 1489 keyJSON = ZOO.Format.JSON.prototype.write.apply(this, 1490 [key, this.pretty]); 1491 valueJSON = ZOO.Format.JSON.prototype.write.apply(this, 1492 [object[key], this.pretty]); 1493 if(keyJSON != null && valueJSON != null) { 1494 if(addComma) 1495 pieces.push(','); 1496 pieces.push(this.writeNewline(), this.writeIndent(), 1497 keyJSON, ':', this.writeSpace(), valueJSON); 1498 addComma = true; 1499 } 1500 } 1501 } 1502 this.level -= 1; 1503 pieces.push(this.writeNewline(), this.writeIndent(), '}'); 1504 return pieces.join(''); 1505 }, 1506 /** 1507 * Method: serialize.array 1508 * Transform an array into a JSON string. 1509 * 1510 * Parameters: 1511 * array - {Array} The array to be serialized 1512 * 1513 * Returns: 1514 * {String} A JSON string representing the array. 1515 */ 1516 'array': function(array) { 1517 var json; 1518 var pieces = ['[']; 1519 this.level += 1; 1520 for(var i=0, len=array.length; i<len; ++i) { 1521 // recursive calls need to allow for sub-classing 1522 json = ZOO.Format.JSON.prototype.write.apply(this, 1523 [array[i], this.pretty]); 1524 if(json != null) { 1525 if(i > 0) 1526 pieces.push(','); 1527 pieces.push(this.writeNewline(), this.writeIndent(), json); 1528 } 1529 } 1530 this.level -= 1; 1531 pieces.push(this.writeNewline(), this.writeIndent(), ']'); 1532 return pieces.join(''); 1533 }, 1534 /** 1535 * Method: serialize.string 1536 * Transform a string into a JSON string. 1537 * 1538 * Parameters: 1539 * string - {String} The string to be serialized 1540 * 1541 * Returns: 1542 * {String} A JSON string representing the string. 1543 */ 1544 'string': function(string) { 1545 var m = { 1546 '\b': '\\b', 1547 '\t': '\\t', 1548 '\n': '\\n', 1549 '\f': '\\f', 1550 '\r': '\\r', 1551 '"' : '\\"', 1552 '\\': '\\\\' 1553 }; 1554 if(/["\\\x00-\x1f]/.test(string)) { 1555 return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) { 1556 var c = m[b]; 1557 if(c) 1558 return c; 1559 c = b.charCodeAt(); 1560 return '\\u00' + 1561 Math.floor(c / 16).toString(16) + 1562 (c % 16).toString(16); 1563 }) + '"'; 1564 } 1565 return '"' + string + '"'; 1566 }, 1567 /** 1568 * Method: serialize.number 1569 * Transform a number into a JSON string. 1570 * 1571 * Parameters: 1572 * number - {Number} The number to be serialized. 1573 * 1574 * Returns: 1575 * {String} A JSON string representing the number. 1576 */ 1577 'number': function(number) { 1578 return isFinite(number) ? String(number) : "null"; 1579 }, 1580 /** 1581 * Method: serialize.boolean 1582 * Transform a boolean into a JSON string. 1583 * 1584 * Parameters: 1585 * bool - {Boolean} The boolean to be serialized. 1586 * 1587 * Returns: 1588 * {String} A JSON string representing the boolean. 1589 */ 1590 'boolean': function(bool) { 1591 return String(bool); 1592 }, 1593 /** 1594 * Method: serialize.date 1595 * Transform a date into a JSON string. 1596 * 1597 * Parameters: 1598 * date - {Date} The date to be serialized. 1599 * 1600 * Returns: 1601 * {String} A JSON string representing the date. 1602 */ 1603 'date': function(date) { 1604 function format(number) { 1605 // Format integers to have at least two digits. 1606 return (number < 10) ? '0' + number : number; 1607 } 1608 return '"' + date.getFullYear() + '-' + 1609 format(date.getMonth() + 1) + '-' + 1610 format(date.getDate()) + 'T' + 1611 format(date.getHours()) + ':' + 1612 format(date.getMinutes()) + ':' + 1613 format(date.getSeconds()) + '"'; 1614 } 1615 }, 1616 CLASS_NAME: 'ZOO.Format.JSON' 1617 }); 1618 /** 1619 * Class: ZOO.Format.GeoJSON 1620 * Read and write GeoJSON. Create a new parser with the 1621 * <ZOO.Format.GeoJSON> constructor. 1622 * 1623 * Inherits from: 1624 * - <ZOO.Format.JSON> 1625 */ 1626 ZOO.Format.GeoJSON = ZOO.Class(ZOO.Format.JSON, { 1627 /** 1628 * Constructor: ZOO.Format.GeoJSON 1629 * Create a new parser for GeoJSON. 1630 * 1631 * Parameters: 1632 * options - {Object} An optional object whose properties will be set on 1633 * this instance. 1634 */ 1635 initialize: function(options) { 1636 ZOO.Format.JSON.prototype.initialize.apply(this, [options]); 1637 }, 1638 /** 1639 * Method: read 1640 * Deserialize a GeoJSON string. 1641 * 1642 * Parameters: 1643 * json - {String} A GeoJSON string 1644 * type - {String} Optional string that determines the structure of 1645 * the output. Supported values are "Geometry", "Feature", and 1646 * "FeatureCollection". If absent or null, a default of 1647 * "FeatureCollection" is assumed. 1648 * filter - {Function} A function which will be called for every key and 1649 * value at every level of the final result. Each value will be 1650 * replaced by the result of the filter function. This can be used to 1651 * reform generic objects into instances of classes, or to transform 1652 * date strings into Date objects. 1653 * 1654 * Returns: 1655 * {Object} The return depends on the value of the type argument. If type 1656 * is "FeatureCollection" (the default), the return will be an array 1657 * of <ZOO.Feature>. If type is "Geometry", the input json 1658 * must represent a single geometry, and the return will be an 1659 * <ZOO.Geometry>. If type is "Feature", the input json must 1660 * represent a single feature, and the return will be an 1661 * <ZOO.Feature>. 1662 */ 1663 read: function(json, type, filter) { 1664 type = (type) ? type : "FeatureCollection"; 1665 var results = null; 1666 var obj = null; 1667 if (typeof json == "string") 1668 obj = ZOO.Format.JSON.prototype.read.apply(this,[json, filter]); 1669 else 1670 obj = json; 1671 if(!obj) { 1672 //ZOO.Console.error("Bad JSON: " + json); 1673 } else if(typeof(obj.type) != "string") { 1674 //ZOO.Console.error("Bad GeoJSON - no type: " + json); 1675 } else if(this.isValidType(obj, type)) { 1676 switch(type) { 1677 case "Geometry": 1678 try { 1679 results = this.parseGeometry(obj); 1680 } catch(err) { 1681 //ZOO.Console.error(err); 1682 } 1683 break; 1684 case "Feature": 1685 try { 1686 results = this.parseFeature(obj); 1687 results.type = "Feature"; 1688 } catch(err) { 1689 //ZOO.Console.error(err); 1690 } 1691 break; 1692 case "FeatureCollection": 1693 // for type FeatureCollection, we allow input to be any type 1694 results = []; 1695 switch(obj.type) { 1696 case "Feature": 1697 try { 1698 results.push(this.parseFeature(obj)); 1699 } catch(err) { 1700 results = null; 1701 //ZOO.Console.error(err); 1702 } 1703 break; 1704 case "FeatureCollection": 1705 for(var i=0, len=obj.features.length; i<len; ++i) { 1706 try { 1707 results.push(this.parseFeature(obj.features[i])); 1708 } catch(err) { 1709 results = null; 1710 //ZOO.Console.error(err); 1711 } 1712 } 1713 break; 1714 default: 1715 try { 1716 var geom = this.parseGeometry(obj); 1717 results.push(new ZOO.Feature(geom)); 1718 } catch(err) { 1719 results = null; 1720 //ZOO.Console.error(err); 1721 } 1722 } 1723 break; 1724 } 1725 } 1726 return results; 1727 }, 1728 /** 1729 * Method: isValidType 1730 * Check if a GeoJSON object is a valid representative of the given type. 1731 * 1732 * Returns: 1733 * {Boolean} The object is valid GeoJSON object of the given type. 1734 */ 1735 isValidType: function(obj, type) { 1736 var valid = false; 1737 switch(type) { 1738 case "Geometry": 1739 if(ZOO.indexOf( 1740 ["Point", "MultiPoint", "LineString", "MultiLineString", 1741 "Polygon", "MultiPolygon", "Box", "GeometryCollection"], 1742 obj.type) == -1) { 1743 // unsupported geometry type 1744 //ZOO.Console.error("Unsupported geometry type: " +obj.type); 1745 } else { 1746 valid = true; 1747 } 1748 break; 1749 case "FeatureCollection": 1750 // allow for any type to be converted to a feature collection 1751 valid = true; 1752 break; 1753 default: 1754 // for Feature types must match 1755 if(obj.type == type) { 1756 valid = true; 1757 } else { 1758 //ZOO.Console.error("Cannot convert types from " +obj.type + " to " + type); 1759 } 1760 } 1761 return valid; 1762 }, 1763 /** 1764 * Method: parseFeature 1765 * Convert a feature object from GeoJSON into an 1766 * <ZOO.Feature>. 1767 * 1768 * Parameters: 1769 * obj - {Object} An object created from a GeoJSON object 1770 * 1771 * Returns: 1772 * {<ZOO.Feature>} A feature. 1773 */ 1774 parseFeature: function(obj) { 1775 var feature, geometry, attributes, bbox; 1776 attributes = (obj.properties) ? obj.properties : {}; 1777 bbox = (obj.geometry && obj.geometry.bbox) || obj.bbox; 1778 try { 1779 geometry = this.parseGeometry(obj.geometry); 1780 } catch(err) { 1781 // deal with bad geometries 1782 throw err; 1783 } 1784 feature = new ZOO.Feature(geometry, attributes); 1785 if(bbox) 1786 feature.bounds = ZOO.Bounds.fromArray(bbox); 1787 if(obj.id) 1788 feature.fid = obj.id; 1789 return feature; 1790 }, 1791 /** 1792 * Method: parseGeometry 1793 * Convert a geometry object from GeoJSON into an <ZOO.Geometry>. 1794 * 1795 * Parameters: 1796 * obj - {Object} An object created from a GeoJSON object 1797 * 1798 * Returns: 1799 * {<ZOO.Geometry>} A geometry. 1800 */ 1801 parseGeometry: function(obj) { 1802 if (obj == null) 1803 return null; 1804 var geometry, collection = false; 1805 if(obj.type == "GeometryCollection") { 1806 if(!(obj.geometries instanceof Array)) { 1807 throw "GeometryCollection must have geometries array: " + obj; 1808 } 1809 var numGeom = obj.geometries.length; 1810 var components = new Array(numGeom); 1811 for(var i=0; i<numGeom; ++i) { 1812 components[i] = this.parseGeometry.apply( 1813 this, [obj.geometries[i]] 1814 ); 1815 } 1816 geometry = new ZOO.Geometry.Collection(components); 1817 collection = true; 1818 } else { 1819 if(!(obj.coordinates instanceof Array)) { 1820 throw "Geometry must have coordinates array: " + obj; 1821 } 1822 if(!this.parseCoords[obj.type.toLowerCase()]) { 1823 throw "Unsupported geometry type: " + obj.type; 1824 } 1825 try { 1826 geometry = this.parseCoords[obj.type.toLowerCase()].apply( 1827 this, [obj.coordinates] 1828 ); 1829 } catch(err) { 1830 // deal with bad coordinates 1831 throw err; 1832 } 1833 } 1834 // We don't reproject collections because the children are reprojected 1835 // for us when they are created. 1836 if (this.internalProjection && this.externalProjection && !collection) { 1837 geometry.transform(this.externalProjection, 1838 this.internalProjection); 1839 } 1840 return geometry; 1841 }, 1842 /** 1843 * Property: parseCoords 1844 * Object with properties corresponding to the GeoJSON geometry types. 1845 * Property values are functions that do the actual parsing. 1846 */ 1847 parseCoords: { 1848 /** 1849 * Method: parseCoords.point 1850 * Convert a coordinate array from GeoJSON into an 1851 * <ZOO.Geometry.Point>. 1852 * 1853 * Parameters: 1854 * array - {Object} The coordinates array from the GeoJSON fragment. 1855 * 1856 * Returns: 1857 * {<ZOO.Geometry.Point>} A geometry. 1858 */ 1859 "point": function(array) { 1860 if(array.length != 2) { 1861 throw "Only 2D points are supported: " + array; 1862 } 1863 return new ZOO.Geometry.Point(array[0], array[1]); 1864 }, 1865 /** 1866 * Method: parseCoords.multipoint 1867 * Convert a coordinate array from GeoJSON into an 1868 * <ZOO.Geometry.MultiPoint>. 1869 * 1870 * Parameters: 1871 * array - {Object} The coordinates array from the GeoJSON fragment. 1872 * 1873 * Returns: 1874 * {<ZOO.Geometry.MultiPoint>} A geometry. 1875 */ 1876 "multipoint": function(array) { 1877 var points = []; 1878 var p = null; 1879 for(var i=0, len=array.length; i<len; ++i) { 1880 try { 1881 p = this.parseCoords["point"].apply(this, [array[i]]); 1882 } catch(err) { 1883 throw err; 1884 } 1885 points.push(p); 1886 } 1887 return new ZOO.Geometry.MultiPoint(points); 1888 }, 1889 /** 1890 * Method: parseCoords.linestring 1891 * Convert a coordinate array from GeoJSON into an 1892 * <ZOO.Geometry.LineString>. 1893 * 1894 * Parameters: 1895 * array - {Object} The coordinates array from the GeoJSON fragment. 1896 * 1897 * Returns: 1898 * {<ZOO.Geometry.LineString>} A geometry. 1899 */ 1900 "linestring": function(array) { 1901 var points = []; 1902 var p = null; 1903 for(var i=0, len=array.length; i<len; ++i) { 1904 try { 1905 p = this.parseCoords["point"].apply(this, [array[i]]); 1906 } catch(err) { 1907 throw err; 1908 } 1909 points.push(p); 1910 } 1911 return new ZOO.Geometry.LineString(points); 1912 }, 1913 /** 1914 * Method: parseCoords.multilinestring 1915 * Convert a coordinate array from GeoJSON into an 1916 * <ZOO.Geometry.MultiLineString>. 1917 * 1918 * Parameters: 1919 * array - {Object} The coordinates array from the GeoJSON fragment. 1920 * 1921 * Returns: 1922 * {<ZOO.Geometry.MultiLineString>} A geometry. 1923 */ 1924 "multilinestring": function(array) { 1925 var lines = []; 1926 var l = null; 1927 for(var i=0, len=array.length; i<len; ++i) { 1928 try { 1929 l = this.parseCoords["linestring"].apply(this, [array[i]]); 1930 } catch(err) { 1931 throw err; 1932 } 1933 lines.push(l); 1934 } 1935 return new ZOO.Geometry.MultiLineString(lines); 1936 }, 1937 /** 1938 * Method: parseCoords.polygon 1939 * Convert a coordinate array from GeoJSON into an 1940 * <ZOO.Geometry.Polygon>. 1941 * 1942 * Parameters: 1943 * array - {Object} The coordinates array from the GeoJSON fragment. 1944 * 1945 * Returns: 1946 * {<ZOO.Geometry.Polygon>} A geometry. 1947 */ 1948 "polygon": function(array) { 1949 var rings = []; 1950 var r, l; 1951 for(var i=0, len=array.length; i<len; ++i) { 1952 try { 1953 l = this.parseCoords["linestring"].apply(this, [array[i]]); 1954 } catch(err) { 1955 throw err; 1956 } 1957 r = new ZOO.Geometry.LinearRing(l.components); 1958 rings.push(r); 1959 } 1960 return new ZOO.Geometry.Polygon(rings); 1961 }, 1962 /** 1963 * Method: parseCoords.multipolygon 1964 * Convert a coordinate array from GeoJSON into an 1965 * <ZOO.Geometry.MultiPolygon>. 1966 * 1967 * Parameters: 1968 * array - {Object} The coordinates array from the GeoJSON fragment. 1969 * 1970 * Returns: 1971 * {<ZOO.Geometry.MultiPolygon>} A geometry. 1972 */ 1973 "multipolygon": function(array) { 1974 var polys = []; 1975 var p = null; 1976 for(var i=0, len=array.length; i<len; ++i) { 1977 try { 1978 p = this.parseCoords["polygon"].apply(this, [array[i]]); 1979 } catch(err) { 1980 throw err; 1981 } 1982 polys.push(p); 1983 } 1984 return new ZOO.Geometry.MultiPolygon(polys); 1985 }, 1986 /** 1987 * Method: parseCoords.box 1988 * Convert a coordinate array from GeoJSON into an 1989 * <ZOO.Geometry.Polygon>. 1990 * 1991 * Parameters: 1992 * array - {Object} The coordinates array from the GeoJSON fragment. 1993 * 1994 * Returns: 1995 * {<ZOO.Geometry.Polygon>} A geometry. 1996 */ 1997 "box": function(array) { 1998 if(array.length != 2) { 1999 throw "GeoJSON box coordinates must have 2 elements"; 2000 } 2001 return new ZOO.Geometry.Polygon([ 2002 new ZOO.Geometry.LinearRing([ 2003 new ZOO.Geometry.Point(array[0][0], array[0][1]), 2004 new ZOO.Geometry.Point(array[1][0], array[0][1]), 2005 new ZOO.Geometry.Point(array[1][0], array[1][1]), 2006 new ZOO.Geometry.Point(array[0][0], array[1][1]), 2007 new Z0O.Geometry.Point(array[0][0], array[0][1]) 2008 ]) 2009 ]); 2010 } 2011 }, 2012 /** 2013 * Method: write 2014 * Serialize a feature, geometry, array of features into a GeoJSON string. 2015 * 2016 * Parameters: 2017 * obj - {Object} An <ZOO.Feature>, <ZOO.Geometry>, 2018 * or an array of features. 2019 * pretty - {Boolean} Structure the output with newlines and indentation. 2020 * Default is false. 2021 * 2022 * Returns: 2023 * {String} The GeoJSON string representation of the input geometry, 2024 * features, or array of features. 2025 */ 2026 write: function(obj, pretty) { 2027 var geojson = { 2028 "type": null 2029 }; 2030 if(obj instanceof Array) { 2031 geojson.type = "FeatureCollection"; 2032 var numFeatures = obj.length; 2033 geojson.features = new Array(numFeatures); 2034 for(var i=0; i<numFeatures; ++i) { 2035 var element = obj[i]; 2036 if(!element instanceof ZOO.Feature) { 2037 var msg = "FeatureCollection only supports collections " + 2038 "of features: " + element; 2039 throw msg; 2040 } 2041 geojson.features[i] = this.extract.feature.apply(this, [element]); 2042 } 2043 } else if (obj.CLASS_NAME.indexOf("ZOO.Geometry") == 0) { 2044 geojson = this.extract.geometry.apply(this, [obj]); 2045 } else if (obj instanceof ZOO.Feature) { 2046 geojson = this.extract.feature.apply(this, [obj]); 2047 /* 2048 if(obj.layer && obj.layer.projection) { 2049 geojson.crs = this.createCRSObject(obj); 2050 } 2051 */ 2052 } 2053 return ZOO.Format.JSON.prototype.write.apply(this, 2054 [geojson, pretty]); 2055 }, 2056 /** 2057 * Method: createCRSObject 2058 * Create the CRS object for an object. 2059 * 2060 * Parameters: 2061 * object - {<ZOO.Feature>} 2062 * 2063 * Returns: 2064 * {Object} An object which can be assigned to the crs property 2065 * of a GeoJSON object. 2066 */ 2067 createCRSObject: function(object) { 2068 //var proj = object.layer.projection.toString(); 2069 var proj = object.projection.toString(); 2070 var crs = {}; 2071 if (proj.match(/epsg:/i)) { 2072 var code = parseInt(proj.substring(proj.indexOf(":") + 1)); 2073 if (code == 4326) { 2074 crs = { 2075 "type": "OGC", 2076 "properties": { 2077 "urn": "urn:ogc:def:crs:OGC:1.3:CRS84" 2078 } 2079 }; 2080 } else { 2081 crs = { 2082 "type": "EPSG", 2083 "properties": { 2084 "code": code 2085 } 2086 }; 2087 } 2088 } 2089 return crs; 2090 }, 2091 /** 2092 * Property: extract 2093 * Object with properties corresponding to the GeoJSON types. 2094 * Property values are functions that do the actual value extraction. 2095 */ 2096 extract: { 2097 /** 2098 * Method: extract.feature 2099 * Return a partial GeoJSON object representing a single feature. 2100 * 2101 * Parameters: 2102 * feature - {<ZOO.Feature>} 2103 * 2104 * Returns: 2105 * {Object} An object representing the point. 2106 */ 2107 'feature': function(feature) { 2108 var geom = this.extract.geometry.apply(this, [feature.geometry]); 2109 return { 2110 "type": "Feature", 2111 "id": feature.fid == null ? feature.id : feature.fid, 2112 "properties": feature.attributes, 2113 "geometry": geom 2114 }; 2115 }, 2116 /** 2117 * Method: extract.geometry 2118 * Return a GeoJSON object representing a single geometry. 2119 * 2120 * Parameters: 2121 * geometry - {<ZOO.Geometry>} 2122 * 2123 * Returns: 2124 * {Object} An object representing the geometry. 2125 */ 2126 'geometry': function(geometry) { 2127 if (geometry == null) 2128 return null; 2129 if (this.internalProjection && this.externalProjection) { 2130 geometry = geometry.clone(); 2131 geometry.transform(this.internalProjection, 2132 this.externalProjection); 2133 } 2134 var geometryType = geometry.CLASS_NAME.split('.')[2]; 2135 var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]); 2136 var json; 2137 if(geometryType == "Collection") 2138 json = { 2139 "type": "GeometryCollection", 2140 "geometries": data 2141 }; 2142 else 2143 json = { 2144 "type": geometryType, 2145 "coordinates": data 2146 }; 2147 return json; 2148 }, 2149 /** 2150 * Method: extract.point 2151 * Return an array of coordinates from a point. 2152 * 2153 * Parameters: 2154 * point - {<ZOO.Geometry.Point>} 2155 * 2156 * Returns: 2157 * {Array} An array of coordinates representing the point. 2158 */ 2159 'point': function(point) { 2160 return [point.x, point.y]; 2161 }, 2162 /** 2163 * Method: extract.multipoint 2164 * Return an array of coordinates from a multipoint. 2165 * 2166 * Parameters: 2167 * multipoint - {<ZOO.Geometry.MultiPoint>} 2168 * 2169 * Returns: 2170 * {Array} An array of point coordinate arrays representing 2171 * the multipoint. 2172 */ 2173 'multipoint': function(multipoint) { 2174 var array = []; 2175 for(var i=0, len=multipoint.components.length; i<len; ++i) { 2176 array.push(this.extract.point.apply(this, [multipoint.components[i]])); 2177 } 2178 return array; 2179 }, 2180 /** 2181 * Method: extract.linestring 2182 * Return an array of coordinate arrays from a linestring. 2183 * 2184 * Parameters: 2185 * linestring - {<ZOO.Geometry.LineString>} 2186 * 2187 * Returns: 2188 * {Array} An array of coordinate arrays representing 2189 * the linestring. 2190 */ 2191 'linestring': function(linestring) { 2192 var array = []; 2193 for(var i=0, len=linestring.components.length; i<len; ++i) { 2194 array.push(this.extract.point.apply(this, [linestring.components[i]])); 2195 } 2196 return array; 2197 }, 2198 /** 2199 * Method: extract.multilinestring 2200 * Return an array of linestring arrays from a linestring. 2201 * 2202 * Parameters: 2203 * multilinestring - {<ZOO.Geometry.MultiLineString>} 2204 * 2205 * Returns: 2206 * {Array} An array of linestring arrays representing 2207 * the multilinestring. 2208 */ 2209 'multilinestring': function(multilinestring) { 2210 var array = []; 2211 for(var i=0, len=multilinestring.components.length; i<len; ++i) { 2212 array.push(this.extract.linestring.apply(this, [multilinestring.components[i]])); 2213 } 2214 return array; 2215 }, 2216 /** 2217 * Method: extract.polygon 2218 * Return an array of linear ring arrays from a polygon. 2219 * 2220 * Parameters: 2221 * polygon - {<ZOO.Geometry.Polygon>} 2222 * 2223 * Returns: 2224 * {Array} An array of linear ring arrays representing the polygon. 2225 */ 2226 'polygon': function(polygon) { 2227 var array = []; 2228 for(var i=0, len=polygon.components.length; i<len; ++i) { 2229 array.push(this.extract.linestring.apply(this, [polygon.components[i]])); 2230 } 2231 return array; 2232 }, 2233 /** 2234 * Method: extract.multipolygon 2235 * Return an array of polygon arrays from a multipolygon. 2236 * 2237 * Parameters: 2238 * multipolygon - {<ZOO.Geometry.MultiPolygon>} 2239 * 2240 * Returns: 2241 * {Array} An array of polygon arrays representing 2242 * the multipolygon 2243 */ 2244 'multipolygon': function(multipolygon) { 2245 var array = []; 2246 for(var i=0, len=multipolygon.components.length; i<len; ++i) { 2247 array.push(this.extract.polygon.apply(this, [multipolygon.components[i]])); 2248 } 2249 return array; 2250 }, 2251 /** 2252 * Method: extract.collection 2253 * Return an array of geometries from a geometry collection. 2254 * 2255 * Parameters: 2256 * collection - {<ZOO.Geometry.Collection>} 2257 * 2258 * Returns: 2259 * {Array} An array of geometry objects representing the geometry 2260 * collection. 2261 */ 2262 'collection': function(collection) { 2263 var len = collection.components.length; 2264 var array = new Array(len); 2265 for(var i=0; i<len; ++i) { 2266 array[i] = this.extract.geometry.apply( 2267 this, [collection.components[i]] 2268 ); 2269 } 2270 return array; 2271 } 2272 }, 2273 CLASS_NAME: 'ZOO.Format.GeoJSON' 2274 }); 2275 /** 2276 * Class: ZOO.Format.KML 2277 * Read/Write KML. Create a new instance with the <ZOO.Format.KML> 2278 * constructor. 2279 * 2280 * Inherits from: 2281 * - <ZOO.Format> 2282 */ 2283 ZOO.Format.KML = ZOO.Class(ZOO.Format, { 2284 /** 2285 * Property: kmlns 2286 * {String} KML Namespace to use. Defaults to 2.2 namespace. 2287 */ 2288 kmlns: "http://www.opengis.net/kml/2.2", 2289 /** 2290 * Property: foldersName 2291 * {String} Name of the folders. Default is "ZOO export". 2292 * If set to null, no name element will be created. 2293 */ 2294 foldersName: "ZOO export", 2295 /** 2296 * Property: foldersDesc 2297 * {String} Description of the folders. Default is "Exported on [date]." 2298 * If set to null, no description element will be created. 2299 */ 2300 foldersDesc: "Created on " + new Date(), 2301 /** 2302 * Property: placemarksDesc 2303 * {String} Name of the placemarks. Default is "No description available". 2304 */ 2305 placemarksDesc: "No description available", 2306 /** 2307 * Property: extractAttributes 2308 * {Boolean} Extract attributes from KML. Default is true. 2309 * Extracting styleUrls requires this to be set to true 2310 */ 2311 extractAttributes: true, 2312 /** 2313 * Constructor: ZOO.Format.KML 2314 * Create a new parser for KML. 2315 * 2316 * Parameters: 2317 * options - {Object} An optional object whose properties will be set on 2318 * this instance. 2319 */ 2320 initialize: function(options) { 2321 // compile regular expressions once instead of every time they are used 2322 this.regExes = { 2323 trimSpace: (/^\s*|\s*$/g), 2324 removeSpace: (/\s*/g), 2325 splitSpace: (/\s+/), 2326 trimComma: (/\s*,\s*/g), 2327 kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/), 2328 kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/), 2329 straightBracket: (/\$\[(.*?)\]/g) 2330 }; 2331 // KML coordinates are always in longlat WGS84 2332 this.externalProjection = new ZOO.Projection("EPSG:4326"); 2333 ZOO.Format.prototype.initialize.apply(this, [options]); 2334 }, 2335 /** 2336 * APIMethod: read 2337 * Read data from a string, and return a list of features. 2338 * 2339 * Parameters: 2340 * data - {String} data to read/parse. 2341 * 2342 * Returns: 2343 * {Array(<ZOO.Feature>)} List of features. 2344 */ 2345 read: function(data) { 2346 this.features = []; 2347 data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, ""); 2348 data = new XML(data); 2349 var placemarks = data..*::Placemark; 2350 this.parseFeatures(placemarks); 2351 return this.features; 2352 }, 2353 /** 2354 * Method: parseFeatures 2355 * Loop through all Placemark nodes and parse them. 2356 * Will create a list of features 2357 * 2358 * Parameters: 2359 * nodes - {Array} of {E4XElement} data to read/parse. 2360 * options - {Object} Hash of options 2361 * 2362 */ 2363 parseFeatures: function(nodes) { 2364 var features = new Array(nodes.length()); 2365 for(var i=0, len=nodes.length(); i<len; i++) { 2366 var featureNode = nodes[i]; 2367 var feature = this.parseFeature.apply(this,[featureNode]) ; 2368 features[i] = feature; 2369 } 2370 this.features = this.features.concat(features); 2371 }, 2372 /** 2373 * Method: parseFeature 2374 * This function is the core of the KML parsing code in ZOO. 2375 * It creates the geometries that are then attached to the returned 2376 * feature, and calls parseAttributes() to get attribute data out. 2377 * 2378 * Parameters: 2379 * node - {E4XElement} 2380 * 2381 * Returns: 2382 * {<ZOO.Feature>} A vector feature. 2383 */ 2384 parseFeature: function(node) { 2385 // only accept one geometry per feature - look for highest "order" 2386 var order = ["MultiGeometry", "Polygon", "LineString", "Point"]; 2387 var type, nodeList, geometry, parser; 2388 for(var i=0, len=order.length; i<len; ++i) { 2389 type = order[i]; 2390 nodeList = node.descendants(QName(null,type)); 2391 if (nodeList.length()> 0) { 2392 var parser = this.parseGeometry[type.toLowerCase()]; 2393 if(parser) { 2394 geometry = parser.apply(this, [nodeList[0]]); 2395 if (this.internalProjection && this.externalProjection) { 2396 geometry.transform(this.externalProjection, 2397 this.internalProjection); 2398 } 2399 } 2400 // stop looking for different geometry types 2401 break; 2402 } 2403 } 2404 // construct feature (optionally with attributes) 2405 var attributes; 2406 if(this.extractAttributes) { 2407 attributes = this.parseAttributes(node); 2408 } 2409 var feature = new ZOO.Feature(geometry, attributes); 2410 var fid = node.@id || node.@name; 2411 if(fid != null) 2412 feature.fid = fid; 2413 return feature; 2414 }, 2415 /** 2416 * Property: parseGeometry 2417 * Properties of this object are the functions that parse geometries based 2418 * on their type. 2419 */ 2420 parseGeometry: { 2421 /** 2422 * Method: parseGeometry.point 2423 * Given a KML node representing a point geometry, create a ZOO 2424 * point geometry. 2425 * 2426 * Parameters: 2427 * node - {E4XElement} A KML Point node. 2428 * 2429 * Returns: 2430 * {<ZOO.Geometry.Point>} A point geometry. 2431 */ 2432 'point': function(node) { 2433 var coordString = node.*::coordinates.toString(); 2434 coordString = coordString.replace(this.regExes.removeSpace, ""); 2435 coords = coordString.split(","); 2436 var point = null; 2437 if(coords.length > 1) { 2438 // preserve third dimension 2439 if(coords.length == 2) { 2440 coords[2] = null; 2441 } 2442 point = new ZOO.Geometry.Point(coords[0], coords[1], coords[2]); 2443 } 2444 return point; 2445 }, 2446 /** 2447 * Method: parseGeometry.linestring 2448 * Given a KML node representing a linestring geometry, create a 2449 * ZOO linestring geometry. 2450 * 2451 * Parameters: 2452 * node - {E4XElement} A KML LineString node. 2453 * 2454 * Returns: 2455 * {<ZOO.Geometry.LineString>} A linestring geometry. 2456 */ 2457 'linestring': function(node, ring) { 2458 var line = null; 2459 var coordString = node.*::coordinates.toString(); 2460 coordString = coordString.replace(this.regExes.trimSpace, 2461 ""); 2462 coordString = coordString.replace(this.regExes.trimComma, 2463 ","); 2464 var pointList = coordString.split(this.regExes.splitSpace); 2465 var numPoints = pointList.length; 2466 var points = new Array(numPoints); 2467 var coords, numCoords; 2468 for(var i=0; i<numPoints; ++i) { 2469 coords = pointList[i].split(","); 2470 numCoords = coords.length; 2471 if(numCoords > 1) { 2472 if(coords.length == 2) { 2473 coords[2] = null; 2474 } 2475 points[i] = new ZOO.Geometry.Point(coords[0], 2476 coords[1], 2477 coords[2]); 2478 } 2479 } 2480 if(numPoints) { 2481 if(ring) { 2482 line = new ZOO.Geometry.LinearRing(points); 2483 } else { 2484 line = new ZOO.Geometry.LineString(points); 2485 } 2486 } else { 2487 throw "Bad LineString coordinates: " + coordString; 2488 } 2489 return line; 2490 }, 2491 /** 2492 * Method: parseGeometry.polygon 2493 * Given a KML node representing a polygon geometry, create a 2494 * ZOO polygon geometry. 2495 * 2496 * Parameters: 2497 * node - {E4XElement} A KML Polygon node. 2498 * 2499 * Returns: 2500 * {<ZOO.Geometry.Polygon>} A polygon geometry. 2501 */ 2502 'polygon': function(node) { 2503 var nodeList = node..*::LinearRing; 2504 var numRings = nodeList.length(); 2505 var components = new Array(numRings); 2506 if(numRings > 0) { 2507 // this assumes exterior ring first, inner rings after 2508 var ring; 2509 for(var i=0, len=nodeList.length(); i<len; ++i) { 2510 ring = this.parseGeometry.linestring.apply(this, 2511 [nodeList[i], true]); 2512 if(ring) { 2513 components[i] = ring; 2514 } else { 2515 throw "Bad LinearRing geometry: " + i; 2516 } 2517 } 2518 } 2519 return new ZOO.Geometry.Polygon(components); 2520 }, 2521 /** 2522 * Method: parseGeometry.multigeometry 2523 * Given a KML node representing a multigeometry, create a 2524 * ZOO geometry collection. 2525 * 2526 * Parameters: 2527 * node - {E4XElement} A KML MultiGeometry node. 2528 * 2529 * Returns: 2530 * {<ZOO.Geometry.Collection>} A geometry collection. 2531 */ 2532 'multigeometry': function(node) { 2533 var child, parser; 2534 var parts = []; 2535 var children = node.*::*; 2536 for(var i=0, len=children.length(); i<len; ++i ) { 2537 child = children[i]; 2538 var type = child.localName(); 2539 var parser = this.parseGeometry[type.toLowerCase()]; 2540 if(parser) { 2541 parts.push(parser.apply(this, [child])); 2542 } 2543 } 2544 return new ZOO.Geometry.Collection(parts); 2545 } 2546 }, 2547 /** 2548 * Method: parseAttributes 2549 * 2550 * Parameters: 2551 * node - {E4XElement} 2552 * 2553 * Returns: 2554 * {Object} An attributes object. 2555 */ 2556 parseAttributes: function(node) { 2557 var attributes = {}; 2558 var edNodes = node.*::ExtendedData; 2559 if (edNodes.length() > 0) { 2560 attributes = this.parseExtendedData(edNodes[0]) 2561 } 2562 var child, grandchildren; 2563 var children = node.*::*; 2564 for(var i=0, len=children.length(); i<len; ++i) { 2565 child = children[i]; 2566 grandchildren = child..*::*; 2567 if(grandchildren.length() == 1) { 2568 var name = child.localName(); 2569 var value = child.toString(); 2570 if (value) { 2571 value = value.replace(this.regExes.trimSpace, ""); 2572 attributes[name] = value; 2573 } 2574 } 2575 } 2576 return attributes; 2577 }, 2578 /** 2579 * Method: parseExtendedData 2580 * Parse ExtendedData from KML. Limited support for schemas/datatypes. 2581 * See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata 2582 * for more information on extendeddata. 2583 * 2584 * Parameters: 2585 * node - {E4XElement} 2586 * 2587 * Returns: 2588 * {Object} An attributes object. 2589 */ 2590 parseExtendedData: function(node) { 2591 var attributes = {}; 2592 var dataNodes = node.*::Data; 2593 for (var i = 0, len = dataNodes.length(); i < len; i++) { 2594 var data = dataNodes[i]; 2595 var key = data.@name; 2596 var ed = {}; 2597 var valueNode = data.*::value; 2598 if (valueNode.length() > 0) 2599 ed['value'] = valueNode[0].toString(); 2600 var nameNode = data.*::displayName; 2601 if (nameNode.length() > 0) 2602 ed['displayName'] = valueNode[0].toString(); 2603 attributes[key] = ed; 2604 } 2605 return attributes; 2606 }, 2607 /** 2608 * Method: write 2609 * Accept Feature Collection, and return a string. 2610 * 2611 * Parameters: 2612 * features - {Array(<ZOO.Feature>} An array of features. 2613 * 2614 * Returns: 2615 * {String} A KML string. 2616 */ 2617 write: function(features) { 2618 if(!(features instanceof Array)) 2619 features = [features]; 2620 var kml = new XML('<kml xmlns="'+this.kmlns+'"></kml>'); 2621 var folder = kml.Document.Folder; 2622 folder.name = this.foldersName; 2623 folder.description = this.foldersDesc; 2624 for(var i=0, len=features.length; i<len; ++i) { 2625 folder.Placemark[i] = this.createPlacemark(features[i]); 2626 } 2627 return kml.toXMLString(); 2628 }, 2629 /** 2630 * Method: createPlacemark 2631 * Creates and returns a KML placemark node representing the given feature. 2632 * 2633 * Parameters: 2634 * feature - {<ZOO.Feature>} 2635 * 2636 * Returns: 2637 * {E4XElement} 2638 */ 2639 createPlacemark: function(feature) { 2640 var placemark = new XML('<Placemark xmlns="'+this.kmlns+'"></Placemark>'); 2641 placemark.name = (feature.attributes.name) ? 2642 feature.attributes.name : feature.id; 2643 placemark.description = (feature.attributes.description) ? 2644 feature.attributes.description : this.placemarksDesc; 2645 if(feature.fid != null) 2646 placemark.@id = feature.fid; 2647 placemark.*[2] = this.buildGeometryNode(feature.geometry); 2648 return placemark; 2649 }, 2650 /** 2651 * Method: buildGeometryNode 2652 * Builds and returns a KML geometry node with the given geometry. 2653 * 2654 * Parameters: 2655 * geometry - {<ZOO.Geometry>} 2656 * 2657 * Returns: 2658 * {E4XElement} 2659 */ 2660 buildGeometryNode: function(geometry) { 2661 if (this.internalProjection && this.externalProjection) { 2662 geometry = geometry.clone(); 2663 geometry.transform(this.internalProjection, 2664 this.externalProjection); 2665 } 2666 var className = geometry.CLASS_NAME; 2667 var type = className.substring(className.lastIndexOf(".") + 1); 2668 var builder = this.buildGeometry[type.toLowerCase()]; 2669 var node = null; 2670 if(builder) { 2671 node = builder.apply(this, [geometry]); 2672 } 2673 return node; 2674 }, 2675 /** 2676 * Property: buildGeometry 2677 * Object containing methods to do the actual geometry node building 2678 * based on geometry type. 2679 */ 2680 buildGeometry: { 2681 /** 2682 * Method: buildGeometry.point 2683 * Given a ZOO point geometry, create a KML point. 2684 * 2685 * Parameters: 2686 * geometry - {<ZOO.Geometry.Point>} A point geometry. 2687 * 2688 * Returns: 2689 * {E4XElement} A KML point node. 2690 */ 2691 'point': function(geometry) { 2692 var kml = new XML('<Point xmlns="'+this.kmlns+'"></Point>'); 2693 kml.coordinates = this.buildCoordinatesNode(geometry); 2694 return kml; 2695 }, 2696 /** 2697 * Method: buildGeometry.multipoint 2698 * Given a ZOO multipoint geometry, create a KML 2699 * GeometryCollection. 2700 * 2701 * Parameters: 2702 * geometry - {<ZOO.Geometry.MultiPoint>} A multipoint geometry. 2703 * 2704 * Returns: 2705 * {E4XElement} A KML GeometryCollection node. 2706 */ 2707 'multipoint': function(geometry) { 2708 return this.buildGeometry.collection.apply(this, [geometry]); 2709 }, 2710 /** 2711 * Method: buildGeometry.linestring 2712 * Given a ZOO linestring geometry, create a KML linestring. 2713 * 2714 * Parameters: 2715 * geometry - {<ZOO.Geometry.LineString>} A linestring geometry. 2716 * 2717 * Returns: 2718 * {E4XElement} A KML linestring node. 2719 */ 2720 'linestring': function(geometry) { 2721 var kml = new XML('<LineString xmlns="'+this.kmlns+'"></LineString>'); 2722 kml.coordinates = this.buildCoordinatesNode(geometry); 2723 return kml; 2724 }, 2725 /** 2726 * Method: buildGeometry.multilinestring 2727 * Given a ZOO multilinestring geometry, create a KML 2728 * GeometryCollection. 2729 * 2730 * Parameters: 2731 * geometry - {<ZOO.Geometry.MultiLineString>} A multilinestring geometry. 2732 * 2733 * Returns: 2734 * {E4XElement} A KML GeometryCollection node. 2735 */ 2736 'multilinestring': function(geometry) { 2737 return this.buildGeometry.collection.apply(this, [geometry]); 2738 }, 2739 /** 2740 * Method: buildGeometry.linearring 2741 * Given a ZOO linearring geometry, create a KML linearring. 2742 * 2743 * Parameters: 2744 * geometry - {<ZOO.Geometry.LinearRing>} A linearring geometry. 2745 * 2746 * Returns: 2747 * {E4XElement} A KML linearring node. 2748 */ 2749 'linearring': function(geometry) { 2750 var kml = new XML('<LinearRing xmlns="'+this.kmlns+'"></LinearRing>'); 2751 kml.coordinates = this.buildCoordinatesNode(geometry); 2752 return kml; 2753 }, 2754 /** 2755 * Method: buildGeometry.polygon 2756 * Given a ZOO polygon geometry, create a KML polygon. 2757 * 2758 * Parameters: 2759 * geometry - {<ZOO.Geometry.Polygon>} A polygon geometry. 2760 * 2761 * Returns: 2762 * {E4XElement} A KML polygon node. 2763 */ 2764 'polygon': function(geometry) { 2765 var kml = new XML('<Polygon xmlns="'+this.kmlns+'"></Polygon>'); 2766 var rings = geometry.components; 2767 var ringMember, ringGeom, type; 2768 for(var i=0, len=rings.length; i<len; ++i) { 2769 type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs"; 2770 ringMember = new XML('<'+type+' xmlns="'+this.kmlns+'"></'+type+'>'); 2771 ringMember.LinearRing = this.buildGeometry.linearring.apply(this,[rings[i]]); 2772 kml.*[i] = ringMember; 2773 } 2774 return kml; 2775 }, 2776 /** 2777 * Method: buildGeometry.multipolygon 2778 * Given a ZOO multipolygon geometry, create a KML 2779 * GeometryCollection. 2780 * 2781 * Parameters: 2782 * geometry - {<ZOO.Geometry.Point>} A multipolygon geometry. 2783 * 2784 * Returns: 2785 * {E4XElement} A KML GeometryCollection node. 2786 */ 2787 'multipolygon': function(geometry) { 2788 return this.buildGeometry.collection.apply(this, [geometry]); 2789 }, 2790 /** 2791 * Method: buildGeometry.collection 2792 * Given a ZOO geometry collection, create a KML MultiGeometry. 2793 * 2794 * Parameters: 2795 * geometry - {<ZOO.Geometry.Collection>} A geometry collection. 2796 * 2797 * Returns: 2798 * {E4XElement} A KML MultiGeometry node. 2799 */ 2800 'collection': function(geometry) { 2801 var kml = new XML('<MultiGeometry xmlns="'+this.kmlns+'"></MultiGeometry>'); 2802 var child; 2803 for(var i=0, len=geometry.components.length; i<len; ++i) { 2804 kml.*[i] = this.buildGeometryNode.apply(this,[geometry.components[i]]); 2805 } 2806 return kml; 2807 } 2808 }, 2809 /** 2810 * Method: buildCoordinatesNode 2811 * Builds and returns the KML coordinates node with the given geometry 2812 * <coordinates>...</coordinates> 2813 * 2814 * Parameters: 2815 * geometry - {<ZOO.Geometry>} 2816 * 2817 * Return: 2818 * {E4XElement} 2819 */ 2820 buildCoordinatesNode: function(geometry) { 2821 var cooridnates = new XML('<coordinates xmlns="'+this.kmlns+'"></coordinates>'); 2822 var points = geometry.components; 2823 if(points) { 2824 // LineString or LinearRing 2825 var point; 2826 var numPoints = points.length; 2827 var parts = new Array(numPoints); 2828 for(var i=0; i<numPoints; ++i) { 2829 point = points[i]; 2830 parts[i] = point.x + "," + point.y; 2831 } 2832 coordinates = parts.join(" "); 2833 } else { 2834 // Point 2835 coordinates = geometry.x + "," + geometry.y; 2836 } 2837 return coordinates; 2838 }, 2839 CLASS_NAME: 'ZOO.Format.KML' 2840 }); 2841 /** 2842 * Class: ZOO.Format.GML 2843 * Read/Write GML. Create a new instance with the <ZOO.Format.GML> 2844 * constructor. Supports the GML simple features profile. 2845 * 2846 * Inherits from: 2847 * - <ZOO.Format> 2848 */ 2849 ZOO.Format.GML = ZOO.Class(ZOO.Format, { 2850 /** 2851 * Property: schemaLocation 2852 * {String} Schema location for a particular minor version. 2853 */ 2854 schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", 2855 /** 2856 * Property: namespaces 2857 * {Object} Mapping of namespace aliases to namespace URIs. 2858 */ 2859 namespaces: { 2860 ogr: "http://ogr.maptools.org/", 2861 gml: "http://www.opengis.net/gml", 2862 xlink: "http://www.w3.org/1999/xlink", 2863 xsi: "http://www.w3.org/2001/XMLSchema-instance", 2864 wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection 2865 }, 2866 /** 2867 * Property: defaultPrefix 2868 */ 2869 defaultPrefix: 'ogr', 2870 /** 2871 * Property: collectionName 2872 * {String} Name of featureCollection element. 2873 */ 2874 collectionName: "FeatureCollection", 2875 /* 2876 * Property: featureName 2877 * {String} Element name for features. Default is "sql_statement". 2878 */ 2879 featureName: "sql_statement", 2880 /** 2881 * Property: geometryName 2882 * {String} Name of geometry element. Defaults to "geometryProperty". 2883 */ 2884 geometryName: "geometryProperty", 2885 /** 2886 * Property: xy 2887 * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x) 2888 * Changing is not recommended, a new Format should be instantiated. 2889 */ 2890 xy: true, 2891 /** 2892 * Constructor: ZOO.Format.GML 2893 * Create a new parser for GML. 2894 * 2895 * Parameters: 2896 * options - {Object} An optional object whose properties will be set on 2897 * this instance. 2898 */ 2899 initialize: function(options) { 2900 // compile regular expressions once instead of every time they are used 2901 this.regExes = { 2902 trimSpace: (/^\s*|\s*$/g), 2903 removeSpace: (/\s*/g), 2904 splitSpace: (/\s+/), 2905 trimComma: (/\s*,\s*/g) 2906 }; 2907 ZOO.Format.prototype.initialize.apply(this, [options]); 2908 }, 2909 /** 2910 * Method: read 2911 * Read data from a string, and return a list of features. 2912 * 2913 * Parameters: 2914 * data - {String} data to read/parse. 2915 * 2916 * Returns: 2917 * {Array(<ZOO.Feature>)} An array of features. 2918 */ 2919 read: function(data) { 2920 this.features = []; 2921 data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, ""); 2922 data = new XML(data); 2923 2924 var gmlns = Namespace(this.namespaces['gml']); 2925 var featureNodes = data..gmlns::featureMember; 2926 var features = []; 2927 for(var i=0,len=featureNodes.length(); i<len; i++) { 2928 var feature = this.parseFeature(featureNodes[i]); 2929 if(feature) { 2930 features.push(feature); 2931 } 2932 } 2933 return features; 2934 }, 2935 /** 2936 * Method: parseFeature 2937 * This function is the core of the GML parsing code in ZOO. 2938 * It creates the geometries that are then attached to the returned 2939 * feature, and calls parseAttributes() to get attribute data out. 2940 * 2941 * Parameters: 2942 * node - {E4XElement} A GML feature node. 2943 */ 2944 parseFeature: function(node) { 2945 // only accept one geometry per feature - look for highest "order" 2946 var gmlns = Namespace(this.namespaces['gml']); 2947 var order = ["MultiPolygon", "Polygon", 2948 "MultiLineString", "LineString", 2949 "MultiPoint", "Point", "Envelope", "Box"]; 2950 var type, nodeList, geometry, parser; 2951 for(var i=0; i<order.length; ++i) { 2952 type = order[i]; 2953 nodeList = node.descendants(QName(gmlns,type)); 2954 if (nodeList.length() > 0) { 2955 var parser = this.parseGeometry[type.toLowerCase()]; 2956 if(parser) { 2957 geometry = parser.apply(this, [nodeList[0]]); 2958 if (this.internalProjection && this.externalProjection) { 2959 geometry.transform(this.externalProjection, 2960 this.internalProjection); 2961 } 2962 } 2963 // stop looking for different geometry types 2964 break; 2965 } 2966 } 2967 var attributes; 2968 if(this.extractAttributes) { 2969 attributes = this.parseAttributes(node); 2970 } 2971 var feature = new ZOO.Feature(geometry, attributes); 2972 return feature; 2973 }, 2974 /** 2975 * Property: parseGeometry 2976 * Properties of this object are the functions that parse geometries based 2977 * on their type. 2978 */ 2979 parseGeometry: { 2980 /** 2981 * Method: parseGeometry.point 2982 * Given a GML node representing a point geometry, create a ZOO 2983 * point geometry. 2984 * 2985 * Parameters: 2986 * node - {E4XElement} A GML node. 2987 * 2988 * Returns: 2989 * {<ZOO.Geometry.Point>} A point geometry. 2990 */ 2991 'point': function(node) { 2992 /** 2993 * Three coordinate variations to consider: 2994 * 1) <gml:pos>x y z</gml:pos> 2995 * 2) <gml:coordinates>x, y, z</gml:coordinates> 2996 * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord> 2997 */ 2998 var nodeList, coordString; 2999 var coords = []; 3000 // look for <gml:pos> 3001 var nodeList = node..*::pos; 3002 if(nodeList.length() > 0) { 3003 coordString = nodeList[0].toString(); 3004 coordString = coordString.replace(this.regExes.trimSpace, ""); 3005 coords = coordString.split(this.regExes.splitSpace); 3006 } 3007 // look for <gml:coordinates> 3008 if(coords.length == 0) { 3009 nodeList = node..*::coordinates; 3010 if(nodeList.length() > 0) { 3011 coordString = nodeList[0].toString(); 3012 coordString = coordString.replace(this.regExes.removeSpace,""); 3013 coords = coordString.split(","); 3014 } 3015 } 3016 // look for <gml:coord> 3017 if(coords.length == 0) { 3018 nodeList = node..*::coord; 3019 if(nodeList.length() > 0) { 3020 var xList = nodeList[0].*::X; 3021 var yList = nodeList[0].*::Y; 3022 if(xList.length() > 0 && yList.length() > 0) 3023 coords = [xList[0].toString(), 3024 yList[0].toString()]; 3025 } 3026 } 3027 // preserve third dimension 3028 if(coords.length == 2) 3029 coords[2] = null; 3030 if (this.xy) 3031 return new ZOO.Geometry.Point(coords[0],coords[1],coords[2]); 3032 else 3033 return new ZOO.Geometry.Point(coords[1],coords[0],coords[2]); 3034 }, 3035 /** 3036 * Method: parseGeometry.multipoint 3037 * Given a GML node representing a multipoint geometry, create a 3038 * ZOO multipoint geometry. 3039 * 3040 * Parameters: 3041 * node - {E4XElement} A GML node. 3042 * 3043 * Returns: 3044 * {<ZOO.Geometry.MultiPoint>} A multipoint geometry. 3045 */ 3046 'multipoint': function(node) { 3047 var nodeList = node..*::Point; 3048 var components = []; 3049 if(nodeList.length() > 0) { 3050 var point; 3051 for(var i=0, len=nodeList.length(); i<len; ++i) { 3052 point = this.parseGeometry.point.apply(this, [nodeList[i]]); 3053 if(point) 3054 components.push(point); 3055 } 3056 } 3057 return new ZOO.Geometry.MultiPoint(components); 3058 }, 3059 /** 3060 * Method: parseGeometry.linestring 3061 * Given a GML node representing a linestring geometry, create a 3062 * ZOO linestring geometry. 3063 * 3064 * Parameters: 3065 * node - {E4XElement} A GML node. 3066 * 3067 * Returns: 3068 * {<ZOO.Geometry.LineString>} A linestring geometry. 3069 */ 3070 'linestring': function(node, ring) { 3071 /** 3072 * Two coordinate variations to consider: 3073 * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList> 3074 * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates> 3075 */ 3076 var nodeList, coordString; 3077 var coords = []; 3078 var points = []; 3079 // look for <gml:posList> 3080 nodeList = node..*::posList; 3081 if(nodeList.length() > 0) { 3082 coordString = nodeList[0].toString(); 3083 coordString = coordString.replace(this.regExes.trimSpace, ""); 3084 coords = coordString.split(this.regExes.splitSpace); 3085 var dim = parseInt(nodeList[0].@dimension); 3086 var j, x, y, z; 3087 for(var i=0; i<coords.length/dim; ++i) { 3088 j = i * dim; 3089 x = coords[j]; 3090 y = coords[j+1]; 3091 z = (dim == 2) ? null : coords[j+2]; 3092 if (this.xy) 3093 points.push(new ZOO.Geometry.Point(x, y, z)); 3094 else 3095 points.push(new Z0O.Geometry.Point(y, x, z)); 3096 } 3097 } 3098 // look for <gml:coordinates> 3099 if(coords.length == 0) { 3100 nodeList = node..*::coordinates; 3101 if(nodeList.length() > 0) { 3102 coordString = nodeList[0].toString(); 3103 coordString = coordString.replace(this.regExes.trimSpace,""); 3104 coordString = coordString.replace(this.regExes.trimComma,","); 3105 var pointList = coordString.split(this.regExes.splitSpace); 3106 for(var i=0; i<pointList.length; ++i) { 3107 coords = pointList[i].split(","); 3108 if(coords.length == 2) 3109 coords[2] = null; 3110 if (this.xy) 3111 points.push(new ZOO.Geometry.Point(coords[0],coords[1],coords[2])); 3112 else 3113 points.push(new ZOO.Geometry.Point(coords[1],coords[0],coords[2])); 3114 } 3115 } 3116 } 3117 var line = null; 3118 if(points.length != 0) { 3119 if(ring) 3120 line = new ZOO.Geometry.LinearRing(points); 3121 else 3122 line = new ZOO.Geometry.LineString(points); 3123 } 3124 return line; 3125 }, 3126 /** 3127 * Method: parseGeometry.multilinestring 3128 * Given a GML node representing a multilinestring geometry, create a 3129 * ZOO multilinestring geometry. 3130 * 3131 * Parameters: 3132 * node - {E4XElement} A GML node. 3133 * 3134 * Returns: 3135 * {<ZOO.Geometry.MultiLineString>} A multilinestring geometry. 3136 */ 3137 'multilinestring': function(node) { 3138 var nodeList = node..*::LineString; 3139 var components = []; 3140 if(nodeList.length() > 0) { 3141 var line; 3142 for(var i=0, len=nodeList.length(); i<len; ++i) { 3143 line = this.parseGeometry.linestring.apply(this, [nodeList[i]]); 3144 if(point) 3145 components.push(point); 3146 } 3147 } 3148 return new ZOO.Geometry.MultiLineString(components); 3149 }, 3150 /** 3151 * Method: parseGeometry.polygon 3152 * Given a GML node representing a polygon geometry, create a 3153 * ZOO polygon geometry. 3154 * 3155 * Parameters: 3156 * node - {E4XElement} A GML node. 3157 * 3158 * Returns: 3159 * {<ZOO.Geometry.Polygon>} A polygon geometry. 3160 */ 3161 'polygon': function(node) { 3162 nodeList = node..*::LinearRing; 3163 var components = []; 3164 if(nodeList.length() > 0) { 3165 // this assumes exterior ring first, inner rings after 3166 var ring; 3167 for(var i=0, len = nodeList.length(); i<len; ++i) { 3168 ring = this.parseGeometry.linestring.apply(this,[nodeList[i], true]); 3169 if(ring) 3170 components.push(ring); 3171 } 3172 } 3173 return new ZOO.Geometry.Polygon(components); 3174 }, 3175 /** 3176 * Method: parseGeometry.multipolygon 3177 * Given a GML node representing a multipolygon geometry, create a 3178 * ZOO multipolygon geometry. 3179 * 3180 * Parameters: 3181 * node - {E4XElement} A GML node. 3182 * 3183 * Returns: 3184 * {<ZOO.Geometry.MultiPolygon>} A multipolygon geometry. 3185 */ 3186 'multipolygon': function(node) { 3187 var nodeList = node..*::Polygon; 3188 var components = []; 3189 if(nodeList.length() > 0) { 3190 var polygon; 3191 for(var i=0, len=nodeList.length(); i<len; ++i) { 3192 polygon = this.parseGeometry.polygon.apply(this, [nodeList[i]]); 3193 if(polygon) 3194 components.push(polygon); 3195 } 3196 } 3197 return new ZOO.Geometry.MultiPolygon(components); 3198 }, 3199 /** 3200 * Method: parseGeometry.polygon 3201 * Given a GML node representing an envelope, create a 3202 * ZOO polygon geometry. 3203 * 3204 * Parameters: 3205 * node - {E4XElement} A GML node. 3206 * 3207 * Returns: 3208 * {<ZOO.Geometry.Polygon>} A polygon geometry. 3209 */ 3210 'envelope': function(node) { 3211 var components = []; 3212 var coordString; 3213 var envelope; 3214 var lpoint = node..*::lowerCorner; 3215 if (lpoint.length() > 0) { 3216 var coords = []; 3217 if(lpoint.length() > 0) { 3218 coordString = lpoint[0].toString(); 3219 coordString = coordString.replace(this.regExes.trimSpace, ""); 3220 coords = coordString.split(this.regExes.splitSpace); 3221 } 3222 if(coords.length == 2) 3223 coords[2] = null; 3224 if (this.xy) 3225 var lowerPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]); 3226 else 3227 var lowerPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]); 3228 } 3229 var upoint = node..*::upperCorner; 3230 if (upoint.length() > 0) { 3231 var coords = []; 3232 if(upoint.length > 0) { 3233 coordString = upoint[0].toString(); 3234 coordString = coordString.replace(this.regExes.trimSpace, ""); 3235 coords = coordString.split(this.regExes.splitSpace); 3236 } 3237 if(coords.length == 2) 3238 coords[2] = null; 3239 if (this.xy) 3240 var upperPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]); 3241 else 3242 var upperPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]); 3243 } 3244 if (lowerPoint && upperPoint) { 3245 components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y)); 3246 components.push(new ZOO.Geometry.Point(upperPoint.x, lowerPoint.y)); 3247 components.push(new ZOO.Geometry.Point(upperPoint.x, upperPoint.y)); 3248 components.push(new ZOO.Geometry.Point(lowerPoint.x, upperPoint.y)); 3249 components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y)); 3250 var ring = new ZOO.Geometry.LinearRing(components); 3251 envelope = new ZOO.Geometry.Polygon([ring]); 3252 } 3253 return envelope; 3254 } 3255 }, 3256 /** 3257 * Method: parseAttributes 3258 * 3259 * Parameters: 3260 * node - {<E4XElement>} 3261 * 3262 * Returns: 3263 * {Object} An attributes object. 3264 */ 3265 parseAttributes: function(node) { 3266 var attributes = {}; 3267 // assume attributes are children of the first type 1 child 3268 var childNode = node.*::*[0]; 3269 var child, grandchildren; 3270 var children = childNode.*::*; 3271 for(var i=0, len=children.length(); i<len; ++i) { 3272 child = children[i]; 3273 grandchildren = child..*::*; 3274 if(grandchildren.length() == 1) { 3275 var name = child.localName(); 3276 var value = child.toString(); 3277 if (value) { 3278 value = value.replace(this.regExes.trimSpace, ""); 3279 attributes[name] = value; 3280 } else 3281 attributes[name] = null; 3282 } 3283 } 3284 return attributes; 3285 }, 3286 /** 3287 * Method: write 3288 * Generate a GML document string given a list of features. 3289 * 3290 * Parameters: 3291 * features - {Array(<ZOO.Feature>)} List of features to 3292 * serialize into a string. 3293 * 3294 * Returns: 3295 * {String} A string representing the GML document. 3296 */ 3297 write: function(features) { 3298 if(!(features instanceof Array)) { 3299 features = [features]; 3300 } 3301 var pfx = this.defaultPrefix; 3302 var name = pfx+':'+this.collectionName; 3303 var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" xmlns:gml="'+this.namespaces['gml']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"></'+name+'>'); 3304 for(var i=0; i<features.length; i++) { 3305 gml.*::*[i] = this.createFeature(features[i]); 3306 } 3307 return gml.toXMLString(); 3308 }, 3309 /** 3310 * Method: createFeature 3311 * Accept an ZOO.Feature, and build a GML node for it. 3312 * 3313 * Parameters: 3314 * feature - {<ZOO.Feature>} The feature to be built as GML. 3315 * 3316 * Returns: 3317 * {E4XElement} A node reprensting the feature in GML. 3318 */ 3319 createFeature: function(feature) { 3320 var pfx = this.defaultPrefix; 3321 var name = pfx+':'+this.featureName; 3322 var fid = feature.fid || feature.id; 3323 var gml = new XML('<gml:featureMember xmlns:gml="'+this.namespaces['gml']+'"><'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" fid="'+fid+'"></'+name+'></gml:featureMember>'); 3324 var geometry = feature.geometry; 3325 gml.*::*[0].*::* = this.buildGeometryNode(geometry); 3326 for(var attr in feature.attributes) { 3327 var attrNode = new XML('<'+pfx+':'+attr+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'">'+feature.attributes[attr]+'</'+pfx+':'+attr+'>'); 3328 gml.*::*[0].appendChild(attrNode); 3329 } 3330 return gml; 3331 }, 3332 /** 3333 * Method: buildGeometryNode 3334 * 3335 * Parameters: 3336 * geometry - {<ZOO.Geometry>} The geometry to be built as GML. 3337 * 3338 * Returns: 3339 * {E4XElement} A node reprensting the geometry in GML. 3340 */ 3341 buildGeometryNode: function(geometry) { 3342 if (this.externalProjection && this.internalProjection) { 3343 geometry = geometry.clone(); 3344 geometry.transform(this.internalProjection, 3345 this.externalProjection); 3346 } 3347 var className = geometry.CLASS_NAME; 3348 var type = className.substring(className.lastIndexOf(".") + 1); 3349 var builder = this.buildGeometry[type.toLowerCase()]; 3350 var pfx = this.defaultPrefix; 3351 var name = pfx+':'+this.geometryName; 3352 var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'"></'+name+'>'); 3353 if (builder) 3354 gml.*::* = builder.apply(this, [geometry]); 3355 return gml; 3356 }, 3357 /** 3358 * Property: buildGeometry 3359 * Object containing methods to do the actual geometry node building 3360 * based on geometry type. 3361 */ 3362 buildGeometry: { 3363 /** 3364 * Method: buildGeometry.point 3365 * Given a ZOO point geometry, create a GML point. 3366 * 3367 * Parameters: 3368 * geometry - {<ZOO.Geometry.Point>} A point geometry. 3369 * 3370 * Returns: 3371 * {E4XElement} A GML point node. 3372 */ 3373 'point': function(geometry) { 3374 var gml = new XML('<gml:Point xmlns:gml="'+this.namespaces['gml']+'"></gml:Point>'); 3375 gml.*::*[0] = this.buildCoordinatesNode(geometry); 3376 return gml; 3377 }, 3378 /** 3379 * Method: buildGeometry.multipoint 3380 * Given a ZOO multipoint geometry, create a GML multipoint. 3381 * 3382 * Parameters: 3383 * geometry - {<ZOO.Geometry.MultiPoint>} A multipoint geometry. 3384 * 3385 * Returns: 3386 * {E4XElement} A GML multipoint node. 3387 */ 3388 'multipoint': function(geometry) { 3389 var gml = new XML('<gml:MultiPoint xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiPoint>'); 3390 var points = geometry.components; 3391 var pointMember; 3392 for(var i=0; i<points.length; i++) { 3393 pointMember = new XML('<gml:pointMember xmlns:gml="'+this.namespaces['gml']+'"></gml:pointMember>'); 3394 pointMember.*::* = this.buildGeometry.point.apply(this,[points[i]]); 3395 gml.*::*[i] = pointMember; 3396 } 3397 return gml; 3398 }, 3399 /** 3400 * Method: buildGeometry.linestring 3401 * Given a ZOO linestring geometry, create a GML linestring. 3402 * 3403 * Parameters: 3404 * geometry - {<ZOO.Geometry.LineString>} A linestring geometry. 3405 * 3406 * Returns: 3407 * {E4XElement} A GML linestring node. 3408 */ 3409 'linestring': function(geometry) { 3410 var gml = new XML('<gml:LineString xmlns:gml="'+this.namespaces['gml']+'"></gml:LineString>'); 3411 gml.*::*[0] = this.buildCoordinatesNode(geometry); 3412 return gml; 3413 }, 3414 /** 3415 * Method: buildGeometry.multilinestring 3416 * Given a ZOO multilinestring geometry, create a GML 3417 * multilinestring. 3418 * 3419 * Parameters: 3420 * geometry - {<ZOO.Geometry.MultiLineString>} A multilinestring 3421 * geometry. 3422 * 3423 * Returns: 3424 * {E4XElement} A GML multilinestring node. 3425 */ 3426 'multilinestring': function(geometry) { 3427 var gml = new XML('<gml:MultiLineString xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiLineString>'); 3428 var lines = geometry.components; 3429 var lineMember; 3430 for(var i=0; i<lines.length; i++) { 3431 lineMember = new XML('<gml:lineStringMember xmlns:gml="'+this.namespaces['gml']+'"></gml:lineStringMember>'); 3432 lineMember.*::* = this.buildGeometry.linestring.apply(this,[lines[i]]); 3433 gml.*::*[i] = lineMember; 3434 } 3435 return gml; 3436 }, 3437 /** 3438 * Method: buildGeometry.linearring 3439 * Given a ZOO linearring geometry, create a GML linearring. 3440 * 3441 * Parameters: 3442 * geometry - {<ZOO.Geometry.LinearRing>} A linearring geometry. 3443 * 3444 * Returns: 3445 * {E4XElement} A GML linearring node. 3446 */ 3447 'linearring': function(geometry) { 3448 var gml = new XML('<gml:LinearRing xmlns:gml="'+this.namespaces['gml']+'"></gml:LinearRing>'); 3449 gml.*::*[0] = this.buildCoordinatesNode(geometry); 3450 return gml; 3451 }, 3452 /** 3453 * Method: buildGeometry.polygon 3454 * Given an ZOO polygon geometry, create a GML polygon. 3455 * 3456 * Parameters: 3457 * geometry - {<ZOO.Geometry.Polygon>} A polygon geometry. 3458 * 3459 * Returns: 3460 * {E4XElement} A GML polygon node. 3461 */ 3462 'polygon': function(geometry) { 3463 var gml = new XML('<gml:Polygon xmlns:gml="'+this.namespaces['gml']+'"></gml:Polygon>'); 3464 var rings = geometry.components; 3465 var ringMember, type; 3466 for(var i=0; i<rings.length; ++i) { 3467 type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs"; 3468 var ringMember = new XML('<gml:'+type+' xmlns:gml="'+this.namespaces['gml']+'"></gml:'+type+'>'); 3469 ringMember.*::* = this.buildGeometry.linearring.apply(this,[rings[i]]); 3470 gml.*::*[i] = ringMember; 3471 } 3472 return gml; 3473 }, 3474 /** 3475 * Method: buildGeometry.multipolygon 3476 * Given a ZOO multipolygon geometry, create a GML multipolygon. 3477 * 3478 * Parameters: 3479 * geometry - {<ZOO.Geometry.MultiPolygon>} A multipolygon 3480 * geometry. 3481 * 3482 * Returns: 3483 * {E4XElement} A GML multipolygon node. 3484 */ 3485 'multipolygon': function(geometry) { 3486 var gml = new XML('<gml:MultiPolygon xmlns:gml="'+this.namespaces['gml']+'"></gml:MultiPolygon>'); 3487 var polys = geometry.components; 3488 var polyMember; 3489 for(var i=0; i<polys.length; i++) { 3490 polyMember = new XML('<gml:polygonMember xmlns:gml="'+this.namespaces['gml']+'"></gml:polygonMember>'); 3491 polyMember.*::* = this.buildGeometry.polygon.apply(this,[polys[i]]); 3492 gml.*::*[i] = polyMember; 3493 } 3494 return gml; 3495 } 3496 }, 3497 /** 3498 * Method: buildCoordinatesNode 3499 * builds the coordinates XmlNode 3500 * (code) 3501 * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates> 3502 * (end) 3503 * Parameters: 3504 * geometry - {<ZOO.Geometry>} 3505 * 3506 * Returns: 3507 * {E4XElement} created E4XElement 3508 */ 3509 buildCoordinatesNode: function(geometry) { 3510 var parts = []; 3511 if(geometry instanceof ZOO.Bounds){ 3512 parts.push(geometry.left + "," + geometry.bottom); 3513 parts.push(geometry.right + "," + geometry.top); 3514 } else { 3515 var points = (geometry.components) ? geometry.components : [geometry]; 3516 for(var i=0; i<points.length; i++) { 3517 parts.push(points[i].x + "," + points[i].y); 3518 } 3519 } 3520 return new XML('<gml:coordinates xmlns:gml="'+this.namespaces['gml']+'" decimal="." cs=", " ts=" ">'+parts.join(" ")+'</gml:coordinates>'); 3521 }, 3522 CLASS_NAME: 'ZOO.Format.GML' 3523 }); 3524 /** 3525 * Class: ZOO.Format.WPS 3526 * Read/Write WPS. Create a new instance with the <ZOO.Format.WPS> 3527 * constructor. Supports only parseExecuteResponse. 3528 * 3529 * Inherits from: 3530 * - <ZOO.Format> 3531 */ 3532 ZOO.Format.WPS = ZOO.Class(ZOO.Format, { 3533 /** 3534 * Property: schemaLocation 3535 * {String} Schema location for a particular minor version. 3536 */ 3537 schemaLocation: "http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd", 3538 /** 3539 * Property: namespaces 3540 * {Object} Mapping of namespace aliases to namespace URIs. 3541 */ 3542 namespaces: { 3543 ows: "http://www.opengis.net/ows/1.1", 3544 wps: "http://www.opengis.net/wps/1.0.0", 3545 xlink: "http://www.w3.org/1999/xlink", 3546 xsi: "http://www.w3.org/2001/XMLSchema-instance", 3547 }, 3548 /** 3549 * Method: read 3550 * 3551 * Parameters: 3552 * data - {String} A WPS xml document 3553 * 3554 * Returns: 3555 * {Object} Execute response. 3556 */ 3557 read:function(data) { 3558 data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, ""); 3559 data = new XML(data); 3560 switch (data.localName()) { 3561 case 'ExecuteResponse': 3562 return this.parseExecuteResponse(data); 3563 default: 3564 return null; 3565 } 3566 }, 3567 /** 3568 * Method: parseExecuteResponse 3569 * 3570 * Parameters: 3571 * node - {E4XElement} A WPS ExecuteResponse document 3572 * 3573 * Returns: 3574 * {Object} Execute response. 3575 */ 3576 parseExecuteResponse: function(node) { 3577 var outputs = node.*::ProcessOutputs.*::Output; 3578 if (outputs.length() > 0) { 3579 var data = outputs[0].*::Data.*::*[0]; 3580 var builder = this.parseData[data.localName().toLowerCase()]; 3581 if (builder) 3582 return builder.apply(this,[data]); 3583 else 3584 return null; 3585 } else 3586 return null; 3587 }, 3588 /** 3589 * Property: parseData 3590 * Object containing methods to analyse data response. 3591 */ 3592 parseData: { 3593 /** 3594 * Method: parseData.complexdata 3595 * Given an Object representing the WPS complex data response. 3596 * 3597 * Parameters: 3598 * node - {E4XElement} A WPS node. 3599 * 3600 * Returns: 3601 * {Object} A WPS complex data response. 3602 */ 3603 'complexdata': function(node) { 3604 var result = {value:node.toString()}; 3605 if (node.@mimeType.length()>0) 3606 result.mimeType = node.@mimeType; 3607 if (node.@encoding.length()>0) 3608 result.encoding = node.@encoding; 3609 if (node.@schema.length()>0) 3610 result.schema = node.@schema; 3611 return result; 3612 }, 3613 /** 3614 * Method: parseData.literaldata 3615 * Given an Object representing the WPS literal data response. 3616 * 3617 * Parameters: 3618 * node - {E4XElement} A WPS node. 3619 * 3620 * Returns: 3621 * {Object} A WPS literal data response. 3622 */ 3623 'literaldata': function(node) { 3624 var result = {value:node.toString()}; 3625 if (node.@dataType.length()>0) 3626 result.dataType = node.@dataType; 3627 if (node.@uom.length()>0) 3628 result.uom = node.@uom; 3629 return result; 3630 } 3631 }, 3632 CLASS_NAME: 'ZOO.Format.WPS' 3633 }); 3634 3635 /** 3636 * Class: ZOO.Feature 3637 * Vector features use the ZOO.Geometry classes as geometry description. 3638 * They have an 'attributes' property, which is the data object 3639 */ 3640 ZOO.Feature = ZOO.Class({ 3641 /** 3642 * Property: fid 3643 * {String} 3644 */ 3645 fid: null, 3646 /** 3647 * Property: geometry 3648 * {<ZOO.Geometry>} 3649 */ 3650 geometry: null, 3651 /** 3652 * Property: attributes 3653 * {Object} This object holds arbitrary properties that describe the 3654 * feature. 3655 */ 3656 attributes: null, 3657 /** 3658 * Property: bounds 3659 * {<ZOO.Bounds>} The box bounding that feature's geometry, that 3660 * property can be set by an <ZOO.Format> object when 3661 * deserializing the feature, so in most cases it represents an 3662 * information set by the server. 3663 */ 3664 bounds: null, 3665 /** 3666 * Constructor: ZOO.Feature 3667 * Create a vector feature. 3668 * 3669 * Parameters: 3670 * geometry - {<ZOO.Geometry>} The geometry that this feature 3671 * represents. 3672 * attributes - {Object} An optional object that will be mapped to the 3673 * <attributes> property. 3674 */ 3675 initialize: function(geometry, attributes) { 3676 this.geometry = geometry ? geometry : null; 3677 this.attributes = {}; 3678 if (attributes) 3679 this.attributes = ZOO.extend(this.attributes,attributes); 3680 }, 3681 /** 3682 * Method: destroy 3683 * nullify references to prevent circular references and memory leaks 3684 */ 3685 destroy: function() { 3686 this.geometry = null; 3687 }, 3688 /** 3689 * Method: clone 3690 * Create a clone of this vector feature. Does not set any non-standard 3691 * properties. 3692 * 3693 * Returns: 3694 * {<ZOO.Feature>} An exact clone of this vector feature. 3695 */ 3696 clone: function () { 3697 return new ZOO.Feature(this.geometry ? this.geometry.clone() : null, 3698 this.attributes); 3699 }, 3700 /** 3701 * Method: move 3702 * Moves the feature and redraws it at its new location 3703 * 3704 * Parameters: 3705 * x - {Float} 3706 * y - {Float} 3707 */ 3708 move: function(x, y) { 3709 if(!this.geometry.move) 3710 return; 3711 3712 this.geometry.move(x,y); 3713 return this.geometry; 3714 }, 3715 CLASS_NAME: 'ZOO.Feature' 3716 }); 3717 3718 /** 3719 * Class: ZOO.Geometry 3720 * A Geometry is a description of a geographic object. Create an instance 3721 * of this class with the <ZOO.Geometry> constructor. This is a base class, 3722 * typical geometry types are described by subclasses of this class. 3723 */ 3724 ZOO.Geometry = ZOO.Class({ 3725 /** 3726 * Property: id 3727 * {String} A unique identifier for this geometry. 3728 */ 3729 id: null, 3730 /** 3731 * Property: parent 3732 * {<ZOO.Geometry>}This is set when a Geometry is added as component 3733 * of another geometry 3734 */ 3735 parent: null, 3736 /** 3737 * Property: bounds 3738 * {<ZOO.Bounds>} The bounds of this geometry 3739 */ 3740 bounds: null, 3741 /** 3742 * Constructor: ZOO.Geometry 3743 * Creates a geometry object. 3744 */ 3745 initialize: function() { 3746 //generate unique id 3747 }, 3748 /** 3749 * Method: destroy 3750 * Destroy this geometry. 3751 */ 3752 destroy: function() { 3753 this.id = null; 3754 this.bounds = null; 3755 }, 3756 /** 3757 * Method: clone 3758 * Create a clone of this geometry. Does not set any non-standard 3759 * properties of the cloned geometry. 3760 * 3761 * Returns: 3762 * {<ZOO.Geometry>} An exact clone of this geometry. 3763 */ 3764 clone: function() { 3765 return new ZOO.Geometry(); 3766 }, 3767 /** 3768 * Method: extendBounds 3769 * Extend the existing bounds to include the new bounds. 3770 * If geometry's bounds is not yet set, then set a new Bounds. 3771 * 3772 * Parameters: 3773 * newBounds - {<ZOO.Bounds>} 3774 */ 3775 extendBounds: function(newBounds){ 3776 var bounds = this.getBounds(); 3777 if (!bounds) 3778 this.setBounds(newBounds); 3779 else 3780 this.bounds.extend(newBounds); 3781 }, 3782 /** 3783 * Set the bounds for this Geometry. 3784 * 3785 * Parameters: 3786 * bounds - {<ZOO.Bounds>} 3787 */ 3788 setBounds: function(bounds) { 3789 if (bounds) 3790 this.bounds = bounds.clone(); 3791 }, 3792 /** 3793 * Method: clearBounds 3794 * Nullify this components bounds and that of its parent as well. 3795 */ 3796 clearBounds: function() { 3797 this.bounds = null; 3798 if (this.parent) 3799 this.parent.clearBounds(); 3800 }, 3801 /** 3802 * Method: getBounds 3803 * Get the bounds for this Geometry. If bounds is not set, it 3804 * is calculated again, this makes queries faster. 3805 * 3806 * Returns: 3807 * {<ZOO.Bounds>} 3808 */ 3809 getBounds: function() { 3810 if (this.bounds == null) { 3811 this.calculateBounds(); 3812 } 3813 return this.bounds; 3814 }, 3815 /** 3816 * Method: calculateBounds 3817 * Recalculate the bounds for the geometry. 3818 */ 3819 calculateBounds: function() { 3820 // This should be overridden by subclasses. 3821 return this.bounds; 3822 }, 3823 distanceTo: function(geometry, options) { 3824 }, 3825 getVertices: function(nodes) { 3826 }, 3827 getLength: function() { 3828 return 0.0; 3829 }, 3830 getArea: function() { 3831 return 0.0; 3832 }, 3833 getCentroid: function() { 3834 return null; 3835 }, 3836 /** 3837 * Method: toString 3838 * Returns the Well-Known Text representation of a geometry 3839 * 3840 * Returns: 3841 * {String} Well-Known Text 3842 */ 3843 toString: function() { 3844 return ZOO.Format.WKT.prototype.write( 3845 new ZOO.Feature(this) 3846 ); 3847 }, 3848 CLASS_NAME: 'ZOO.Geometry' 3849 }); 3850 /** 3851 * Function: OpenLayers.Geometry.fromWKT 3852 * Generate a geometry given a Well-Known Text string. 3853 * 3854 * Parameters: 3855 * wkt - {String} A string representing the geometry in Well-Known Text. 3856 * 3857 * Returns: 3858 * {<ZOO.Geometry>} A geometry of the appropriate class. 3859 */ 3860 ZOO.Geometry.fromWKT = function(wkt) { 3861 var format = arguments.callee.format; 3862 if(!format) { 3863 format = new ZOO.Format.WKT(); 3864 arguments.callee.format = format; 3865 } 3866 var geom; 3867 var result = format.read(wkt); 3868 if(result instanceof ZOO.Feature) { 3869 geom = result.geometry; 3870 } else if(result instanceof Array) { 3871 var len = result.length; 3872 var components = new Array(len); 3873 for(var i=0; i<len; ++i) { 3874 components[i] = result[i].geometry; 3875 } 3876 geom = new ZOO.Geometry.Collection(components); 3877 } 3878 return geom; 3879 }; 3880 ZOO.Geometry.segmentsIntersect = function(seg1, seg2, options) { 3881 var point = options && options.point; 3882 var tolerance = options && options.tolerance; 3883 var intersection = false; 3884 var x11_21 = seg1.x1 - seg2.x1; 3885 var y11_21 = seg1.y1 - seg2.y1; 3886 var x12_11 = seg1.x2 - seg1.x1; 3887 var y12_11 = seg1.y2 - seg1.y1; 3888 var y22_21 = seg2.y2 - seg2.y1; 3889 var x22_21 = seg2.x2 - seg2.x1; 3890 var d = (y22_21 * x12_11) - (x22_21 * y12_11); 3891 var n1 = (x22_21 * y11_21) - (y22_21 * x11_21); 3892 var n2 = (x12_11 * y11_21) - (y12_11 * x11_21); 3893 if(d == 0) { 3894 // parallel 3895 if(n1 == 0 && n2 == 0) { 3896 // coincident 3897 intersection = true; 3898 } 3899 } else { 3900 var along1 = n1 / d; 3901 var along2 = n2 / d; 3902 if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) { 3903 // intersect 3904 if(!point) { 3905 intersection = true; 3906 } else { 3907 // calculate the intersection point 3908 var x = seg1.x1 + (along1 * x12_11); 3909 var y = seg1.y1 + (along1 * y12_11); 3910 intersection = new ZOO.Geometry.Point(x, y); 3911 } 3912 } 3913 } 3914 if(tolerance) { 3915 var dist; 3916 if(intersection) { 3917 if(point) { 3918 var segs = [seg1, seg2]; 3919 var seg, x, y; 3920 // check segment endpoints for proximity to intersection 3921 // set intersection to first endpoint within the tolerance 3922 outer: for(var i=0; i<2; ++i) { 3923 seg = segs[i]; 3924 for(var j=1; j<3; ++j) { 3925 x = seg["x" + j]; 3926 y = seg["y" + j]; 3927 dist = Math.sqrt( 3928 Math.pow(x - intersection.x, 2) + 3929 Math.pow(y - intersection.y, 2) 3930 ); 3931 if(dist < tolerance) { 3932 intersection.x = x; 3933 intersection.y = y; 3934 break outer; 3935 } 3936 } 3937 } 3938 } 3939 } else { 3940 // no calculated intersection, but segments could be within 3941 // the tolerance of one another 3942 var segs = [seg1, seg2]; 3943 var source, target, x, y, p, result; 3944 // check segment endpoints for proximity to intersection 3945 // set intersection to first endpoint within the tolerance 3946 outer: for(var i=0; i<2; ++i) { 3947 source = segs[i]; 3948 target = segs[(i+1)%2]; 3949 for(var j=1; j<3; ++j) { 3950 p = {x: source["x"+j], y: source["y"+j]}; 3951 result = ZOO.Geometry.distanceToSegment(p, target); 3952 if(result.distance < tolerance) { 3953 if(point) { 3954 intersection = new ZOO.Geometry.Point(p.x, p.y); 3955 } else { 3956 intersection = true; 3957 } 3958 break outer; 3959 } 3960 } 3961 } 3962 } 3963 } 3964 return intersection; 3965 }; 3966 ZOO.Geometry.distanceToSegment = function(point, segment) { 3967 var x0 = point.x; 3968 var y0 = point.y; 3969 var x1 = segment.x1; 3970 var y1 = segment.y1; 3971 var x2 = segment.x2; 3972 var y2 = segment.y2; 3973 var dx = x2 - x1; 3974 var dy = y2 - y1; 3975 var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / 3976 (Math.pow(dx, 2) + Math.pow(dy, 2)); 3977 var x, y; 3978 if(along <= 0.0) { 3979 x = x1; 3980 y = y1; 3981 } else if(along >= 1.0) { 3982 x = x2; 3983 y = y2; 3984 } else { 3985 x = x1 + along * dx; 3986 y = y1 + along * dy; 3987 } 3988 return { 3989 distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)), 3990 x: x, y: y 3991 }; 3992 }; 3993 /** 3994 * Class: OpenLayers.Geometry.Collection 3995 * A Collection is exactly what it sounds like: A collection of different 3996 * Geometries. These are stored in the local parameter <components> (which 3997 * can be passed as a parameter to the constructor). 3998 * 3999 * As new geometries are added to the collection, they are NOT cloned. 4000 * When removing geometries, they need to be specified by reference (ie you 4001 * have to pass in the *exact* geometry to be removed). 4002 * 4003 * The <getArea> and <getLength> functions here merely iterate through 4004 * the components, summing their respective areas and lengths. 4005 * 4006 * Create a new instance with the <ZOO.Geometry.Collection> constructor. 4007 * 4008 * Inerhits from: 4009 * - <ZOO.Geometry> 4010 */ 4011 ZOO.Geometry.Collection = ZOO.Class(ZOO.Geometry, { 4012 /** 4013 * Property: components 4014 * {Array(<ZOO.Geometry>)} The component parts of this geometry 4015 */ 4016 components: null, 4017 /** 4018 * Property: componentTypes 4019 * {Array(String)} An array of class names representing the types of 4020 * components that the collection can include. A null value means the 4021 * component types are not restricted. 4022 */ 4023 componentTypes: null, 4024 /** 4025 * Constructor: ZOO.Geometry.Collection 4026 * Creates a Geometry Collection -- a list of geoms. 4027 * 4028 * Parameters: 4029 * components - {Array(<ZOO.Geometry>)} Optional array of geometries 4030 * 4031 */ 4032 initialize: function (components) { 4033 ZOO.Geometry.prototype.initialize.apply(this, arguments); 4034 this.components = []; 4035 if (components != null) { 4036 this.addComponents(components); 4037 } 4038 }, 4039 /** 4040 * Method: destroy 4041 * Destroy this geometry. 4042 */ 4043 destroy: function () { 4044 this.components.length = 0; 4045 this.components = null; 4046 }, 4047 /** 4048 * Method: clone 4049 * Clone this geometry. 4050 * 4051 * Returns: 4052 * {<ZOO.Geometry.Collection>} An exact clone of this collection 4053 */ 4054 clone: function() { 4055 var geometry = eval("new " + this.CLASS_NAME + "()"); 4056 for(var i=0, len=this.components.length; i<len; i++) { 4057 geometry.addComponent(this.components[i].clone()); 4058 } 4059 return geometry; 4060 }, 4061 /** 4062 * Method: getComponentsString 4063 * Get a string representing the components for this collection 4064 * 4065 * Returns: 4066 * {String} A string representation of the components of this geometry 4067 */ 4068 getComponentsString: function(){ 4069 var strings = []; 4070 for(var i=0, len=this.components.length; i<len; i++) { 4071 strings.push(this.components[i].toShortString()); 4072 } 4073 return strings.join(","); 4074 }, 4075 /** 4076 * Method: calculateBounds 4077 * Recalculate the bounds by iterating through the components and 4078 * calling calling extendBounds() on each item. 4079 */ 4080 calculateBounds: function() { 4081 this.bounds = null; 4082 if ( this.components && this.components.length > 0) { 4083 this.setBounds(this.components[0].getBounds()); 4084 for (var i=1, len=this.components.length; i<len; i++) { 4085 this.extendBounds(this.components[i].getBounds()); 4086 } 4087 } 4088 return this.bounds 4089 }, 4090 /** 4091 * APIMethod: addComponents 4092 * Add components to this geometry. 4093 * 4094 * Parameters: 4095 * components - {Array(<ZOO.Geometry>)} An array of geometries to add 4096 */ 4097 addComponents: function(components){ 4098 if(!(components instanceof Array)) 4099 components = [components]; 4100 for(var i=0, len=components.length; i<len; i++) { 4101 this.addComponent(components[i]); 4102 } 4103 }, 4104 /** 4105 * Method: addComponent 4106 * Add a new component (geometry) to the collection. If this.componentTypes 4107 * is set, then the component class name must be in the componentTypes array. 4108 * 4109 * The bounds cache is reset. 4110 * 4111 * Parameters: 4112 * component - {<ZOO.Geometry>} A geometry to add 4113 * index - {int} Optional index into the array to insert the component 4114 * 4115 * Returns: 4116 * {Boolean} The component geometry was successfully added 4117 */ 4118 addComponent: function(component, index) { 4119 var added = false; 4120 if(component) { 4121 if(this.componentTypes == null || 4122 (ZOO.indexOf(this.componentTypes, 4123 component.CLASS_NAME) > -1)) { 4124 if(index != null && (index < this.components.length)) { 4125 var components1 = this.components.slice(0, index); 4126 var components2 = this.components.slice(index, 4127 this.components.length); 4128 components1.push(component); 4129 this.components = components1.concat(components2); 4130 } else { 4131 this.components.push(component); 4132 } 4133 component.parent = this; 4134 this.clearBounds(); 4135 added = true; 4136 } 4137 } 4138 return added; 4139 }, 4140 /** 4141 * Method: removeComponents 4142 * Remove components from this geometry. 4143 * 4144 * Parameters: 4145 * components - {Array(<ZOO.Geometry>)} The components to be removed 4146 */ 4147 removeComponents: function(components) { 4148 if(!(components instanceof Array)) 4149 components = [components]; 4150 for(var i=components.length-1; i>=0; --i) { 4151 this.removeComponent(components[i]); 4152 } 4153 }, 4154 /** 4155 * Method: removeComponent 4156 * Remove a component from this geometry. 4157 * 4158 * Parameters: 4159 * component - {<ZOO.Geometry>} 4160 */ 4161 removeComponent: function(component) { 4162 ZOO.removeItem(this.components, component); 4163 // clearBounds() so that it gets recalculated on the next call 4164 // to this.getBounds(); 4165 this.clearBounds(); 4166 }, 4167 /** 4168 * Method: getLength 4169 * Calculate the length of this geometry 4170 * 4171 * Returns: 4172 * {Float} The length of the geometry 4173 */ 4174 getLength: function() { 4175 var length = 0.0; 4176 for (var i=0, len=this.components.length; i<len; i++) { 4177 length += this.components[i].getLength(); 4178 } 4179 return length; 4180 }, 4181 /** 4182 * APIMethod: getArea 4183 * Calculate the area of this geometry. Note how this function is 4184 * overridden in <ZOO.Geometry.Polygon>. 4185 * 4186 * Returns: 4187 * {Float} The area of the collection by summing its parts 4188 */ 4189 getArea: function() { 4190 var area = 0.0; 4191 for (var i=0, len=this.components.length; i<len; i++) { 4192 area += this.components[i].getArea(); 4193 } 4194 return area; 4195 }, 4196 /** 4197 * APIMethod: getGeodesicArea 4198 * Calculate the approximate area of the polygon were it projected onto 4199 * the earth. 4200 * 4201 * Parameters: 4202 * projection - {<ZOO.Projection>} The spatial reference system 4203 * for the geometry coordinates. If not provided, Geographic/WGS84 is 4204 * assumed. 4205 * 4206 * Reference: 4207 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for 4208 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion 4209 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 4210 * 4211 * Returns: 4212 * {float} The approximate geodesic area of the geometry in square meters. 4213 */ 4214 getGeodesicArea: function(projection) { 4215 var area = 0.0; 4216 for(var i=0, len=this.components.length; i<len; i++) { 4217 area += this.components[i].getGeodesicArea(projection); 4218 } 4219 return area; 4220 }, 4221 /** 4222 * Method: getCentroid 4223 * 4224 * Returns: 4225 * {<ZOO.Geometry.Point>} The centroid of the collection 4226 */ 4227 getCentroid: function() { 4228 return this.components.length && this.components[0].getCentroid(); 4229 }, 4230 /** 4231 * Method: getGeodesicLength 4232 * Calculate the approximate length of the geometry were it projected onto 4233 * the earth. 4234 * 4235 * projection - {<ZOO.Projection>} The spatial reference system 4236 * for the geometry coordinates. If not provided, Geographic/WGS84 is 4237 * assumed. 4238 * 4239 * Returns: 4240 * {Float} The appoximate geodesic length of the geometry in meters. 4241 */ 4242 getGeodesicLength: function(projection) { 4243 var length = 0.0; 4244 for(var i=0, len=this.components.length; i<len; i++) { 4245 length += this.components[i].getGeodesicLength(projection); 4246 } 4247 return length; 4248 }, 4249 /** 4250 * Method: move 4251 * Moves a geometry by the given displacement along positive x and y axes. 4252 * This modifies the position of the geometry and clears the cached 4253 * bounds. 4254 * 4255 * Parameters: 4256 * x - {Float} Distance to move geometry in positive x direction. 4257 * y - {Float} Distance to move geometry in positive y direction. 4258 */ 4259 move: function(x, y) { 4260 for(var i=0, len=this.components.length; i<len; i++) { 4261 this.components[i].move(x, y); 4262 } 4263 }, 4264 /** 4265 * Method: rotate 4266 * Rotate a geometry around some origin 4267 * 4268 * Parameters: 4269 * angle - {Float} Rotation angle in degrees (measured counterclockwise 4270 * from the positive x-axis) 4271 * origin - {<ZOO.Geometry.Point>} Center point for the rotation 4272 */ 4273 rotate: function(angle, origin) { 4274 for(var i=0, len=this.components.length; i<len; ++i) { 4275 this.components[i].rotate(angle, origin); 4276 } 4277 }, 4278 /** 4279 * Method: resize 4280 * Resize a geometry relative to some origin. Use this method to apply 4281 * a uniform scaling to a geometry. 4282 * 4283 * Parameters: 4284 * scale - {Float} Factor by which to scale the geometry. A scale of 2 4285 * doubles the size of the geometry in each dimension 4286 * (lines, for example, will be twice as long, and polygons 4287 * will have four times the area). 4288 * origin - {<ZOO.Geometry.Point>} Point of origin for resizing 4289 * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. 4290 * 4291 * Returns: 4292 * {ZOO.Geometry} - The current geometry. 4293 */ 4294 resize: function(scale, origin, ratio) { 4295 for(var i=0; i<this.components.length; ++i) { 4296 this.components[i].resize(scale, origin, ratio); 4297 } 4298 return this; 4299 }, 4300 distanceTo: function(geometry, options) { 4301 var edge = !(options && options.edge === false); 4302 var details = edge && options && options.details; 4303 var result, best; 4304 var min = Number.POSITIVE_INFINITY; 4305 for(var i=0, len=this.components.length; i<len; ++i) { 4306 result = this.components[i].distanceTo(geometry, options); 4307 distance = details ? result.distance : result; 4308 if(distance < min) { 4309 min = distance; 4310 best = result; 4311 if(min == 0) 4312 break; 4313 } 4314 } 4315 return best; 4316 }, 4317 /** 4318 * Method: equals 4319 * Determine whether another geometry is equivalent to this one. Geometries 4320 * are considered equivalent if all components have the same coordinates. 4321 * 4322 * Parameters: 4323 * geom - {<ZOO.Geometry>} The geometry to test. 4324 * 4325 * Returns: 4326 * {Boolean} The supplied geometry is equivalent to this geometry. 4327 */ 4328 equals: function(geometry) { 4329 var equivalent = true; 4330 if(!geometry || !geometry.CLASS_NAME || 4331 (this.CLASS_NAME != geometry.CLASS_NAME)) 4332 equivalent = false; 4333 else if(!(geometry.components instanceof Array) || 4334 (geometry.components.length != this.components.length)) 4335 equivalent = false; 4336 else 4337 for(var i=0, len=this.components.length; i<len; ++i) { 4338 if(!this.components[i].equals(geometry.components[i])) { 4339 equivalent = false; 4340 break; 4341 } 4342 } 4343 return equivalent; 4344 }, 4345 /** 4346 * Method: transform 4347 * Reproject the components geometry from source to dest. 4348 * 4349 * Parameters: 4350 * source - {<ZOO.Projection>} 4351 * dest - {<ZOO.Projection>} 4352 * 4353 * Returns: 4354 * {<ZOO.Geometry>} 4355 */ 4356 transform: function(source, dest) { 4357 if (source && dest) { 4358 for (var i=0, len=this.components.length; i<len; i++) { 4359 var component = this.components[i]; 4360 component.transform(source, dest); 4361 } 4362 this.bounds = null; 4363 } 4364 return this; 4365 }, 4366 /** 4367 * Method: intersects 4368 * Determine if the input geometry intersects this one. 4369 * 4370 * Parameters: 4371 * geometry - {<ZOO.Geometry>} Any type of geometry. 4372 * 4373 * Returns: 4374 * {Boolean} The input geometry intersects this one. 4375 */ 4376 intersects: function(geometry) { 4377 var intersect = false; 4378 for(var i=0, len=this.components.length; i<len; ++ i) { 4379 intersect = geometry.intersects(this.components[i]); 4380 if(intersect) 4381 break; 4382 } 4383 return intersect; 4384 }, 4385 /** 4386 * Method: getVertices 4387 * Return a list of all points in this geometry. 4388 * 4389 * Parameters: 4390 * nodes - {Boolean} For lines, only return vertices that are 4391 * endpoints. If false, for lines, only vertices that are not 4392 * endpoints will be returned. If not provided, all vertices will 4393 * be returned. 4394 * 4395 * Returns: 4396 * {Array} A list of all vertices in the geometry. 4397 */ 4398 getVertices: function(nodes) { 4399 var vertices = []; 4400 for(var i=0, len=this.components.length; i<len; ++i) { 4401 Array.prototype.push.apply( 4402 vertices, this.components[i].getVertices(nodes) 4403 ); 4404 } 4405 return vertices; 4406 }, 4407 CLASS_NAME: 'ZOO.Geometry.Collection' 4408 }); 4409 /** 4410 * Class: ZOO.Geometry.Point 4411 * Point geometry class. 4412 * 4413 * Inherits from: 4414 * - <ZOO.Geometry> 4415 */ 4416 ZOO.Geometry.Point = ZOO.Class(ZOO.Geometry, { 4417 /** 4418 * Property: x 4419 * {float} 4420 */ 4421 x: null, 4422 /** 4423 * Property: y 4424 * {float} 4425 */ 4426 y: null, 4427 /** 4428 * Constructor: ZOO.Geometry.Point 4429 * Construct a point geometry. 4430 * 4431 * Parameters: 4432 * x - {float} 4433 * y - {float} 4434 * 4435 */ 4436 initialize: function(x, y) { 4437 ZOO.Geometry.prototype.initialize.apply(this, arguments); 4438 this.x = parseFloat(x); 4439 this.y = parseFloat(y); 4440 }, 4441 /** 4442 * Method: clone 4443 * 4444 * Returns: 4445 * {<ZOO.Geometry.Point>} An exact clone of this ZOO.Geometry.Point 4446 */ 4447 clone: function(obj) { 4448 if (obj == null) 4449 obj = new ZOO.Geometry.Point(this.x, this.y); 4450 // catch any randomly tagged-on properties 4451 // ZOO.Util.applyDefaults(obj, this); 4452 return obj; 4453 }, 4454 /** 4455 * Method: calculateBounds 4456 * Create a new Bounds based on the x/y 4457 */ 4458 calculateBounds: function () { 4459 this.bounds = new ZOO.Bounds(this.x, this.y, 4460 this.x, this.y); 4461 }, 4462 distanceTo: function(geometry, options) { 4463 var edge = !(options && options.edge === false); 4464 var details = edge && options && options.details; 4465 var distance, x0, y0, x1, y1, result; 4466 if(geometry instanceof ZOO.Geometry.Point) { 4467 x0 = this.x; 4468 y0 = this.y; 4469 x1 = geometry.x; 4470 y1 = geometry.y; 4471 distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2)); 4472 result = !details ? 4473 distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance}; 4474 } else { 4475 result = geometry.distanceTo(this, options); 4476 if(details) { 4477 // switch coord order since this geom is target 4478 result = { 4479 x0: result.x1, y0: result.y1, 4480 x1: result.x0, y1: result.y0, 4481 distance: result.distance 4482 }; 4483 } 4484 } 4485 return result; 4486 }, 4487 /** 4488 * Method: equals 4489 * Determine whether another geometry is equivalent to this one. Geometries 4490 * are considered equivalent if all components have the same coordinates. 4491 * 4492 * Parameters: 4493 * geom - {<ZOO.Geometry.Point>} The geometry to test. 4494 * 4495 * Returns: 4496 * {Boolean} The supplied geometry is equivalent to this geometry. 4497 */ 4498 equals: function(geom) { 4499 var equals = false; 4500 if (geom != null) 4501 equals = ((this.x == geom.x && this.y == geom.y) || 4502 (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y))); 4503 return equals; 4504 }, 4505 /** 4506 * Method: toShortString 4507 * 4508 * Returns: 4509 * {String} Shortened String representation of Point object. 4510 * (ex. <i>"5, 42"</i>) 4511 */ 4512 toShortString: function() { 4513 return (this.x + ", " + this.y); 4514 }, 4515 /** 4516 * Method: move 4517 * Moves a geometry by the given displacement along positive x and y axes. 4518 * This modifies the position of the geometry and clears the cached 4519 * bounds. 4520 * 4521 * Parameters: 4522 * x - {Float} Distance to move geometry in positive x direction. 4523 * y - {Float} Distance to move geometry in positive y direction. 4524 */ 4525 move: function(x, y) { 4526 this.x = this.x + x; 4527 this.y = this.y + y; 4528 this.clearBounds(); 4529 }, 4530 /** 4531 * Method: rotate 4532 * Rotate a point around another. 4533 * 4534 * Parameters: 4535 * angle - {Float} Rotation angle in degrees (measured counterclockwise 4536 * from the positive x-axis) 4537 * origin - {<ZOO.Geometry.Point>} Center point for the rotation 4538 */ 4539 rotate: function(angle, origin) { 4540 angle *= Math.PI / 180; 4541 var radius = this.distanceTo(origin); 4542 var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x); 4543 this.x = origin.x + (radius * Math.cos(theta)); 4544 this.y = origin.y + (radius * Math.sin(theta)); 4545 this.clearBounds(); 4546 }, 4547 /** 4548 * Method: getCentroid 4549 * 4550 * Returns: 4551 * {<ZOO.Geometry.Point>} The centroid of the collection 4552 */ 4553 getCentroid: function() { 4554 return new ZOO.Geometry.Point(this.x, this.y); 4555 }, 4556 /** 4557 * Method: resize 4558 * Resize a point relative to some origin. For points, this has the effect 4559 * of scaling a vector (from the origin to the point). This method is 4560 * more useful on geometry collection subclasses. 4561 * 4562 * Parameters: 4563 * scale - {Float} Ratio of the new distance from the origin to the old 4564 * distance from the origin. A scale of 2 doubles the 4565 * distance between the point and origin. 4566 * origin - {<ZOO.Geometry.Point>} Point of origin for resizing 4567 * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. 4568 * 4569 * Returns: 4570 * {ZOO.Geometry} - The current geometry. 4571 */ 4572 resize: function(scale, origin, ratio) { 4573 ratio = (ratio == undefined) ? 1 : ratio; 4574 this.x = origin.x + (scale * ratio * (this.x - origin.x)); 4575 this.y = origin.y + (scale * (this.y - origin.y)); 4576 this.clearBounds(); 4577 return this; 4578 }, 4579 /** 4580 * Method: intersects 4581 * Determine if the input geometry intersects this one. 4582 * 4583 * Parameters: 4584 * geometry - {<ZOO.Geometry>} Any type of geometry. 4585 * 4586 * Returns: 4587 * {Boolean} The input geometry intersects this one. 4588 */ 4589 intersects: function(geometry) { 4590 var intersect = false; 4591 if(geometry.CLASS_NAME == "ZOO.Geometry.Point") { 4592 intersect = this.equals(geometry); 4593 } else { 4594 intersect = geometry.intersects(this); 4595 } 4596 return intersect; 4597 }, 4598 /** 4599 * Method: transform 4600 * Translate the x,y properties of the point from source to dest. 4601 * 4602 * Parameters: 4603 * source - {<ZOO.Projection>} 4604 * dest - {<ZOO.Projection>} 4605 * 4606 * Returns: 4607 * {<ZOO.Geometry>} 4608 */ 4609 transform: function(source, dest) { 4610 if ((source && dest)) { 4611 ZOO.Projection.transform( 4612 this, source, dest); 4613 this.bounds = null; 4614 } 4615 return this; 4616 }, 4617 /** 4618 * Method: getVertices 4619 * Return a list of all points in this geometry. 4620 * 4621 * Parameters: 4622 * nodes - {Boolean} For lines, only return vertices that are 4623 * endpoints. If false, for lines, only vertices that are not 4624 * endpoints will be returned. If not provided, all vertices will 4625 * be returned. 4626 * 4627 * Returns: 4628 * {Array} A list of all vertices in the geometry. 4629 */ 4630 getVertices: function(nodes) { 4631 return [this]; 4632 }, 4633 CLASS_NAME: 'ZOO.Geometry.Point' 4634 }); 4635 /** 4636 * Class: ZOO.Geometry.Surface 4637 * Surface geometry class. 4638 * 4639 * Inherits from: 4640 * - <ZOO.Geometry> 4641 */ 4642 ZOO.Geometry.Surface = ZOO.Class(ZOO.Geometry, { 4643 initialize: function() { 4644 ZOO.Geometry.prototype.initialize.apply(this, arguments); 4645 }, 4646 CLASS_NAME: "ZOO.Geometry.Surface" 4647 }); 4648 /** 4649 * Class: ZOO.Geometry.MultiPoint 4650 * MultiPoint is a collection of Points. Create a new instance with the 4651 * <ZOO.Geometry.MultiPoint> constructor. 4652 * 4653 * Inherits from: 4654 * - <ZOO.Geometry.Collection> 4655 */ 4656 ZOO.Geometry.MultiPoint = ZOO.Class( 4657 ZOO.Geometry.Collection, { 4658 /** 4659 * Property: componentTypes 4660 * {Array(String)} An array of class names representing the types of 4661 * components that the collection can include. A null value means the 4662 * component types are not restricted. 4663 */ 4664 componentTypes: ["ZOO.Geometry.Point"], 4665 /** 4666 * Constructor: ZOO.Geometry.MultiPoint 4667 * Create a new MultiPoint Geometry 4668 * 4669 * Parameters: 4670 * components - {Array(<ZOO.Geometry.Point>)} 4671 * 4672 * Returns: 4673 * {<ZOO.Geometry.MultiPoint>} 4674 */ 4675 initialize: function(components) { 4676 ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments); 4677 }, 4678 /** 4679 * Method: addPoint 4680 * Wrapper for <ZOO.Geometry.Collection.addComponent> 4681 * 4682 * Parameters: 4683 * point - {<ZOO.Geometry.Point>} Point to be added 4684 * index - {Integer} Optional index 4685 */ 4686 addPoint: function(point, index) { 4687 this.addComponent(point, index); 4688 }, 4689 /** 4690 * Method: removePoint 4691 * Wrapper for <ZOO.Geometry.Collection.removeComponent> 4692 * 4693 * Parameters: 4694 * point - {<ZOO.Geometry.Point>} Point to be removed 4695 */ 4696 removePoint: function(point){ 4697 this.removeComponent(point); 4698 }, 4699 CLASS_NAME: "ZOO.Geometry.MultiPoint" 4700 }); 4701 /** 4702 * Class: ZOO.Geometry.Curve 4703 * A Curve is a MultiPoint, whose points are assumed to be connected. To 4704 * this end, we provide a "getLength()" function, which iterates through 4705 * the points, summing the distances between them. 4706 * 4707 * Inherits: 4708 * - <ZOO.Geometry.MultiPoint> 4709 */ 4710 ZOO.Geometry.Curve = ZOO.Class(ZOO.Geometry.MultiPoint, { 4711 /** 4712 * Property: componentTypes 4713 * {Array(String)} An array of class names representing the types of 4714 * components that the collection can include. A null 4715 * value means the component types are not restricted. 4716 */ 4717 componentTypes: ["ZOO.Geometry.Point"], 4718 /** 4719 * Constructor: ZOO.Geometry.Curve 4720 * 4721 * Parameters: 4722 * point - {Array(<ZOO.Geometry.Point>)} 4723 */ 4724 initialize: function(points) { 4725 ZOO.Geometry.MultiPoint.prototype.initialize.apply(this,arguments); 4726 }, 4727 /** 4728 * Method: getLength 4729 * 4730 * Returns: 4731 * {Float} The length of the curve 4732 */ 4733 getLength: function() { 4734 var length = 0.0; 4735 if ( this.components && (this.components.length > 1)) { 4736 for(var i=1, len=this.components.length; i<len; i++) { 4737 length += this.components[i-1].distanceTo(this.components[i]); 4738 } 4739 } 4740 return length; 4741 }, 4742 /** 4743 * APIMethod: getGeodesicLength 4744 * Calculate the approximate length of the geometry were it projected onto 4745 * the earth. 4746 * 4747 * projection - {<ZOO.Projection>} The spatial reference system 4748 * for the geometry coordinates. If not provided, Geographic/WGS84 is 4749 * assumed. 4750 * 4751 * Returns: 4752 * {Float} The appoximate geodesic length of the geometry in meters. 4753 */ 4754 getGeodesicLength: function(projection) { 4755 var geom = this; // so we can work with a clone if needed 4756 if(projection) { 4757 var gg = new ZOO.Projection("EPSG:4326"); 4758 if(!gg.equals(projection)) { 4759 geom = this.clone().transform(projection, gg); 4760 } 4761 } 4762 var length = 0.0; 4763 if(geom.components && (geom.components.length > 1)) { 4764 var p1, p2; 4765 for(var i=1, len=geom.components.length; i<len; i++) { 4766 p1 = geom.components[i-1]; 4767 p2 = geom.components[i]; 4768 // this returns km and requires x/y properties 4769 length += ZOO.distVincenty(p1,p2); 4770 } 4771 } 4772 // convert to m 4773 return length * 1000; 4774 }, 4775 CLASS_NAME: "ZOO.Geometry.Curve" 4776 }); 4777 /** 4778 * Class: ZOO.Geometry.LineString 4779 * A LineString is a Curve which, once two points have been added to it, can 4780 * never be less than two points long. 4781 * 4782 * Inherits from: 4783 * - <ZOO.Geometry.Curve> 4784 */ 4785 ZOO.Geometry.LineString = ZOO.Class(ZOO.Geometry.Curve, { 4786 /** 4787 * Constructor: ZOO.Geometry.LineString 4788 * Create a new LineString geometry 4789 * 4790 * Parameters: 4791 * points - {Array(<ZOO.Geometry.Point>)} An array of points used to 4792 * generate the linestring 4793 * 4794 */ 4795 initialize: function(points) { 4796 ZOO.Geometry.Curve.prototype.initialize.apply(this, arguments); 4797 }, 4798 /** 4799 * Method: removeComponent 4800 * Only allows removal of a point if there are three or more points in 4801 * the linestring. (otherwise the result would be just a single point) 4802 * 4803 * Parameters: 4804 * point - {<ZOO.Geometry.Point>} The point to be removed 4805 */ 4806 removeComponent: function(point) { 4807 if ( this.components && (this.components.length > 2)) 4808 ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments); 4809 }, 4810 /** 4811 * Method: intersects 4812 * Test for instersection between two geometries. This is a cheapo 4813 * implementation of the Bently-Ottmann algorigithm. It doesn't 4814 * really keep track of a sweep line data structure. It is closer 4815 * to the brute force method, except that segments are sorted and 4816 * potential intersections are only calculated when bounding boxes 4817 * intersect. 4818 * 4819 * Parameters: 4820 * geometry - {<ZOO.Geometry>} 4821 * 4822 * Returns: 4823 * {Boolean} The input geometry intersects this geometry. 4824 */ 4825 intersects: function(geometry) { 4826 var intersect = false; 4827 var type = geometry.CLASS_NAME; 4828 if(type == "ZOO.Geometry.LineString" || 4829 type == "ZOO.Geometry.LinearRing" || 4830 type == "ZOO.Geometry.Point") { 4831 var segs1 = this.getSortedSegments(); 4832 var segs2; 4833 if(type == "ZOO.Geometry.Point") 4834 segs2 = [{ 4835 x1: geometry.x, y1: geometry.y, 4836 x2: geometry.x, y2: geometry.y 4837 }]; 4838 else 4839 segs2 = geometry.getSortedSegments(); 4840 var seg1, seg1x1, seg1x2, seg1y1, seg1y2, 4841 seg2, seg2y1, seg2y2; 4842 // sweep right 4843 outer: for(var i=0, len=segs1.length; i<len; ++i) { 4844 seg1 = segs1[i]; 4845 seg1x1 = seg1.x1; 4846 seg1x2 = seg1.x2; 4847 seg1y1 = seg1.y1; 4848 seg1y2 = seg1.y2; 4849 inner: for(var j=0, jlen=segs2.length; j<jlen; ++j) { 4850 seg2 = segs2[j]; 4851 if(seg2.x1 > seg1x2) 4852 break; 4853 if(seg2.x2 < seg1x1) 4854 continue; 4855 seg2y1 = seg2.y1; 4856 seg2y2 = seg2.y2; 4857 if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) 4858 continue; 4859 if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) 4860 continue; 4861 if(ZOO.Geometry.segmentsIntersect(seg1, seg2)) { 4862 intersect = true; 4863 break outer; 4864 } 4865 } 4866 } 4867 } else { 4868 intersect = geometry.intersects(this); 4869 } 4870 return intersect; 4871 }, 4872 /** 4873 * Method: getSortedSegments 4874 * 4875 * Returns: 4876 * {Array} An array of segment objects. Segment objects have properties 4877 * x1, y1, x2, and y2. The start point is represented by x1 and y1. 4878 * The end point is represented by x2 and y2. Start and end are 4879 * ordered so that x1 < x2. 4880 */ 4881 getSortedSegments: function() { 4882 var numSeg = this.components.length - 1; 4883 var segments = new Array(numSeg); 4884 for(var i=0; i<numSeg; ++i) { 4885 point1 = this.components[i]; 4886 point2 = this.components[i + 1]; 4887 if(point1.x < point2.x) 4888 segments[i] = { 4889 x1: point1.x, 4890 y1: point1.y, 4891 x2: point2.x, 4892 y2: point2.y 4893 }; 4894 else 4895 segments[i] = { 4896 x1: point2.x, 4897 y1: point2.y, 4898 x2: point1.x, 4899 y2: point1.y 4900 }; 4901 } 4902 // more efficient to define this somewhere static 4903 function byX1(seg1, seg2) { 4904 return seg1.x1 - seg2.x1; 4905 } 4906 return segments.sort(byX1); 4907 }, 4908 /** 4909 * Method: splitWithSegment 4910 * Split this geometry with the given segment. 4911 * 4912 * Parameters: 4913 * seg - {Object} An object with x1, y1, x2, and y2 properties referencing 4914 * segment endpoint coordinates. 4915 * options - {Object} Properties of this object will be used to determine 4916 * how the split is conducted. 4917 * 4918 * Valid options: 4919 * edge - {Boolean} Allow splitting when only edges intersect. Default is 4920 * true. If false, a vertex on the source segment must be within the 4921 * tolerance distance of the intersection to be considered a split. 4922 * tolerance - {Number} If a non-null value is provided, intersections 4923 * within the tolerance distance of one of the source segment's 4924 * endpoints will be assumed to occur at the endpoint. 4925 * 4926 * Returns: 4927 * {Object} An object with *lines* and *points* properties. If the given 4928 * segment intersects this linestring, the lines array will reference 4929 * geometries that result from the split. The points array will contain 4930 * all intersection points. Intersection points are sorted along the 4931 * segment (in order from x1,y1 to x2,y2). 4932 */ 4933 splitWithSegment: function(seg, options) { 4934 var edge = !(options && options.edge === false); 4935 var tolerance = options && options.tolerance; 4936 var lines = []; 4937 var verts = this.getVertices(); 4938 var points = []; 4939 var intersections = []; 4940 var split = false; 4941 var vert1, vert2, point; 4942 var node, vertex, target; 4943 var interOptions = {point: true, tolerance: tolerance}; 4944 var result = null; 4945 for(var i=0, stop=verts.length-2; i<=stop; ++i) { 4946 vert1 = verts[i]; 4947 points.push(vert1.clone()); 4948 vert2 = verts[i+1]; 4949 target = {x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y}; 4950 point = ZOO.Geometry.segmentsIntersect(seg, target, interOptions); 4951 if(point instanceof ZOO.Geometry.Point) { 4952 if((point.x === seg.x1 && point.y === seg.y1) || 4953 (point.x === seg.x2 && point.y === seg.y2) || 4954 point.equals(vert1) || point.equals(vert2)) 4955 vertex = true; 4956 else 4957 vertex = false; 4958 if(vertex || edge) { 4959 // push intersections different than the previous 4960 if(!point.equals(intersections[intersections.length-1])) 4961 intersections.push(point.clone()); 4962 if(i === 0) { 4963 if(point.equals(vert1)) 4964 continue; 4965 } 4966 if(point.equals(vert2)) 4967 continue; 4968 split = true; 4969 if(!point.equals(vert1)) 4970 points.push(point); 4971 lines.push(new ZOO.Geometry.LineString(points)); 4972 points = [point.clone()]; 4973 } 4974 } 4975 } 4976 if(split) { 4977 points.push(vert2.clone()); 4978 lines.push(new ZOO.Geometry.LineString(points)); 4979 } 4980 if(intersections.length > 0) { 4981 // sort intersections along segment 4982 var xDir = seg.x1 < seg.x2 ? 1 : -1; 4983 var yDir = seg.y1 < seg.y2 ? 1 : -1; 4984 result = { 4985 lines: lines, 4986 points: intersections.sort(function(p1, p2) { 4987 return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y); 4988 }) 4989 }; 4990 } 4991 return result; 4992 }, 4993 /** 4994 * Method: split 4995 * Use this geometry (the source) to attempt to split a target geometry. 4996 * 4997 * Parameters: 4998 * target - {<ZOO.Geometry>} The target geometry. 4999 * options - {Object} Properties of this object will be used to determine 5000 * how the split is conducted. 5001 * 5002 * Valid options: 5003 * mutual - {Boolean} Split the source geometry in addition to the target 5004 * geometry. Default is false. 5005 * edge - {Boolean} Allow splitting when only edges intersect. Default is 5006 * true. If false, a vertex on the source must be within the tolerance 5007 * distance of the intersection to be considered a split. 5008 * tolerance - {Number} If a non-null value is provided, intersections 5009 * within the tolerance distance of an existing vertex on the source 5010 * will be assumed to occur at the vertex. 5011 * 5012 * Returns: 5013 * {Array} A list of geometries (of this same type as the target) that 5014 * result from splitting the target with the source geometry. The 5015 * source and target geometry will remain unmodified. If no split 5016 * results, null will be returned. If mutual is true and a split 5017 * results, return will be an array of two arrays - the first will be 5018 * all geometries that result from splitting the source geometry and 5019 * the second will be all geometries that result from splitting the 5020 * target geometry. 5021 */ 5022 split: function(target, options) { 5023 var results = null; 5024 var mutual = options && options.mutual; 5025 var sourceSplit, targetSplit, sourceParts, targetParts; 5026 if(target instanceof ZOO.Geometry.LineString) { 5027 var verts = this.getVertices(); 5028 var vert1, vert2, seg, splits, lines, point; 5029 var points = []; 5030 sourceParts = []; 5031 for(var i=0, stop=verts.length-2; i<=stop; ++i) { 5032 vert1 = verts[i]; 5033 vert2 = verts[i+1]; 5034 seg = { 5035 x1: vert1.x, y1: vert1.y, 5036 x2: vert2.x, y2: vert2.y 5037 }; 5038 targetParts = targetParts || [target]; 5039 if(mutual) 5040 points.push(vert1.clone()); 5041 for(var j=0; j<targetParts.length; ++j) { 5042 splits = targetParts[j].splitWithSegment(seg, options); 5043 if(splits) { 5044 // splice in new features 5045 lines = splits.lines; 5046 if(lines.length > 0) { 5047 lines.unshift(j, 1); 5048 Array.prototype.splice.apply(targetParts, lines); 5049 j += lines.length - 2; 5050 } 5051 if(mutual) { 5052 for(var k=0, len=splits.points.length; k<len; ++k) { 5053 point = splits.points[k]; 5054 if(!point.equals(vert1)) { 5055 points.push(point); 5056 sourceParts.push(new ZOO.Geometry.LineString(points)); 5057 if(point.equals(vert2)) 5058 points = []; 5059 else 5060 points = [point.clone()]; 5061 } 5062 } 5063 } 5064 } 5065 } 5066 } 5067 if(mutual && sourceParts.length > 0 && points.length > 0) { 5068 points.push(vert2.clone()); 5069 sourceParts.push(new ZOO.Geometry.LineString(points)); 5070 } 5071 } else { 5072 results = target.splitWith(this, options); 5073 } 5074 if(targetParts && targetParts.length > 1) 5075 targetSplit = true; 5076 else 5077 targetParts = []; 5078 if(sourceParts && sourceParts.length > 1) 5079 sourceSplit = true; 5080 else 5081 sourceParts = []; 5082 if(targetSplit || sourceSplit) { 5083 if(mutual) 5084 results = [sourceParts, targetParts]; 5085 else 5086 results = targetParts; 5087 } 5088 return results; 5089 }, 5090 /** 5091 * Method: splitWith 5092 * Split this geometry (the target) with the given geometry (the source). 5093 * 5094 * Parameters: 5095 * geometry - {<ZOO.Geometry>} A geometry used to split this 5096 * geometry (the source). 5097 * options - {Object} Properties of this object will be used to determine 5098 * how the split is conducted. 5099 * 5100 * Valid options: 5101 * mutual - {Boolean} Split the source geometry in addition to the target 5102 * geometry. Default is false. 5103 * edge - {Boolean} Allow splitting when only edges intersect. Default is 5104 * true. If false, a vertex on the source must be within the tolerance 5105 * distance of the intersection to be considered a split. 5106 * tolerance - {Number} If a non-null value is provided, intersections 5107 * within the tolerance distance of an existing vertex on the source 5108 * will be assumed to occur at the vertex. 5109 * 5110 * Returns: 5111 * {Array} A list of geometries (of this same type as the target) that 5112 * result from splitting the target with the source geometry. The 5113 * source and target geometry will remain unmodified. If no split 5114 * results, null will be returned. If mutual is true and a split 5115 * results, return will be an array of two arrays - the first will be 5116 * all geometries that result from splitting the source geometry and 5117 * the second will be all geometries that result from splitting the 5118 * target geometry. 5119 */ 5120 splitWith: function(geometry, options) { 5121 return geometry.split(this, options); 5122 }, 5123 /** 5124 * Method: getVertices 5125 * Return a list of all points in this geometry. 5126 * 5127 * Parameters: 5128 * nodes - {Boolean} For lines, only return vertices that are 5129 * endpoints. If false, for lines, only vertices that are not 5130 * endpoints will be returned. If not provided, all vertices will 5131 * be returned. 5132 * 5133 * Returns: 5134 * {Array} A list of all vertices in the geometry. 5135 */ 5136 getVertices: function(nodes) { 5137 var vertices; 5138 if(nodes === true) 5139 vertices = [ 5140 this.components[0], 5141 this.components[this.components.length-1] 5142 ]; 5143 else if (nodes === false) 5144 vertices = this.components.slice(1, this.components.length-1); 5145 else 5146 vertices = this.components.slice(); 5147 return vertices; 5148 }, 5149 distanceTo: function(geometry, options) { 5150 var edge = !(options && options.edge === false); 5151 var details = edge && options && options.details; 5152 var result, best = {}; 5153 var min = Number.POSITIVE_INFINITY; 5154 if(geometry instanceof ZOO.Geometry.Point) { 5155 var segs = this.getSortedSegments(); 5156 var x = geometry.x; 5157 var y = geometry.y; 5158 var seg; 5159 for(var i=0, len=segs.length; i<len; ++i) { 5160 seg = segs[i]; 5161 result = ZOO.Geometry.distanceToSegment(geometry, seg); 5162 if(result.distance < min) { 5163 min = result.distance; 5164 best = result; 5165 if(min === 0) 5166 break; 5167 } else { 5168 // if distance increases and we cross y0 to the right of x0, no need to keep looking. 5169 if(seg.x2 > x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) 5170 break; 5171 } 5172 } 5173 if(details) 5174 best = { 5175 distance: best.distance, 5176 x0: best.x, y0: best.y, 5177 x1: x, y1: y 5178 }; 5179 else 5180 best = best.distance; 5181 } else if(geometry instanceof ZOO.Geometry.LineString) { 5182 var segs0 = this.getSortedSegments(); 5183 var segs1 = geometry.getSortedSegments(); 5184 var seg0, seg1, intersection, x0, y0; 5185 var len1 = segs1.length; 5186 var interOptions = {point: true}; 5187 outer: for(var i=0, len=segs0.length; i<len; ++i) { 5188 seg0 = segs0[i]; 5189 x0 = seg0.x1; 5190 y0 = seg0.y1; 5191 for(var j=0; j<len1; ++j) { 5192 seg1 = segs1[j]; 5193 intersection = ZOO.Geometry.segmentsIntersect(seg0, seg1, interOptions); 5194 if(intersection) { 5195 min = 0; 5196 best = { 5197 distance: 0, 5198 x0: intersection.x, y0: intersection.y, 5199 x1: intersection.x, y1: intersection.y 5200 }; 5201 break outer; 5202 } else { 5203 result = ZOO.Geometry.distanceToSegment({x: x0, y: y0}, seg1); 5204 if(result.distance < min) { 5205 min = result.distance; 5206 best = { 5207 distance: min, 5208 x0: x0, y0: y0, 5209 x1: result.x, y1: result.y 5210 }; 5211 } 5212 } 5213 } 5214 } 5215 if(!details) 5216 best = best.distance; 5217 if(min !== 0) { 5218 // check the final vertex in this line's sorted segments 5219 if(seg0) { 5220 result = geometry.distanceTo( 5221 new ZOO.Geometry.Point(seg0.x2, seg0.y2), 5222 options 5223 ); 5224 var dist = details ? result.distance : result; 5225 if(dist < min) { 5226 if(details) 5227 best = { 5228 distance: min, 5229 x0: result.x1, y0: result.y1, 5230 x1: result.x0, y1: result.y0 5231 }; 5232 else 5233 best = dist; 5234 } 5235 } 5236 } 5237 } else { 5238 best = geometry.distanceTo(this, options); 5239 // swap since target comes from this line 5240 if(details) 5241 best = { 5242 distance: best.distance, 5243 x0: best.x1, y0: best.y1, 5244 x1: best.x0, y1: best.y0 5245 }; 5246 } 5247 return best; 5248 }, 5249 CLASS_NAME: "ZOO.Geometry.LineString" 5250 }); 5251 /** 5252 * Class: ZOO.Geometry.LinearRing 5253 * 5254 * A Linear Ring is a special LineString which is closed. It closes itself 5255 * automatically on every addPoint/removePoint by adding a copy of the first 5256 * point as the last point. 5257 * 5258 * Also, as it is the first in the line family to close itself, a getArea() 5259 * function is defined to calculate the enclosed area of the linearRing 5260 * 5261 * Inherits: 5262 * - <OpenLayers.Geometry.LineString> 5263 */ 5264 ZOO.Geometry.LinearRing = ZOO.Class( 5265 ZOO.Geometry.LineString, { 5266 /** 5267 * Property: componentTypes 5268 * {Array(String)} An array of class names representing the types of 5269 * components that the collection can include. A null 5270 * value means the component types are not restricted. 5271 */ 5272 componentTypes: ["ZOO.Geometry.Point"], 5273 /** 5274 * Constructor: OpenLayers.Geometry.LinearRing 5275 * Linear rings are constructed with an array of points. This array 5276 * can represent a closed or open ring. If the ring is open (the last 5277 * point does not equal the first point), the constructor will close 5278 * the ring. If the ring is already closed (the last point does equal 5279 * the first point), it will be left closed. 5280 * 5281 * Parameters: 5282 * points - {Array(<ZOO.Geometry.Point>)} points 5283 */ 5284 initialize: function(points) { 5285 ZOO.Geometry.LineString.prototype.initialize.apply(this,arguments); 5286 }, 5287 /** 5288 * Method: addComponent 5289 * Adds a point to geometry components. If the point is to be added to 5290 * the end of the components array and it is the same as the last point 5291 * already in that array, the duplicate point is not added. This has 5292 * the effect of closing the ring if it is not already closed, and 5293 * doing the right thing if it is already closed. This behavior can 5294 * be overridden by calling the method with a non-null index as the 5295 * second argument. 5296 * 5297 * Parameter: 5298 * point - {<ZOO.Geometry.Point>} 5299 * index - {Integer} Index into the array to insert the component 5300 * 5301 * Returns: 5302 * {Boolean} Was the Point successfully added? 5303 */ 5304 addComponent: function(point, index) { 5305 var added = false; 5306 //remove last point 5307 var lastPoint = this.components.pop(); 5308 // given an index, add the point 5309 // without an index only add non-duplicate points 5310 if(index != null || !point.equals(lastPoint)) 5311 added = ZOO.Geometry.Collection.prototype.addComponent.apply(this,arguments); 5312 //append copy of first point 5313 var firstPoint = this.components[0]; 5314 ZOO.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]); 5315 return added; 5316 }, 5317 /** 5318 * APIMethod: removeComponent 5319 * Removes a point from geometry components. 5320 * 5321 * Parameters: 5322 * point - {<ZOO.Geometry.Point>} 5323 */ 5324 removeComponent: function(point) { 5325 if (this.components.length > 4) { 5326 //remove last point 5327 this.components.pop(); 5328 //remove our point 5329 ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments); 5330 //append copy of first point 5331 var firstPoint = this.components[0]; 5332 ZOO.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]); 5333 } 5334 }, 5335 /** 5336 * Method: move 5337 * Moves a geometry by the given displacement along positive x and y axes. 5338 * This modifies the position of the geometry and clears the cached 5339 * bounds. 5340 * 5341 * Parameters: 5342 * x - {Float} Distance to move geometry in positive x direction. 5343 * y - {Float} Distance to move geometry in positive y direction. 5344 */ 5345 move: function(x, y) { 5346 for(var i = 0, len=this.components.length; i<len - 1; i++) { 5347 this.components[i].move(x, y); 5348 } 5349 }, 5350 /** 5351 * Method: rotate 5352 * Rotate a geometry around some origin 5353 * 5354 * Parameters: 5355 * angle - {Float} Rotation angle in degrees (measured counterclockwise 5356 * from the positive x-axis) 5357 * origin - {<ZOO.Geometry.Point>} Center point for the rotation 5358 */ 5359 rotate: function(angle, origin) { 5360 for(var i=0, len=this.components.length; i<len - 1; ++i) { 5361 this.components[i].rotate(angle, origin); 5362 } 5363 }, 5364 /** 5365 * Method: resize 5366 * Resize a geometry relative to some origin. Use this method to apply 5367 * a uniform scaling to a geometry. 5368 * 5369 * Parameters: 5370 * scale - {Float} Factor by which to scale the geometry. A scale of 2 5371 * doubles the size of the geometry in each dimension 5372 * (lines, for example, will be twice as long, and polygons 5373 * will have four times the area). 5374 * origin - {<ZOO.Geometry.Point>} Point of origin for resizing 5375 * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. 5376 * 5377 * Returns: 5378 * {ZOO.Geometry} - The current geometry. 5379 */ 5380 resize: function(scale, origin, ratio) { 5381 for(var i=0, len=this.components.length; i<len - 1; ++i) { 5382 this.components[i].resize(scale, origin, ratio); 5383 } 5384 return this; 5385 }, 5386 /** 5387 * Method: transform 5388 * Reproject the components geometry from source to dest. 5389 * 5390 * Parameters: 5391 * source - {<ZOO.Projection>} 5392 * dest - {<ZOO.Projection>} 5393 * 5394 * Returns: 5395 * {<ZOO.Geometry>} 5396 */ 5397 transform: function(source, dest) { 5398 if (source && dest) { 5399 for (var i=0, len=this.components.length; i<len - 1; i++) { 5400 var component = this.components[i]; 5401 component.transform(source, dest); 5402 } 5403 this.bounds = null; 5404 } 5405 return this; 5406 }, 5407 /** 5408 * Method: getCentroid 5409 * 5410 * Returns: 5411 * {<ZOO.Geometry.Point>} The centroid of the ring 5412 */ 5413 getCentroid: function() { 5414 if ( this.components && (this.components.length > 2)) { 5415 var sumX = 0.0; 5416 var sumY = 0.0; 5417 for (var i = 0; i < this.components.length - 1; i++) { 5418 var b = this.components[i]; 5419 var c = this.components[i+1]; 5420 sumX += (b.x + c.x) * (b.x * c.y - c.x * b.y); 5421 sumY += (b.y + c.y) * (b.x * c.y - c.x * b.y); 5422 } 5423 var area = -1 * this.getArea(); 5424 var x = sumX / (6 * area); 5425 var y = sumY / (6 * area); 5426 } 5427 return new ZOO.Geometry.Point(x, y); 5428 }, 5429 /** 5430 * Method: getArea 5431 * Note - The area is positive if the ring is oriented CW, otherwise 5432 * it will be negative. 5433 * 5434 * Returns: 5435 * {Float} The signed area for a ring. 5436 */ 5437 getArea: function() { 5438 var area = 0.0; 5439 if ( this.components && (this.components.length > 2)) { 5440 var sum = 0.0; 5441 for (var i=0, len=this.components.length; i<len - 1; i++) { 5442 var b = this.components[i]; 5443 var c = this.components[i+1]; 5444 sum += (b.x + c.x) * (c.y - b.y); 5445 } 5446 area = - sum / 2.0; 5447 } 5448 return area; 5449 }, 5450 /** 5451 * Method: getGeodesicArea 5452 * Calculate the approximate area of the polygon were it projected onto 5453 * the earth. Note that this area will be positive if ring is oriented 5454 * clockwise, otherwise it will be negative. 5455 * 5456 * Parameters: 5457 * projection - {<ZOO.Projection>} The spatial reference system 5458 * for the geometry coordinates. If not provided, Geographic/WGS84 is 5459 * assumed. 5460 * 5461 * Reference: 5462 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for 5463 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion 5464 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 5465 * 5466 * Returns: 5467 * {float} The approximate signed geodesic area of the polygon in square 5468 * meters. 5469 */ 5470 getGeodesicArea: function(projection) { 5471 var ring = this; // so we can work with a clone if needed 5472 if(projection) { 5473 var gg = new ZOO.Projection("EPSG:4326"); 5474 if(!gg.equals(projection)) { 5475 ring = this.clone().transform(projection, gg); 5476 } 5477 } 5478 var area = 0.0; 5479 var len = ring.components && ring.components.length; 5480 if(len > 2) { 5481 var p1, p2; 5482 for(var i=0; i<len-1; i++) { 5483 p1 = ring.components[i]; 5484 p2 = ring.components[i+1]; 5485 area += ZOO.rad(p2.x - p1.x) * 5486 (2 + Math.sin(ZOO.rad(p1.y)) + 5487 Math.sin(ZOO.rad(p2.y))); 5488 } 5489 area = area * 6378137.0 * 6378137.0 / 2.0; 5490 } 5491 return area; 5492 }, 5493 /** 5494 * Method: containsPoint 5495 * Test if a point is inside a linear ring. For the case where a point 5496 * is coincident with a linear ring edge, returns 1. Otherwise, 5497 * returns boolean. 5498 * 5499 * Parameters: 5500 * point - {<ZOO.Geometry.Point>} 5501 * 5502 * Returns: 5503 * {Boolean | Number} The point is inside the linear ring. Returns 1 if 5504 * the point is coincident with an edge. Returns boolean otherwise. 5505 */ 5506 containsPoint: function(point) { 5507 var approx = OpenLayers.Number.limitSigDigs; 5508 var digs = 14; 5509 var px = approx(point.x, digs); 5510 var py = approx(point.y, digs); 5511 function getX(y, x1, y1, x2, y2) { 5512 return (((x1 - x2) * y) + ((x2 * y1) - (x1 * y2))) / (y1 - y2); 5513 } 5514 var numSeg = this.components.length - 1; 5515 var start, end, x1, y1, x2, y2, cx, cy; 5516 var crosses = 0; 5517 for(var i=0; i<numSeg; ++i) { 5518 start = this.components[i]; 5519 x1 = approx(start.x, digs); 5520 y1 = approx(start.y, digs); 5521 end = this.components[i + 1]; 5522 x2 = approx(end.x, digs); 5523 y2 = approx(end.y, digs); 5524 5525 /** 5526 * The following conditions enforce five edge-crossing rules: 5527 * 1. points coincident with edges are considered contained; 5528 * 2. an upward edge includes its starting endpoint, and 5529 * excludes its final endpoint; 5530 * 3. a downward edge excludes its starting endpoint, and 5531 * includes its final endpoint; 5532 * 4. horizontal edges are excluded; and 5533 * 5. the edge-ray intersection point must be strictly right 5534 * of the point P. 5535 */ 5536 if(y1 == y2) { 5537 // horizontal edge 5538 if(py == y1) { 5539 // point on horizontal line 5540 if(x1 <= x2 && (px >= x1 && px <= x2) || // right or vert 5541 x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert 5542 // point on edge 5543 crosses = -1; 5544 break; 5545 } 5546 } 5547 // ignore other horizontal edges 5548 continue; 5549 } 5550 cx = approx(getX(py, x1, y1, x2, y2), digs); 5551 if(cx == px) { 5552 // point on line 5553 if(y1 < y2 && (py >= y1 && py <= y2) || // upward 5554 y1 > y2 && (py <= y1 && py >= y2)) { // downward 5555 // point on edge 5556 crosses = -1; 5557 break; 5558 } 5559 } 5560 if(cx <= px) { 5561 // no crossing to the right 5562 continue; 5563 } 5564 if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { 5565 // no crossing 5566 continue; 5567 } 5568 if(y1 < y2 && (py >= y1 && py < y2) || // upward 5569 y1 > y2 && (py < y1 && py >= y2)) { // downward 5570 ++crosses; 5571 } 5572 } 5573 var contained = (crosses == -1) ? 5574 // on edge 5575 1 : 5576 // even (out) or odd (in) 5577 !!(crosses & 1); 5578 5579 return contained; 5580 }, 5581 intersects: function(geometry) { 5582 var intersect = false; 5583 if(geometry.CLASS_NAME == "ZOO.Geometry.Point") 5584 intersect = this.containsPoint(geometry); 5585 else if(geometry.CLASS_NAME == "ZOO.Geometry.LineString") 5586 intersect = geometry.intersects(this); 5587 else if(geometry.CLASS_NAME == "ZOO.Geometry.LinearRing") 5588 intersect = ZOO.Geometry.LineString.prototype.intersects.apply( 5589 this, [geometry] 5590 ); 5591 else 5592 for(var i=0, len=geometry.components.length; i<len; ++ i) { 5593 intersect = geometry.components[i].intersects(this); 5594 if(intersect) 5595 break; 5596 } 5597 return intersect; 5598 }, 5599 getVertices: function(nodes) { 5600 return (nodes === true) ? [] : this.components.slice(0, this.components.length-1); 5601 }, 5602 CLASS_NAME: "ZOO.Geometry.LinearRing" 5603 }); 5604 /** 5605 * Class: ZOO.Geometry.MultiLineString 5606 * A MultiLineString is a geometry with multiple <ZOO.Geometry.LineString> 5607 * components. 5608 * 5609 * Inherits from: 5610 * - <ZOO.Geometry.Collection> 5611 */ 5612 ZOO.Geometry.MultiLineString = ZOO.Class( 5613 ZOO.Geometry.Collection, { 5614 componentTypes: ["ZOO.Geometry.LineString"], 5615 /** 5616 * Constructor: ZOO.Geometry.MultiLineString 5617 * Constructor for a MultiLineString Geometry. 5618 * 5619 * Parameters: 5620 * components - {Array(<ZOO.Geometry.LineString>)} 5621 * 5622 */ 5623 initialize: function(components) { 5624 ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments); 5625 }, 5626 split: function(geometry, options) { 5627 var results = null; 5628 var mutual = options && options.mutual; 5629 var splits, sourceLine, sourceLines, sourceSplit, targetSplit; 5630 var sourceParts = []; 5631 var targetParts = [geometry]; 5632 for(var i=0, len=this.components.length; i<len; ++i) { 5633 sourceLine = this.components[i]; 5634 sourceSplit = false; 5635 for(var j=0; j < targetParts.length; ++j) { 5636 splits = sourceLine.split(targetParts[j], options); 5637 if(splits) { 5638 if(mutual) { 5639 sourceLines = splits[0]; 5640 for(var k=0, klen=sourceLines.length; k<klen; ++k) { 5641 if(k===0 && sourceParts.length) 5642 sourceParts[sourceParts.length-1].addComponent( 5643 sourceLines[k] 5644 ); 5645 else 5646 sourceParts.push( 5647 new ZOO.Geometry.MultiLineString([ 5648 sourceLines[k] 5649 ]) 5650 ); 5651 } 5652 sourceSplit = true; 5653 splits = splits[1]; 5654 } 5655 if(splits.length) { 5656 // splice in new target parts 5657 splits.unshift(j, 1); 5658 Array.prototype.splice.apply(targetParts, splits); 5659 break; 5660 } 5661 } 5662 } 5663 if(!sourceSplit) { 5664 // source line was not hit 5665 if(sourceParts.length) { 5666 // add line to existing multi 5667 sourceParts[sourceParts.length-1].addComponent( 5668 sourceLine.clone() 5669 ); 5670 } else { 5671 // create a fresh multi 5672 sourceParts = [ 5673 new ZOO.Geometry.MultiLineString( 5674 sourceLine.clone() 5675 ) 5676 ]; 5677 } 5678 } 5679 } 5680 if(sourceParts && sourceParts.length > 1) 5681 sourceSplit = true; 5682 else 5683 sourceParts = []; 5684 if(targetParts && targetParts.length > 1) 5685 targetSplit = true; 5686 else 5687 targetParts = []; 5688 if(sourceSplit || targetSplit) { 5689 if(mutual) 5690 results = [sourceParts, targetParts]; 5691 else 5692 results = targetParts; 5693 } 5694 return results; 5695 }, 5696 splitWith: function(geometry, options) { 5697 var results = null; 5698 var mutual = options && options.mutual; 5699 var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts; 5700 if(geometry instanceof ZOO.Geometry.LineString) { 5701 targetParts = []; 5702 sourceParts = [geometry]; 5703 for(var i=0, len=this.components.length; i<len; ++i) { 5704 targetSplit = false; 5705 targetLine = this.components[i]; 5706 for(var j=0; j<sourceParts.length; ++j) { 5707 splits = sourceParts[j].split(targetLine, options); 5708 if(splits) { 5709 if(mutual) { 5710 sourceLines = splits[0]; 5711 if(sourceLines.length) { 5712 // splice in new source parts 5713 sourceLines.unshift(j, 1); 5714 Array.prototype.splice.apply(sourceParts, sourceLines); 5715 j += sourceLines.length - 2; 5716 } 5717 splits = splits[1]; 5718 if(splits.length === 0) { 5719 splits = [targetLine.clone()]; 5720 } 5721 } 5722 for(var k=0, klen=splits.length; k<klen; ++k) { 5723 if(k===0 && targetParts.length) { 5724 targetParts[targetParts.length-1].addComponent( 5725 splits[k] 5726 ); 5727 } else { 5728 targetParts.push( 5729 new ZOO.Geometry.MultiLineString([ 5730 splits[k] 5731 ]) 5732 ); 5733 } 5734 } 5735 targetSplit = true; 5736 } 5737 } 5738 if(!targetSplit) { 5739 // target component was not hit 5740 if(targetParts.length) { 5741 // add it to any existing multi-line 5742 targetParts[targetParts.length-1].addComponent( 5743 targetLine.clone() 5744 ); 5745 } else { 5746 // or start with a fresh multi-line 5747 targetParts = [ 5748 new ZOO.Geometry.MultiLineString([ 5749 targetLine.clone() 5750 ]) 5751 ]; 5752 } 5753 5754 } 5755 } 5756 } else { 5757 results = geometry.split(this); 5758 } 5759 if(sourceParts && sourceParts.length > 1) 5760 sourceSplit = true; 5761 else 5762 sourceParts = []; 5763 if(targetParts && targetParts.length > 1) 5764 targetSplit = true; 5765 else 5766 targetParts = []; 5767 if(sourceSplit || targetSplit) { 5768 if(mutual) 5769 results = [sourceParts, targetParts]; 5770 else 5771 results = targetParts; 5772 } 5773 return results; 5774 }, 5775 CLASS_NAME: "ZOO.Geometry.MultiLineString" 5776 }); 5777 /** 5778 * Class: ZOO.Geometry.Polygon 5779 * Polygon is a collection of <ZOO.Geometry.LinearRing>. 5780 * 5781 * Inherits from: 5782 * - <ZOO.Geometry.Collection> 5783 */ 5784 ZOO.Geometry.Polygon = ZOO.Class( 5785 ZOO.Geometry.Collection, { 5786 componentTypes: ["ZOO.Geometry.LinearRing"], 5787 /** 5788 * Constructor: OpenLayers.Geometry.Polygon 5789 * Constructor for a Polygon geometry. 5790 * The first ring (this.component[0])is the outer bounds of the polygon and 5791 * all subsequent rings (this.component[1-n]) are internal holes. 5792 * 5793 * 5794 * Parameters: 5795 * components - {Array(<ZOO.Geometry.LinearRing>)} 5796 */ 5797 initialize: function(components) { 5798 ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments); 5799 }, 5800 /** 5801 * Method: getArea 5802 * Calculated by subtracting the areas of the internal holes from the 5803 * area of the outer hole. 5804 * 5805 * Returns: 5806 * {float} The area of the geometry 5807 */ 5808 getArea: function() { 5809 var area = 0.0; 5810 if ( this.components && (this.components.length > 0)) { 5811 area += Math.abs(this.components[0].getArea()); 5812 for (var i=1, len=this.components.length; i<len; i++) { 5813 area -= Math.abs(this.components[i].getArea()); 5814 } 5815 } 5816 return area; 5817 }, 5818 /** 5819 * APIMethod: getGeodesicArea 5820 * Calculate the approximate area of the polygon were it projected onto 5821 * the earth. 5822 * 5823 * Parameters: 5824 * projection - {<ZOO.Projection>} The spatial reference system 5825 * for the geometry coordinates. If not provided, Geographic/WGS84 is 5826 * assumed. 5827 * 5828 * Reference: 5829 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for 5830 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion 5831 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 5832 * 5833 * Returns: 5834 * {float} The approximate geodesic area of the polygon in square meters. 5835 */ 5836 getGeodesicArea: function(projection) { 5837 var area = 0.0; 5838 if(this.components && (this.components.length > 0)) { 5839 area += Math.abs(this.components[0].getGeodesicArea(projection)); 5840 for(var i=1, len=this.components.length; i<len; i++) { 5841 area -= Math.abs(this.components[i].getGeodesicArea(projection)); 5842 } 5843 } 5844 return area; 5845 }, 5846 /** 5847 * Method: containsPoint 5848 * Test if a point is inside a polygon. Points on a polygon edge are 5849 * considered inside. 5850 * 5851 * Parameters: 5852 * point - {<ZOO.Geometry.Point>} 5853 * 5854 * Returns: 5855 * {Boolean | Number} The point is inside the polygon. Returns 1 if the 5856 * point is on an edge. Returns boolean otherwise. 5857 */ 5858 containsPoint: function(point) { 5859 var numRings = this.components.length; 5860 var contained = false; 5861 if(numRings > 0) { 5862 // check exterior ring - 1 means on edge, boolean otherwise 5863 contained = this.components[0].containsPoint(point); 5864 if(contained !== 1) { 5865 if(contained && numRings > 1) { 5866 // check interior rings 5867 var hole; 5868 for(var i=1; i<numRings; ++i) { 5869 hole = this.components[i].containsPoint(point); 5870 if(hole) { 5871 if(hole === 1) 5872 contained = 1; 5873 else 5874 contained = false; 5875 break; 5876 } 5877 } 5878 } 5879 } 5880 } 5881 return contained; 5882 }, 5883 intersects: function(geometry) { 5884 var intersect = false; 5885 var i, len; 5886 if(geometry.CLASS_NAME == "ZOO.Geometry.Point") { 5887 intersect = this.containsPoint(geometry); 5888 } else if(geometry.CLASS_NAME == "ZOO.Geometry.LineString" || 5889 geometry.CLASS_NAME == "ZOO.Geometry.LinearRing") { 5890 // check if rings/linestrings intersect 5891 for(i=0, len=this.components.length; i<len; ++i) { 5892 intersect = geometry.intersects(this.components[i]); 5893 if(intersect) { 5894 break; 5895 } 5896 } 5897 if(!intersect) { 5898 // check if this poly contains points of the ring/linestring 5899 for(i=0, len=geometry.components.length; i<len; ++i) { 5900 intersect = this.containsPoint(geometry.components[i]); 5901 if(intersect) { 5902 break; 5903 } 5904 } 5905 } 5906 } else { 5907 for(i=0, len=geometry.components.length; i<len; ++ i) { 5908 intersect = this.intersects(geometry.components[i]); 5909 if(intersect) 5910 break; 5911 } 5912 } 5913 // check case where this poly is wholly contained by another 5914 if(!intersect && geometry.CLASS_NAME == "ZOO.Geometry.Polygon") { 5915 // exterior ring points will be contained in the other geometry 5916 var ring = this.components[0]; 5917 for(i=0, len=ring.components.length; i<len; ++i) { 5918 intersect = geometry.containsPoint(ring.components[i]); 5919 if(intersect) 5920 break; 5921 } 5922 } 5923 return intersect; 5924 }, 5925 distanceTo: function(geometry, options) { 5926 var edge = !(options && options.edge === false); 5927 var result; 5928 // this is the case where we might not be looking for distance to edge 5929 if(!edge && this.intersects(geometry)) 5930 result = 0; 5931 else 5932 result = ZOO.Geometry.Collection.prototype.distanceTo.apply( 5933 this, [geometry, options] 5934 ); 5935 return result; 5936 }, 5937 CLASS_NAME: "ZOO.Geometry.Polygon" 5938 }); 5939 /** 5940 * Method: createRegularPolygon 5941 * Create a regular polygon around a radius. Useful for creating circles 5942 * and the like. 5943 * 5944 * Parameters: 5945 * origin - {<ZOO.Geometry.Point>} center of polygon. 5946 * radius - {Float} distance to vertex, in map units. 5947 * sides - {Integer} Number of sides. 20 approximates a circle. 5948 * rotation - {Float} original angle of rotation, in degrees. 5949 */ 5950 OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) { 5951 var angle = Math.PI * ((1/sides) - (1/2)); 5952 if(rotation) { 5953 angle += (rotation / 180) * Math.PI; 5954 } 5955 var rotatedAngle, x, y; 5956 var points = []; 5957 for(var i=0; i<sides; ++i) { 5958 rotatedAngle = angle + (i * 2 * Math.PI / sides); 5959 x = origin.x + (radius * Math.cos(rotatedAngle)); 5960 y = origin.y + (radius * Math.sin(rotatedAngle)); 5961 points.push(new ZOO.Geometry.Point(x, y)); 5962 } 5963 var ring = new ZOO.Geometry.LinearRing(points); 5964 return new ZOO.Geometry.Polygon([ring]); 5965 }; 5966 /** 5967 * Class: ZOO.Geometry.MultiPolygon 5968 * MultiPolygon is a geometry with multiple <ZOO.Geometry.Polygon> 5969 * components. Create a new instance with the <ZOO.Geometry.MultiPolygon> 5970 * constructor. 5971 * 5972 * Inherits from: 5973 * - <ZOO.Geometry.Collection> 5974 */ 5975 ZOO.Geometry.MultiPolygon = ZOO.Class( 5976 ZOO.Geometry.Collection, { 5977 componentTypes: ["ZOO.Geometry.Polygon"], 5978 /** 5979 * Constructor: OpenLayers.Geometry.MultiPolygon 5980 * Create a new MultiPolygon geometry 5981 * 5982 * Parameters: 5983 * components - {Array(<ZOO.Geometry.Polygon>)} An array of polygons 5984 * used to generate the MultiPolygon 5985 * 5986 */ 5987 initialize: function(components) { 5988 ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments); 5989 }, 5990 CLASS_NAME: "ZOO.Geometry.MultiPolygon" 5991 }); 5992 5993 ZOO.Process = ZOO.Class({ 5994 schemaLocation: "http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd", 5995 namespaces: { 5996 ows: "http://www.opengis.net/ows/1.1", 5997 wps: "http://www.opengis.net/wps/1.0.0", 5998 xlink: "http://www.w3.org/1999/xlink", 5999 xsi: "http://www.w3.org/2001/XMLSchema-instance", 6000 }, 6001 url: 'http://localhost/zoo', 6002 identifier: null, 6003 initialize: function(url,identifier) { 6004 this.url = url; 6005 this.identifier = identifier; 6006 }, 6007 Execute: function(inputs) { 6008 if (this.identifier == null) 6009 return null; 6010 var body = new XML('<wps:Execute service="WPS" version="1.0.0" xmlns:wps="'+this.namespaces['wps']+'" xmlns:ows="'+this.namespaces['ows']+'" xmlns:xlink="'+this.namespaces['xlink']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'"><ows:Identifier>'+this.identifier+'</ows:Identifier>'+this.buildDataInputsNode(inputs)+'</wps:Execute>'); 6011 body = body.toXMLString(); 6012 var response = ZOO.Request.Post(this.url,body,['Content-Type: text/xml; charset=UTF-8']); 6013 return response; 6014 }, 6015 buildInput: { 6016 'complex': function(identifier,data) { 6017 var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:ComplexData>'+data.value+'</wps:ComplexData></wps:Data></wps:Input>'); 6018 input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'text/plain'; 6019 if (data.encoding) 6020 input.*::Data.*::ComplexData.@encoding = data.encoding; 6021 if (data.schema) 6022 input.*::Data.*::ComplexData.@schema = data.schema; 6023 input = input.toXMLString(); 6024 return input; 6025 }, 6026 'reference': function(identifier,data) { 6027 return '<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Reference xmlns:xlink="'+this.namespaces['xlink']+'" xlink:href="'+data.value.replace('&','&','gi')+'"/></wps:Input>'; 6028 }, 6029 'literal': function(identifier,data) { 6030 var input = new XML('<wps:Input xmlns:wps="'+this.namespaces['wps']+'"><ows:Identifier xmlns:ows="'+this.namespaces['ows']+'">'+identifier+'</ows:Identifier><wps:Data><wps:LiteralData>'+data.value+'</wps:LiteralData></wps:Data></wps:Input>'); 6031 if (data.type) 6032 input.*::Data.*::LiteralData.@dataType = data.type; 6033 if (data.uom) 6034 input.*::Data.*::LiteralData.@uom = data.uom; 6035 input = input.toXMLString(); 6036 return input; 6037 } 6038 }, 6039 buildDataInputsNode:function(inputs){ 6040 var data, builder, inputsArray=[]; 6041 for (var attr in inputs) { 6042 data = inputs[attr]; 6043 if (data.mimetype || data.type == 'complex') 6044 builder = this.buildInput['complex']; 6045 else if (data.type == 'reference' || data.type == 'url') 6046 builder = this.buildInput['reference']; 6047 else 6048 builder = this.buildInput['literal']; 6049 inputsArray.push(builder.apply(this,[attr,data])); 6050 } 6051 return '<wps:DataInputs xmlns:wps="'+this.namespaces['wps']+'">'+inputsArray.join('\n')+'</wps:DataInputs>'; 6052 }, 6053 CLASS_NAME: "ZOO.Process" 6054 }); 100 loadProjCodeSuccess:function(projName){if(Proj4js.Proj[projName].dependsOn){this.loadProjCode(Proj4js.Proj[projName].dependsOn);}else{this.initTransforms();}},loadProjCodeFailure:function(projName){Proj4js.reportError("failed to find projection file for: "+projName);},checkCodeLoaded:function(projName){if(Proj4js.Proj[projName]){return true;}else{return false;}},initTransforms:function(){Proj4js.extend(this,Proj4js.Proj[this.projName]);this.init();this.readyToUse=true;},parseDefs:function(){this.defData=Proj4js.defs[this.srsCode];var paramName,paramVal;if(!this.defData){return;} 101 var paramArray=this.defData.split("+");for(var prop=0;prop<paramArray.length;prop++){var property=paramArray[prop].split("=");paramName=property[0].toLowerCase();paramVal=property[1];switch(paramName.replace(/\s/gi,"")){case"":break;case"title":this.title=paramVal;break;case"proj":this.projName=paramVal.replace(/\s/gi,"");break;case"units":this.units=paramVal.replace(/\s/gi,"");break;case"datum":this.datumCode=paramVal.replace(/\s/gi,"");break;case"nadgrids":this.nagrids=paramVal.replace(/\s/gi,"");break;case"ellps":this.ellps=paramVal.replace(/\s/gi,"");break;case"a":this.a=parseFloat(paramVal);break;case"b":this.b=parseFloat(paramVal);break;case"rf":this.rf=parseFloat(paramVal);break;case"lat_0":this.lat0=paramVal*Proj4js.common.D2R;break;case"lat_1":this.lat1=paramVal*Proj4js.common.D2R;break;case"lat_2":this.lat2=paramVal*Proj4js.common.D2R;break;case"lat_ts":this.lat_ts=paramVal*Proj4js.common.D2R;break;case"lon_0":this.long0=paramVal*Proj4js.common.D2R;break;case"alpha":this.alpha=parseFloat(paramVal)*Proj4js.common.D2R;break;case"lonc":this.longc=paramVal*Proj4js.common.D2R;break;case"x_0":this.x0=parseFloat(paramVal);break;case"y_0":this.y0=parseFloat(paramVal);break;case"k_0":this.k0=parseFloat(paramVal);break;case"k":this.k0=parseFloat(paramVal);break;case"r_a":this.R_A=true;break;case"zone":this.zone=parseInt(paramVal);break;case"south":this.utmSouth=true;break;case"towgs84":this.datum_params=paramVal.split(",");break;case"to_meter":this.to_meter=parseFloat(paramVal);break;case"from_greenwich":this.from_greenwich=paramVal*Proj4js.common.D2R;break;case"pm":paramVal=paramVal.replace(/\s/gi,"");this.from_greenwich=Proj4js.PrimeMeridian[paramVal]?Proj4js.PrimeMeridian[paramVal]:parseFloat(paramVal);this.from_greenwich*=Proj4js.common.D2R;break;case"no_defs":break;default:}} 102 this.deriveConstants();},deriveConstants:function(){if(this.nagrids=='@null')this.datumCode='none';if(this.datumCode&&this.datumCode!='none'){var datumDef=Proj4js.Datum[this.datumCode];if(datumDef){this.datum_params=datumDef.towgs84?datumDef.towgs84.split(','):null;this.ellps=datumDef.ellipse;this.datumName=datumDef.datumName?datumDef.datumName:this.datumCode;}} 103 if(!this.a){var ellipse=Proj4js.Ellipsoid[this.ellps]?Proj4js.Ellipsoid[this.ellps]:Proj4js.Ellipsoid['WGS84'];Proj4js.extend(this,ellipse);} 104 if(this.rf&&!this.b)this.b=(1.0-1.0/this.rf)*this.a;if(Math.abs(this.a-this.b)<Proj4js.common.EPSLN){this.sphere=true;this.b=this.a;} 105 this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=(this.a2-this.b2)/this.a2;this.e=Math.sqrt(this.es);if(this.R_A){this.a*=1.-this.es*(Proj4js.common.SIXTH+this.es*(Proj4js.common.RA4+this.es*Proj4js.common.RA6));this.a2=this.a*this.a;this.b2=this.b*this.b;this.es=0.;} 106 this.ep2=(this.a2-this.b2)/this.b2;if(!this.k0)this.k0=1.0;this.datum=new Proj4js.datum(this);}});Proj4js.Proj.longlat={init:function(){},forward:function(pt){return pt;},inverse:function(pt){return pt;}};Proj4js.defs={'WGS84':"+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4326':"+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees",'EPSG:4269':"+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees",'EPSG:3785':"+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"};Proj4js.defs['GOOGLE']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:900913']=Proj4js.defs['EPSG:3785'];Proj4js.defs['EPSG:102113']=Proj4js.defs['EPSG:3785'];Proj4js.common={PI:3.141592653589793238,HALF_PI:1.570796326794896619,TWO_PI:6.283185307179586477,FORTPI:0.78539816339744833,R2D:57.29577951308232088,D2R:0.01745329251994329577,SEC_TO_RAD:4.84813681109535993589914102357e-6,EPSLN:1.0e-10,MAX_ITER:20,COS_67P5:0.38268343236508977,AD_C:1.0026000,PJD_UNKNOWN:0,PJD_3PARAM:1,PJD_7PARAM:2,PJD_GRIDSHIFT:3,PJD_WGS84:4,PJD_NODATUM:5,SRS_WGS84_SEMIMAJOR:6378137.0,SIXTH:.1666666666666666667,RA4:.04722222222222222222,RA6:.02215608465608465608,RV4:.06944444444444444444,RV6:.04243827160493827160,msfnz:function(eccent,sinphi,cosphi){var con=eccent*sinphi;return cosphi/(Math.sqrt(1.0-con*con));},tsfnz:function(eccent,phi,sinphi){var con=eccent*sinphi;var com=.5*eccent;con=Math.pow(((1.0-con)/(1.0+con)),com);return(Math.tan(.5*(this.HALF_PI-phi))/con);},phi2z:function(eccent,ts){var eccnth=.5*eccent;var con,dphi;var phi=this.HALF_PI-2*Math.atan(ts);for(i=0;i<=15;i++){con=eccent*Math.sin(phi);dphi=this.HALF_PI-2*Math.atan(ts*(Math.pow(((1.0-con)/(1.0+con)),eccnth)))-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001)return phi;} 107 alert("phi2z has NoConvergence");return(-9999);},qsfnz:function(eccent,sinphi){var con;if(eccent>1.0e-7){con=eccent*sinphi;return((1.0-eccent*eccent)*(sinphi/(1.0-con*con)-(.5/eccent)*Math.log((1.0-con)/(1.0+con))));}else{return(2.0*sinphi);}},asinz:function(x){if(Math.abs(x)>1.0){x=(x>1.0)?1.0:-1.0;} 108 return Math.asin(x);},e0fn:function(x){return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));},e1fn:function(x){return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));},e2fn:function(x){return(0.05859375*x*x*(1.0+0.75*x));},e3fn:function(x){return(x*x*x*(35.0/3072.0));},mlfn:function(e0,e1,e2,e3,phi){return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));},srat:function(esinp,exp){return(Math.pow((1.0-esinp)/(1.0+esinp),exp));},sign:function(x){if(x<0.0)return(-1);else return(1);},adjust_lon:function(x){x=(Math.abs(x)<this.PI)?x:(x-(this.sign(x)*this.TWO_PI));return x;},adjust_lat:function(x){x=(Math.abs(x)<this.HALF_PI)?x:(x-(this.sign(x)*this.PI));return x;},latiso:function(eccent,phi,sinphi){if(Math.abs(phi)>this.HALF_PI)return+Number.NaN;if(phi==this.HALF_PI)return Number.POSITIVE_INFINITY;if(phi==-1.0*this.HALF_PI)return-1.0*Number.POSITIVE_INFINITY;var con=eccent*sinphi;return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0;},fL:function(x,L){return 2.0*Math.atan(x*Math.exp(L))-this.HALF_PI;},invlatiso:function(eccent,ts){var phi=this.fL(1.0,ts);var Iphi=0.0;var con=0.0;do{Iphi=phi;con=eccent*Math.sin(Iphi);phi=this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts)}while(Math.abs(phi-Iphi)>1.0e-12);return phi;},sinh:function(x) 109 {var r=Math.exp(x);r=(r-1.0/r)/2.0;return r;},cosh:function(x) 110 {var r=Math.exp(x);r=(r+1.0/r)/2.0;return r;},tanh:function(x) 111 {var r=Math.exp(x);r=(r-1.0/r)/(r+1.0/r);return r;},asinh:function(x) 112 {var s=(x>=0?1.0:-1.0);return s*(Math.log(Math.abs(x)+Math.sqrt(x*x+1.0)));},acosh:function(x) 113 {return 2.0*Math.log(Math.sqrt((x+1.0)/2.0)+Math.sqrt((x-1.0)/2.0));},atanh:function(x) 114 {return Math.log((x-1.0)/(x+1.0))/2.0;},gN:function(a,e,sinphi) 115 {var temp=e*sinphi;return a/Math.sqrt(1.0-temp*temp);}};Proj4js.datum=Proj4js.Class({initialize:function(proj){this.datum_type=Proj4js.common.PJD_WGS84;if(proj.datumCode&&proj.datumCode=='none'){this.datum_type=Proj4js.common.PJD_NODATUM;} 116 if(proj&&proj.datum_params){for(var i=0;i<proj.datum_params.length;i++){proj.datum_params[i]=parseFloat(proj.datum_params[i]);} 117 if(proj.datum_params[0]!=0||proj.datum_params[1]!=0||proj.datum_params[2]!=0){this.datum_type=Proj4js.common.PJD_3PARAM;} 118 if(proj.datum_params.length>3){if(proj.datum_params[3]!=0||proj.datum_params[4]!=0||proj.datum_params[5]!=0||proj.datum_params[6]!=0){this.datum_type=Proj4js.common.PJD_7PARAM;proj.datum_params[3]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[4]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[5]*=Proj4js.common.SEC_TO_RAD;proj.datum_params[6]=(proj.datum_params[6]/1000000.0)+1.0;}}} 119 if(proj){this.a=proj.a;this.b=proj.b;this.es=proj.es;this.ep2=proj.ep2;this.datum_params=proj.datum_params;}},compare_datums:function(dest){if(this.datum_type!=dest.datum_type){return false;}else if(this.a!=dest.a||Math.abs(this.es-dest.es)>0.000000000050){return false;}else if(this.datum_type==Proj4js.common.PJD_3PARAM){return(this.datum_params[0]==dest.datum_params[0]&&this.datum_params[1]==dest.datum_params[1]&&this.datum_params[2]==dest.datum_params[2]);}else if(this.datum_type==Proj4js.common.PJD_7PARAM){return(this.datum_params[0]==dest.datum_params[0]&&this.datum_params[1]==dest.datum_params[1]&&this.datum_params[2]==dest.datum_params[2]&&this.datum_params[3]==dest.datum_params[3]&&this.datum_params[4]==dest.datum_params[4]&&this.datum_params[5]==dest.datum_params[5]&&this.datum_params[6]==dest.datum_params[6]);}else if(this.datum_type==Proj4js.common.PJD_GRIDSHIFT){return strcmp(pj_param(this.params,"snadgrids").s,pj_param(dest.params,"snadgrids").s)==0;}else{return true;}},geodetic_to_geocentric:function(p){var Longitude=p.x;var Latitude=p.y;var Height=p.z?p.z:0;var X;var Y;var Z;var Error_Code=0;var Rn;var Sin_Lat;var Sin2_Lat;var Cos_Lat;if(Latitude<-Proj4js.common.HALF_PI&&Latitude>-1.001*Proj4js.common.HALF_PI){Latitude=-Proj4js.common.HALF_PI;}else if(Latitude>Proj4js.common.HALF_PI&&Latitude<1.001*Proj4js.common.HALF_PI){Latitude=Proj4js.common.HALF_PI;}else if((Latitude<-Proj4js.common.HALF_PI)||(Latitude>Proj4js.common.HALF_PI)){Proj4js.reportError('geocent:lat out of range:'+Latitude);return null;} 120 if(Longitude>Proj4js.common.PI)Longitude-=(2*Proj4js.common.PI);Sin_Lat=Math.sin(Latitude);Cos_Lat=Math.cos(Latitude);Sin2_Lat=Sin_Lat*Sin_Lat;Rn=this.a/(Math.sqrt(1.0e0-this.es*Sin2_Lat));X=(Rn+Height)*Cos_Lat*Math.cos(Longitude);Y=(Rn+Height)*Cos_Lat*Math.sin(Longitude);Z=((Rn*(1-this.es))+Height)*Sin_Lat;p.x=X;p.y=Y;p.z=Z;return Error_Code;},geocentric_to_geodetic:function(p){var genau=1.E-12;var genau2=(genau*genau);var maxiter=30;var P;var RR;var CT;var ST;var RX;var RK;var RN;var CPHI0;var SPHI0;var CPHI;var SPHI;var SDPHI;var At_Pole;var iter;var X=p.x;var Y=p.y;var Z=p.z?p.z:0.0;var Longitude;var Latitude;var Height;At_Pole=false;P=Math.sqrt(X*X+Y*Y);RR=Math.sqrt(X*X+Y*Y+Z*Z);if(P/this.a<genau){At_Pole=true;Longitude=0.0;if(RR/this.a<genau){Latitude=Proj4js.common.HALF_PI;Height=-this.b;return;}}else{Longitude=Math.atan2(Y,X);} 121 CT=Z/RR;ST=P/RR;RX=1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST);CPHI0=ST*(1.0-this.es)*RX;SPHI0=CT*RX;iter=0;do 122 {iter++;RN=this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0);Height=P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0);RK=this.es*RN/(RN+Height);RX=1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST);CPHI=ST*(1.0-RK)*RX;SPHI=CT*RX;SDPHI=SPHI*CPHI0-CPHI*SPHI0;CPHI0=CPHI;SPHI0=SPHI;} 123 while(SDPHI*SDPHI>genau2&&iter<maxiter);Latitude=Math.atan(SPHI/Math.abs(CPHI));p.x=Longitude;p.y=Latitude;p.z=Height;return p;},geocentric_to_geodetic_noniter:function(p){var X=p.x;var Y=p.y;var Z=p.z?p.z:0;var Longitude;var Latitude;var Height;var W;var W2;var T0;var T1;var S0;var S1;var Sin_B0;var Sin3_B0;var Cos_B0;var Sin_p1;var Cos_p1;var Rn;var Sum;var At_Pole;X=parseFloat(X);Y=parseFloat(Y);Z=parseFloat(Z);At_Pole=false;if(X!=0.0) 124 {Longitude=Math.atan2(Y,X);} 125 else 126 {if(Y>0) 127 {Longitude=Proj4js.common.HALF_PI;} 128 else if(Y<0) 129 {Longitude=-Proj4js.common.HALF_PI;} 130 else 131 {At_Pole=true;Longitude=0.0;if(Z>0.0) 132 {Latitude=Proj4js.common.HALF_PI;} 133 else if(Z<0.0) 134 {Latitude=-Proj4js.common.HALF_PI;} 135 else 136 {Latitude=Proj4js.common.HALF_PI;Height=-this.b;return;}}} 137 W2=X*X+Y*Y;W=Math.sqrt(W2);T0=Z*Proj4js.common.AD_C;S0=Math.sqrt(T0*T0+W2);Sin_B0=T0/S0;Cos_B0=W/S0;Sin3_B0=Sin_B0*Sin_B0*Sin_B0;T1=Z+this.b*this.ep2*Sin3_B0;Sum=W-this.a*this.es*Cos_B0*Cos_B0*Cos_B0;S1=Math.sqrt(T1*T1+Sum*Sum);Sin_p1=T1/S1;Cos_p1=Sum/S1;Rn=this.a/Math.sqrt(1.0-this.es*Sin_p1*Sin_p1);if(Cos_p1>=Proj4js.common.COS_67P5) 138 {Height=W/Cos_p1-Rn;} 139 else if(Cos_p1<=-Proj4js.common.COS_67P5) 140 {Height=W/-Cos_p1-Rn;} 141 else 142 {Height=Z/Sin_p1+Rn*(this.es-1.0);} 143 if(At_Pole==false) 144 {Latitude=Math.atan(Sin_p1/Cos_p1);} 145 p.x=Longitude;p.y=Latitude;p.z=Height;return p;},geocentric_to_wgs84:function(p){if(this.datum_type==Proj4js.common.PJD_3PARAM) 146 {p.x+=this.datum_params[0];p.y+=this.datum_params[1];p.z+=this.datum_params[2];} 147 else if(this.datum_type==Proj4js.common.PJD_7PARAM) 148 {var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_out=M_BF*(p.x-Rz_BF*p.y+Ry_BF*p.z)+Dx_BF;var y_out=M_BF*(Rz_BF*p.x+p.y-Rx_BF*p.z)+Dy_BF;var z_out=M_BF*(-Ry_BF*p.x+Rx_BF*p.y+p.z)+Dz_BF;p.x=x_out;p.y=y_out;p.z=z_out;}},geocentric_from_wgs84:function(p){if(this.datum_type==Proj4js.common.PJD_3PARAM) 149 {p.x-=this.datum_params[0];p.y-=this.datum_params[1];p.z-=this.datum_params[2];} 150 else if(this.datum_type==Proj4js.common.PJD_7PARAM) 151 {var Dx_BF=this.datum_params[0];var Dy_BF=this.datum_params[1];var Dz_BF=this.datum_params[2];var Rx_BF=this.datum_params[3];var Ry_BF=this.datum_params[4];var Rz_BF=this.datum_params[5];var M_BF=this.datum_params[6];var x_tmp=(p.x-Dx_BF)/M_BF;var y_tmp=(p.y-Dy_BF)/M_BF;var z_tmp=(p.z-Dz_BF)/M_BF;p.x=x_tmp+Rz_BF*y_tmp-Ry_BF*z_tmp;p.y=-Rz_BF*x_tmp+y_tmp+Rx_BF*z_tmp;p.z=Ry_BF*x_tmp-Rx_BF*y_tmp+z_tmp;}}});Proj4js.Point=Proj4js.Class({initialize:function(x,y,z){if(typeof x=='object'){this.x=x[0];this.y=x[1];this.z=x[2]||0.0;}else if(typeof x=='string'){var coords=x.split(',');this.x=parseFloat(coords[0]);this.y=parseFloat(coords[1]);this.z=parseFloat(coords[2])||0.0;}else{this.x=x;this.y=y;this.z=z||0.0;}},clone:function(){return new Proj4js.Point(this.x,this.y,this.z);},toString:function(){return("x="+this.x+",y="+this.y);},toShortString:function(){return(this.x+", "+this.y);}});Proj4js.PrimeMeridian={"greenwich":0.0,"lisbon":-9.131906111111,"paris":2.337229166667,"bogota":-74.080916666667,"madrid":-3.687938888889,"rome":12.452333333333,"bern":7.439583333333,"jakarta":106.807719444444,"ferro":-17.666666666667,"brussels":4.367975,"stockholm":18.058277777778,"athens":23.7163375,"oslo":10.722916666667};Proj4js.Ellipsoid={"MERIT":{a:6378137.0,rf:298.257,ellipseName:"MERIT 1983"},"SGS85":{a:6378136.0,rf:298.257,ellipseName:"Soviet Geodetic System 85"},"GRS80":{a:6378137.0,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},"IAU76":{a:6378140.0,rf:298.257,ellipseName:"IAU 1976"},"airy":{a:6377563.396,b:6356256.910,ellipseName:"Airy 1830"},"APL4.":{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},"NWL9D":{a:6378145.0,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},"mod_airy":{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},"andrae":{a:6377104.43,rf:300.0,ellipseName:"Andrae 1876 (Den., Iclnd.)"},"aust_SA":{a:6378160.0,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},"GRS67":{a:6378160.0,rf:298.2471674270,ellipseName:"GRS 67(IUGG 1967)"},"bessel":{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},"bess_nam":{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},"clrk66":{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},"clrk80":{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},"CPM":{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},"delmbr":{a:6376428.0,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},"engelis":{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},"evrst30":{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},"evrst48":{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},"evrst56":{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},"evrst69":{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},"evrstSS":{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},"fschr60":{a:6378166.0,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},"fschr60m":{a:6378155.0,rf:298.3,ellipseName:"Fischer 1960"},"fschr68":{a:6378150.0,rf:298.3,ellipseName:"Fischer 1968"},"helmert":{a:6378200.0,rf:298.3,ellipseName:"Helmert 1906"},"hough":{a:6378270.0,rf:297.0,ellipseName:"Hough"},"intl":{a:6378388.0,rf:297.0,ellipseName:"International 1909 (Hayford)"},"kaula":{a:6378163.0,rf:298.24,ellipseName:"Kaula 1961"},"lerch":{a:6378139.0,rf:298.257,ellipseName:"Lerch 1979"},"mprts":{a:6397300.0,rf:191.0,ellipseName:"Maupertius 1738"},"new_intl":{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},"plessis":{a:6376523.0,rf:6355863.0,ellipseName:"Plessis 1817 (France)"},"krass":{a:6378245.0,rf:298.3,ellipseName:"Krassovsky, 1942"},"SEasia":{a:6378155.0,b:6356773.3205,ellipseName:"Southeast Asia"},"walbeck":{a:6376896.0,b:6355834.8467,ellipseName:"Walbeck"},"WGS60":{a:6378165.0,rf:298.3,ellipseName:"WGS 60"},"WGS66":{a:6378145.0,rf:298.25,ellipseName:"WGS 66"},"WGS72":{a:6378135.0,rf:298.26,ellipseName:"WGS 72"},"WGS84":{a:6378137.0,rf:298.257223563,ellipseName:"WGS 84"},"sphere":{a:6370997.0,b:6370997.0,ellipseName:"Normal Sphere (r=6370997)"}};Proj4js.Datum={"WGS84":{towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},"GGRS87":{towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},"NAD83":{towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},"NAD27":{nadgrids:"@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},"potsdam":{towgs84:"606.0,23.0,413.0",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},"carthage":{towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},"hermannskogel":{towgs84:"653.0,-212.0,449.0",ellipse:"bessel",datumName:"Hermannskogel"},"ire65":{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},"nzgd49":{towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},"OSGB36":{towgs84:"446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"}};Proj4js.WGS84=new Proj4js.Proj('WGS84');Proj4js.Datum['OSB36']=Proj4js.Datum['OSGB36'];Proj4js.Proj.aea={init:function(){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("aeaInitEqualLatitudes");return;} 152 this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e3=Math.sqrt(this.es);this.sin_po=Math.sin(this.lat1);this.cos_po=Math.cos(this.lat1);this.t1=this.sin_po;this.con=this.sin_po;this.ms1=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs1=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat2);this.cos_po=Math.cos(this.lat2);this.t2=this.sin_po;this.ms2=Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);this.qs2=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);this.sin_po=Math.sin(this.lat0);this.cos_po=Math.cos(this.lat0);this.t3=this.sin_po;this.qs0=Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);if(Math.abs(this.lat1-this.lat2)>Proj4js.common.EPSLN){this.ns0=(this.ms1*this.ms1-this.ms2*this.ms2)/(this.qs2-this.qs1);}else{this.ns0=this.con;} 153 this.c=this.ms1*this.ms1+this.ns0*this.qs1;this.rh=this.a*Math.sqrt(this.c-this.ns0*this.qs0)/this.ns0;},forward:function(p){var lon=p.x;var lat=p.y;this.sin_phi=Math.sin(lat);this.cos_phi=Math.cos(lat);var qs=Proj4js.common.qsfnz(this.e3,this.sin_phi,this.cos_phi);var rh1=this.a*Math.sqrt(this.c-this.ns0*qs)/this.ns0;var theta=this.ns0*Proj4js.common.adjust_lon(lon-this.long0);var x=rh1*Math.sin(theta)+this.x0;var y=this.rh-rh1*Math.cos(theta)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var rh1,qs,con,theta,lon,lat;p.x-=this.x0;p.y=this.rh-p.y+this.y0;if(this.ns0>=0){rh1=Math.sqrt(p.x*p.x+p.y*p.y);con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;} 154 theta=0.0;if(rh1!=0.0){theta=Math.atan2(con*p.x,con*p.y);} 155 con=rh1*this.ns0/this.a;qs=(this.c-con*con)/this.ns0;if(this.e3>=1e-10){con=1-.5*(1.0-this.es)*Math.log((1.0-this.e3)/(1.0+this.e3))/this.e3;if(Math.abs(Math.abs(con)-Math.abs(qs))>.0000000001){lat=this.phi1z(this.e3,qs);}else{if(qs>=0){lat=.5*PI;}else{lat=-.5*PI;}}}else{lat=this.phi1z(e3,qs);} 156 lon=Proj4js.common.adjust_lon(theta/this.ns0+this.long0);p.x=lon;p.y=lat;return p;},phi1z:function(eccent,qs){var con,com,dphi;var phi=Proj4js.common.asinz(.5*qs);if(eccent<Proj4js.common.EPSLN)return phi;var eccnts=eccent*eccent;for(var i=1;i<=25;i++){sinphi=Math.sin(phi);cosphi=Math.cos(phi);con=eccent*sinphi;com=1.0-con*con;dphi=.5*com*com/cosphi*(qs/(1.0-eccnts)-sinphi/com+.5/eccent*Math.log((1.0-con)/(1.0+con)));phi=phi+dphi;if(Math.abs(dphi)<=1e-7)return phi;} 157 Proj4js.reportError("aea:phi1z:Convergence error");return null;}};Proj4js.Proj.sterea={dependsOn:'gauss',init:function(){Proj4js.Proj['gauss'].init.apply(this);if(!this.rc){Proj4js.reportError("sterea:init:E_ERROR_0");return;} 158 this.sinc0=Math.sin(this.phic0);this.cosc0=Math.cos(this.phic0);this.R2=2.0*this.rc;if(!this.title)this.title="Oblique Stereographic Alternative";},forward:function(p){p.x=Proj4js.common.adjust_lon(p.x-this.long0);Proj4js.Proj['gauss'].forward.apply(this,[p]);sinc=Math.sin(p.y);cosc=Math.cos(p.y);cosl=Math.cos(p.x);k=this.k0*this.R2/(1.0+this.sinc0*sinc+this.cosc0*cosc*cosl);p.x=k*cosc*Math.sin(p.x);p.y=k*(this.cosc0*sinc-this.sinc0*cosc*cosl);p.x=this.a*p.x+this.x0;p.y=this.a*p.y+this.y0;return p;},inverse:function(p){var lon,lat;p.x=(p.x-this.x0)/this.a;p.y=(p.y-this.y0)/this.a;p.x/=this.k0;p.y/=this.k0;if((rho=Math.sqrt(p.x*p.x+p.y*p.y))){c=2.0*Math.atan2(rho,this.R2);sinc=Math.sin(c);cosc=Math.cos(c);lat=Math.asin(cosc*this.sinc0+p.y*sinc*this.cosc0/rho);lon=Math.atan2(p.x*sinc,rho*this.cosc0*cosc-p.y*this.sinc0*sinc);}else{lat=this.phic0;lon=0.;} 159 p.x=lon;p.y=lat;Proj4js.Proj['gauss'].inverse.apply(this,[p]);p.x=Proj4js.common.adjust_lon(p.x+this.long0);return p;}};function phi4z(eccent,e0,e1,e2,e3,a,b,c,phi){var sinphi,sin2ph,tanph,ml,mlp,con1,con2,con3,dphi,i;phi=a;for(i=1;i<=15;i++){sinphi=Math.sin(phi);tanphi=Math.tan(phi);c=tanphi*Math.sqrt(1.0-eccent*sinphi*sinphi);sin2ph=Math.sin(2.0*phi);ml=e0*phi-e1*sin2ph+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi);mlp=e0-2.0*e1*Math.cos(2.0*phi)+4.0*e2*Math.cos(4.0*phi)-6.0*e3*Math.cos(6.0*phi);con1=2.0*ml+c*(ml*ml+b)-2.0*a*(c*ml+1.0);con2=eccent*sin2ph*(ml*ml+b-2.0*a*ml)/(2.0*c);con3=2.0*(a-ml)*(c*mlp-2.0/sin2ph)-2.0*mlp;dphi=con1/(con2+con3);phi+=dphi;if(Math.abs(dphi)<=.0000000001)return(phi);} 160 Proj4js.reportError("phi4z: No convergence");return null;} 161 function e4fn(x){var con,com;con=1.0+x;com=1.0-x;return(Math.sqrt((Math.pow(con,con))*(Math.pow(com,com))));} 162 Proj4js.Proj.poly={init:function(){var temp;if(this.lat0=0)this.lat0=90;this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e=Math.sqrt(this.es);this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.ml0=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);},forward:function(p){var sinphi,cosphi;var al;var c;var con,ml;var ms;var x,y;var lon=p.x;var lat=p.y;con=Proj4js.common.adjust_lon(lon-this.long0);if(Math.abs(lat)<=.0000001){x=this.x0+this.a*con;y=this.y0-this.a*this.ml0;}else{sinphi=Math.sin(lat);cosphi=Math.cos(lat);ml=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);ms=Proj4js.common.msfnz(this.e,sinphi,cosphi);con=sinphi;x=this.x0+this.a*ms*Math.sin(con)/sinphi;y=this.y0+this.a*(ml-this.ml0+ms*(1.0-Math.cos(con))/sinphi);} 163 p.x=x;p.y=y;return p;},inverse:function(p){var sin_phi,cos_phi;var al;var b;var c;var con,ml;var iflg;var lon,lat;p.x-=this.x0;p.y-=this.y0;al=this.ml0+p.y/this.a;iflg=0;if(Math.abs(al)<=.0000001){lon=p.x/this.a+this.long0;lat=0.0;}else{b=al*al+(p.x/this.a)*(p.x/this.a);iflg=phi4z(this.es,this.e0,this.e1,this.e2,this.e3,this.al,b,c,lat);if(iflg!=1)return(iflg);lon=Proj4js.common.adjust_lon((Proj4js.common.asinz(p.x*c/this.a)/Math.sin(lat))+this.long0);} 164 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.equi={init:function(){if(!this.x0)this.x0=0;if(!this.y0)this.y0=0;if(!this.lat0)this.lat0=0;if(!this.long0)this.long0=0;},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon*Math.cos(this.lat0);var y=this.y0+this.a*lat;this.t1=x;this.t2=Math.cos(this.lat0);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lat=p.y/this.a;if(Math.abs(lat)>Proj4js.common.HALF_PI){Proj4js.reportError("equi:Inv:DataError");} 165 var lon=Proj4js.common.adjust_lon(this.long0+p.x/(this.a*Math.cos(this.lat0)));p.x=lon;p.y=lat;}};Proj4js.Proj.merc={init:function(){if(this.lat_ts){if(this.sphere){this.k0=Math.cos(this.lat_ts);}else{this.k0=Proj4js.common.msfnz(this.es,Math.sin(this.lat_ts),Math.cos(this.lat_ts));}}},forward:function(p){var lon=p.x;var lat=p.y;if(lat*Proj4js.common.R2D>90.0&&lat*Proj4js.common.R2D<-90.0&&lon*Proj4js.common.R2D>180.0&&lon*Proj4js.common.R2D<-180.0){Proj4js.reportError("merc:forward: llInputOutOfRange: "+lon+" : "+lat);return null;} 166 var x,y;if(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN){Proj4js.reportError("merc:forward: ll2mAtPoles");return null;}else{if(this.sphere){x=this.x0+this.a*this.k0*Proj4js.common.adjust_lon(lon-this.long0);y=this.y0+this.a*this.k0*Math.log(Math.tan(Proj4js.common.FORTPI+0.5*lat));}else{var sinphi=Math.sin(lat);var ts=Proj4js.common.tsfnz(this.e,lat,sinphi);x=this.x0+this.a*this.k0*Proj4js.common.adjust_lon(lon-this.long0);y=this.y0-this.a*this.k0*Math.log(ts);} 167 p.x=x;p.y=y;return p;}},inverse:function(p){var x=p.x-this.x0;var y=p.y-this.y0;var lon,lat;if(this.sphere){lat=Proj4js.common.HALF_PI-2.0*Math.atan(Math.exp(-y/this.a*this.k0));}else{var ts=Math.exp(-y/(this.a*this.k0));lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999){Proj4js.reportError("merc:inverse: lat = -9999");return null;}} 168 lon=Proj4js.common.adjust_lon(this.long0+x/(this.a*this.k0));p.x=lon;p.y=lat;return p;}};Proj4js.Proj.utm={dependsOn:'tmerc',init:function(){if(!this.zone){Proj4js.reportError("utm:init: zone must be specified for UTM");return;} 169 this.lat0=0.0;this.long0=((6*Math.abs(this.zone))-183)*Proj4js.common.D2R;this.x0=500000.0;this.y0=this.utmSouth?10000000.0:0.0;this.k0=0.9996;Proj4js.Proj['tmerc'].init.apply(this);this.forward=Proj4js.Proj['tmerc'].forward;this.inverse=Proj4js.Proj['tmerc'].inverse;}};Proj4js.Proj.eqdc={init:function(){if(!this.mode)this.mode=0;this.temp=this.b/this.a;this.es=1.0-Math.pow(this.temp,2);this.e=Math.sqrt(this.es);this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.sinphi=Math.sin(this.lat1);this.cosphi=Math.cos(this.lat1);this.ms1=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml1=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat1);if(this.mode!=0){if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("eqdc:Init:EqualLatitudes");} 170 this.sinphi=Math.sin(this.lat2);this.cosphi=Math.cos(this.lat2);this.ms2=Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);this.ml2=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat2);if(Math.abs(this.lat1-this.lat2)>=Proj4js.common.EPSLN){this.ns=(this.ms1-this.ms2)/(this.ml2-this.ml1);}else{this.ns=this.sinphi;}}else{this.ns=this.sinphi;} 171 this.g=this.ml1+this.ms1/this.ns;this.ml0=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);this.rh=this.a*(this.g-this.ml0);},forward:function(p){var lon=p.x;var lat=p.y;var ml=Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);var rh1=this.a*(this.g-ml);var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+rh1*Math.sin(theta);var y=this.y0+this.rh-rh1*Math.cos(theta);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y=this.rh-p.y+this.y0;var con,rh1;if(this.ns>=0){var rh1=Math.sqrt(p.x*p.x+p.y*p.y);var con=1.0;}else{rh1=-Math.sqrt(p.x*p.x+p.y*p.y);con=-1.0;} 172 var theta=0.0;if(rh1!=0.0)theta=Math.atan2(con*p.x,con*p.y);var ml=this.g-rh1/this.a;var lat=this.phi3z(this.ml,this.e0,this.e1,this.e2,this.e3);var lon=Proj4js.common.adjust_lon(this.long0+theta/this.ns);p.x=lon;p.y=lat;return p;},phi3z:function(ml,e0,e1,e2,e3){var phi;var dphi;phi=ml;for(var i=0;i<15;i++){dphi=(ml+e1*Math.sin(2.0*phi)-e2*Math.sin(4.0*phi)+e3*Math.sin(6.0*phi))/e0-phi;phi+=dphi;if(Math.abs(dphi)<=.0000000001){return phi;}} 173 Proj4js.reportError("PHI3Z-CONV:Latitude failed to converge after 15 iterations");return null;}};Proj4js.Proj.tmerc={init:function(){this.e0=Proj4js.common.e0fn(this.es);this.e1=Proj4js.common.e1fn(this.es);this.e2=Proj4js.common.e2fn(this.es);this.e3=Proj4js.common.e3fn(this.es);this.ml0=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,this.lat0);},forward:function(p){var lon=p.x;var lat=p.y;var delta_lon=Proj4js.common.adjust_lon(lon-this.long0);var con;var x,y;var sin_phi=Math.sin(lat);var cos_phi=Math.cos(lat);if(this.sphere){var b=cos_phi*Math.sin(delta_lon);if((Math.abs(Math.abs(b)-1.0))<.0000000001){Proj4js.reportError("tmerc:forward: Point projects into infinity");return(93);}else{x=.5*this.a*this.k0*Math.log((1.0+b)/(1.0-b));con=Math.acos(cos_phi*Math.cos(delta_lon)/Math.sqrt(1.0-b*b));if(lat<0)con=-con;y=this.a*this.k0*(con-this.lat0);}}else{var al=cos_phi*delta_lon;var als=Math.pow(al,2);var c=this.ep2*Math.pow(cos_phi,2);var tq=Math.tan(lat);var t=Math.pow(tq,2);con=1.0-this.es*Math.pow(sin_phi,2);var n=this.a/Math.sqrt(con);var ml=this.a*Proj4js.common.mlfn(this.e0,this.e1,this.e2,this.e3,lat);x=this.k0*n*al*(1.0+als/6.0*(1.0-t+c+als/20.0*(5.0-18.0*t+Math.pow(t,2)+72.0*c-58.0*this.ep2)))+this.x0;y=this.k0*(ml-this.ml0+n*tq*(als*(0.5+als/24.0*(5.0-t+9.0*c+4.0*Math.pow(c,2)+als/30.0*(61.0-58.0*t+Math.pow(t,2)+600.0*c-330.0*this.ep2)))))+this.y0;} 174 p.x=x;p.y=y;return p;},inverse:function(p){var con,phi;var delta_phi;var i;var max_iter=6;var lat,lon;if(this.sphere){var f=Math.exp(p.x/(this.a*this.k0));var g=.5*(f-1/f);var temp=this.lat0+p.y/(this.a*this.k0);var h=Math.cos(temp);con=Math.sqrt((1.0-h*h)/(1.0+g*g));lat=Proj4js.common.asinz(con);if(temp<0) 175 lat=-lat;if((g==0)&&(h==0)){lon=this.long0;}else{lon=Proj4js.common.adjust_lon(Math.atan2(g,h)+this.long0);}}else{var x=p.x-this.x0;var y=p.y-this.y0;con=(this.ml0+y/this.k0)/this.a;phi=con;for(i=0;true;i++){delta_phi=((con+this.e1*Math.sin(2.0*phi)-this.e2*Math.sin(4.0*phi)+this.e3*Math.sin(6.0*phi))/this.e0)-phi;phi+=delta_phi;if(Math.abs(delta_phi)<=Proj4js.common.EPSLN)break;if(i>=max_iter){Proj4js.reportError("tmerc:inverse: Latitude failed to converge");return(95);}} 176 if(Math.abs(phi)<Proj4js.common.HALF_PI){var sin_phi=Math.sin(phi);var cos_phi=Math.cos(phi);var tan_phi=Math.tan(phi);var c=this.ep2*Math.pow(cos_phi,2);var cs=Math.pow(c,2);var t=Math.pow(tan_phi,2);var ts=Math.pow(t,2);con=1.0-this.es*Math.pow(sin_phi,2);var n=this.a/Math.sqrt(con);var r=n*(1.0-this.es)/con;var d=x/(n*this.k0);var ds=Math.pow(d,2);lat=phi-(n*tan_phi*ds/r)*(0.5-ds/24.0*(5.0+3.0*t+10.0*c-4.0*cs-9.0*this.ep2-ds/30.0*(61.0+90.0*t+298.0*c+45.0*ts-252.0*this.ep2-3.0*cs)));lon=Proj4js.common.adjust_lon(this.long0+(d*(1.0-ds/6.0*(1.0+2.0*t+c-ds/20.0*(5.0-2.0*c+28.0*t-3.0*cs+8.0*this.ep2+24.0*ts)))/cos_phi));}else{lat=Proj4js.common.HALF_PI*Proj4js.common.sign(y);lon=this.long0;}} 177 p.x=lon;p.y=lat;return p;}};Proj4js.defs["GOOGLE"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";Proj4js.defs["EPSG:900913"]=Proj4js.defs["GOOGLE"];Proj4js.Proj.gstmerc={init:function(){var temp=this.b/this.a;this.e=Math.sqrt(1.0-temp*temp);this.lc=this.long0;this.rs=Math.sqrt(1.0+this.e*this.e*Math.pow(Math.cos(this.lat0),4.0)/(1.0-this.e*this.e));var sinz=Math.sin(this.lat0);var pc=Math.asin(sinz/this.rs);var sinzpc=Math.sin(pc);this.cp=Proj4js.common.latiso(0.0,pc,sinzpc)-this.rs*Proj4js.common.latiso(this.e,this.lat0,sinz);this.n2=this.k0*this.a*Math.sqrt(1.0-this.e*this.e)/(1.0-this.e*this.e*sinz*sinz);this.xs=this.x0;this.ys=this.y0-this.n2*pc;if(!this.title)this.title="Gauss Schreiber transverse mercator";},forward:function(p){var lon=p.x;var lat=p.y;var L=this.rs*(lon-this.lc);var Ls=this.cp+(this.rs*Proj4js.common.latiso(this.e,lat,Math.sin(lat)));var lat1=Math.asin(Math.sin(L)/Proj4js.common.cosh(Ls));var Ls1=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.xs+(this.n2*Ls1);p.y=this.ys+(this.n2*Math.atan(Proj4js.common.sinh(Ls)/Math.cos(L)));return p;},inverse:function(p){var x=p.x;var y=p.y;var L=Math.atan(Proj4js.common.sinh((x-this.xs)/this.n2)/Math.cos((y-this.ys)/this.n2));var lat1=Math.asin(Math.sin((y-this.ys)/this.n2)/Proj4js.common.cosh((x-this.xs)/this.n2));var LC=Proj4js.common.latiso(0.0,lat1,Math.sin(lat1));p.x=this.lc+L/this.rs;p.y=Proj4js.common.invlatiso(this.e,(LC-this.cp)/this.rs);return p;}};Proj4js.Proj.ortho={init:function(def){;this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){var x=this.a*ksp*cosphi*Math.sin(dlon);var y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);}else{Proj4js.reportError("orthoFwdPointError");} 178 p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinz,cosz;var temp;var con;var lon,lat;p.x-=this.x0;p.y-=this.y0;rh=Math.sqrt(p.x*p.x+p.y*p.y);if(rh>this.a+.0000001){Proj4js.reportError("orthoInvDataError");} 179 z=Proj4js.common.asinz(rh/this.a);sinz=Math.sin(z);cosz=Math.cos(z);lon=this.long0;if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.lat0;} 180 lat=Proj4js.common.asinz(cosz*this.sin_p14+(p.y*sinz*this.cos_p14)/rh);con=Math.abs(lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(this.lat0>=0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}} 181 con=cosz-this.sin_p14*Math.sin(lat);if((Math.abs(con)>=Proj4js.common.EPSLN)||(Math.abs(x)>=Proj4js.common.EPSLN)){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2((p.x*sinz*this.cos_p14),(con*rh)));} 182 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.somerc={init:function(){var phy0=this.lat0;this.lambda0=this.long0;var sinPhy0=Math.sin(phy0);var semiMajorAxis=this.a;var invF=this.rf;var flattening=1/invF;var e2=2*flattening-Math.pow(flattening,2);var e=this.e=Math.sqrt(e2);this.R=semiMajorAxis*Math.sqrt(1-e2)/(1-e2*Math.pow(sinPhy0,2.0));this.alpha=Math.sqrt(1+e2/(1-e2)*Math.pow(Math.cos(phy0),4.0));this.b0=Math.asin(sinPhy0/this.alpha);this.K=Math.log(Math.tan(Math.PI/4.0+this.b0/2.0)) 183 -this.alpha*Math.log(Math.tan(Math.PI/4.0+phy0/2.0)) 184 +this.alpha*e/2*Math.log((1+e*sinPhy0)/(1-e*sinPhy0));},forward:function(p){var Sa1=Math.log(Math.tan(Math.PI/4.0-p.y/2.0));var Sa2=this.e/2.0*Math.log((1+this.e*Math.sin(p.y))/(1-this.e*Math.sin(p.y)));var S=-this.alpha*(Sa1+Sa2)+this.K;var b=2.0*(Math.atan(Math.exp(S))-Math.PI/4.0);var I=this.alpha*(p.x-this.lambda0);var rotI=Math.atan(Math.sin(I)/(Math.sin(this.b0)*Math.tan(b)+ 185 Math.cos(this.b0)*Math.cos(I)));var rotB=Math.asin(Math.cos(this.b0)*Math.sin(b)- 186 Math.sin(this.b0)*Math.cos(b)*Math.cos(I));p.y=this.R/2.0*Math.log((1+Math.sin(rotB))/(1-Math.sin(rotB))) 187 +this.y0;p.x=this.R*rotI+this.x0;return p;},inverse:function(p){var Y=p.x-this.x0;var X=p.y-this.y0;var rotI=Y/this.R;var rotB=2*(Math.atan(Math.exp(X/this.R))-Math.PI/4.0);var b=Math.asin(Math.cos(this.b0)*Math.sin(rotB) 188 +Math.sin(this.b0)*Math.cos(rotB)*Math.cos(rotI));var I=Math.atan(Math.sin(rotI)/(Math.cos(this.b0)*Math.cos(rotI)-Math.sin(this.b0)*Math.tan(rotB)));var lambda=this.lambda0+I/this.alpha;var S=0.0;var phy=b;var prevPhy=-1000.0;var iteration=0;while(Math.abs(phy-prevPhy)>0.0000001) 189 {if(++iteration>20) 190 {Proj4js.reportError("omercFwdInfinity");return;} 191 S=1.0/this.alpha*(Math.log(Math.tan(Math.PI/4.0+b/2.0))-this.K) 192 +this.e*Math.log(Math.tan(Math.PI/4.0 193 +Math.asin(this.e*Math.sin(phy))/2.0));prevPhy=phy;phy=2.0*Math.atan(Math.exp(S))-Math.PI/2.0;} 194 p.x=lambda;p.y=phy;return p;}};Proj4js.Proj.stere={ssfn_:function(phit,sinphi,eccen){sinphi*=eccen;return(Math.tan(.5*(Proj4js.common.HALF_PI+phit))*Math.pow((1.-sinphi)/(1.+sinphi),.5*eccen));},TOL:1.e-8,NITER:8,CONV:1.e-10,S_POLE:0,N_POLE:1,OBLIQ:2,EQUIT:3,init:function(){this.phits=this.lat_ts?this.lat_ts:Proj4js.common.HALF_PI;var t=Math.abs(this.lat0);if((Math.abs(t)-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else{this.mode=t>Proj4js.common.EPSLN?this.OBLIQ:this.EQUIT;} 195 this.phits=Math.abs(this.phits);if(this.es){var X;switch(this.mode){case this.N_POLE:case this.S_POLE:if(Math.abs(this.phits-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.akm1=2.*this.k0/Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e));}else{t=Math.sin(this.phits);this.akm1=Math.cos(this.phits)/Proj4js.common.tsfnz(this.e,this.phits,t);t*=this.e;this.akm1/=Math.sqrt(1.-t*t);} 196 break;case this.EQUIT:this.akm1=2.*this.k0;break;case this.OBLIQ:t=Math.sin(this.lat0);X=2.*Math.atan(this.ssfn_(this.lat0,t,this.e))-Proj4js.common.HALF_PI;t*=this.e;this.akm1=2.*this.k0*Math.cos(this.lat0)/Math.sqrt(1.-t*t);this.sinX1=Math.sin(X);this.cosX1=Math.cos(X);break;}}else{switch(this.mode){case this.OBLIQ:this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);case this.EQUIT:this.akm1=2.*this.k0;break;case this.S_POLE:case this.N_POLE:this.akm1=Math.abs(this.phits-Proj4js.common.HALF_PI)>=Proj4js.common.EPSLN?Math.cos(this.phits)/Math.tan(Proj4js.common.FORTPI-.5*this.phits):2.*this.k0;break;}}},forward:function(p){var lon=p.x;lon=Proj4js.common.adjust_lon(lon-this.long0);var lat=p.y;var x,y;if(this.sphere){var sinphi,cosphi,coslam,sinlam;sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslam=Math.cos(lon);sinlam=Math.sin(lon);switch(this.mode){case this.EQUIT:y=1.+cosphi*coslam;if(y<=Proj4js.common.EPSLN){F_ERROR;} 197 y=this.akm1/y;x=y*cosphi*sinlam;y*=sinphi;break;case this.OBLIQ:y=1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){F_ERROR;} 198 y=this.akm1/y;x=y*cosphi*sinlam;y*=this.cosph0*sinphi-this.sinph0*cosphi*coslam;break;case this.N_POLE:coslam=-coslam;lat=-lat;case this.S_POLE:if(Math.abs(lat-Proj4js.common.HALF_PI)<this.TOL){F_ERROR;} 199 y=this.akm1*Math.tan(Proj4js.common.FORTPI+.5*lat);x=sinlam*y;y*=coslam;break;}}else{coslam=Math.cos(lon);sinlam=Math.sin(lon);sinphi=Math.sin(lat);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){X=2.*Math.atan(this.ssfn_(lat,sinphi,this.e));sinX=Math.sin(X-Proj4js.common.HALF_PI);cosX=Math.cos(X);} 200 switch(this.mode){case this.OBLIQ:A=this.akm1/(this.cosX1*(1.+this.sinX1*sinX+this.cosX1*cosX*coslam));y=A*(this.cosX1*sinX-this.sinX1*cosX*coslam);x=A*cosX;break;case this.EQUIT:A=2.*this.akm1/(1.+cosX*coslam);y=A*sinX;x=A*cosX;break;case this.S_POLE:lat=-lat;coslam=-coslam;sinphi=-sinphi;case this.N_POLE:x=this.akm1*Proj4js.common.tsfnz(this.e,lat,sinphi);y=-x*coslam;break;} 201 x=x*sinlam;} 202 p.x=x*this.a+this.x0;p.y=y*this.a+this.y0;return p;},inverse:function(p){var x=(p.x-this.x0)/this.a;var y=(p.y-this.y0)/this.a;var lon,lat;var cosphi,sinphi,tp=0.0,phi_l=0.0,rho,halfe=0.0,pi2=0.0;var i;if(this.sphere){var c,rh,sinc,cosc;rh=Math.sqrt(x*x+y*y);c=2.*Math.atan(rh/this.akm1);sinc=Math.sin(c);cosc=Math.cos(c);lon=0.;switch(this.mode){case this.EQUIT:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=0.;}else{lat=Math.asin(y*sinc/rh);} 203 if(cosc!=0.||x!=0.)lon=Math.atan2(x*sinc,cosc*rh);break;case this.OBLIQ:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(cosc*sinph0+y*sinc*cosph0/rh);} 204 c=cosc-sinph0*Math.sin(lat);if(c!=0.||x!=0.){lon=Math.atan2(x*sinc*cosph0,c*rh);} 205 break;case this.N_POLE:y=-y;case this.S_POLE:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(this.mode==this.S_POLE?-cosc:cosc);} 206 lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);break;}}else{rho=Math.sqrt(x*x+y*y);switch(this.mode){case this.OBLIQ:case this.EQUIT:tp=2.*Math.atan2(rho*this.cosX1,this.akm1);cosphi=Math.cos(tp);sinphi=Math.sin(tp);if(rho==0.0){phi_l=Math.asin(cosphi*this.sinX1);}else{phi_l=Math.asin(cosphi*this.sinX1+(y*sinphi*this.cosX1/rho));} 207 tp=Math.tan(.5*(Proj4js.common.HALF_PI+phi_l));x*=sinphi;y=rho*this.cosX1*cosphi-y*this.sinX1*sinphi;pi2=Proj4js.common.HALF_PI;halfe=.5*this.e;break;case this.N_POLE:y=-y;case this.S_POLE:tp=-rho/this.akm1;phi_l=Proj4js.common.HALF_PI-2.*Math.atan(tp);pi2=-Proj4js.common.HALF_PI;halfe=-.5*this.e;break;} 208 for(i=this.NITER;i--;phi_l=lat){sinphi=this.e*Math.sin(phi_l);lat=2.*Math.atan(tp*Math.pow((1.+sinphi)/(1.-sinphi),halfe))-pi2;if(Math.abs(phi_l-lat)<this.CONV){if(this.mode==this.S_POLE)lat=-lat;lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);p.x=Proj4js.common.adjust_lon(lon+this.long0);p.y=lat;return p;}}}}};Proj4js.Proj.nzmg={iterations:1,init:function(){this.A=new Array();this.A[1]=+0.6399175073;this.A[2]=-0.1358797613;this.A[3]=+0.063294409;this.A[4]=-0.02526853;this.A[5]=+0.0117879;this.A[6]=-0.0055161;this.A[7]=+0.0026906;this.A[8]=-0.001333;this.A[9]=+0.00067;this.A[10]=-0.00034;this.B_re=new Array();this.B_im=new Array();this.B_re[1]=+0.7557853228;this.B_im[1]=0.0;this.B_re[2]=+0.249204646;this.B_im[2]=+0.003371507;this.B_re[3]=-0.001541739;this.B_im[3]=+0.041058560;this.B_re[4]=-0.10162907;this.B_im[4]=+0.01727609;this.B_re[5]=-0.26623489;this.B_im[5]=-0.36249218;this.B_re[6]=-0.6870983;this.B_im[6]=-1.1651967;this.C_re=new Array();this.C_im=new Array();this.C_re[1]=+1.3231270439;this.C_im[1]=0.0;this.C_re[2]=-0.577245789;this.C_im[2]=-0.007809598;this.C_re[3]=+0.508307513;this.C_im[3]=-0.112208952;this.C_re[4]=-0.15094762;this.C_im[4]=+0.18200602;this.C_re[5]=+1.01418179;this.C_im[5]=+1.64497696;this.C_re[6]=+1.9660549;this.C_im[6]=+2.5127645;this.D=new Array();this.D[1]=+1.5627014243;this.D[2]=+0.5185406398;this.D[3]=-0.03333098;this.D[4]=-0.1052906;this.D[5]=-0.0368594;this.D[6]=+0.007317;this.D[7]=+0.01220;this.D[8]=+0.00394;this.D[9]=-0.0013;},forward:function(p){var lon=p.x;var lat=p.y;var delta_lat=lat-this.lat0;var delta_lon=lon-this.long0;var d_phi=delta_lat/Proj4js.common.SEC_TO_RAD*1E-5;var d_lambda=delta_lon;var d_phi_n=1;var d_psi=0;for(n=1;n<=10;n++){d_phi_n=d_phi_n*d_phi;d_psi=d_psi+this.A[n]*d_phi_n;} 209 var th_re=d_psi;var th_im=d_lambda;var th_n_re=1;var th_n_im=0;var th_n_re1;var th_n_im1;var z_re=0;var z_im=0;for(n=1;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;z_re=z_re+this.B_re[n]*th_n_re-this.B_im[n]*th_n_im;z_im=z_im+this.B_im[n]*th_n_re+this.B_re[n]*th_n_im;} 210 x=(z_im*this.a)+this.x0;y=(z_re*this.a)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var x=p.x;var y=p.y;var delta_x=x-this.x0;var delta_y=y-this.y0;var z_re=delta_y/this.a;var z_im=delta_x/this.a;var z_n_re=1;var z_n_im=0;var z_n_re1;var z_n_im1;var th_re=0;var th_im=0;for(n=1;n<=6;n++){z_n_re1=z_n_re*z_re-z_n_im*z_im;z_n_im1=z_n_im*z_re+z_n_re*z_im;z_n_re=z_n_re1;z_n_im=z_n_im1;th_re=th_re+this.C_re[n]*z_n_re-this.C_im[n]*z_n_im;th_im=th_im+this.C_im[n]*z_n_re+this.C_re[n]*z_n_im;} 211 for(i=0;i<this.iterations;i++){var th_n_re=th_re;var th_n_im=th_im;var th_n_re1;var th_n_im1;var num_re=z_re;var num_im=z_im;for(n=2;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;num_re=num_re+(n-1)*(this.B_re[n]*th_n_re-this.B_im[n]*th_n_im);num_im=num_im+(n-1)*(this.B_im[n]*th_n_re+this.B_re[n]*th_n_im);} 212 th_n_re=1;th_n_im=0;var den_re=this.B_re[1];var den_im=this.B_im[1];for(n=2;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;den_re=den_re+n*(this.B_re[n]*th_n_re-this.B_im[n]*th_n_im);den_im=den_im+n*(this.B_im[n]*th_n_re+this.B_re[n]*th_n_im);} 213 var den2=den_re*den_re+den_im*den_im;th_re=(num_re*den_re+num_im*den_im)/den2;th_im=(num_im*den_re-num_re*den_im)/den2;} 214 var d_psi=th_re;var d_lambda=th_im;var d_psi_n=1;var d_phi=0;for(n=1;n<=9;n++){d_psi_n=d_psi_n*d_psi;d_phi=d_phi+this.D[n]*d_psi_n;} 215 var lat=this.lat0+(d_phi*Proj4js.common.SEC_TO_RAD*1E5);var lon=this.long0+d_lambda;p.x=lon;p.y=lat;return p;}};Proj4js.Proj.mill={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon;var y=this.y0+this.a*Math.log(Math.tan((Proj4js.common.PI/4.0)+(lat/2.5)))*1.25;p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+p.x/this.a);var lat=2.5*(Math.atan(Math.exp(0.8*p.y/this.a))-Proj4js.common.PI/4.0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.gnom={init:function(def){this.sin_p14=Math.sin(this.lat0);this.cos_p14=Math.cos(this.lat0);this.infinity_dist=1000*this.a;},forward:function(p){var sinphi,cosphi;var dlon;var coslon;var ksp;var g;var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);sinphi=Math.sin(lat);cosphi=Math.cos(lat);coslon=Math.cos(dlon);g=this.sin_p14*sinphi+this.cos_p14*cosphi*coslon;ksp=1.0;if((g>0)||(Math.abs(g)<=Proj4js.common.EPSLN)){x=this.x0+this.a*ksp*cosphi*Math.sin(dlon)/g;y=this.y0+this.a*ksp*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon)/g;}else{Proj4js.reportError("orthoFwdPointError");x=this.x0+this.infinity_dist*cosphi*Math.sin(dlon);y=this.y0+this.infinity_dist*(this.cos_p14*sinphi-this.sin_p14*cosphi*coslon);} 216 p.x=x;p.y=y;return p;},inverse:function(p){var rh;var z;var sinc,cosc;var c;var lon,lat;p.x=(p.x-this.x0)/this.a;p.y=(p.y-this.y0)/this.a;p.x/=this.k0;p.y/=this.k0;if((rh=Math.sqrt(p.x*p.x+p.y*p.y))){c=Math.atan2(rh,this.rc);sinc=Math.sin(c);cosc=Math.cos(c);lat=Proj4js.common.asinz(cosc*this.sin_p14+(p.y*sinc*this.cos_p14)/rh);lon=Math.atan2(p.x*sinc,rh*this.cos_p14*cosc-p.y*this.sin_p14*sinc);lon=Proj4js.common.adjust_lon(this.long0+lon);}else{lat=this.phic0;lon=0.0;} 217 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.sinu={init:function(){this.R=6370997.0;},forward:function(p){var x,y,delta_lon;var lon=p.x;var lat=p.y;delta_lon=Proj4js.common.adjust_lon(lon-this.long0);x=this.R*delta_lon*Math.cos(lat)+this.x0;y=this.R*lat+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var lat,temp,lon;p.x-=this.x0;p.y-=this.y0;lat=p.y/this.R;if(Math.abs(lat)>Proj4js.common.HALF_PI){Proj4js.reportError("sinu:Inv:DataError");} 218 temp=Math.abs(lat)-Proj4js.common.HALF_PI;if(Math.abs(temp)>Proj4js.common.EPSLN){temp=this.long0+p.x/(this.R*Math.cos(lat));lon=Proj4js.common.adjust_lon(temp);}else{lon=this.long0;} 219 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.vandg={init:function(){this.R=6370997.0;},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var x,y;if(Math.abs(lat)<=Proj4js.common.EPSLN){x=this.x0+this.R*dlon;y=this.y0;} 220 var theta=Proj4js.common.asinz(2.0*Math.abs(lat/Proj4js.common.PI));if((Math.abs(dlon)<=Proj4js.common.EPSLN)||(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN)){x=this.x0;if(lat>=0){y=this.y0+Proj4js.common.PI*this.R*Math.tan(.5*theta);}else{y=this.y0+Proj4js.common.PI*this.R*-Math.tan(.5*theta);}} 221 var al=.5*Math.abs((Proj4js.common.PI/dlon)-(dlon/Proj4js.common.PI));var asq=al*al;var sinth=Math.sin(theta);var costh=Math.cos(theta);var g=costh/(sinth+costh-1.0);var gsq=g*g;var m=g*(2.0/sinth-1.0);var msq=m*m;var con=Proj4js.common.PI*this.R*(al*(g-msq)+Math.sqrt(asq*(g-msq)*(g-msq)-(msq+asq)*(gsq-msq)))/(msq+asq);if(dlon<0){con=-con;} 222 x=this.x0+con;con=Math.abs(con/(Proj4js.common.PI*this.R));if(lat>=0){y=this.y0+Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);}else{y=this.y0-Proj4js.common.PI*this.R*Math.sqrt(1.0-con*con-2.0*al*con);} 223 p.x=x;p.y=y;return p;},inverse:function(p){var dlon;var xx,yy,xys,c1,c2,c3;var al,asq;var a1;var m1;var con;var th1;var d;p.x-=this.x0;p.y-=this.y0;con=Proj4js.common.PI*this.R;xx=p.x/con;yy=p.y/con;xys=xx*xx+yy*yy;c1=-Math.abs(yy)*(1.0+xys);c2=c1-2.0*yy*yy+xx*xx;c3=-2.0*c1+1.0+2.0*yy*yy+xys*xys;d=yy*yy/c3+(2.0*c2*c2*c2/c3/c3/c3-9.0*c1*c2/c3/c3)/27.0;a1=(c1-c2*c2/3.0/c3)/c3;m1=2.0*Math.sqrt(-a1/3.0);con=((3.0*d)/a1)/m1;if(Math.abs(con)>1.0){if(con>=0.0){con=1.0;}else{con=-1.0;}} 224 th1=Math.acos(con)/3.0;if(p.y>=0){lat=(-m1*Math.cos(th1+Proj4js.common.PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;}else{lat=-(-m1*Math.cos(th1+PI/3.0)-c2/3.0/c3)*Proj4js.common.PI;} 225 if(Math.abs(xx)<Proj4js.common.EPSLN){lon=this.long0;} 226 lon=Proj4js.common.adjust_lon(this.long0+Proj4js.common.PI*(xys-1.0+Math.sqrt(1.0+2.0*(xx*xx-yy*yy)+xys*xys))/2.0/xx);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.cea={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;dlon=Proj4js.common.adjust_lon(lon-this.long0);var x=this.x0+this.a*dlon*Math.cos(this.lat_ts);var y=this.y0+this.a*Math.sin(lat)/Math.cos(this.lat_ts);p.x=x;p.y=y;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var lon=Proj4js.common.adjust_lon(this.long0+(p.x/this.a)/Math.cos(this.lat_ts));var lat=Math.asin((p.y/this.a)*Math.cos(this.lat_ts));p.x=lon;p.y=lat;return p;}};Proj4js.Proj.eqc={init:function(){if(!this.x0)this.x0=0;if(!this.y0)this.y0=0;if(!this.lat0)this.lat0=0;if(!this.long0)this.long0=0;if(!this.lat_ts)this.lat_ts=0;if(!this.title)this.title="Equidistant Cylindrical (Plate Carre)";this.rc=Math.cos(this.lat_ts);},forward:function(p){var lon=p.x;var lat=p.y;var dlon=Proj4js.common.adjust_lon(lon-this.long0);var dlat=Proj4js.common.adjust_lat(lat-this.lat0);p.x=this.x0+(this.a*dlon*this.rc);p.y=this.y0+(this.a*dlat);return p;},inverse:function(p){var x=p.x;var y=p.y;p.x=Proj4js.common.adjust_lon(this.long0+((x-this.x0)/(this.a*this.rc)));p.y=Proj4js.common.adjust_lat(this.lat0+((y-this.y0)/(this.a)));return p;}};Proj4js.Proj.cass={init:function(){if(!this.sphere){this.en=this.pj_enfn(this.es) 227 this.m0=this.pj_mlfn(this.lat0,Math.sin(this.lat0),Math.cos(this.lat0),this.en);}},C1:.16666666666666666666,C2:.00833333333333333333,C3:.04166666666666666666,C4:.33333333333333333333,C5:.06666666666666666666,forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){x=Math.asin(Math.cos(phi)*Math.sin(lam));y=Math.atan2(Math.tan(phi),Math.cos(lam))-this.phi0;}else{this.n=Math.sin(phi);this.c=Math.cos(phi);y=this.pj_mlfn(phi,this.n,this.c,this.en);this.n=1./Math.sqrt(1.-this.es*this.n*this.n);this.tn=Math.tan(phi);this.t=this.tn*this.tn;this.a1=lam*this.c;this.c*=this.es*this.c/(1-this.es);this.a2=this.a1*this.a1;x=this.n*this.a1*(1.-this.a2*this.t*(this.C1-(8.-this.t+8.*this.c)*this.a2*this.C2));y-=this.m0-this.n*this.tn*this.a2*(.5+(5.-this.t+6.*this.c)*this.a2*this.C3);} 228 p.x=this.a*x+this.x0;p.y=this.a*y+this.y0;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var x=p.x/this.a;var y=p.y/this.a;if(this.sphere){this.dd=y+this.lat0;phi=Math.asin(Math.sin(this.dd)*Math.cos(x));lam=Math.atan2(Math.tan(x),Math.cos(this.dd));}else{ph1=this.pj_inv_mlfn(this.m0+y,this.es,this.en);this.tn=Math.tan(ph1);this.t=this.tn*this.tn;this.n=Math.sin(ph1);this.r=1./(1.-this.es*this.n*this.n);this.n=Math.sqrt(this.r);this.r*=(1.-this.es)*this.n;this.dd=x/this.n;this.d2=this.dd*this.dd;phi=ph1-(this.n*this.tn/this.r)*this.d2*(.5-(1.+3.*this.t)*this.d2*this.C3);lam=this.dd*(1.+this.t*this.d2*(-this.C4+(1.+3.*this.t)*this.d2*this.C5))/Math.cos(ph1);} 229 p.x=Proj4js.common.adjust_lon(this.long0+lam);p.y=phi;return p;},pj_enfn:function(es){en=new Array();en[0]=this.C00-es*(this.C02+es*(this.C04+es*(this.C06+es*this.C08)));en[1]=es*(this.C22-es*(this.C04+es*(this.C06+es*this.C08)));var t=es*es;en[2]=t*(this.C44-es*(this.C46+es*this.C48));t*=es;en[3]=t*(this.C66-es*this.C68);en[4]=t*es*this.C88;return en;},pj_mlfn:function(phi,sphi,cphi,en){cphi*=sphi;sphi*=sphi;return(en[0]*phi-cphi*(en[1]+sphi*(en[2]+sphi*(en[3]+sphi*en[4]))));},pj_inv_mlfn:function(arg,es,en){k=1./(1.-es);phi=arg;for(i=Proj4js.common.MAX_ITER;i;--i){s=Math.sin(phi);t=1.-es*s*s;t=(this.pj_mlfn(phi,s,Math.cos(phi),en)-arg)*(t*Math.sqrt(t))*k;phi-=t;if(Math.abs(t)<Proj4js.common.EPSLN) 230 return phi;} 231 Proj4js.reportError("cass:pj_inv_mlfn: Convergence error");return phi;},C00:1.0,C02:.25,C04:.046875,C06:.01953125,C08:.01068115234375,C22:.75,C44:.46875,C46:.01302083333333333333,C48:.00712076822916666666,C66:.36458333333333333333,C68:.00569661458333333333,C88:.3076171875} 232 Proj4js.Proj.gauss={init:function(){sphi=Math.sin(this.lat0);cphi=Math.cos(this.lat0);cphi*=cphi;this.rc=Math.sqrt(1.0-this.es)/(1.0-this.es*sphi*sphi);this.C=Math.sqrt(1.0+this.es*cphi*cphi/(1.0-this.es));this.phic0=Math.asin(sphi/this.C);this.ratexp=0.5*this.C*this.e;this.K=Math.tan(0.5*this.phic0+Proj4js.common.FORTPI)/(Math.pow(Math.tan(0.5*this.lat0+Proj4js.common.FORTPI),this.C)*Proj4js.common.srat(this.e*sphi,this.ratexp));},forward:function(p){var lon=p.x;var lat=p.y;p.y=2.0*Math.atan(this.K*Math.pow(Math.tan(0.5*lat+Proj4js.common.FORTPI),this.C)*Proj4js.common.srat(this.e*Math.sin(lat),this.ratexp))-Proj4js.common.HALF_PI;p.x=this.C*lon;return p;},inverse:function(p){var DEL_TOL=1e-14;var lon=p.x/this.C;var lat=p.y;num=Math.pow(Math.tan(0.5*lat+Proj4js.common.FORTPI)/this.K,1./this.C);for(var i=Proj4js.common.MAX_ITER;i>0;--i){lat=2.0*Math.atan(num*Proj4js.common.srat(this.e*Math.sin(p.y),-0.5*this.e))-Proj4js.common.HALF_PI;if(Math.abs(lat-p.y)<DEL_TOL)break;p.y=lat;} 233 if(!i){Proj4js.reportError("gauss:inverse:convergence failed");return null;} 234 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.omerc={init:function(){if(!this.mode)this.mode=0;if(!this.lon1){this.lon1=0;this.mode=1;} 235 if(!this.lon2)this.lon2=0;if(!this.lat2)this.lat2=0;var temp=this.b/this.a;var es=1.0-Math.pow(temp,2);var e=Math.sqrt(es);this.sin_p20=Math.sin(this.lat0);this.cos_p20=Math.cos(this.lat0);this.con=1.0-this.es*this.sin_p20*this.sin_p20;this.com=Math.sqrt(1.0-es);this.bl=Math.sqrt(1.0+this.es*Math.pow(this.cos_p20,4.0)/(1.0-es));this.al=this.a*this.bl*this.k0*this.com/this.con;if(Math.abs(this.lat0)<Proj4js.common.EPSLN){this.ts=1.0;this.d=1.0;this.el=1.0;}else{this.ts=Proj4js.common.tsfnz(this.e,this.lat0,this.sin_p20);this.con=Math.sqrt(this.con);this.d=this.bl*this.com/(this.cos_p20*this.con);if((this.d*this.d-1.0)>0.0){if(this.lat0>=0.0){this.f=this.d+Math.sqrt(this.d*this.d-1.0);}else{this.f=this.d-Math.sqrt(this.d*this.d-1.0);}}else{this.f=this.d;} 236 this.el=this.f*Math.pow(this.ts,this.bl);} 237 if(this.mode!=0){this.g=.5*(this.f-1.0/this.f);this.gama=Proj4js.common.asinz(Math.sin(this.alpha)/this.d);this.longc=this.longc-Proj4js.common.asinz(this.g*Math.tan(this.gama))/this.bl;this.con=Math.abs(this.lat0);if((this.con>Proj4js.common.EPSLN)&&(Math.abs(this.con-Proj4js.common.HALF_PI)>Proj4js.common.EPSLN)){this.singam=Math.sin(this.gama);this.cosgam=Math.cos(this.gama);this.sinaz=Math.sin(this.alpha);this.cosaz=Math.cos(this.alpha);if(this.lat0>=0){this.u=(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}else{this.u=-(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}}else{Proj4js.reportError("omerc:Init:DataError");}}else{this.sinphi=Math.sin(this.at1);this.ts1=Proj4js.common.tsfnz(this.e,this.lat1,this.sinphi);this.sinphi=Math.sin(this.lat2);this.ts2=Proj4js.common.tsfnz(this.e,this.lat2,this.sinphi);this.h=Math.pow(this.ts1,this.bl);this.l=Math.pow(this.ts2,this.bl);this.f=this.el/this.h;this.g=.5*(this.f-1.0/this.f);this.j=(this.el*this.el-this.l*this.h)/(this.el*this.el+this.l*this.h);this.p=(this.l-this.h)/(this.l+this.h);this.dlon=this.lon1-this.lon2;if(this.dlon<-Proj4js.common.PI)this.lon2=this.lon2-2.0*Proj4js.common.PI;if(this.dlon>Proj4js.common.PI)this.lon2=this.lon2+2.0*Proj4js.common.PI;this.dlon=this.lon1-this.lon2;this.longc=.5*(this.lon1+this.lon2)-Math.atan(this.j*Math.tan(.5*this.bl*this.dlon)/this.p)/this.bl;this.dlon=Proj4js.common.adjust_lon(this.lon1-this.longc);this.gama=Math.atan(Math.sin(this.bl*this.dlon)/this.g);this.alpha=Proj4js.common.asinz(this.d*Math.sin(this.gama));if(Math.abs(this.lat1-this.lat2)<=Proj4js.common.EPSLN){Proj4js.reportError("omercInitDataError");}else{this.con=Math.abs(this.lat1);} 238 if((this.con<=Proj4js.common.EPSLN)||(Math.abs(this.con-HALF_PI)<=Proj4js.common.EPSLN)){Proj4js.reportError("omercInitDataError");}else{if(Math.abs(Math.abs(this.lat0)-Proj4js.common.HALF_PI)<=Proj4js.common.EPSLN){Proj4js.reportError("omercInitDataError");}} 239 this.singam=Math.sin(this.gam);this.cosgam=Math.cos(this.gam);this.sinaz=Math.sin(this.alpha);this.cosaz=Math.cos(this.alpha);if(this.lat0>=0){this.u=(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}else{this.u=-(this.al/this.bl)*Math.atan(Math.sqrt(this.d*this.d-1.0)/this.cosaz);}}},forward:function(p){var theta;var sin_phi,cos_phi;var b;var c,t,tq;var con,n,ml;var q,us,vl;var ul,vs;var s;var dlon;var ts1;var lon=p.x;var lat=p.y;sin_phi=Math.sin(lat);dlon=Proj4js.common.adjust_lon(lon-this.longc);vl=Math.sin(this.bl*dlon);if(Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI)>Proj4js.common.EPSLN){ts1=Proj4js.common.tsfnz(this.e,lat,sin_phi);q=this.el/(Math.pow(ts1,this.bl));s=.5*(q-1.0/q);t=.5*(q+1.0/q);ul=(s*this.singam-vl*this.cosgam)/t;con=Math.cos(this.bl*dlon);if(Math.abs(con)<.0000001){us=this.al*this.bl*dlon;}else{us=this.al*Math.atan((s*this.cosgam+vl*this.singam)/con)/this.bl;if(con<0)us=us+Proj4js.common.PI*this.al/this.bl;}}else{if(lat>=0){ul=this.singam;}else{ul=-this.singam;} 240 us=this.al*lat/this.bl;} 241 if(Math.abs(Math.abs(ul)-1.0)<=Proj4js.common.EPSLN){Proj4js.reportError("omercFwdInfinity");} 242 vs=.5*this.al*Math.log((1.0-ul)/(1.0+ul))/this.bl;us=us-this.u;var x=this.x0+vs*this.cosaz+us*this.sinaz;var y=this.y0+us*this.cosaz-vs*this.sinaz;p.x=x;p.y=y;return p;},inverse:function(p){var delta_lon;var theta;var delta_theta;var sin_phi,cos_phi;var b;var c,t,tq;var con,n,ml;var vs,us,q,s,ts1;var vl,ul,bs;var dlon;var flag;p.x-=this.x0;p.y-=this.y0;flag=0;vs=p.x*this.cosaz-p.y*this.sinaz;us=p.y*this.cosaz+p.x*this.sinaz;us=us+this.u;q=Math.exp(-this.bl*vs/this.al);s=.5*(q-1.0/q);t=.5*(q+1.0/q);vl=Math.sin(this.bl*us/this.al);ul=(vl*this.cosgam+s*this.singam)/t;if(Math.abs(Math.abs(ul)-1.0)<=Proj4js.common.EPSLN) 243 {lon=this.longc;if(ul>=0.0){lat=Proj4js.common.HALF_PI;}else{lat=-Proj4js.common.HALF_PI;}}else{con=1.0/this.bl;ts1=Math.pow((this.el/Math.sqrt((1.0+ul)/(1.0-ul))),con);lat=Proj4js.common.phi2z(this.e,ts1);theta=this.longc-Math.atan2((s*this.cosgam-vl*this.singam),con)/this.bl;lon=Proj4js.common.adjust_lon(theta);} 244 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.lcc={init:function(){if(!this.lat2){this.lat2=this.lat0;} 245 if(!this.k0)this.k0=1.0;if(Math.abs(this.lat1+this.lat2)<Proj4js.common.EPSLN){Proj4js.reportError("lcc:init: Equal Latitudes");return;} 246 var temp=this.b/this.a;this.e=Math.sqrt(1.0-temp*temp);var sin1=Math.sin(this.lat1);var cos1=Math.cos(this.lat1);var ms1=Proj4js.common.msfnz(this.e,sin1,cos1);var ts1=Proj4js.common.tsfnz(this.e,this.lat1,sin1);var sin2=Math.sin(this.lat2);var cos2=Math.cos(this.lat2);var ms2=Proj4js.common.msfnz(this.e,sin2,cos2);var ts2=Proj4js.common.tsfnz(this.e,this.lat2,sin2);var ts0=Proj4js.common.tsfnz(this.e,this.lat0,Math.sin(this.lat0));if(Math.abs(this.lat1-this.lat2)>Proj4js.common.EPSLN){this.ns=Math.log(ms1/ms2)/Math.log(ts1/ts2);}else{this.ns=sin1;} 247 this.f0=ms1/(this.ns*Math.pow(ts1,this.ns));this.rh=this.a*this.f0*Math.pow(ts0,this.ns);if(!this.title)this.title="Lambert Conformal Conic";},forward:function(p){var lon=p.x;var lat=p.y;if(lat<=90.0&&lat>=-90.0&&lon<=180.0&&lon>=-180.0){}else{Proj4js.reportError("lcc:forward: llInputOutOfRange: "+lon+" : "+lat);return null;} 248 var con=Math.abs(Math.abs(lat)-Proj4js.common.HALF_PI);var ts,rh1;if(con>Proj4js.common.EPSLN){ts=Proj4js.common.tsfnz(this.e,lat,Math.sin(lat));rh1=this.a*this.f0*Math.pow(ts,this.ns);}else{con=lat*this.ns;if(con<=0){Proj4js.reportError("lcc:forward: No Projection");return null;} 249 rh1=0;} 250 var theta=this.ns*Proj4js.common.adjust_lon(lon-this.long0);p.x=this.k0*(rh1*Math.sin(theta))+this.x0;p.y=this.k0*(this.rh-rh1*Math.cos(theta))+this.y0;return p;},inverse:function(p){var rh1,con,ts;var lat,lon;x=(p.x-this.x0)/this.k0;y=(this.rh-(p.y-this.y0)/this.k0);if(this.ns>0){rh1=Math.sqrt(x*x+y*y);con=1.0;}else{rh1=-Math.sqrt(x*x+y*y);con=-1.0;} 251 var theta=0.0;if(rh1!=0){theta=Math.atan2((con*x),(con*y));} 252 if((rh1!=0)||(this.ns>0.0)){con=1.0/this.ns;ts=Math.pow((rh1/(this.a*this.f0)),con);lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999)return null;}else{lat=-Proj4js.common.HALF_PI;} 253 lon=Proj4js.common.adjust_lon(theta/this.ns+this.long0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.laea={S_POLE:1,N_POLE:2,EQUIT:3,OBLIQ:4,init:function(){var t=Math.abs(this.lat0);if(Math.abs(t-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else if(Math.abs(t)<Proj4js.common.EPSLN){this.mode=this.EQUIT;}else{this.mode=this.OBLIQ;} 254 if(this.es>0){var sinphi;this.qp=Proj4js.common.qsfnz(this.e,1.0);this.mmf=.5/(1.-this.es);this.apa=this.authset(this.es);switch(this.mode){case this.N_POLE:case this.S_POLE:this.dd=1.;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp);this.dd=1./this.rq;this.xmf=1.;this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp);sinphi=Math.sin(this.lat0);this.sinb1=Proj4js.common.qsfnz(this.e,sinphi)/this.qp;this.cosb1=Math.sqrt(1.-this.sinb1*this.sinb1);this.dd=Math.cos(this.lat0)/(Math.sqrt(1.-this.es*sinphi*sinphi)*this.rq*this.cosb1);this.ymf=(this.xmf=this.rq)/this.dd;this.xmf*=this.dd;break;}}else{if(this.mode==this.OBLIQ){this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);}}},forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){var coslam,cosphi,sinphi;sinphi=Math.sin(phi);cosphi=Math.cos(phi);coslam=Math.cos(lam);switch(this.mode){case this.EQUIT:y=(this.mode==this.EQUIT)?1.+cosphi*coslam:1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:y less than eps");return null;} 255 y=Math.sqrt(2./y);x=y*cosphi*Math.sin(lam);y*=(this.mode==this.EQUIT)?sinphi:this.cosph0*sinphi-this.sinph0*cosphi*coslam;break;case this.N_POLE:coslam=-coslam;case this.S_POLE:if(Math.abs(phi+this.phi0)<Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:phi < eps");return null;} 256 y=Proj4js.common.FORTPI-phi*.5;y=2.*((this.mode==this.S_POLE)?Math.cos(y):Math.sin(y));x=y*Math.sin(lam);y*=coslam;break;}}else{var coslam,sinlam,sinphi,q,sinb=0.0,cosb=0.0,b=0.0;coslam=Math.cos(lam);sinlam=Math.sin(lam);sinphi=Math.sin(phi);q=Proj4js.common.qsfnz(this.e,sinphi);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){sinb=q/this.qp;cosb=Math.sqrt(1.-sinb*sinb);} 257 switch(this.mode){case this.OBLIQ:b=1.+this.sinb1*sinb+this.cosb1*cosb*coslam;break;case this.EQUIT:b=1.+cosb*coslam;break;case this.N_POLE:b=Proj4js.common.HALF_PI+phi;q=this.qp-q;break;case this.S_POLE:b=phi-Proj4js.common.HALF_PI;q=this.qp+q;break;} 258 if(Math.abs(b)<Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:b < eps");return null;} 259 switch(this.mode){case this.OBLIQ:case this.EQUIT:b=Math.sqrt(2./b);if(this.mode==this.OBLIQ){y=this.ymf*b*(this.cosb1*sinb-this.sinb1*cosb*coslam);}else{y=(b=Math.sqrt(2./(1.+cosb*coslam)))*sinb*this.ymf;} 260 x=this.xmf*b*cosb*sinlam;break;case this.N_POLE:case this.S_POLE:if(q>=0.){x=(b=Math.sqrt(q))*sinlam;y=coslam*((this.mode==this.S_POLE)?b:-b);}else{x=y=0.;} 261 break;}} 262 p.x=this.a*x+this.x0;p.y=this.a*y+this.y0;return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var x=p.x/this.a;var y=p.y/this.a;if(this.sphere){var cosz=0.0,rh,sinz=0.0;rh=Math.sqrt(x*x+y*y);var phi=rh*.5;if(phi>1.){Proj4js.reportError("laea:Inv:DataError");return null;} 263 phi=2.*Math.asin(phi);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){sinz=Math.sin(phi);cosz=Math.cos(phi);} 264 switch(this.mode){case this.EQUIT:phi=(Math.abs(rh)<=Proj4js.common.EPSLN)?0.:Math.asin(y*sinz/rh);x*=sinz;y=cosz*rh;break;case this.OBLIQ:phi=(Math.abs(rh)<=Proj4js.common.EPSLN)?this.phi0:Math.asin(cosz*sinph0+y*sinz*cosph0/rh);x*=sinz*cosph0;y=(cosz-Math.sin(phi)*sinph0)*rh;break;case this.N_POLE:y=-y;phi=Proj4js.common.HALF_PI-phi;break;case this.S_POLE:phi-=Proj4js.common.HALF_PI;break;} 265 lam=(y==0.&&(this.mode==this.EQUIT||this.mode==this.OBLIQ))?0.:Math.atan2(x,y);}else{var cCe,sCe,q,rho,ab=0.0;switch(this.mode){case this.EQUIT:case this.OBLIQ:x/=this.dd;y*=this.dd;rho=Math.sqrt(x*x+y*y);if(rho<Proj4js.common.EPSLN){p.x=0.;p.y=this.phi0;return p;} 266 sCe=2.*Math.asin(.5*rho/this.rq);cCe=Math.cos(sCe);x*=(sCe=Math.sin(sCe));if(this.mode==this.OBLIQ){ab=cCe*this.sinb1+y*sCe*this.cosb1/rho 267 q=this.qp*ab;y=rho*this.cosb1*cCe-y*this.sinb1*sCe;}else{ab=y*sCe/rho;q=this.qp*ab;y=rho*cCe;} 268 break;case this.N_POLE:y=-y;case this.S_POLE:q=(x*x+y*y);if(!q){p.x=0.;p.y=this.phi0;return p;} 269 ab=1.-q/this.qp;if(this.mode==this.S_POLE){ab=-ab;} 270 break;} 271 lam=Math.atan2(x,y);phi=this.authlat(Math.asin(ab),this.apa);} 272 p.x=Proj4js.common.adjust_lon(this.long0+lam);p.y=phi;return p;},P00:.33333333333333333333,P01:.17222222222222222222,P02:.10257936507936507936,P10:.06388888888888888888,P11:.06640211640211640211,P20:.01641501294219154443,authset:function(es){var t;var APA=new Array();APA[0]=es*this.P00;t=es*es;APA[0]+=t*this.P01;APA[1]=t*this.P10;t*=es;APA[0]+=t*this.P02;APA[1]+=t*this.P11;APA[2]=t*this.P20;return APA;},authlat:function(beta,APA){var t=beta+beta;return(beta+APA[0]*Math.sin(t)+APA[1]*Math.sin(t+t)+APA[2]*Math.sin(t+t+t));}};Proj4js.Proj.aeqd={init:function(){this.sin_p12=Math.sin(this.lat0);this.cos_p12=Math.cos(this.lat0);},forward:function(p){var lon=p.x;var lat=p.y;var ksp;var sinphi=Math.sin(p.y);var cosphi=Math.cos(p.y);var dlon=Proj4js.common.adjust_lon(lon-this.long0);var coslon=Math.cos(dlon);var g=this.sin_p12*sinphi+this.cos_p12*cosphi*coslon;if(Math.abs(Math.abs(g)-1.0)<Proj4js.common.EPSLN){ksp=1.0;if(g<0.0){Proj4js.reportError("aeqd:Fwd:PointError");return;}}else{var z=Math.acos(g);ksp=z/Math.sin(z);} 273 p.x=this.x0+this.a*ksp*cosphi*Math.sin(dlon);p.y=this.y0+this.a*ksp*(this.cos_p12*sinphi-this.sin_p12*cosphi*coslon);return p;},inverse:function(p){p.x-=this.x0;p.y-=this.y0;var rh=Math.sqrt(p.x*p.x+p.y*p.y);if(rh>(2.0*Proj4js.common.HALF_PI*this.a)){Proj4js.reportError("aeqdInvDataError");return;} 274 var z=rh/this.a;var sinz=Math.sin(z);var cosz=Math.cos(z);var lon=this.long0;var lat;if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.lat0;}else{lat=Proj4js.common.asinz(cosz*this.sin_p12+(p.y*sinz*this.cos_p12)/rh);var con=Math.abs(this.lat0)-Proj4js.common.HALF_PI;if(Math.abs(con)<=Proj4js.common.EPSLN){if(lat0>=0.0){lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x,-p.y));}else{lon=Proj4js.common.adjust_lon(this.long0-Math.atan2(-p.x,p.y));}}else{con=cosz-this.sin_p12*Math.sin(lat);if((Math.abs(con)<Proj4js.common.EPSLN)&&(Math.abs(p.x)<Proj4js.common.EPSLN)){}else{var temp=Math.atan2((p.x*sinz*this.cos_p12),(con*rh));lon=Proj4js.common.adjust_lon(this.long0+Math.atan2((p.x*sinz*this.cos_p12),(con*rh)));}}} 275 p.x=lon;p.y=lat;return p;}};Proj4js.Proj.moll={init:function(){},forward:function(p){var lon=p.x;var lat=p.y;var delta_lon=Proj4js.common.adjust_lon(lon-this.long0);var theta=lat;var con=Proj4js.common.PI*Math.sin(lat);for(var i=0;true;i++){var delta_theta=-(theta+Math.sin(theta)-con)/(1.0+Math.cos(theta));theta+=delta_theta;if(Math.abs(delta_theta)<Proj4js.common.EPSLN)break;if(i>=50){Proj4js.reportError("moll:Fwd:IterationError");}} 276 theta/=2.0;if(Proj4js.common.PI/2-Math.abs(lat)<Proj4js.common.EPSLN)delta_lon=0;var x=0.900316316158*this.a*delta_lon*Math.cos(theta)+this.x0;var y=1.4142135623731*this.a*Math.sin(theta)+this.y0;p.x=x;p.y=y;return p;},inverse:function(p){var theta;var arg;p.x-=this.x0;var arg=p.y/(1.4142135623731*this.a);if(Math.abs(arg)>0.999999999999)arg=0.999999999999;var theta=Math.asin(arg);var lon=Proj4js.common.adjust_lon(this.long0+(p.x/(0.900316316158*this.a*Math.cos(theta))));if(lon<(-Proj4js.common.PI))lon=-Proj4js.common.PI;if(lon>Proj4js.common.PI)lon=Proj4js.common.PI;arg=(2.0*theta+Math.sin(2.0*theta))/Proj4js.common.PI;if(Math.abs(arg)>1.0)arg=1.0;var lat=Math.asin(arg);p.x=lon;p.y=lat;return p;}};
Note: See TracChangeset
for help on using the changeset viewer.