WKT.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the 2-clause BSD license.
  3. * See license.txt in the OpenLayers distribution or repository for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Format.js
  7. * @requires OpenLayers/Feature/Vector.js
  8. * @requires OpenLayers/Geometry/Point.js
  9. * @requires OpenLayers/Geometry/MultiPoint.js
  10. * @requires OpenLayers/Geometry/LineString.js
  11. * @requires OpenLayers/Geometry/MultiLineString.js
  12. * @requires OpenLayers/Geometry/Polygon.js
  13. * @requires OpenLayers/Geometry/MultiPolygon.js
  14. */
  15. /**
  16. * Class: OpenLayers.Format.WKT
  17. * Class for reading and writing Well-Known Text. Create a new instance
  18. * with the <OpenLayers.Format.WKT> constructor.
  19. *
  20. * Inherits from:
  21. * - <OpenLayers.Format>
  22. */
  23. OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
  24. /**
  25. * Constructor: OpenLayers.Format.WKT
  26. * Create a new parser for WKT
  27. *
  28. * Parameters:
  29. * options - {Object} An optional object whose properties will be set on
  30. * this instance
  31. *
  32. * Returns:
  33. * {<OpenLayers.Format.WKT>} A new WKT parser.
  34. */
  35. initialize: function(options) {
  36. this.regExes = {
  37. 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
  38. 'spaces': /\s+/,
  39. 'parenComma': /\)\s*,\s*\(/,
  40. 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here
  41. 'trimParens': /^\s*\(?(.*?)\)?\s*$/
  42. };
  43. OpenLayers.Format.prototype.initialize.apply(this, [options]);
  44. },
  45. /**
  46. * APIMethod: read
  47. * Deserialize a WKT string and return a vector feature or an
  48. * array of vector features. Supports WKT for POINT, MULTIPOINT,
  49. * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
  50. * GEOMETRYCOLLECTION.
  51. *
  52. * Parameters:
  53. * wkt - {String} A WKT string
  54. *
  55. * Returns:
  56. * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
  57. * GEOMETRYCOLLECTION WKT.
  58. */
  59. read: function(wkt) {
  60. var features, type, str;
  61. wkt = wkt.replace(/[\n\r]/g, " ");
  62. var matches = this.regExes.typeStr.exec(wkt);
  63. if(matches) {
  64. type = matches[1].toLowerCase();
  65. str = matches[2];
  66. if(this.parse[type]) {
  67. features = this.parse[type].apply(this, [str]);
  68. }
  69. if (this.internalProjection && this.externalProjection) {
  70. if (features &&
  71. features.CLASS_NAME == "OpenLayers.Feature.Vector") {
  72. features.geometry.transform(this.externalProjection,
  73. this.internalProjection);
  74. } else if (features &&
  75. type != "geometrycollection" &&
  76. typeof features == "object") {
  77. for (var i=0, len=features.length; i<len; i++) {
  78. var component = features[i];
  79. component.geometry.transform(this.externalProjection,
  80. this.internalProjection);
  81. }
  82. }
  83. }
  84. }
  85. return features;
  86. },
  87. /**
  88. * APIMethod: write
  89. * Serialize a feature or array of features into a WKT string.
  90. *
  91. * Parameters:
  92. * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
  93. * features
  94. *
  95. * Returns:
  96. * {String} The WKT string representation of the input geometries
  97. */
  98. write: function(features) {
  99. var collection, geometry, isCollection;
  100. if (features.constructor == Array) {
  101. collection = features;
  102. isCollection = true;
  103. } else {
  104. collection = [features];
  105. isCollection = false;
  106. }
  107. var pieces = [];
  108. if (isCollection) {
  109. pieces.push('GEOMETRYCOLLECTION(');
  110. }
  111. for (var i=0, len=collection.length; i<len; ++i) {
  112. if (isCollection && i>0) {
  113. pieces.push(',');
  114. }
  115. geometry = collection[i].geometry;
  116. pieces.push(this.extractGeometry(geometry));
  117. }
  118. if (isCollection) {
  119. pieces.push(')');
  120. }
  121. return pieces.join('');
  122. },
  123. /**
  124. * Method: extractGeometry
  125. * Entry point to construct the WKT for a single Geometry object.
  126. *
  127. * Parameters:
  128. * geometry - {<OpenLayers.Geometry.Geometry>}
  129. *
  130. * Returns:
  131. * {String} A WKT string of representing the geometry
  132. */
  133. extractGeometry: function(geometry) {
  134. var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
  135. if (!this.extract[type]) {
  136. return null;
  137. }
  138. if (this.internalProjection && this.externalProjection) {
  139. geometry = geometry.clone();
  140. geometry.transform(this.internalProjection, this.externalProjection);
  141. }
  142. var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
  143. var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
  144. return data;
  145. },
  146. /**
  147. * Object with properties corresponding to the geometry types.
  148. * Property values are functions that do the actual data extraction.
  149. */
  150. extract: {
  151. /**
  152. * Return a space delimited string of point coordinates.
  153. * @param {OpenLayers.Geometry.Point} point
  154. * @returns {String} A string of coordinates representing the point
  155. */
  156. 'point': function(point) {
  157. return point.x + ' ' + point.y;
  158. },
  159. /**
  160. * Return a comma delimited string of point coordinates from a multipoint.
  161. * @param {OpenLayers.Geometry.MultiPoint} multipoint
  162. * @returns {String} A string of point coordinate strings representing
  163. * the multipoint
  164. */
  165. 'multipoint': function(multipoint) {
  166. var array = [];
  167. for(var i=0, len=multipoint.components.length; i<len; ++i) {
  168. array.push('(' +
  169. this.extract.point.apply(this, [multipoint.components[i]]) +
  170. ')');
  171. }
  172. return array.join(',');
  173. },
  174. /**
  175. * Return a comma delimited string of point coordinates from a line.
  176. * @param {OpenLayers.Geometry.LineString} linestring
  177. * @returns {String} A string of point coordinate strings representing
  178. * the linestring
  179. */
  180. 'linestring': function(linestring) {
  181. var array = [];
  182. for(var i=0, len=linestring.components.length; i<len; ++i) {
  183. array.push(this.extract.point.apply(this, [linestring.components[i]]));
  184. }
  185. return array.join(',');
  186. },
  187. /**
  188. * Return a comma delimited string of linestring strings from a multilinestring.
  189. * @param {OpenLayers.Geometry.MultiLineString} multilinestring
  190. * @returns {String} A string of of linestring strings representing
  191. * the multilinestring
  192. */
  193. 'multilinestring': function(multilinestring) {
  194. var array = [];
  195. for(var i=0, len=multilinestring.components.length; i<len; ++i) {
  196. array.push('(' +
  197. this.extract.linestring.apply(this, [multilinestring.components[i]]) +
  198. ')');
  199. }
  200. return array.join(',');
  201. },
  202. /**
  203. * Return a comma delimited string of linear ring arrays from a polygon.
  204. * @param {OpenLayers.Geometry.Polygon} polygon
  205. * @returns {String} An array of linear ring arrays representing the polygon
  206. */
  207. 'polygon': function(polygon) {
  208. var array = [];
  209. for(var i=0, len=polygon.components.length; i<len; ++i) {
  210. array.push('(' +
  211. this.extract.linestring.apply(this, [polygon.components[i]]) +
  212. ')');
  213. }
  214. return array.join(',');
  215. },
  216. /**
  217. * Return an array of polygon arrays from a multipolygon.
  218. * @param {OpenLayers.Geometry.MultiPolygon} multipolygon
  219. * @returns {String} An array of polygon arrays representing
  220. * the multipolygon
  221. */
  222. 'multipolygon': function(multipolygon) {
  223. var array = [];
  224. for(var i=0, len=multipolygon.components.length; i<len; ++i) {
  225. array.push('(' +
  226. this.extract.polygon.apply(this, [multipolygon.components[i]]) +
  227. ')');
  228. }
  229. return array.join(',');
  230. },
  231. /**
  232. * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an <OpenLayers.Geometry.Collection>
  233. * @param {OpenLayers.Geometry.Collection} collection
  234. * @returns {String} internal WKT representation of the collection
  235. */
  236. 'collection': function(collection) {
  237. var array = [];
  238. for(var i=0, len=collection.components.length; i<len; ++i) {
  239. array.push(this.extractGeometry.apply(this, [collection.components[i]]));
  240. }
  241. return array.join(',');
  242. }
  243. },
  244. /**
  245. * Object with properties corresponding to the geometry types.
  246. * Property values are functions that do the actual parsing.
  247. */
  248. parse: {
  249. /**
  250. * Return point feature given a point WKT fragment.
  251. * @param {String} str A WKT fragment representing the point
  252. * @returns {OpenLayers.Feature.Vector} A point feature
  253. * @private
  254. */
  255. 'point': function(str) {
  256. var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
  257. return new OpenLayers.Feature.Vector(
  258. new OpenLayers.Geometry.Point(coords[0], coords[1])
  259. );
  260. },
  261. /**
  262. * Return a multipoint feature given a multipoint WKT fragment.
  263. * @param {String} str A WKT fragment representing the multipoint
  264. * @returns {OpenLayers.Feature.Vector} A multipoint feature
  265. * @private
  266. */
  267. 'multipoint': function(str) {
  268. var point;
  269. var points = OpenLayers.String.trim(str).split(',');
  270. var components = [];
  271. for(var i=0, len=points.length; i<len; ++i) {
  272. point = points[i].replace(this.regExes.trimParens, '$1');
  273. components.push(this.parse.point.apply(this, [point]).geometry);
  274. }
  275. return new OpenLayers.Feature.Vector(
  276. new OpenLayers.Geometry.MultiPoint(components)
  277. );
  278. },
  279. /**
  280. * Return a linestring feature given a linestring WKT fragment.
  281. * @param {String} str A WKT fragment representing the linestring
  282. * @returns {OpenLayers.Feature.Vector} A linestring feature
  283. * @private
  284. */
  285. 'linestring': function(str) {
  286. var points = OpenLayers.String.trim(str).split(',');
  287. var components = [];
  288. for(var i=0, len=points.length; i<len; ++i) {
  289. components.push(this.parse.point.apply(this, [points[i]]).geometry);
  290. }
  291. return new OpenLayers.Feature.Vector(
  292. new OpenLayers.Geometry.LineString(components)
  293. );
  294. },
  295. /**
  296. * Return a multilinestring feature given a multilinestring WKT fragment.
  297. * @param {String} str A WKT fragment representing the multilinestring
  298. * @returns {OpenLayers.Feature.Vector} A multilinestring feature
  299. * @private
  300. */
  301. 'multilinestring': function(str) {
  302. var line;
  303. var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
  304. var components = [];
  305. for(var i=0, len=lines.length; i<len; ++i) {
  306. line = lines[i].replace(this.regExes.trimParens, '$1');
  307. components.push(this.parse.linestring.apply(this, [line]).geometry);
  308. }
  309. return new OpenLayers.Feature.Vector(
  310. new OpenLayers.Geometry.MultiLineString(components)
  311. );
  312. },
  313. /**
  314. * Return a polygon feature given a polygon WKT fragment.
  315. * @param {String} str A WKT fragment representing the polygon
  316. * @returns {OpenLayers.Feature.Vector} A polygon feature
  317. * @private
  318. */
  319. 'polygon': function(str) {
  320. var ring, linestring, linearring;
  321. var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
  322. var components = [];
  323. for(var i=0, len=rings.length; i<len; ++i) {
  324. ring = rings[i].replace(this.regExes.trimParens, '$1');
  325. linestring = this.parse.linestring.apply(this, [ring]).geometry;
  326. linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
  327. components.push(linearring);
  328. }
  329. return new OpenLayers.Feature.Vector(
  330. new OpenLayers.Geometry.Polygon(components)
  331. );
  332. },
  333. /**
  334. * Return a multipolygon feature given a multipolygon WKT fragment.
  335. * @param {String} str A WKT fragment representing the multipolygon
  336. * @returns {OpenLayers.Feature.Vector} A multipolygon feature
  337. * @private
  338. */
  339. 'multipolygon': function(str) {
  340. var polygon;
  341. var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
  342. var components = [];
  343. for(var i=0, len=polygons.length; i<len; ++i) {
  344. polygon = polygons[i].replace(this.regExes.trimParens, '$1');
  345. components.push(this.parse.polygon.apply(this, [polygon]).geometry);
  346. }
  347. return new OpenLayers.Feature.Vector(
  348. new OpenLayers.Geometry.MultiPolygon(components)
  349. );
  350. },
  351. /**
  352. * Return an array of features given a geometrycollection WKT fragment.
  353. * @param {String} str A WKT fragment representing the geometrycollection
  354. * @returns {Array} An array of OpenLayers.Feature.Vector
  355. * @private
  356. */
  357. 'geometrycollection': function(str) {
  358. // separate components of the collection with |
  359. str = str.replace(/,\s*([A-Za-z])/g, '|$1');
  360. var wktArray = OpenLayers.String.trim(str).split('|');
  361. var components = [];
  362. for(var i=0, len=wktArray.length; i<len; ++i) {
  363. components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
  364. }
  365. return components;
  366. }
  367. },
  368. CLASS_NAME: "OpenLayers.Format.WKT"
  369. });