/** * Author : René-Luc D'Hont * * Copyright 2010 3liz SARL. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ ZOO = { SERVICE_ACCEPTED: 0, SERVICE_STARTED: 1, SERVICE_PAUSED: 2, SERVICE_SUCCEEDED: 3, SERVICE_FAILED: 4, removeItem: function(array, item) { for(var i = array.length - 1; i >= 0; i--) { if(array[i] == item) { array.splice(i,1); } } return array; }, indexOf: function(array, obj) { for(var i=0, len=array.length; i 0) { var separator = (url.indexOf('?') > -1) ? '&' : '?'; url += separator + paramString; } return ZOORequest('GET',url); }, Post: function(url,body,headers) { if(!(headers instanceof Array)) { var headersArray = []; for (var hname in headers) { headersArray.push(name+': '+headers[name]); } headers = headersArray; } return ZOORequest('POST',url,body,headers); } }; ZOO.Bounds = ZOO.Class({ left: null, bottom: null, right: null, top: null, initialize: function(left, bottom, right, top) { if (left != null) this.left = parseFloat(left); if (bottom != null) this.bottom = parseFloat(bottom); if (right != null) this.right = parseFloat(right); if (top != null) this.top = parseFloat(top); }, clone:function() { return new ZOO.Bounds(this.left, this.bottom, this.right, this.top); }, equals:function(bounds) { var equals = false; if (bounds != null) equals = ((this.left == bounds.left) && (this.right == bounds.right) && (this.top == bounds.top) && (this.bottom == bounds.bottom)); return equals; }, toString:function() { return ( "left-bottom=(" + this.left + "," + this.bottom + ")" + " right-top=(" + this.right + "," + this.top + ")" ); }, toArray: function() { return [this.left, this.bottom, this.right, this.top]; }, toBBOX:function(decimal) { if (decimal== null) decimal = 6; var mult = Math.pow(10, decimal); var bbox = Math.round(this.left * mult) / mult + "," + Math.round(this.bottom * mult) / mult + "," + Math.round(this.right * mult) / mult + "," + Math.round(this.top * mult) / mult; return bbox; }, toGeometry: function() { return new ZOO.Geometry.Polygon([ new ZOO.Geometry.LinearRing([ new ZOO.Geometry.Point(this.left, this.bottom), new ZOO.Geometry.Point(this.right, this.bottom), new ZOO.Geometry.Point(this.right, this.top), new ZOO.Geometry.Point(this.left, this.top) ]) ]); }, getWidth:function() { return (this.right - this.left); }, getHeight:function() { return (this.top - this.bottom); }, add:function(x, y) { if ( (x == null) || (y == null) ) return null; return new ZOO.Bounds(this.left + x, this.bottom + y, this.right + x, this.top + y); }, extend:function(object) { var bounds = null; if (object) { // clear cached center location switch(object.CLASS_NAME) { case "ZOO.Geometry.Point": bounds = new ZOO.Bounds(object.x, object.y, object.x, object.y); break; case "ZOO.Bounds": bounds = object; break; } if (bounds) { if ( (this.left == null) || (bounds.left < this.left)) this.left = bounds.left; if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) this.bottom = bounds.bottom; if ( (this.right == null) || (bounds.right > this.right) ) this.right = bounds.right; if ( (this.top == null) || (bounds.top > this.top) ) this.top = bounds.top; } } }, contains:function(x, y, inclusive) { //set default if (inclusive == null) inclusive = true; if (x == null || y == null) return false; x = parseFloat(x); y = parseFloat(y); var contains = false; if (inclusive) contains = ((x >= this.left) && (x <= this.right) && (y >= this.bottom) && (y <= this.top)); else contains = ((x > this.left) && (x < this.right) && (y > this.bottom) && (y < this.top)); return contains; }, intersectsBounds:function(bounds, inclusive) { if (inclusive == null) inclusive = true; var intersects = false; var mightTouch = ( this.left == bounds.right || this.right == bounds.left || this.top == bounds.bottom || this.bottom == bounds.top ); if (inclusive || !mightTouch) { var inBottom = ( ((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) || ((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top)) ); var inTop = ( ((bounds.top >= this.bottom) && (bounds.top <= this.top)) || ((this.top > bounds.bottom) && (this.top < bounds.top)) ); var inLeft = ( ((bounds.left >= this.left) && (bounds.left <= this.right)) || ((this.left >= bounds.left) && (this.left <= bounds.right)) ); var inRight = ( ((bounds.right >= this.left) && (bounds.right <= this.right)) || ((this.right >= bounds.left) && (this.right <= bounds.right)) ); intersects = ((inBottom || inTop) && (inLeft || inRight)); } return intersects; }, containsBounds:function(bounds, partial, inclusive) { if (partial == null) partial = false; if (inclusive == null) inclusive = true; var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive); var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive); var topLeft = this.contains(bounds.left, bounds.top, inclusive); var topRight = this.contains(bounds.right, bounds.top, inclusive); return (partial) ? (bottomLeft || bottomRight || topLeft || topRight) : (bottomLeft && bottomRight && topLeft && topRight); }, CLASS_NAME: 'ZOO.Bounds' }); ZOO.Projection = ZOO.Class({ proj: null, projCode: null, initialize: function(projCode, options) { ZOO.extend(this, options); this.projCode = projCode; if (Proj4js) { this.proj = new Proj4js.Proj(projCode); } }, getCode: function() { return this.proj ? this.proj.srsCode : this.projCode; }, getUnits: function() { return this.proj ? this.proj.units : null; }, toString: function() { return this.getCode(); }, equals: function(projection) { if (projection && projection.getCode) return this.getCode() == projection.getCode(); else return false; }, destroy: function() { this.proj = null; this.projCode = null; }, CLASS_NAME: 'ZOO.Projection' }); ZOO.Projection.transform = function(point, source, dest) { if (source.proj && dest.proj) point = Proj4js.transform(source.proj, dest.proj, point); return point; }; ZOO.Format = ZOO.Class({ options:null, externalProjection: null, internalProjection: null, data: null, keepData: false, initialize: function(options) { ZOO.extend(this, options); this.options = options; }, destroy: function() { }, read: function(data) { }, write: function(data) { }, CLASS_NAME: 'ZOO.Format' }); ZOO.Format.WKT = ZOO.Class(ZOO.Format, { initialize: function(options) { this.regExes = { 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/, 'spaces': /\s+/, 'parenComma': /\)\s*,\s*\(/, 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here 'trimParens': /^\s*\(?(.*?)\)?\s*$/ }; ZOO.Format.prototype.initialize.apply(this, [options]); }, read: function(wkt) { var features, type, str; var matches = this.regExes.typeStr.exec(wkt); if(matches) { type = matches[1].toLowerCase(); str = matches[2]; if(this.parse[type]) { features = this.parse[type].apply(this, [str]); } if (this.internalProjection && this.externalProjection) { if (features && features.CLASS_NAME == "ZOO.Feature") { features.geometry.transform(this.externalProjection, this.internalProjection); } else if (features && type != "geometrycollection" && typeof features == "object") { for (var i=0, len=features.length; i0) pieces.push(','); geometry = collection[i].geometry; type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); if(!this.extract[type]) return null; if (this.internalProjection && this.externalProjection) { geometry = geometry.clone(); geometry.transform(this.internalProjection, this.externalProjection); } data = this.extract[type].apply(this, [geometry]); pieces.push(type.toUpperCase() + '(' + data + ')'); } if(isCollection) pieces.push(')'); return pieces.join(''); }, extract: { 'point': function(point) { return point.x + ' ' + point.y; }, 'multipoint': function(multipoint) { var array = []; for(var i=0, len=multipoint.components.length; i 0) pieces.push(','); pieces.push(this.writeNewline(), this.writeIndent(), json); } } this.level -= 1; pieces.push(this.writeNewline(), this.writeIndent(), ']'); return pieces.join(''); }, 'string': function(string) { var m = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }; if(/["\\\x00-\x1f]/.test(string)) { return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) { var c = m[b]; if(c) return c; c = b.charCodeAt(); return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16); }) + '"'; } return '"' + string + '"'; }, 'number': function(number) { return isFinite(number) ? String(number) : "null"; }, 'boolean': function(bool) { return String(bool); }, 'date': function(date) { function format(number) { // Format integers to have at least two digits. return (number < 10) ? '0' + number : number; } return '"' + date.getFullYear() + '-' + format(date.getMonth() + 1) + '-' + format(date.getDate()) + 'T' + format(date.getHours()) + ':' + format(date.getMinutes()) + ':' + format(date.getSeconds()) + '"'; } }, CLASS_NAME: 'ZOO.Format.JSON' }); ZOO.Format.GeoJSON = ZOO.Class(ZOO.Format.JSON, { initialize: function(options) { ZOO.Format.JSON.prototype.initialize.apply(this, [options]); }, read: function(json, type, filter) { type = (type) ? type : "FeatureCollection"; var results = null; var obj = null; if (typeof json == "string") obj = ZOO.Format.JSON.prototype.read.apply(this,[json, filter]); else obj = json; if(!obj) { //OpenLayers.Console.error("Bad JSON: " + json); } else if(typeof(obj.type) != "string") { //OpenLayers.Console.error("Bad GeoJSON - no type: " + json); } else if(this.isValidType(obj, type)) { switch(type) { case "Geometry": try { results = this.parseGeometry(obj); } catch(err) { //OpenLayers.Console.error(err); } break; case "Feature": try { results = this.parseFeature(obj); results.type = "Feature"; } catch(err) { //OpenLayers.Console.error(err); } break; case "FeatureCollection": // for type FeatureCollection, we allow input to be any type results = []; switch(obj.type) { case "Feature": try { results.push(this.parseFeature(obj)); } catch(err) { results = null; //OpenLayers.Console.error(err); } break; case "FeatureCollection": for(var i=0, len=obj.features.length; i/, ""); data = new XML(data); var placemarks = data..*::Placemark; this.parseFeatures(placemarks); return this.features; }, parseFeatures: function(nodes) { var features = new Array(nodes.length()); for(var i=0, len=nodes.length(); i 0) { var parser = this.parseGeometry[type.toLowerCase()]; if(parser) { geometry = parser.apply(this, [nodeList[0]]); if (this.internalProjection && this.externalProjection) { geometry.transform(this.externalProjection, this.internalProjection); } } break; } } var attributes; if(this.extractAttributes) { attributes = this.parseAttributes(node); } var feature = new ZOO.Feature(geometry, attributes); var fid = node.@id || node.@name; if(fid != null) feature.fid = fid; return feature; }, parseGeometry: { 'point': function(node) { var coordString = node.*::coordinates.toString(); coordString = coordString.replace(this.regExes.removeSpace, ""); coords = coordString.split(","); var point = null; if(coords.length > 1) { // preserve third dimension if(coords.length == 2) { coords[2] = null; } point = new ZOO.Geometry.Point(coords[0], coords[1], coords[2]); } return point; }, 'linestring': function(node, ring) { var line = null; var coordString = node.*::coordinates.toString(); coordString = coordString.replace(this.regExes.trimSpace, ""); coordString = coordString.replace(this.regExes.trimComma, ","); var pointList = coordString.split(this.regExes.splitSpace); var numPoints = pointList.length; var points = new Array(numPoints); var coords, numCoords; for(var i=0; i 1) { if(coords.length == 2) { coords[2] = null; } points[i] = new ZOO.Geometry.Point(coords[0], coords[1], coords[2]); } } if(numPoints) { if(ring) { line = new ZOO.Geometry.LinearRing(points); } else { line = new ZOO.Geometry.LineString(points); } } else { throw "Bad LineString coordinates: " + coordString; } return line; }, 'polygon': function(node) { var nodeList = node..*::LinearRing; var numRings = nodeList.length(); var components = new Array(numRings); if(numRings > 0) { // this assumes exterior ring first, inner rings after var ring; for(var i=0, len=nodeList.length(); i 0) { attributes = this.parseExtendedData(edNodes[0]) } var child, grandchildren; var children = node.*::*; for(var i=0, len=children.length(); i 0) ed['value'] = valueNode[0].toString(); var nameNode = data.*::displayName; if (nameNode.length() > 0) ed['displayName'] = valueNode[0].toString(); attributes[key] = ed; } return attributes; }, write: function(features) { if(!(features instanceof Array)) features = [features]; var kml = new XML(''); var folder = kml.Document.Folder; folder.name = this.foldersName; folder.description = this.foldersDesc; for(var i=0, len=features.length; i'); placemark.name = (feature.attributes.name) ? feature.attributes.name : feature.id; placemark.description = (feature.attributes.description) ? feature.attributes.description : this.placemarksDesc; if(feature.fid != null) placemark.@id = feature.fid; placemark.*[2] = this.buildGeometryNode(feature.geometry); return placemark; }, buildGeometryNode: function(geometry) { if (this.internalProjection && this.externalProjection) { geometry = geometry.clone(); geometry.transform(this.internalProjection, this.externalProjection); } var className = geometry.CLASS_NAME; var type = className.substring(className.lastIndexOf(".") + 1); var builder = this.buildGeometry[type.toLowerCase()]; var node = null; if(builder) { node = builder.apply(this, [geometry]); } return node; }, buildGeometry: { 'point': function(geometry) { var kml = new XML(''); kml.coordinates = this.buildCoordinatesNode(geometry); return kml; }, 'multipoint': function(geometry) { return this.buildGeometry.collection.apply(this, [geometry]); }, 'linestring': function(geometry) { var kml = new XML(''); kml.coordinates = this.buildCoordinatesNode(geometry); return kml; }, 'multilinestring': function(geometry) { return this.buildGeometry.collection.apply(this, [geometry]); }, 'linearring': function(geometry) { var kml = new XML(''); kml.coordinates = this.buildCoordinatesNode(geometry); return kml; }, 'polygon': function(geometry) { var kml = new XML(''); var rings = geometry.components; var ringMember, ringGeom, type; for(var i=0, len=rings.length; i'); ringMember.LinearRing = this.buildGeometry.linearring.apply(this,[rings[i]]); kml.*[i] = ringMember; } return kml; }, 'multipolygon': function(geometry) { return this.buildGeometry.collection.apply(this, [geometry]); }, 'collection': function(geometry) { var kml = new XML(''); var child; for(var i=0, len=geometry.components.length; i'); var points = geometry.components; if(points) { // LineString or LinearRing var point; var numPoints = points.length; var parts = new Array(numPoints); for(var i=0; i/, ""); data = new XML(data); var gmlns = Namespace(this.namespaces['gml']); var featureNodes = data..gmlns::featureMember; var features = []; for(var i=0,len=featureNodes.length(); i 0) { var parser = this.parseGeometry[type.toLowerCase()]; if(parser) { geometry = parser.apply(this, [nodeList[0]]); if (this.internalProjection && this.externalProjection) { geometry.transform(this.externalProjection, this.internalProjection); } } break; } } var attributes; if(this.extractAttributes) { //attributes = this.parseAttributes(node); } var feature = new ZOO.Feature(geometry, attributes); return feature; }, parseGeometry: { 'point': function(node) { /** * Three coordinate variations to consider: * 1) x y z * 2) x, y, z * 3) xy */ var nodeList, coordString; var coords = []; // look for var nodeList = node..*::pos; if(nodeList.length() > 0) { coordString = nodeList[0].toString(); coordString = coordString.replace(this.regExes.trimSpace, ""); coords = coordString.split(this.regExes.splitSpace); } // look for if(coords.length == 0) { nodeList = node..*::coordinates; if(nodeList.length() > 0) { coordString = nodeList[0].toString(); coordString = coordString.replace(this.regExes.removeSpace,""); coords = coordString.split(","); } } // look for if(coords.length == 0) { nodeList = node..*::coord; if(nodeList.length() > 0) { var xList = nodeList[0].*::X; var yList = nodeList[0].*::Y; if(xList.length() > 0 && yList.length() > 0) coords = [xList[0].toString(), yList[0].toString()]; } } // preserve third dimension if(coords.length == 2) coords[2] = null; if (this.xy) return new ZOO.Geometry.Point(coords[0],coords[1],coords[2]); else return new ZOO.Geometry.Point(coords[1],coords[0],coords[2]); }, 'multipoint': function(node) { var nodeList = node..*::Point; var components = []; if(nodeList.length() > 0) { var point; for(var i=0, len=nodeList.length(); ix0 y0 z0 x1 y1 z1 * 2) x0, y0, z0 x1, y1, z1 */ var nodeList, coordString; var coords = []; var points = []; // look for nodeList = node..*::posList; if(nodeList.length() > 0) { coordString = nodeList[0].toString(); coordString = coordString.replace(this.regExes.trimSpace, ""); coords = coordString.split(this.regExes.splitSpace); var dim = parseInt(nodeList[0].@dimension); var j, x, y, z; for(var i=0; i if(coords.length == 0) { nodeList = node..*::coordinates; if(nodeList.length() > 0) { coordString = nodeList[0].toString(); coordString = coordString.replace(this.regExes.trimSpace,""); coordString = coordString.replace(this.regExes.trimComma,","); var pointList = coordString.split(this.regExes.splitSpace); for(var i=0; i 0) { var line; for(var i=0, len=nodeList.length(); i 0) { // this assumes exterior ring first, inner rings after var ring; for(var i=0, len = nodeList.length(); i 0) { var polygon; for(var i=0, len=nodeList.length(); i 0) { var coords = []; if(lpoint.length() > 0) { coordString = lpoint[0].toString(); coordString = coordString.replace(this.regExes.trimSpace, ""); coords = coordString.split(this.regExes.splitSpace); } if(coords.length == 2) coords[2] = null; if (this.xy) var lowerPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]); else var lowerPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]); } var upoint = node..*::upperCorner; if (upoint.length() > 0) { var coords = []; if(upoint.length > 0) { coordString = upoint[0].toString(); coordString = coordString.replace(this.regExes.trimSpace, ""); coords = coordString.split(this.regExes.splitSpace); } if(coords.length == 2) coords[2] = null; if (this.xy) var upperPoint = new ZOO.Geometry.Point(coords[0], coords[1],coords[2]); else var upperPoint = new ZOO.Geometry.Point(coords[1], coords[0],coords[2]); } if (lowerPoint && upperPoint) { components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y)); components.push(new ZOO.Geometry.Point(upperPoint.x, lowerPoint.y)); components.push(new ZOO.Geometry.Point(upperPoint.x, upperPoint.y)); components.push(new ZOO.Geometry.Point(lowerPoint.x, upperPoint.y)); components.push(new ZOO.Geometry.Point(lowerPoint.x, lowerPoint.y)); var ring = new ZOO.Geometry.LinearRing(components); envelope = new ZOO.Geometry.Polygon([ring]); } return envelope; } }, write: function(features) { if(!(features instanceof Array)) { features = [features]; } var pfx = this.defaultPrefix; var name = pfx+':'+this.collectionName; var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" xmlns:gml="'+this.namespaces['gml']+'" xmlns:xsi="'+this.namespaces['xsi']+'" xsi:schemaLocation="'+this.schemaLocation+'">'); for(var i=0; i<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'" fid="'+fid+'">'); var geometry = feature.geometry; gml.*::*[0].*::* = this.buildGeometryNode(geometry); for(var attr in feature.attributes) { var attrNode = new XML('<'+pfx+':'+attr+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'">'+feature.attributes[attr]+''); gml.*::*[0].appendChild(attrNode); } return gml; }, buildGeometryNode: function(geometry) { if (this.externalProjection && this.internalProjection) { geometry = geometry.clone(); geometry.transform(this.internalProjection, this.externalProjection); } var className = geometry.CLASS_NAME; var type = className.substring(className.lastIndexOf(".") + 1); var builder = this.buildGeometry[type.toLowerCase()]; var pfx = this.defaultPrefix; var name = pfx+':'+this.geometryName; var gml = new XML('<'+name+' xmlns:'+pfx+'="'+this.namespaces[pfx]+'">'); if (builder) gml.*::* = builder.apply(this, [geometry]); return gml; }, buildGeometry: { 'point': function(geometry) { var gml = new XML(''); gml.*::*[0] = this.buildCoordinatesNode(geometry); return gml; }, 'multipoint': function(geometry) { var gml = new XML(''); var points = geometry.components; var pointMember; for(var i=0; i'); pointMember.*::* = this.buildGeometry.point.apply(this,[points[i]]); gml.*::*[i] = pointMember; } return gml; }, 'linestring': function(geometry) { var gml = new XML(''); gml.*::*[0] = this.buildCoordinatesNode(geometry); return gml; }, 'multilinestring': function(geometry) { var gml = new XML(''); var lines = geometry.components; var lineMember; for(var i=0; i'); lineMember.*::* = this.buildGeometry.linestring.apply(this,[lines[i]]); gml.*::*[i] = lineMember; } return gml; }, 'linearring': function(geometry) { var gml = new XML(''); gml.*::*[0] = this.buildCoordinatesNode(geometry); return gml; }, 'polygon': function(geometry) { var gml = new XML(''); var rings = geometry.components; var ringMember, type; for(var i=0; i'); ringMember.*::* = this.buildGeometry.linearring.apply(this,[rings[i]]); gml.*::*[i] = ringMember; } return gml; }, 'multipolygon': function(geometry) { var gml = new XML(''); var polys = geometry.components; var polyMember; for(var i=0; i'); polyMember.*::* = this.buildGeometry.polygon.apply(this,[polys[i]]); gml.*::*[i] = polyMember; } return gml; }, 'bounds': function(bounds) { var gml = new XML(''); gml.*::*[0] = this.buildCoordinatesNode(bounds); return gml; } }, buildCoordinatesNode: function(geometry) { var parts = []; if(geometry instanceof ZOO.Bounds){ parts.push(geometry.left + "," + geometry.bottom); parts.push(geometry.right + "," + geometry.top); } else { var points = (geometry.components) ? geometry.components : [geometry]; for(var i=0; i'+parts.join(" ")+''); }, CLASS_NAME: 'ZOO.Format.GML' }); ZOO.Format.WPS = ZOO.Class(ZOO.Format, { schemaLocation: "http://www.opengis.net/wps/1.0.0/../wpsExecute_request.xsd", namespaces: { ows: "http://www.opengis.net/ows/1.1", wps: "http://www.opengis.net/wps/1.0.0", xlink: "http://www.w3.org/1999/xlink", xsi: "http://www.w3.org/2001/XMLSchema-instance", }, read:function(data) { data = data.replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>/, ""); data = new XML(data); switch (data.localName()) { case 'ExecuteResponse': return this.parseExecuteResponse(data); default: return null; } }, parseExecuteResponse: function(node) { var outputs = node.*::ProcessOutputs.*::Output; if (outputs.length() > 0) { var data = outputs[0].*::Data.*::*[0]; var builder = this.parseData[data.localName().toLowerCase()]; if (builder) return builder.apply(this,[data]); else return null; } else return null; }, parseData: { 'complexdata': function(node) { var result = {value:node.toString()}; if (node.@mimeType.length()>0) result.mimeType = node.@mimeType; if (node.@encoding.length()>0) result.encoding = node.@encoding; if (node.@schema.length()>0) result.schema = node.@schema; return result; }, 'literaldata': function(node) { var result = {value:node.toString()}; if (node.@dataType.length()>0) result.dataType = node.@dataType; if (node.@uom.length()>0) result.uom = node.@uom; return result; } }, CLASS_NAME: 'ZOO.Format.WPS' }); ZOO.Feature = ZOO.Class({ fid: null, geometry: null, attributes: null, bounds: null, initialize: function(geometry, attributes) { this.geometry = geometry ? geometry : null; this.attributes = {}; if (attributes) this.attributes = ZOO.extend(this.attributes,attributes); }, destroy: function() { this.geometry = null; }, clone: function () { return new ZOO.Feature(this.geometry ? this.geometry.clone() : null, this.attributes); }, move: function(x, y) { if(!this.geometry.move) return; this.geometry.move(x,y); return this.geometry; }, CLASS_NAME: 'ZOO.Feature' }); ZOO.Geometry = ZOO.Class({ id: null, parent: null, bounds: null, initialize: function() { //generate unique id }, destroy: function() { this.id = null; this.bounds = null; }, clone: function() { return new ZOO.Geometry(); }, extendBounds: function(newBounds){ var bounds = this.getBounds(); if (!bounds) this.setBounds(newBounds); else this.bounds.extend(newBounds); }, setBounds: function(bounds) { if (bounds) this.bounds = bounds.clone(); }, clearBounds: function() { this.bounds = null; if (this.parent) this.parent.clearBounds(); }, getBounds: function() { if (this.bounds == null) { this.calculateBounds(); } return this.bounds; }, calculateBounds: function() { return this.bounds = null; }, distanceTo: function(geometry, options) { }, getVertices: function(nodes) { }, getLength: function() { return 0.0; }, getArea: function() { return 0.0; }, getCentroid: function() { return null; }, toString: function() { return ZOO.Format.WKT.prototype.write( new ZOO.Feature(this) ); }, CLASS_NAME: 'ZOO.Geometry' }); ZOO.Geometry.fromWKT = function(wkt) { var format = arguments.callee.format; if(!format) { format = new ZOO.Format.WKT(); arguments.callee.format = format; } var geom; var result = format.read(wkt); if(result instanceof ZOO.Feature) { geom = result.geometry; } else if(result instanceof Array) { var len = result.length; var components = new Array(len); for(var i=0; i= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) { // intersect if(!point) { intersection = true; } else { // calculate the intersection point var x = seg1.x1 + (along1 * x12_11); var y = seg1.y1 + (along1 * y12_11); intersection = new ZOO.Geometry.Point(x, y); } } } if(tolerance) { var dist; if(intersection) { if(point) { var segs = [seg1, seg2]; var seg, x, y; // check segment endpoints for proximity to intersection // set intersection to first endpoint within the tolerance outer: for(var i=0; i<2; ++i) { seg = segs[i]; for(var j=1; j<3; ++j) { x = seg["x" + j]; y = seg["y" + j]; dist = Math.sqrt( Math.pow(x - intersection.x, 2) + Math.pow(y - intersection.y, 2) ); if(dist < tolerance) { intersection.x = x; intersection.y = y; break outer; } } } } } else { // no calculated intersection, but segments could be within // the tolerance of one another var segs = [seg1, seg2]; var source, target, x, y, p, result; // check segment endpoints for proximity to intersection // set intersection to first endpoint within the tolerance outer: for(var i=0; i<2; ++i) { source = segs[i]; target = segs[(i+1)%2]; for(var j=1; j<3; ++j) { p = {x: source["x"+j], y: source["y"+j]}; result = ZOO.Geometry.distanceToSegment(p, target); if(result.distance < tolerance) { if(point) { intersection = new ZOO.Geometry.Point(p.x, p.y); } else { intersection = true; } break outer; } } } } } return intersection; }; ZOO.Geometry.distanceToSegment = function(point, segment) { var x0 = point.x; var y0 = point.y; var x1 = segment.x1; var y1 = segment.y1; var x2 = segment.x2; var y2 = segment.y2; var dx = x2 - x1; var dy = y2 - y1; var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / (Math.pow(dx, 2) + Math.pow(dy, 2)); var x, y; if(along <= 0.0) { x = x1; y = y1; } else if(along >= 1.0) { x = x2; y = y2; } else { x = x1 + along * dx; y = y1 + along * dy; } return { distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)), x: x, y: y }; }; ZOO.Geometry.Collection = ZOO.Class(ZOO.Geometry, { components: null, componentTypes: null, initialize: function (components) { ZOO.Geometry.prototype.initialize.apply(this, arguments); this.components = []; if (components != null) { this.addComponents(components); } }, destroy: function () { this.components.length = 0; this.components = null; }, clone: function() { var geometry = eval("new " + this.CLASS_NAME + "()"); for(var i=0, len=this.components.length; i 0) { this.setBounds(this.components[0].getBounds()); for (var i=1, len=this.components.length; i -1)) { if(index != null && (index < this.components.length)) { var components1 = this.components.slice(0, index); var components2 = this.components.slice(index, this.components.length); components1.push(component); this.components = components1.concat(components2); } else { this.components.push(component); } component.parent = this; this.clearBounds(); added = true; } } return added; }, removeComponents: function(components) { if(!(components instanceof Array)) components = [components]; for(var i=components.length-1; i>=0; --i) { this.removeComponent(components[i]); } }, removeComponent: function(component) { ZOO.removeItem(this.components, component); // clearBounds() so that it gets recalculated on the next call // to this.getBounds(); this.clearBounds(); }, getLength: function() { var length = 0.0; for (var i=0, len=this.components.length; i 1)) { for(var i=1, len=this.components.length; i 2)) ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments); }, intersects: function(geometry) { var intersect = false; var type = geometry.CLASS_NAME; if(type == "ZOO.Geometry.LineString" || type == "ZOO.Geometry.LinearRing" || type == "ZOO.Geometry.Point") { var segs1 = this.getSortedSegments(); var segs2; if(type == "ZOO.Geometry.Point") segs2 = [{ x1: geometry.x, y1: geometry.y, x2: geometry.x, y2: geometry.y }]; else segs2 = geometry.getSortedSegments(); var seg1, seg1x1, seg1x2, seg1y1, seg1y2, seg2, seg2y1, seg2y2; // sweep right outer: for(var i=0, len=segs1.length; i seg1x2) break; if(seg2.x2 < seg1x1) continue; seg2y1 = seg2.y1; seg2y2 = seg2.y2; if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) continue; if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) continue; if(ZOO.Geometry.segmentsIntersect(seg1, seg2)) { intersect = true; break outer; } } } } else { intersect = geometry.intersects(this); } return intersect; }, getSortedSegments: function() { var numSeg = this.components.length - 1; var segments = new Array(numSeg); for(var i=0; i 0) { // sort intersections along segment var xDir = seg.x1 < seg.x2 ? 1 : -1; var yDir = seg.y1 < seg.y2 ? 1 : -1; result = { lines: lines, points: intersections.sort(function(p1, p2) { return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y); }) }; } return result; }, split: function(target, options) { var results = null; var mutual = options && options.mutual; var sourceSplit, targetSplit, sourceParts, targetParts; if(target instanceof ZOO.Geometry.LineString) { var verts = this.getVertices(); var vert1, vert2, seg, splits, lines, point; var points = []; sourceParts = []; for(var i=0, stop=verts.length-2; i<=stop; ++i) { vert1 = verts[i]; vert2 = verts[i+1]; seg = { x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y }; targetParts = targetParts || [target]; if(mutual) points.push(vert1.clone()); for(var j=0; j 0) { lines.unshift(j, 1); Array.prototype.splice.apply(targetParts, lines); j += lines.length - 2; } if(mutual) { for(var k=0, len=splits.points.length; k 0 && points.length > 0) { points.push(vert2.clone()); sourceParts.push(new ZOO.Geometry.LineString(points)); } } else { results = target.splitWith(this, options); } if(targetParts && targetParts.length > 1) targetSplit = true; else targetParts = []; if(sourceParts && sourceParts.length > 1) sourceSplit = true; else sourceParts = []; if(targetSplit || sourceSplit) { if(mutual) results = [sourceParts, targetParts]; else results = targetParts; } return results; }, splitWith: function(geometry, options) { return geometry.split(this, options); }, getVertices: function(nodes) { var vertices; if(nodes === true) vertices = [ this.components[0], this.components[this.components.length-1] ]; else if (nodes === false) vertices = this.components.slice(1, this.components.length-1); else vertices = this.components.slice(); return vertices; }, distanceTo: function(geometry, options) { var edge = !(options && options.edge === false); var details = edge && options && options.details; var result, best = {}; var min = Number.POSITIVE_INFINITY; if(geometry instanceof ZOO.Geometry.Point) { var segs = this.getSortedSegments(); var x = geometry.x; var y = geometry.y; var seg; for(var i=0, len=segs.length; i x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) break; } } if(details) best = { distance: best.distance, x0: best.x, y0: best.y, x1: x, y1: y }; else best = best.distance; } else if(geometry instanceof ZOO.Geometry.LineString) { var segs0 = this.getSortedSegments(); var segs1 = geometry.getSortedSegments(); var seg0, seg1, intersection, x0, y0; var len1 = segs1.length; var interOptions = {point: true}; outer: for(var i=0, len=segs0.length; i 4) { //remove last point this.components.pop(); //remove our point ZOO.Geometry.Collection.prototype.removeComponent.apply(this,arguments); //append copy of first point var firstPoint = this.components[0]; ZOO.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]); } }, move: function(x, y) { for(var i = 0, len=this.components.length; i 2)) { var sumX = 0.0; var sumY = 0.0; for (var i = 0; i < this.components.length - 1; i++) { var b = this.components[i]; var c = this.components[i+1]; sumX += (b.x + c.x) * (b.x * c.y - c.x * b.y); sumY += (b.y + c.y) * (b.x * c.y - c.x * b.y); } var area = -1 * this.getArea(); var x = sumX / (6 * area); var y = sumY / (6 * area); } return new ZOO.Geometry.Point(x, y); }, getArea: function() { var area = 0.0; if ( this.components && (this.components.length > 2)) { var sum = 0.0; for (var i=0, len=this.components.length; i= x1 && px <= x2) || // right or vert x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert // point on edge crosses = -1; break; } } // ignore other horizontal edges continue; } cx = approx(getX(py, x1, y1, x2, y2), digs); if(cx == px) { // point on line if(y1 < y2 && (py >= y1 && py <= y2) || // upward y1 > y2 && (py <= y1 && py >= y2)) { // downward // point on edge crosses = -1; break; } } if(cx <= px) { // no crossing to the right continue; } if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { // no crossing continue; } if(y1 < y2 && (py >= y1 && py < y2) || // upward y1 > y2 && (py < y1 && py >= y2)) { // downward ++crosses; } } var contained = (crosses == -1) ? // on edge 1 : // even (out) or odd (in) !!(crosses & 1); return contained; }, intersects: function(geometry) { var intersect = false; if(geometry.CLASS_NAME == "ZOO.Geometry.Point") intersect = this.containsPoint(geometry); else if(geometry.CLASS_NAME == "ZOO.Geometry.LineString") intersect = geometry.intersects(this); else if(geometry.CLASS_NAME == "ZOO.Geometry.LinearRing") intersect = ZOO.Geometry.LineString.prototype.intersects.apply( this, [geometry] ); else for(var i=0, len=geometry.components.length; i 1) sourceSplit = true; else sourceParts = []; if(targetParts && targetParts.length > 1) targetSplit = true; else targetParts = []; if(sourceSplit || targetSplit) { if(mutual) results = [sourceParts, targetParts]; else results = targetParts; } return results; }, splitWith: function(geometry, options) { var results = null; var mutual = options && options.mutual; var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts; if(geometry instanceof ZOO.Geometry.LineString) { targetParts = []; sourceParts = [geometry]; for(var i=0, len=this.components.length; i 1) sourceSplit = true; else sourceParts = []; if(targetParts && targetParts.length > 1) targetSplit = true; else targetParts = []; if(sourceSplit || targetSplit) { if(mutual) results = [sourceParts, targetParts]; else results = targetParts; } return results; }, CLASS_NAME: "ZOO.Geometry.MultiLineString" }); ZOO.Geometry.Polygon = ZOO.Class( ZOO.Geometry.Collection, { componentTypes: ["ZOO.Geometry.LinearRing"], initialize: function(components) { ZOO.Geometry.Collection.prototype.initialize.apply(this,arguments); }, getArea: function() { var area = 0.0; if ( this.components && (this.components.length > 0)) { area += Math.abs(this.components[0].getArea()); for (var i=1, len=this.components.length; i 0) { // check exterior ring - 1 means on edge, boolean otherwise contained = this.components[0].containsPoint(point); if(contained !== 1) { if(contained && numRings > 1) { // check interior rings var hole; for(var i=1; i'+this.identifier+''+this.buildDataInputsNode(inputs)+''); body = body.toXMLString(); var response = ZOO.Request.Post(this.url,body,['Content-Type: text/xml; charset=UTF-8']); return response; }, buildInput: { 'complex': function(identifier,data) { var input = new XML(''+identifier+''+data.value+''); input.*::Data.*::ComplexData.@mimeType = data.mimetype ? data.mimetype : 'text/plain'; if (data.encoding) input.*::Data.*::ComplexData.@encoding = data.encoding; if (data.schema) input.*::Data.*::ComplexData.@schema = data.schema; input = input.toXMLString(); return input; }, 'reference': function(identifier,data) { return ''+identifier+''; }, 'literal': function(identifier,data) { var input = new XML(''+identifier+''+data.value+''); if (data.type) input.*::Data.*::LiteralData.@dataType = data.type; if (data.uom) input.*::Data.*::LiteralData.@uom = data.uom; input = input.toXMLString(); return input; } }, buildDataInputsNode:function(inputs){ var data, builder, inputsArray=[]; for (var attr in inputs) { data = inputs[attr]; if (data.mimetype || data.type == 'complex') builder = this.buildInput['complex']; else if (data.type == 'reference' || data.type == 'url') builder = this.buildInput['reference']; else builder = this.buildInput['literal']; inputsArray.push(builder.apply(this,[attr,data])); } return ''+inputsArray.join('\n')+''; }, CLASS_NAME: "ZOO.Process" });