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