--- a/labs/openlayers/lib/OpenLayers/Format/WKT.js +++ b/labs/openlayers/lib/OpenLayers/Format/WKT.js @@ -1,1 +1,359 @@ - +/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Format.WKT + * Class for reading and writing Well-Known Text. Create a new instance + * with the <OpenLayers.Format.WKT> constructor. + * + * Inherits from: + * - <OpenLayers.Format> + */ +OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, { + + /** + * Constructor: OpenLayers.Format.WKT + * Create a new parser for WKT + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance + * + * Returns: + * {<OpenLayers.Format.WKT>} A new WKT parser. + */ + 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*$/ + }; + OpenLayers.Format.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: read + * Deserialize a WKT string and return a vector feature or an + * array of vector features. Supports WKT for POINT, MULTIPOINT, + * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and + * GEOMETRYCOLLECTION. + * + * Parameters: + * wkt - {String} A WKT string + * + * Returns: + * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for + * GEOMETRYCOLLECTION WKT. + */ + 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 == "OpenLayers.Feature.Vector") { + features.geometry.transform(this.externalProjection, + this.internalProjection); + } else if (features && + type != "geometrycollection" && + typeof features == "object") { + for (var i=0, len=features.length; i<len; i++) { + var component = features[i]; + component.geometry.transform(this.externalProjection, + this.internalProjection); + } + } + } + } + return features; + }, + + /** + * Method: write + * Serialize a feature or array of features into a WKT string. + * + * Parameters: + * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of + * features + * + * Returns: + * {String} The WKT string representation of the input geometries + */ + write: function(features) { + var collection, geometry, type, data, isCollection; + if(features.constructor == Array) { + collection = features; + isCollection = true; + } else { + collection = [features]; + isCollection = false; + } + var pieces = []; + if(isCollection) { + pieces.push('GEOMETRYCOLLECTION('); + } + for(var i=0, len=collection.length; i<len; ++i) { + if(isCollection && i>0) { + 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(''); + }, + + /** + * Object with properties corresponding to the geometry types. + * Property values are functions that do the actual data extraction. + */ + extract: { + /** + * Return a space delimited string of point coordinates. + * @param {<OpenLayers.Geometry.Point>} point + * @returns {String} A string of coordinates representing the point + */ + 'point': function(point) { + return point.x + ' ' + point.y; + }, + + /** + * Return a comma delimited string of point coordinates from a multipoint. + * @param {<OpenLayers.Geometry.MultiPoint>} multipoint + * @returns {String} A string of point coordinate strings representing + * the multipoint + */ + 'multipoint': function(multipoint) { + var array = []; + for(var i=0, len=multipoint.components.length; i<len; ++i) { + array.push('(' + + this.extract.point.apply(this, [multipoint.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of point coordinates from a line. + * @param {<OpenLayers.Geometry.LineString>} linestring + * @returns {String} A string of point coordinate strings representing + * the linestring + */ + 'linestring': function(linestring) { + var array = []; + for(var i=0, len=linestring.components.length; i<len; ++i) { + array.push(this.extract.point.apply(this, [linestring.components[i]])); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of linestring strings from a multilinestring. + * @param {<OpenLayers.Geometry.MultiLineString>} multilinestring + * @returns {String} A string of of linestring strings representing + * the multilinestring + */ + 'multilinestring': function(multilinestring) { + var array = []; + for(var i=0, len=multilinestring.components.length; i<len; ++i) { + array.push('(' + + this.extract.linestring.apply(this, [multilinestring.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return a comma delimited string of linear ring arrays from a polygon. + * @param {<OpenLayers.Geometry.Polygon>} polygon + * @returns {String} An array of linear ring arrays representing the polygon + */ + 'polygon': function(polygon) { + var array = []; + for(var i=0, len=polygon.components.length; i<len; ++i) { + array.push('(' + + this.extract.linestring.apply(this, [polygon.components[i]]) + + ')'); + } + return array.join(','); + }, + + /** + * Return an array of polygon arrays from a multipolygon. + * @param {<OpenLayers.Geometry.MultiPolygon>} multipolygon + * @returns {Array} An array of polygon arrays representing + * the multipolygon + */ + 'multipolygon': function(multipolygon) { + var array = []; + for(var i=0, len=multipolygon.components.length; i<len; ++i) { + array.push('(' + + this.extract.polygon.apply(this, [multipolygon.components[i]]) + + ')'); + } + return array.join(','); + } + + }, + + /** + * Object with properties corresponding to the geometry types. + * Property values are functions that do the actual parsing. + */ + parse: { + /** + * Return point feature given a point WKT fragment. + * @param {String} str A WKT fragment representing the point + * @returns {<OpenLayers.Feature.Vector>} A point feature + * @private + */ + 'point': function(str) { + var coords = OpenLayers.String.trim(str).split(this.regExes.spaces); + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Point(coords[0], coords[1]) + ); + }, + + /** + * Return a multipoint feature given a multipoint WKT fragment. + * @param {String} A WKT fragment representing the multipoint + * @returns {<OpenLayers.Feature.Vector>} A multipoint feature + * @private + */ + 'multipoint': function(str) { + var point; + var points = OpenLayers.String.trim(str).split(this.regExes.parenComma); + var components = []; + for(var i=0, len=points.length; i<len; ++i) { + point = points[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.point.apply(this, [point]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiPoint(components) + ); + }, + + /** + * Return a linestring feature given a linestring WKT fragment. + * @param {String} A WKT fragment representing the linestring + * @returns {<OpenLayers.Feature.Vector>} A linestring feature + * @private + */ + 'linestring': function(str) { + var points = OpenLayers.String.trim(str).split(','); + var components = []; + for(var i=0, len=points.length; i<len; ++i) { + components.push(this.parse.point.apply(this, [points[i]]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.LineString(components) + ); + }, + + /** + * Return a multilinestring feature given a multilinestring WKT fragment. + * @param {String} A WKT fragment representing the multilinestring + * @returns {<OpenLayers.Feature.Vector>} A multilinestring feature + * @private + */ + 'multilinestring': function(str) { + var line; + var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma); + var components = []; + for(var i=0, len=lines.length; i<len; ++i) { + line = lines[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.linestring.apply(this, [line]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiLineString(components) + ); + }, + + /** + * Return a polygon feature given a polygon WKT fragment. + * @param {String} A WKT fragment representing the polygon + * @returns {<OpenLayers.Feature.Vector>} A polygon feature + * @private + */ + 'polygon': function(str) { + var ring, linestring, linearring; + var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma); + var components = []; + for(var i=0, len=rings.length; i<len; ++i) { + ring = rings[i].replace(this.regExes.trimParens, '$1'); + linestring = this.parse.linestring.apply(this, [ring]).geometry; + linearring = new OpenLayers.Geometry.LinearRing(linestring.components); + components.push(linearring); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon(components) + ); + }, + + /** + * Return a multipolygon feature given a multipolygon WKT fragment. + * @param {String} A WKT fragment representing the multipolygon + * @returns {<OpenLayers.Feature.Vector>} A multipolygon feature + * @private + */ + 'multipolygon': function(str) { + var polygon; + var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma); + var components = []; + for(var i=0, len=polygons.length; i<len; ++i) { + polygon = polygons[i].replace(this.regExes.trimParens, '$1'); + components.push(this.parse.polygon.apply(this, [polygon]).geometry); + } + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.MultiPolygon(components) + ); + }, + + /** + * Return an array of features given a geometrycollection WKT fragment. + * @param {String} A WKT fragment representing the geometrycollection + * @returns {Array} An array of OpenLayers.Feature.Vector + * @private + */ + 'geometrycollection': function(str) { + // separate components of the collection with | + str = str.replace(/,\s*([A-Za-z])/g, '|$1'); + var wktArray = OpenLayers.String.trim(str).split('|'); + var components = []; + for(var i=0, len=wktArray.length; i<len; ++i) { + components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]])); + } + return components; + } + + }, + + CLASS_NAME: "OpenLayers.Format.WKT" +}); +