├── .gitignore ├── bower.json ├── component.json ├── .zuul.yml ├── .travis.yml ├── cli.js ├── LICENSE ├── test ├── fuzz.js ├── stringify.js ├── data │ ├── geometrycollection.wkt │ └── geometrycollection.geojson └── wellknown.test.js ├── CHANGELOG.md ├── package.json ├── README.md ├── index.js └── wellknown.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wellknown", 3 | "description": "convert wkt to geojson", 4 | "version": "0.3.0", 5 | "license": "BSD", 6 | "keywords": [ 7 | "wkt", 8 | "geojson", 9 | "maps" 10 | ], 11 | "main": "wellknown.js" 12 | } 13 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wellknown", 3 | "description": "convert wkt to geojson", 4 | "version": "0.3.0", 5 | "license": "BSD", 6 | "keywords": [ 7 | "wkt", 8 | "geojson", 9 | "maps" 10 | ], 11 | "scripts": [ 12 | "index.js" 13 | ] 14 | } -------------------------------------------------------------------------------- /.zuul.yml: -------------------------------------------------------------------------------- 1 | ui: tape 2 | transform: 3 | - transform: brfs 4 | browsers: 5 | - name: chrome 6 | version: latest 7 | - name: firefox 8 | version: latest 9 | - name: safari 10 | version: latest 11 | - name: opera 12 | version: latest 13 | - name: ie 14 | version: 10..latest 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.12' 5 | - 'iojs' 6 | sudo: false 7 | env: 8 | global: 9 | - secure: Xy1Jl53Yovuj9tProdpmMmPThyA+iBxQYhceOqb+1O9FX8+6/9ohrgN+yF7VqvwX5cLPiico7/NCbS/BG/yufuxK8nddc4hPOYR1zZlwz0j1QBGDRsRG8PK3DlOtxyNHJTiDkNGjrDeeuM31uxL2qErl9IpEbE+8qi1bswRpKi8= 10 | - secure: A39ISE6SAsqOCGJNV2UdqVlGEpg0VefYOw6qVuihksRIy5UoBtlmq1YzaXq0Q9Vd6TsYbMdEkBz5Zcok4+uZZIUpgvr90iMYpFHLWm2Qdr87X1PwSrTrce6nVfVUU9D/G0vZXd/LUyw0Lo8DngMHrUMaLuM9Vu10h9SXdDFMM+Y= 11 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var concat = require('concat-stream'), 4 | wellknown = require('./'), 5 | fs = require('fs'), 6 | argv = require('minimist')(process.argv.slice(2)); 7 | 8 | if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) return help(); 9 | 10 | ((argv._[0] && fs.createReadStream(argv._[0])) || process.stdin).pipe(concat(openData)); 11 | 12 | function openData(body) { 13 | try { 14 | console.log(JSON.stringify(wellknown(body.toString()), null, 2)); 15 | } catch(e) { 16 | console.error('Valid GeoJSON file required as input.'); 17 | help(); 18 | } 19 | } 20 | 21 | function help() { 22 | process.stdout.write(fs.readFileSync(__dirname + '/README.md')); 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Mapbox 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /test/fuzz.js: -------------------------------------------------------------------------------- 1 | var parse = require('../'), 2 | fuzzer = require('fuzzer'), 3 | test = require('tap').test; 4 | 5 | test('fuzz', function(t) { 6 | fuzzer.seed(0); 7 | var inputs = [ 8 | 'MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))', 9 | 'POINT(1.1 1.1)', 10 | 'LINESTRING (30 10, 10 30, 40 40)', 11 | 'GeometryCollection(POINT(4 6),\nLINESTRING(4 6,7 10))']; 12 | inputs.forEach(function(str) { 13 | for (var i = 0; i < 10000; i++) { 14 | try { 15 | var input = fuzzer.mutate.string(str); 16 | parse(input); 17 | } catch(e) { 18 | t.fail('could not parse ' + input + ', exception ' + e + '\n' + e.stack); 19 | } 20 | } 21 | }); 22 | t.end(); 23 | }); 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 0.5.0 4 | 5 | * Add support for `Z` coordinates. 6 | 7 | ## 0.4.1 8 | 9 | * Support for [alternative MultiPoint syntax](https://github.com/mapbox/wellknown/pull/29) 10 | 11 | ## 0.4.0 12 | 13 | * Support for 4D geometries 14 | 15 | ## 0.3.1 16 | 17 | * Fix for coordinate arrays with incorrect lengths 18 | * Now uses semistandard for code formatting and tap for tests 19 | 20 | ## 0.3.0 21 | 22 | * Now parses WKT with exponent values for coordinates. 23 | 24 | ## 0.2.0 25 | 26 | * Introduces `.stringify(geojson)` 27 | 28 | ## 0.1.1 29 | 30 | * Fix issue with multicoords being overeager - fixes GeometryCollection cases 31 | 32 | ## 0.1.0 33 | 34 | * Added cli `wellknown` utility 35 | * Supports linebreaks in geometrycollections 36 | * Supports case-insensitive tags 37 | * Added rant to README 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wellknown", 3 | "version": "0.5.0", 4 | "description": "convert wkt to geojson", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "semistandard index.js && tap --coverage test/*.js", 8 | "prepublish": "browserify -s wellknown index.js > wellknown.js" 9 | }, 10 | "bin": { 11 | "wellknown": "cli.js" 12 | }, 13 | "keywords": [ 14 | "wkt", 15 | "geojson", 16 | "maps" 17 | ], 18 | "author": "Tom MacWright", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/mapbox/wellknown.git" 22 | }, 23 | "license": "ISC", 24 | "devDependencies": { 25 | "fuzzer": "~0.2.0", 26 | "semistandard": "^8.0.0", 27 | "tap": "^6.2.0" 28 | }, 29 | "dependencies": { 30 | "concat-stream": "~1.5.0", 31 | "minimist": "~1.2.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/stringify.js: -------------------------------------------------------------------------------- 1 | var wellknown = require('../'), 2 | test = require('tap').test; 3 | 4 | test('wellknown', function(t) { 5 | t.throws(function() { 6 | wellknown.stringify({ 7 | type: 'FeatureCollection' 8 | }); 9 | }, 'does not accept featurecollections'); 10 | 11 | var fixtures = [ 12 | 'LINESTRING (30 10, 10 30, 40 40)', 13 | 'POINT (1 1)', 14 | 'POINT (1 1 1 1)', 15 | 'LINESTRING (1 2 3, 4 5 6)', 16 | 'LINESTRING (1 2 3 4, 5 6 7 8)', 17 | 'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))', 18 | 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10), (20 30, 35 35, 30 20, 20 30))', 19 | 'MULTIPOINT (1 1, 2 3)', 20 | 'MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5), (10 10, 15 10, 15 15, 10 10)))', 21 | 'MULTILINESTRING ((30 10, 10 30, 40 40), (30 10, 10 30, 40 40))', 22 | 'GEOMETRYCOLLECTION (POINT (4 6), LINESTRING (4 6, 7 10))' 23 | ]; 24 | 25 | fixtures.forEach(function(fix) { 26 | t.equal(fix, loop(fix), fix); 27 | }); 28 | 29 | function loop(s) { 30 | return wellknown.stringify(wellknown(s)); 31 | } 32 | 33 | t.equal(wellknown.stringify({ 34 | type: 'Feature', 35 | properties: {}, 36 | geometry: { 37 | type: 'Point', 38 | coordinates: [42, 20] 39 | } 40 | }), 'POINT (42 20)', 'point equal'); 41 | 42 | t.end(); 43 | }); 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/mapbox/wellknown.svg?branch=master)](https://travis-ci.org/mapbox/wellknown) [![Coverage Status](https://coveralls.io/repos/mapbox/wellknown/badge.svg)](https://coveralls.io/r/mapbox/wellknown) 2 | 3 | # wellknown 4 | 5 | Parse & stringify [Well-Known Text](http://en.wikipedia.org/wiki/Well-known_text) into [GeoJSON](http://www.geojson.org/). 6 | 7 | Support 8 | 9 | * Point + MultiPoint 10 | * LineString + MultiLineString 11 | * Polygon + MultiPolygon 12 | * GeometryCollection 13 | * 2D, 3D, 4D geometries 14 | 15 | ## cli 16 | 17 | install: 18 | 19 | $ npm install -g wellknown 20 | 21 | use: 22 | 23 | $ echo "MultiPoint(0 0, 1 1, 3 3)" | wellknown > multipoint.geojson 24 | 25 | ## usage 26 | 27 | this is a node-style module that works in node.js via npm and in browsers via 28 | [browserify](https://github.com/substack/node-browserify) or a standalone package: 29 | 30 | **npm install**: 31 | 32 | npm install wellknown 33 | 34 | **bower install**: 35 | 36 | bower install wellknown --save 37 | 38 | **standalone**: 39 | 40 | wget https://raw.github.com/mapbox/wellknown/master/wellknown.js 41 | 42 | ## api 43 | 44 | ### `parse(wkt)` 45 | 46 | Given WKT as a string, return a GeoJSON [geometry object](http://geojson.org/geojson-spec.html#geometry-objects) 47 | or `null` if parse fails. 48 | 49 | ### `stringify(geojson)` 50 | 51 | Given a GeoJSON geometry object or Feature object, return a WKT representation 52 | as a string. Throws an error if given a `FeatureCollection` or unknown input. 53 | 54 | ## example 55 | 56 | ```js 57 | var parse = require('wellknown'); 58 | 59 | parse('POINT(1 2)'); 60 | ``` 61 | 62 | #### Integrating with Leaflet 63 | 64 | ```js 65 | // With Leaflet or MapBox.js 66 | var geojsonLayer = L.geoJson(parse('Point(1 2)')); 67 | ``` 68 | 69 | ## See Also 70 | 71 | * [wicket](https://github.com/arthur-e/Wicket) 72 | * [openlayers wkt](https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Format/WKT.js) 73 | * [geomet](https://github.com/geomet/geomet) converts between GeoJSON and WKT in Python 74 | 75 | ## Rant 76 | 77 | The 'WKT Standard' is (mis)managed by the [OGC](http://www.opengeospatial.org/), 78 | and thus is available on page 52 of [this PDF](http://www.opengeospatial.org/standards/sfa). 79 | 80 | Given the inaccessibility of the standard, there are no direct reference to it 81 | in this code. 82 | -------------------------------------------------------------------------------- /test/data/geometrycollection.wkt: -------------------------------------------------------------------------------- 1 | GEOMETRYCOLLECTION (LINESTRING (6308869.40378 356821.22669, 6308867.893 356822.41744, 6308852.75314 356830.22159, 6308869.92754 356844.26638), LINESTRING (6308755.07971 356674.51686, 6308784.81355 356719.16757, 6308815.20022 356765.46178, 6308829.63774 356763.22832, 6308852.87023 356759.82402, 6308867.19982 356771.06823, 6308875.40631 356796.20162, 6308872.51907 356815.17242), LINESTRING (6308874.12086 356813.73392, 6308876.83028 356795.77697, 6308868.23871 356770.06254, 6308853.09618 356758.29456, 6308815.86529 356763.89689, 6308799.76731 356739.37835, 6308747.77971 356662.11613, 6308746.55411 356661.61702, 6308744.06545 356657.72563, 6308731.77184 356668.45076, 6308699.45221 356683.15463, 6308682.44689 356684.63193, 6308654.96629 356683.66846, 6308636.13879 356680.0482, 6308618.19888 356671.76352, 6308608.41685 356661.79428, 6308578.7973 356592.35062, 6308545.33908 356542.14886, 6308517.52088 356509.38474, 6308505.40266 356506.84141, 6308493.59689 356506.98067, 6308375.07918 356520.46209), LINESTRING (6308877.92941 356819.50984, 6309072.26249 356514.14689, 6309073.44938 356513.3739, 6309076.25423 356511.31751, 6309096.05004 356528.52014, 6309103.33938 356535.32615, 6309107.49584 356539.20699, 6309107.78601 356539.47793, 6309119.09139 356550.03322, 6309137.04465 356567.13752, 6309137.6323 356567.69515, 6309138.92096 356568.91355, 6309138.46355 356569.69798, 6309150.68532 356566.34027, 6309151.94333 356567.03108, 6309157.81557 356565.41779, 6309161.54152 356564.33408, 6309174.6464 356579.77423, 6309175.71622 356581.0361, 6309177.25892 356582.84545, 6309225.37695 356611.76515, 6309226.90588 356612.65173, 6309229.72021 356614.34101, 6309232.64678 356598.75445, 6309244.10246 356528.49893, 6309251.20809 356487.90256, 6309252.35489 356481.34967, 6309258.41778 356442.34047, 6309258.56036 356441.19511, 6309258.76115 356440.13123, 6309260.99127 356426.22389, 6309258.49745 356425.57244, 6309240.94882 356422.48836, 6309240.53276 356422.37171, 6309240.10958 356422.29068), LINESTRING (6308870.96141 356823.05522, 6308881.43519 356846.04558, 6308859.94336 356857.75024, 6308859.6305 356857.95378, 6308893.96675 356932.14467, 6308921.19517 356993.60222, 6308942.68768 357040.82051, 6308961.42173 357079.52481, 6308976.48471 357108.08898, 6308992.14194 357136.52543, 6309018.60922 357184.68892, 6309024.87557 357193.57884, 6309025.31785 357194.20629, 6309028.73486 357199.05392, 6309045.86114 357220.97586, 6309078.85225 357261.01696, 6309131.17986 357323.22098, 6309184.03434 357388.33409, 6309212.61182 357423.54026, 6309252.80543 357467.20429, 6309288.51836 357504.59499, 6309318.98068 357536.37443, 6309366.01084 357588.07961, 6309383.32941 357609.89089, 6309383.33718 357609.92579, 6309383.36584 357611.49516), POLYGON ((6309096.87876754 357058.96992573235, 6309100.9240038069 357067.89795246266, 6309103.1497403858 357077.44361610821, 6309103.4704434676 357087.24008216924, 6309101.8737886148 357096.91087794991, 6309098.421134375 357106.08436019259, 6309093.2451643161 357114.40799712023, 6309086.5447880644 357121.56191603432, 6309078.5774973193 357127.27119584358, 6309013.594489282 357164.78915304772, 6309004.6664625369 357168.8343893392, 6308995.1207988719 357171.06012593472, 6308985.3243327877 357171.38082902494, 6308975.6535369828 357169.78417417, 6308966.4800547194 357166.33151992067, 6308958.156417775 357161.1555498438, 6308951.0024988521 357154.45517356717, 6308945.293219042 357146.48788279406, 6308795.0043396624 356886.1799069175, 6308790.959103398 356877.251880196, 6308788.7333668182 356867.70621655986, 6308788.4126637317 356857.90975050797, 6308790.0093185771 356848.2389547351, 6308793.4619728047 356839.0654724979, 6308798.6379428506 356830.74183557258, 6308805.3383190883 356823.587916657, 6308813.3056098176 356817.87863684172, 6308878.2886178084 356780.36067953659, 6308887.2166445563 356776.315443229, 6308896.7623082288 356774.08970661991, 6308906.5587743223 356773.76900351944, 6308916.2295701364 356775.36565836804, 6308925.403052411 356778.81831261492, 6308933.7266893657 356783.99428269314, 6308940.8806082979 356790.69465897442, 6308946.5898881136 356798.66194975481, 6309096.87876754 357058.96992573235))) 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable no-cond-assign */ 2 | module.exports = parse; 3 | module.exports.parse = parse; 4 | module.exports.stringify = stringify; 5 | 6 | var numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/; 7 | // Matches sequences like '100 100' or '100 100 100'. 8 | var tuples = new RegExp('^' + numberRegexp.source + '(\\s' + numberRegexp.source + '){1,}'); 9 | 10 | /* 11 | * Parse WKT and return GeoJSON. 12 | * 13 | * @param {string} _ A WKT geometry 14 | * @return {?Object} A GeoJSON geometry object 15 | */ 16 | function parse (input) { 17 | var parts = input.split(';'); 18 | var _ = parts.pop(); 19 | var srid = (parts.shift() || '').split('=').pop(); 20 | 21 | var i = 0; 22 | 23 | function $ (re) { 24 | var match = _.substring(i).match(re); 25 | if (!match) return null; 26 | else { 27 | i += match[0].length; 28 | return match[0]; 29 | } 30 | } 31 | 32 | function crs (obj) { 33 | if (obj && srid.match(/\d+/)) { 34 | obj.crs = { 35 | type: 'name', 36 | properties: { 37 | name: 'urn:ogc:def:crs:EPSG::' + srid 38 | } 39 | }; 40 | } 41 | 42 | return obj; 43 | } 44 | 45 | function white () { $(/^\s*/); } 46 | 47 | function multicoords () { 48 | white(); 49 | var depth = 0; 50 | var rings = []; 51 | var stack = [rings]; 52 | var pointer = rings; 53 | var elem; 54 | 55 | while (elem = 56 | $(/^(\()/) || 57 | $(/^(\))/) || 58 | $(/^(,)/) || 59 | $(tuples)) { 60 | if (elem === '(') { 61 | stack.push(pointer); 62 | pointer = []; 63 | stack[stack.length - 1].push(pointer); 64 | depth++; 65 | } else if (elem === ')') { 66 | // For the case: Polygon(), ... 67 | if (pointer.length === 0) return null; 68 | 69 | pointer = stack.pop(); 70 | // the stack was empty, input was malformed 71 | if (!pointer) return null; 72 | depth--; 73 | if (depth === 0) break; 74 | } else if (elem === ',') { 75 | pointer = []; 76 | stack[stack.length - 1].push(pointer); 77 | } else if (!elem.split(/\s/g).some(isNaN)) { 78 | Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat)); 79 | } else { 80 | return null; 81 | } 82 | white(); 83 | } 84 | 85 | if (depth !== 0) return null; 86 | 87 | return rings; 88 | } 89 | 90 | function coords () { 91 | var list = []; 92 | var item; 93 | var pt; 94 | while (pt = 95 | $(tuples) || 96 | $(/^(,)/)) { 97 | if (pt === ',') { 98 | list.push(item); 99 | item = []; 100 | } else if (!pt.split(/\s/g).some(isNaN)) { 101 | if (!item) item = []; 102 | Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat)); 103 | } 104 | white(); 105 | } 106 | 107 | if (item) list.push(item); 108 | else return null; 109 | 110 | return list.length ? list : null; 111 | } 112 | 113 | function point () { 114 | if (!$(/^(point(\sz)?)/i)) return null; 115 | white(); 116 | if (!$(/^(\()/)) return null; 117 | var c = coords(); 118 | if (!c) return null; 119 | white(); 120 | if (!$(/^(\))/)) return null; 121 | return { 122 | type: 'Point', 123 | coordinates: c[0] 124 | }; 125 | } 126 | 127 | function multipoint () { 128 | if (!$(/^(multipoint)/i)) return null; 129 | white(); 130 | var newCoordsFormat = _ 131 | .substring(_.indexOf('(') + 1, _.length - 1) 132 | .replace(/\(/g, '') 133 | .replace(/\)/g, ''); 134 | _ = 'MULTIPOINT (' + newCoordsFormat + ')'; 135 | var c = multicoords(); 136 | if (!c) return null; 137 | white(); 138 | return { 139 | type: 'MultiPoint', 140 | coordinates: c 141 | }; 142 | } 143 | 144 | function multilinestring () { 145 | if (!$(/^(multilinestring)/i)) return null; 146 | white(); 147 | var c = multicoords(); 148 | if (!c) return null; 149 | white(); 150 | return { 151 | type: 'MultiLineString', 152 | coordinates: c 153 | }; 154 | } 155 | 156 | function linestring () { 157 | if (!$(/^(linestring(\sz)?)/i)) return null; 158 | white(); 159 | if (!$(/^(\()/)) return null; 160 | var c = coords(); 161 | if (!c) return null; 162 | if (!$(/^(\))/)) return null; 163 | return { 164 | type: 'LineString', 165 | coordinates: c 166 | }; 167 | } 168 | 169 | function polygon () { 170 | if (!$(/^(polygon(\sz)?)/i)) return null; 171 | white(); 172 | var c = multicoords(); 173 | if (!c) return null; 174 | return { 175 | type: 'Polygon', 176 | coordinates: c 177 | }; 178 | } 179 | 180 | function multipolygon () { 181 | if (!$(/^(multipolygon)/i)) return null; 182 | white(); 183 | var c = multicoords(); 184 | if (!c) return null; 185 | return { 186 | type: 'MultiPolygon', 187 | coordinates: c 188 | }; 189 | } 190 | 191 | function geometrycollection () { 192 | var geometries = []; 193 | var geometry; 194 | 195 | if (!$(/^(geometrycollection)/i)) return null; 196 | white(); 197 | 198 | if (!$(/^(\()/)) return null; 199 | while (geometry = root()) { 200 | geometries.push(geometry); 201 | white(); 202 | $(/^(,)/); 203 | white(); 204 | } 205 | if (!$(/^(\))/)) return null; 206 | 207 | return { 208 | type: 'GeometryCollection', 209 | geometries: geometries 210 | }; 211 | } 212 | 213 | function root () { 214 | return point() || 215 | linestring() || 216 | polygon() || 217 | multipoint() || 218 | multilinestring() || 219 | multipolygon() || 220 | geometrycollection(); 221 | } 222 | 223 | return crs(root()); 224 | } 225 | 226 | /** 227 | * Stringifies a GeoJSON object into WKT 228 | */ 229 | function stringify (gj) { 230 | if (gj.type === 'Feature') { 231 | gj = gj.geometry; 232 | } 233 | 234 | function pairWKT (c) { 235 | return c.join(' '); 236 | } 237 | 238 | function ringWKT (r) { 239 | return r.map(pairWKT).join(', '); 240 | } 241 | 242 | function ringsWKT (r) { 243 | return r.map(ringWKT).map(wrapParens).join(', '); 244 | } 245 | 246 | function multiRingsWKT (r) { 247 | return r.map(ringsWKT).map(wrapParens).join(', '); 248 | } 249 | 250 | function wrapParens (s) { return '(' + s + ')'; } 251 | 252 | switch (gj.type) { 253 | case 'Point': 254 | return 'POINT (' + pairWKT(gj.coordinates) + ')'; 255 | case 'LineString': 256 | return 'LINESTRING (' + ringWKT(gj.coordinates) + ')'; 257 | case 'Polygon': 258 | return 'POLYGON (' + ringsWKT(gj.coordinates) + ')'; 259 | case 'MultiPoint': 260 | return 'MULTIPOINT (' + ringWKT(gj.coordinates) + ')'; 261 | case 'MultiPolygon': 262 | return 'MULTIPOLYGON (' + multiRingsWKT(gj.coordinates) + ')'; 263 | case 'MultiLineString': 264 | return 'MULTILINESTRING (' + ringsWKT(gj.coordinates) + ')'; 265 | case 'GeometryCollection': 266 | return 'GEOMETRYCOLLECTION (' + gj.geometries.map(stringify).join(', ') + ')'; 267 | default: 268 | throw new Error('stringify requires a valid GeoJSON Feature or geometry object as input'); 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /wellknown.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.wellknown = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o