diff --git a/pacotes/wicket/LICENSE b/pacotes/wicket/LICENSE new file mode 100644 index 0000000..ef3b042 --- /dev/null +++ b/pacotes/wicket/LICENSE @@ -0,0 +1,16 @@ +Copyright (C) 2012 K. Arthur Endsley (kaendsle@mtu.edu) +Michigan Tech Research Institute (MTRI) +3600 Green Court, Suite 100, Ann Arbor, MI, 48105 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/pacotes/wicket/README.md b/pacotes/wicket/README.md index 4b142b6..98a7f2f 100644 --- a/pacotes/wicket/README.md +++ b/pacotes/wicket/README.md @@ -1,54 +1,144 @@ -########## # Wicket # -########## -Updated **April 8, 2012** by K. Arthur Endsley +![Build Stats](https://travis-ci.org/arthur-e/Wicket.svg?branch=master) -################ -## Motivation ## -################ +Wicket is a lightweight library for translating between [Well-Known Text (WKT)](http://en.wikipedia.org/wiki/Well-known_text) and various client-side mapping frameworks: +* Leaflet [(demo)](http://arthur-e.github.com/Wicket/) +* Google Maps API [(demo)](http://arthur-e.github.com/Wicket/sandbox-gmaps3.html) +* ESRI ArcGIS JavaScript API [(demo)](http://arthur-e.github.com/Wicket/sandbox-arcgis.html) +* Potentially any other web mapping framework through serialization and de-serialization of GeoJSON (with `JSON.parse`) -Wicket was created out of the need for a lightweight Javascript library that can translate Well-Known Text (WKT) strings into geographic features. This problem arose in the context of [OpenClimateGIS](https://github.com/arthur-e/OpenClimateGIS), a web framework for accessing and subsetting online climate data. +The core Wicket library and the Leaflet extension are both compatible with Node.js; the Google Maps and ArcGIS API extensions will not work in Node.js because they require a browser. -OpenClimateGIS emits WKT representations of user-defined geometry. Our [API explorer](http://www.openclimategis.org/builder/) allows users to define arbitrary areas-of-interest (AOIs) and view predefined AOIs on a Google Maps API instance. So, initially, the problem was converting between WKT strings and Google Maps API features. While other mapping libraries, such as [OpenLayers](http://www.openlayers.org), have very nice WKT libraries built-in, the Google Maps API, as of this writing, does not. In the (apparent) absence of lightweight, easy-to-use WKT library in Javascript, I set out to create one. +If you are looking for [Apache Wicket](http://wicket.apache.org/), the web-app development framework for Java, [you'll find it here](http://wicket.apache.org/). -That is what Wicket aspires to be: lightweight, framework-agnostic, and useful. I hope it achieves these goals. If you find it isn't living up to that and you have ideas on how to improve it, please fork the code or [drop me a line](mailto:kaendsle@mtu.edu). +## License ## + +Wicket is released under the [GNU General Public License version 3 (GPLv3)](http://www.gnu.org/licenses/gpl.html). +Accordingly: + +> This program is free software: you can redistribute it and/or modify +> it under the terms of the GNU General Public License as published by +> the Free Software Foundation, either version 3 of the License, or +> (at your option) any later version. + +## Example ## + +The following examples work in any of the mapping environments, as Wicket has a uniform API regardless of the client-side mapping library you're using. + + // Create a new Wicket instance + var wkt = new Wkt.Wkt(); + + // Read in any kind of WKT string + wkt.read("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"); + + // Or a GeoJSON string + wkt.read('{"coordinates": [[[30, 10], [10, 20], [20, 40], [40, 40], [30, 10]]], "type": "Polygon"}'); + + // Access and modify the underlying geometry + console.log(wkt.components); + // "[ [ {x: 30, y: 10}, {x: 10, y: 30}, ...] ]" + wkt.components[0][1].x = 15; + + wkt.merge(new Wkt.Wkt('POLYGON((35 15,15 25,25 45,45 45,35 15))')); + wkt.write(); + // MULTIPOLYGON(((30 10,10 20,20 40,40 40,30 10)),((35 15,15 25,25 45,45 45,35 15))) + + // Create a geometry object, ready to be mapped! + wkt.toObject(); + +Wicket will read from the geometry objects of any mapping client it understands. +**Note:** Don't use the `deconstruct()` method! This is used internally by `Wkt.Wkt()` instances. +Use `fromObject()` instead, as in the following example. + + var wkt = new Wkt.Wkt(); + + // Deconstruct an existing point feature e.g. google.maps.Marker instance + wkt.fromObject(somePointObject); + + console.log(wkt.components); + // "[ {x: 10, y: 30} ]" + + // Serialize a WKT string from that geometry + wkt.write(); + // "POINT(10 30)" + +## See Also ## + +* [wellknown](https://github.com/mapbox/wellknown) +* [OpenLayers WKT](https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Format/WKT.js) +* [wkt-parser](http://terraformer.io/wkt-parser/) + +## Dependencies and Build Information ## + +**Wicket has zero dependencies**, however, JSON parsing (from strings) is not provided. +Wicket looks for the function `JSON.parse`, which is provided in most modern browsers (get it with [this library](https://github.com/douglascrockford/JSON-js/blob/master/json2.js), if you need to support older browsers). + +Minified versions can be generated via: + + npm run build + +### Testing ### + + npm test + +The Google Maps API extension cannot be tested by Node.js at the command line; it requires a browser. The Google Maps API tests are run by Jasmine; navigate to the file `tests/wicket-gmap3.html` in a web browser. + +## Documentation ## + +Read the documentation [here](http://arthur-e.github.io/Wicket/doc/out/). Documentation can be generated with [JSDoc 3](https://github.com/jsdoc3/jsdoc). + + git clone git://github.com/jsdoc3/jsdoc.git + ./jsdoc /var/www/static/wicket/wicket.src.js + +Or, with Node installed: + + sudo npm install -g git://github.com/jsdoc3/jsdoc.git + jsdoc /var/www/static/wicket/wicket.src.js + +Either way, make sure you invoke `jsdoc` from a directory in which you have write access; it will output documentation to your current working directory. -############## ## Colophon ## -############## -######################## +### Motivation ### + +Wicket was created out of the need for a lightweight Javascript library that can translate Well-Known Text (WKT) strings into geographic features. +This problem arose in the context of [OpenClimateGIS](https://github.com/arthur-e/OpenClimateGIS), a web framework for accessing and subsetting online climate data. + +OpenClimateGIS emits WKT representations of user-defined geometry. +The API Explorer allowed users to define arbitrary areas-of-interest (AOIs) and view predefined AOIs on a Google Maps API instance. +So, initially, the problem was converting between WKT strings and Google Maps API features. +While other mapping libraries, such as [OpenLayers](http://www.openlayers.org), have very nice WKT libraries built-in, the Google Maps API, as of this writing, does not. +In the (apparent) absence of a lightweight, easy-to-use WKT library in Javascript, I set out to create one. + +That is what Wicket aspires to be: lightweight, framework-agnostic, and useful. +I hope it achieves these goals. +If you find it isn't living up to that and you have ideas on how to improve it, please fork the code or [drop me a line](mailto:kaendsle@mtu.edu). + ### Acknowledgements ### -######################## -The following open sources were borrowed from; they retain all their original rights: +Wicket borrows heavily from the experiences of others who came before us: * The OpenLayers 2.7 WKT module (OpenLayers.Format.WKT) * Chris Pietshmann's [article on converting Bing Maps shapes (VEShape) to WKT](http://pietschsoft.com/post/2009/04/04/Virtual-Earth-Shapes-%28VEShape%29-to-WKT-%28Well-Known-Text%29-and-Back-using-JavaScript.aspx) * Charles R. Schmidt's and the Python Spatial Analysis Laboratory's (PySAL) WKT writer -################### ### Conventions ### -################### - -The conventions I've adopted in writing this library: -* The Crockford-ian module pattern with a single global (namespace) variable -* The most un-Crockford-ian use of new to instantiate new Objects (when this is required, the Object begins with a capital letter e.g. new Wkt()) -* The namespace is the only name beginning with a capital letter that doesn't need to and shouldn't be preceded by new -* The namespace is the result of a function allowing for private members -* Tricky operators (++ and --) and type-coercing operators (== and !=) are not used +The base library, wicket.js, contains the Wkt.Wkt base object. +This object doesn't do anything on its own except read in WKT strings, allow the underlying geometry to be manipulated programmatically, and write WKT strings. +By loading additional libraries, such as wicket-gmap3.js, users can transform between between WKT and the features of a given framework (e.g. google.maps.Polygon instances). +The intent is to add support for new frameworks as additional Javascript files that alter the Wkt.Wkt prototype. -The base library, wicket.js, contains the Wkt.Wkt base object. This object doesn't do anything on its own except read in WKT strings, allow the underlying geometry to be manipulated programmatically, and write WKT strings. By loading additional libraries, such as wicket-gmap3.js, users can transform between between WKT and the features of a given framework (e.g. google.maps.Polygon instances). The intent is to add support for new frameworks as additional Javascript files that alter the Wkt.Wkt prototype. +**To extend Wicket**, nominally by writing bindings for a new mapping library, add a new file with a name like wicket-libname.src.js (and corresponding minified version wicket-libname.js) where "libname" is some reasonably short, well-known name for the mapping library. -############## ## Concepts ## -############## -WKT geometries are stored internally using the following convention. The atomic unit of geometry is the coordinate pair (e.g. latitude and longitude) which is represented by an Object with x and y properties. An Array with a single coordinate pair represents a a single point (i.e. POINT feature) +WKT geometries are stored internally using the following convention. The atomic unit of geometry is the coordinate pair (e.g. latitude and longitude) which is represented by an Object with x and y properties. An Array with a single coordinate pair represents a a single point (i.e. POINT feature): [ {x: -83.123, y: 42.123} ] + + // POINT(-83.123 42.123) An Array of multiple points (an Array of Arrays) specifies a "collection" of points (i.e. a MULTIPOINT feature): @@ -56,6 +146,7 @@ An Array of multiple points (an Array of Arrays) specifies a "collection" of poi [ {x: -83.123, y: 42.123} ], [ {x: -83.234, y: 42.234} ] ] + // MULTIPOINT(-83.123 42.123,-83.234 42.234) An Array of multiple coordinates specifies a collection of connected points in an ordered sequence (i.e. LINESTRING feature): @@ -64,8 +155,10 @@ An Array of multiple coordinates specifies a collection of connected points in a {x: -83.23, y: 42.23}, {x: -83.34, y: 42.34} ] + // LINESTRING(-83.12 42.12,-83.23 42.23,-83.34 42.34) -An Array can also contain other Arrays. In these cases, the contained Array(s) can each represent one of two geometry types. The contained Array might reprsent a single polygon (i.e. POLYGON feature): +An Array can also contain other Arrays. In these cases, the contained Array(s) can each represent one of two geometry types. +The contained Array might reprsent a single polygon (i.e. POLYGON feature): [ [ @@ -76,8 +169,9 @@ An Array can also contain other Arrays. In these cases, the contained Array(s) c {x: -83, y: 42} ] ] + // POLYGON(-83 42,-83 43,-82 43,-82 42,-83 42) -It might also represent a LINESTRING feature. Both POLYGON and LINESTRING features are internally represented the same way. The difference between the two is specified elsewhere (in the Wkt instance's type) and must be retained. In this particular example (above), we can see that the first coordinate in the Array is repeated at the end, meaning that the geometry is closed. We can therefore infer it represents a POLYGON and not a LINESTRING even before we plot it. Wicket retains the *type* of the feature and will always remember which it is. +The above example cannot represent a LINESTRING feature (one of the few type-based constraints on the internal representations), however it may represent a MULTILINESTRING feature. Both POLYGON and MULTILINESTRING features are internally represented the same way. The difference between the two is specified elsewhere (in the Wkt instance's type) and must be retained. In this particular example (above), we can see that the first coordinate in the Array is repeated at the end, meaning that the geometry is closed. We can therefore infer it represents a POLYGON and not a MULTILINESTRING even before we plot it. Wicket retains the *type* of the feature and will always remember which it is. Similarly, multiple nested Arrays might reprsent a MULTIPOLYGON feature: @@ -101,6 +195,7 @@ Similarly, multiple nested Arrays might reprsent a MULTIPOLYGON feature: ] ] ] + // MULTIPOLYGON(((-83 42,-83 43,-82 43,-82 42,-83 42),(-70 40,-70 41,-69 41,-69 40,-70 40))) Or a POLYGON with inner rings (holes) in it where the outer ring is the polygon envelope and comes first; subsequent Arrays are inner rings (holes): @@ -119,5 +214,6 @@ Or a POLYGON with inner rings (holes) in it where the outer ring is the polygon {x: 20, y: 30} ] ] + // POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 35,30 20,20 30)) Or they might represent a MULTILINESTRING where each nested Array is a different LINESTRING in the collection. Again, Wicket remembers the correct *type* of feature even though the internal representation is ambiguous. diff --git a/pacotes/wicket/bower.json b/pacotes/wicket/bower.json new file mode 100644 index 0000000..44b0f05 --- /dev/null +++ b/pacotes/wicket/bower.json @@ -0,0 +1,14 @@ +{ + "name": "Wicket", + "version": "1.2", + "main": [ + "wicket.js", + "wicket-arcgis.js", + "wicket-gmap3.js", + "wicket-leaflet.js" + ], + "ignore": [ + "doc/*", + "tests/*" + ] +} diff --git a/pacotes/wicket/doc/arcgis.html b/pacotes/wicket/doc/arcgis.html new file mode 100644 index 0000000..34821b3 --- /dev/null +++ b/pacotes/wicket/doc/arcgis.html @@ -0,0 +1,221 @@ + + + + + + + + + + + + + +Wicket - Lightweight Javascript for WKT [ESRI ArcGIS Sandbox] + + + + + + + + +
+
+ +
  +
+
+
+
+
+
+
Wicket
+  It whispers WKT in your application's ear. +
+
+ Wicket is a lightweight Javascript library that reads and writes Well-Known Text (WKT) strings. It can also be extended to parse and to create geometric objects from various mapping frameworks, such as Leaflet and the Google Maps API. +
+
+ + + + +
+
+
+
+ + + diff --git a/pacotes/wicket/doc/index.css b/pacotes/wicket/doc/index.css index 00a8bb2..9f8a16b 100644 --- a/pacotes/wicket/doc/index.css +++ b/pacotes/wicket/doc/index.css @@ -5,7 +5,11 @@ label:hover {color:#333;} a:link, a:visited {color:#460;text-decoration:none;} -.attribute {float:right;padding:10px 0;} +.leaflet-container .leaflet-control-attribution {color:white;background:none !important;box-shadow:none !important;} +.leaflet-container .leaflet-control-attribution a:link, +.leaflet-container .leaflet-control-attribution a:visited {color:#8C0;} + +.attribute {width:290px;float:right;padding:10px 0;text-align:left;font-size:10px;line-height:16px;} .menu {float:left;margin:0;padding:0;list-style:none;} .menu a {display:inline-block;margin:0;padding:5px 0 10px;margin:0 25px 0 0;border-top:5px solid transparent;} .menu a:hover, @@ -20,7 +24,7 @@ a:visited {color:#460;text-decoration:none;} #controls .text {margin:90px 0 0;} #controls a:hover, #controls a:active {text-decoration:underline;} -#forkme {width:141px;height:141px;z-index:9999;position:absolute;left:0;top:0;background:transparent url(/static/ForkMe_Blk.png) no-repeat left top;} +#forkme {width:141px;height:141px;z-index:9999;position:absolute;left:0;top:4px;background:transparent url(https://s3.amazonaws.com/github/ribbons/forkme_left_red_aa0000.png) no-repeat left top;} #form {margin:10px 0 0;font-size:14px;color:#666;font-family:CabinItalic,sans-serif;} #form #wkt {width:100%;height:150px;border:1px solid #999;padding:3px;resize:none;} #form #urlify {vertical-align:baseline;margin:10px 5px 0 0;} diff --git a/pacotes/wicket/doc/index.html b/pacotes/wicket/doc/index.html index fd2961c..7f4c190 100644 --- a/pacotes/wicket/doc/index.html +++ b/pacotes/wicket/doc/index.html @@ -4,7 +4,7 @@ - + + + + + + + + + +Wicket - Lightweight Javascript for WKT [Leaflet Sandbox] + + + + + + + + +
+
+ +
  +
+
+
+
+
+
+
Wicket
+  It whispers WKT in your application's ear. +
+
+ Wicket is a lightweight Javascript library that reads and writes Well-Known Text (WKT) strings. It can also be extended to parse and to create geometric objects from various mapping frameworks, such as Leaflet and the Google Maps API. +
+
+ + + + +
+
+
+
+ + + diff --git a/pacotes/wicket/package.json b/pacotes/wicket/package.json new file mode 100644 index 0000000..bc9d480 --- /dev/null +++ b/pacotes/wicket/package.json @@ -0,0 +1,67 @@ +{ + "name": "wicket", + "version": "1.1.0", + "description": "A modest library for moving between Well-Known Text (WKT) and various framework geometries", + "homepage": "https://github.com/arthur-e/Wicket", + "keywords": [ + "wkt", + "map", + "mapping", + "geometry", + "leaflet" + ], + "maintainers": [{ + "name": "K. Arthur Endsley", + "email": "kaendsle@mtu.edu", + "web": "https://github.com/arthur-e" + }], + "contributors": [{ + "name": "K. Arthur Endsley", + "email": "kaendsle@mtu.edu", + "web": "https://github.com/arthur-e" + }, { + "name": "cuyahoga", + "web": "https://github.com/cuyahoga" + }, { + "name": "Tom Nightingale", + "web": "https://github.com/thegreat" + }, { + "name": "Aaron Ogle", + "web": "https://github.com/atogle" + }, { + "name": "James Seppi", + "web": "https://github.com/jseppi" + }, { + "name": "tchannel", + "web": "https://github.com/tchannel" + }, { + "name": "Felipe Figueroa", + "web": "https://github.com/amenadiel" + }, { + "name": "Matthijs van Henten", + "web": "https://github.com/mvhenten" + }], + "bugs": { + "mail": "kaendsle@mtu.edu", + "url": "https://github.com/arthur-e/Wicket/issues" + }, + "licenses": [{ + "type": "GPLv3", + "url": "https://raw.github.com/arthur-e/Wicket/master/LICENSE" + }], + "repository": { + "type": "git", + "url": "https://github.com/arthur-e/Wicket" + }, + "scripts": { + "postinstall": "export PATH=$PATH:/usr/local/lib/node_modules/uglify-js/bin/;unzip ./node_modules/jasmine-core/dist/jasmine-standalone-2.0.0.zip -d ./node_modules/jasmine-core/dist/", + "build": "uglifyjs wicket.js -o wicket.min.js;uglifyjs wicket-gmap3.js -o wicket-gmap3.min.js;uglifyjs wicket-arcgis.js -o wicket-arcgis.min.js;uglifyjs wicket-leaflet.js -o wicket-leaflet.min.js;", + "test": "./node_modules/mocha/bin/mocha -R tap tests/wicket-spec.js" + }, + "devDependencies": { + "chai": "*", + "mocha": "*", + "uglify-js": "2.4.x", + "jasmine": "git://github.com/pivotal/jasmine#master" + } +} diff --git a/pacotes/wicket/tests/wicket-gmap3-spec.js b/pacotes/wicket/tests/wicket-gmap3-spec.js new file mode 100644 index 0000000..aedb986 --- /dev/null +++ b/pacotes/wicket/tests/wicket-gmap3-spec.js @@ -0,0 +1,880 @@ +describe('Standard WKT Test Cases: ', function () { + var cases, wkt; + + wkt = new Wkt.Wkt(); + + cases = { + + point: { + str: 'POINT(30 10)', + cmp: [{ + x: 30, + y: 10 + }], + obj: new google.maps.Point(30, 10), + json: { + 'coordinates': [30, 10], + 'type': 'Point' + }, + }, + + marker: { + str: 'POINT(30 10)', + cmp: [{ + x: 30, + y: 10 + }], + obj: new google.maps.Marker({ + position: new google.maps.LatLng(10, 30) + }) + }, + + linestring: { + str: 'LINESTRING(30 10,10 30,40 40)', + cmp: [{ + x: 30, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 40, + y: 40 + }], + obj: new google.maps.Polyline({ + editable: false, + path: [ + new google.maps.LatLng(10, 30), + new google.maps.LatLng(30, 10), + new google.maps.LatLng(40, 40) + ] + }), + json: { + 'coordinates': [ + [30, 10], + [10, 30], + [40, 40] + ], + 'type': 'LineString' + }, + }, + + + polygon: { + str: 'POLYGON((30 10,10 20,20 40,40 40,30 10))', + cmp: [ + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 20, + y: 40 + }, { + x: 40, + y: 40 + }, { + x: 30, + y: 10 + }] + ], + obj: new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(10, 30), + new google.maps.LatLng(20, 10), + new google.maps.LatLng(40, 20), + new google.maps.LatLng(40, 40) + ] + ] + }), + json: { + 'coordinates': [ + [ + [30, 10], + [10, 20], + [20, 40], + [40, 40], + [30, 10] + ] + ], + 'type': 'Polygon' + }, + + }, + + polygon2: { + str: 'POLYGON((35 10,10 20,15 40,45 45,35 10),(25 30,35 35,30 20,25 30))', + cmp: [ + [{ + x: 35, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 15, + y: 40 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 10 + }], + [{ + x: 25, + y: 30 + }, { + x: 35, + y: 35 + }, { + x: 30, + y: 20 + }, { + x: 25, + y: 30 + }] + ], + obj: new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(10, 35), + new google.maps.LatLng(20, 10), + new google.maps.LatLng(40, 15), + new google.maps.LatLng(45, 45) + ], + [ // Order in inner rings is reversed + new google.maps.LatLng(20, 30), + new google.maps.LatLng(35, 35), + new google.maps.LatLng(30, 25) + ] + ] + }), + json: { + 'coordinates': [ + [ + [35, 10], + [10, 20], + [15, 40], + [45, 45], + [35, 10] + ], + [ + [25, 30], + [35, 35], + [30, 20], + [25, 30] + ] + ], + 'type': 'Polygon' + }, + jsonStr: '{"coordinates": [[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]], "type": "Polygon"}' + }, + + multipoint: { + str: 'MULTIPOINT((10 40),(40 30),(20 20),(30 10))', + cmp: [ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }] + ], + obj: [ + new google.maps.Marker({ + position: new google.maps.LatLng(40, 10) + }), + new google.maps.Marker({ + position: new google.maps.LatLng(30, 40) + }), + new google.maps.Marker({ + position: new google.maps.LatLng(20, 20) + }), + new google.maps.Marker({ + position: new google.maps.LatLng(10, 30) + }), + ], + json: { + 'coordinates': [ + [10, 40], + [40, 30], + [20, 20], + [30, 10] + ], + 'type': 'MultiPoint' + }, + jsonStr: '{"coordinates": [[10, 40], [40, 30], [20, 20], [30, 10]], "type": "MultiPoint"}' + }, + + multilinestring: { + str: 'MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10))', + cmp: [ + [{ + x: 10, + y: 10 + }, { + x: 20, + y: 20 + }, { + x: 10, + y: 40 + }], + [{ + x: 40, + y: 40 + }, { + x: 30, + y: 30 + }, { + x: 40, + y: 20 + }, { + x: 30, + y: 10 + }] + ], + obj: [ + new google.maps.Polyline({ + editable: false, + path: [ + new google.maps.LatLng(10, 10), + new google.maps.LatLng(20, 20), + new google.maps.LatLng(40, 10) + ] + }), + new google.maps.Polyline({ + editable: false, + path: [ + new google.maps.LatLng(40, 40), + new google.maps.LatLng(30, 30), + new google.maps.LatLng(20, 40), + new google.maps.LatLng(10, 30) + ] + }) + ], + json: { + 'coordinates': [ + [ + [10, 10], + [20, 20], + [10, 40] + ], + [ + [40, 40], + [30, 30], + [40, 20], + [30, 10] + ] + ], + 'type': 'MultiLineString' + }, + jsonStr: '{"coordinates": [[[10, 10], [20, 20], [10, 40]], [[40, 40], [30, 30], [40, 20], [30, 10]]], "type": "MultiLineString"}' + }, + + multipolygon: { + str: 'MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)))', + cmp: [ + [ + [{ + x: 30, + y: 20 + }, { + x: 10, + y: 40 + }, { + x: 45, + y: 40 + }, { + x: 30, + y: 20 + }, ] + ], + [ + [{ + x: 15, + y: 5 + }, { + x: 40, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 5, + y: 10 + }, { + x: 15, + y: 5 + }] + ] + ], + obj: [ + new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(20, 30), + new google.maps.LatLng(40, 10), + new google.maps.LatLng(40, 45) + ] + ] + }), + new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(5, 15), + new google.maps.LatLng(10, 40), + new google.maps.LatLng(20, 10), + new google.maps.LatLng(10, 5) + ] + ] + }) + ], + json: { + 'coordinates': [ + [ + [ + [30, 20], + [10, 40], + [45, 40], + [30, 20] + ] + ], + [ + [ + [15, 5], + [40, 10], + [10, 20], + [5, 10], + [15, 5] + ] + ] + ], + 'type': 'MultiPolygon' + }, + jsonStr: '{"coordinates": [[[[30, 20], [10, 40], [45, 40], [30, 20]]], [[[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]]], "type": "MultiPolygon"}' + }, + + multipolygon2: { + str: 'MULTIPOLYGON(((40 40,20 45,45 30,40 40)),((20 35,45 20,30 5,10 10,10 30,20 35),(30 20,20 25,20 15,30 20)))', + cmp: [ + [ + [{ + x: 40, + y: 40 + }, { + x: 20, + y: 45 + }, { + x: 45, + y: 30 + }, { + x: 40, + y: 40 + }, ] + ], + [ + [{ + x: 20, + y: 35 + }, { + x: 45, + y: 20 + }, { + x: 30, + y: 5 + }, { + x: 10, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 20, + y: 35 + }, ], + [{ + x: 30, + y: 20 + }, { + x: 20, + y: 25 + }, { + x: 20, + y: 15 + }, { + x: 30, + y: 20 + }] + ] + ], + obj: [ + new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(40, 40), + new google.maps.LatLng(45, 20), + new google.maps.LatLng(30, 45) + ] + ] + }), + new google.maps.Polygon({ + editable: false, + paths: [ + [ + new google.maps.LatLng(35, 20), + new google.maps.LatLng(20, 45), + new google.maps.LatLng(5, 30), + new google.maps.LatLng(10, 10), + new google.maps.LatLng(30, 10) + ], + [ + new google.maps.LatLng(15, 20), + new google.maps.LatLng(25, 20), + new google.maps.LatLng(20, 30) + ] + ] + }) + ], + json: { + 'coordinates': [ + [ + [ + [40, 40], + [20, 45], + [45, 30], + [40, 40] + ] + ], + [ + [ + [20, 35], + [45, 20], + [30, 5], + [10, 10], + [10, 30], + [20, 35] + ], + [ + [30, 20], + [20, 25], + [20, 15], + [30, 20] + ] + ] + ], + 'type': 'MultiPolygon' + }, + jsonStr: '{"coordinates": [[[[40, 40], [20, 45], [45, 30], [40, 40]]], [[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]], [[30, 20], [20, 15], [20, 25], [30, 20]]]], "type": "MultiPolygon"}' + }, + + rectangle: { + str: 'POLYGON((-50 20,0 20,0 0,-50 0,-50 20))', + cmp: [ + [{ + x: -50, + y: 20 + }, { + x: 0, + y: 20 + }, { + x: 0, + y: 0 + }, { + x: -50, + y: 0 + }, { + x: -50, + y: 20 + }] + ], + obj: new google.maps.Rectangle({ + bounds: new google.maps.LatLngBounds(new google.maps.LatLng(0, -50), + new google.maps.LatLng(20, 0)) + }) + }, + + + + box: { + str: 'BOX(0 0,20 20)', + cmp: [{ + x: 0, + y: 0 + }, { + x: 20, + y: 20 + }], + obj: new google.maps.Rectangle({ + bounds: new google.maps.LatLngBounds(new google.maps.LatLng(0, 0), + new google.maps.LatLng(20, 20)) + }), + json: { + 'coordinates': [ + [ + [0, 0], + [0, 20], + [20, 20], + [20, 0], + [0, 0] + ] + ], + 'type': 'Polygon', + 'bbox': [0, 0, 20, 20] + } + }, + + geometrycollection: { + str: 'GEOMETRYCOLLECTION(POINT(30 10),LINESTRING(30 10,10 30,40 40),POLYGON((30 10,10 20,20 40,40 40,30 10)))', + json: { + "type": "GeometryCollection", + "geometries": [{ + "type": "Point", + "coordinates": [30, 10] + }, { + 'type': 'LineString', + 'coordinates': [ + [30, 10], + [10, 30], + [40, 40] + ] + }, + + { + "type": "Polygon", + "coordinates": [ + [ + [30, 10], + [10, 20], + [20, 40], + [40, 40], + [30, 10] + ] + ] + } + ] + } + } + + }; + + dataObjects = new google.maps.Data; + + + + + + describe('Converting objects into WKT strings: ', function () { + + afterEach(function () { + wkt.delimiter = ' '; + }); + + it('should convert a Marker instance into a basic POINT string', function () { + wkt.fromObject(cases.point.obj); + expect(wkt.type).toBe('point'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.point.cmp); + expect(wkt.write()).toBe(cases.point.str); + }); + + it('should convert a Polyline instance into a basic LINESTRING string', function () { + wkt.fromObject(cases.linestring.obj); + expect(wkt.type).toBe('linestring'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.linestring.cmp); + expect(wkt.write()).toBe(cases.linestring.str); + }); + + it('should convert a Polygon instance into a basic POLYGON string', function () { + wkt.fromObject(cases.polygon.obj); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon.cmp); + expect(wkt.write()).toBe(cases.polygon.str); + }); + + it('should convert a Polygon instance with a hole into a POLYGON string with the same hole', function () { + wkt.fromObject(cases.polygon2.obj); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon2.cmp); + expect(wkt.write()).toBe(cases.polygon2.str); + }); + + it('should convert a Rectangle instance into a POLYGON string', function () { + wkt.fromObject(cases.rectangle.obj); + expect(wkt.type).toBe('polygon'); + expect(wkt.isRectangle).toBe(true); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.rectangle.cmp); + expect(wkt.write()).toBe(cases.rectangle.str); + }); + + it('should convert an Array of Marker instances into a MULTIPOINT string', function () { + wkt.fromObject(cases.multipoint.obj); + expect(wkt.type).toBe('multipoint'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipoint.cmp); + expect(wkt.write()).toBe(cases.multipoint.str); + }); + + it('should convert an Array of Polyline instances into a MULTILINESTRING string', function () { + wkt.fromObject(cases.multilinestring.obj); + expect(wkt.type).toBe('multilinestring'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multilinestring.cmp); + expect(wkt.write()).toBe(cases.multilinestring.str); + }); + + it('should convert an Array of Polygon instances into a MULTIPOLYGON string', function () { + wkt.fromObject(cases.multipolygon.obj); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon.cmp); + expect(wkt.write()).toBe(cases.multipolygon.str); + }); + + it('should convert an Array of Polygon instances, some with holes, into a MULTIPOLYGON string with the same hole', function () { + wkt.fromObject(cases.multipolygon2.obj); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon2.cmp); + expect(wkt.write()).toBe(cases.multipolygon2.str); + }); + + }); + + describe('Converting google.maps.Data objects into WKT strings: ', function () { + + afterEach(function () { + wkt.delimiter = ' '; + }); + + it('should convert a google.maps.Data.Point instance into a basic POINT string', function () { + var dataPoint = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.point.json + })[0]; + wkt.fromObject(dataPoint.getGeometry()); + expect(wkt.type).toBe('point'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.point.cmp); + expect(wkt.write()).toBe(cases.point.str); + }); + + it('should convert a google.maps.Data.LineString instance into a basic LINESTRING string', function () { + var dataLineString = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.linestring.json + })[0]; + wkt.fromObject(dataLineString.getGeometry()); + expect(wkt.type).toBe('linestring'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.linestring.cmp); + expect(wkt.write()).toBe(cases.linestring.str); + }); + + it('should convert a google.maps.Data.Polygon instance into a basic POLYGON string', function () { + var dataPolygon = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.polygon.json + })[0]; + wkt.fromObject(dataPolygon.getGeometry()); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon.cmp); + expect(wkt.write()).toBe(cases.polygon.str); + }); + + it('should convert a google.maps.Data.Polygon instance with a hole into a POLYGON string with the same hole', function () { + var dataPolygon2 = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.polygon2.json + })[0]; + wkt.fromObject(dataPolygon2.getGeometry()); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon2.cmp); + expect(wkt.write()).toBe(cases.polygon2.str); + }); + + + it('should convert a google.maps.Data.MultiPoint instance into a MULTIPOINT string', function () { + var dataMultiPoint = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.multipoint.json + })[0]; + wkt.fromObject(dataMultiPoint.getGeometry()); + expect(wkt.type).toBe('multipoint'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipoint.cmp); + expect(wkt.write()).toBe(cases.multipoint.str); + }); + + it('should convert a google.maps.Data.MultiLineString instance into a MULTILINESTRING string', function () { + var dataMultiLineString = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.multilinestring.json + })[0]; + wkt.fromObject(dataMultiLineString.getGeometry()); + expect(wkt.type).toBe('multilinestring'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multilinestring.cmp); + expect(wkt.write()).toBe(cases.multilinestring.str); + }); + + it('should convert a google.maps.Data.MultiPolygon instance into a MULTIPOLYGON string', function () { + var dataMultiPolygon = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.multipolygon.json + })[0]; + wkt.fromObject(dataMultiPolygon.getGeometry()); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon.cmp); + expect(wkt.write()).toBe(cases.multipolygon.str); + }); + + it('should convert a google.maps.Data.MultiPolygon with holes, into a MULTIPOLYGON string with the same holes', function () { + var dataMultiPolygon2 = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.multipolygon2.json + })[0]; + wkt.fromObject(dataMultiPolygon2.getGeometry()); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon2.cmp); + expect(wkt.write()).toBe(cases.multipolygon2.str); + }); + + it('should convert a google.maps.Data.GeometryCollection into a GEOMETRYCOLLECTION string', function () { + var dataGeometryCollection = dataObjects.addGeoJson({ + "type": "Feature", + geometry: cases.geometrycollection.json + })[0]; + + wkt.fromObject(dataGeometryCollection.getGeometry()); + expect(wkt.type).toBe('geometrycollection'); + //expect(wkt.isCollection()).toBe(true); + + }); + + }); + + + describe('Coverting WKT strings into objects: ', function () { + + afterEach(function () { + wkt.delimiter = ' '; + }); + + it('should convert a basic POINT string to a Marker instance', function () { + wkt.read(cases.marker.str); + expect(wkt.type).toBe('point'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.marker.cmp); + expect(wkt.toObject().getPosition()).toEqual(cases.marker.obj.getPosition()); + }); + + it('should convert a basic LINESTRING string to a Polyline instance', function () { + wkt.read(cases.linestring.str); + expect(wkt.type).toBe('linestring'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.linestring.cmp); + expect(wkt.toObject().getPath()).toEqual(cases.linestring.obj.getPath()); + }); + + it('should convert a basic POLYGON string to a Polygon instance', function () { + wkt.read(cases.polygon.str); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon.cmp); + expect(wkt.toObject().getPaths()).toEqual(cases.polygon.obj.getPaths()); + }); + + it('should convert a POLYGON string with a hole to a Polygon instance with the same hole', function () { + wkt.read(cases.polygon2.str); + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.polygon2.cmp); + expect(wkt.toObject().getPaths()).toEqual(cases.polygon2.obj.getPaths()); + }); + + it('should convert a POLYGON string, with isRectangle=true, into a Rectangle instance', function () { + wkt.read(cases.rectangle.str); + wkt.isRectangle = true; + expect(wkt.type).toBe('polygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.rectangle.cmp); + expect(wkt.toObject().getBounds()).toEqual(cases.rectangle.obj.getBounds()); + expect(wkt.toObject().constructor).toEqual(google.maps.Rectangle); + }); + + it('should convert a MULTIPOINT string into an Array of Marker instances', function () { + var m; + + wkt.read(cases.multipoint.str); + expect(wkt.type).toBe('multipoint'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipoint.cmp); + + markers = wkt.toObject(); + for (m = 0; m < markers.length; m += 1) { + expect(markers[m].getPosition()).toEqual(cases.multipoint.obj[m].getPosition()); + } + }); + + it('should convert a MULTILINESTRING string into an Array of Polyline instances', function () { + wkt.read(cases.multilinestring.str); + expect(wkt.type).toBe('multilinestring'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multilinestring.cmp); + expect(wkt.toObject()).toEqual(cases.multilinestring.obj); + }); + + it('should convert a MULTIPOLYGON string into an Array of Polygon instances', function () { + wkt.read(cases.multipolygon.str); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon.cmp); + expect(wkt.toObject()).toEqual(cases.multipolygon.obj); + }); + + it('should convert a MULTIPOLYGON string with holes into an Array of Polygon instances with the same holes', function () { + wkt.read(cases.multipolygon2.str); + expect(wkt.type).toBe('multipolygon'); + expect(wkt.isCollection()).toBe(true); + expect(wkt.components).toEqual(cases.multipolygon2.cmp); + expect(wkt.toObject()).toEqual(cases.multipolygon2.obj); + }); + + it('should convert a PostGIS 2DBOX string into a Rectangle instance', function () { + wkt.read(cases.box.str); + expect(wkt.type).toBe('box'); + expect(wkt.isCollection()).toBe(false); + expect(wkt.components).toEqual(cases.box.cmp); + expect(wkt.toObject().getBounds()).toEqual(cases.box.obj.getBounds()); + }); + + }); + +}); \ No newline at end of file diff --git a/pacotes/wicket/tests/wicket-gmap3.html b/pacotes/wicket/tests/wicket-gmap3.html new file mode 100644 index 0000000..a11c594 --- /dev/null +++ b/pacotes/wicket/tests/wicket-gmap3.html @@ -0,0 +1,30 @@ + + + + + Jasmine Spec Runner v2.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pacotes/wicket/tests/wicket-spec.js b/pacotes/wicket/tests/wicket-spec.js new file mode 100644 index 0000000..020963e --- /dev/null +++ b/pacotes/wicket/tests/wicket-spec.js @@ -0,0 +1,1952 @@ +var Wkt = require('../wicket'); +var expect = require('chai').expect; + +describe('Consistent Design Patterns', function() { + + it('should read WKT string when instantiated', function() { + var wkt = new Wkt.Wkt('POINT(30 10)'); + + expect(wkt.components).deep.equal([{ + x: 30, + y: 10 + }]); + }); + + it('should correctly identify an Array', function() { + expect(Wkt.isArray([0, 1])).equal(true); + expect(Wkt.isArray({ + x: 0, + y: 1 + })).equal(false); + expect(Wkt.isArray(0)).equal(false); + expect(Wkt.isArray(new Date())).equal(false); + }); + +}); + +describe('Standard WKT Test Cases: ', function() { + var cases, wkt; + + wkt = new Wkt.Wkt(); + + cases = { + + point: { + str: 'POINT(30 10)', + cmp: [{ + x: 30, + y: 10 + }] + }, + + linestring: { + str: 'LINESTRING(30 10,10 30,40 40)', + cmp: [{ + x: 30, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 40, + y: 40 + }] + }, + + polygon: { + str: 'POLYGON((30 10,10 20,20 40,40 40,30 10))', + cmp: [ + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 20, + y: 40 + }, { + x: 40, + y: 40 + }, { + x: 30, + y: 10 + }] + ] + }, + + polygon2: { + str: 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 35,30 20,20 30))', + cmp: [ + [{ + x: 35, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 15, + y: 40 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 10 + }], + [{ + x: 20, + y: 30 + }, { + x: 35, + y: 35 + }, { + x: 30, + y: 20 + }, { + x: 20, + y: 30 + }] + ] + }, + + multipoint: { + str: 'MULTIPOINT((10 40),(40 30),(20 20),(30 10))', + cmp: [ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }] + ] + }, + + multipoint2: { + str: 'MULTIPOINT(10 40,40 30,20 20,30 10)', + cmp: [ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }] + ] + }, + + multilinestring: { + str: 'MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10))', + cmp: [ + [{ + x: 10, + y: 10 + }, { + x: 20, + y: 20 + }, { + x: 10, + y: 40 + }], + [{ + x: 40, + y: 40 + }, { + x: 30, + y: 30 + }, { + x: 40, + y: 20 + }, { + x: 30, + y: 10 + }] + ] + }, + + multipolygon: { + str: 'MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)))', + cmp: [ + [ + [{ + x: 30, + y: 20 + }, { + x: 10, + y: 40 + }, { + x: 45, + y: 40 + }, { + x: 30, + y: 20 + }, ] + ], + [ + [{ + x: 15, + y: 5 + }, { + x: 40, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 5, + y: 10 + }, { + x: 15, + y: 5 + }] + ] + ] + }, + + multipolygon2: { + str: 'MULTIPOLYGON(((40 40,20 45,45 30,40 40)),((20 35,45 20,30 5,10 10,10 30,20 35),(30 20,20 25,20 15,30 20)))', + cmp: [ + [ + [{ + x: 40, + y: 40 + }, { + x: 20, + y: 45 + }, { + x: 45, + y: 30 + }, { + x: 40, + y: 40 + }, ] + ], + [ + [{ + x: 20, + y: 35 + }, { + x: 45, + y: 20 + }, { + x: 30, + y: 5 + }, { + x: 10, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 20, + y: 35 + }, ], + [{ + x: 30, + y: 20 + }, { + x: 20, + y: 25 + }, { + x: 20, + y: 15 + }, { + x: 30, + y: 20 + }] + ] + ] + }, + + box: { + str: 'BOX(0 0,20 20)', + cmp: [{ + x: 0, + y: 0 + }, { + x: 20, + y: 20 + }] + } + + }; + + describe('Reading WKT Strings: ', function() { + + afterEach(function() { + wkt.delimiter = ' '; + }); + + it('should read basic POINT string', function() { + wkt.read(cases.point.str); + + expect(wkt.type).equal('point'); + expect(wkt.isCollection()).equal(false); + expect(wkt.components).deep.equal(cases.point.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.point.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.point.cmp); + }); + + it('should read basic LINESTRING string', function() { + wkt.read(cases.linestring.str); + + expect(wkt.type).equal('linestring'); + expect(wkt.isCollection()).equal(false); + expect(wkt.components).deep.equal(cases.linestring.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.linestring.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.linestring.cmp); + }); + + it('should read basic POLYGON string', function() { + wkt.read(cases.polygon.str); + + expect(wkt.type).equal('polygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.polygon.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.polygon.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.polygon.cmp); + }); + + it('should read basic POLYGON string with one (1) hole', function() { + wkt.read(cases.polygon2.str); + + expect(wkt.type).equal('polygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.polygon2.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.polygon2.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.polygon2.cmp); + }); + + it('should read basic MULTIPOINT string with wrapped vertices', function() { + wkt.read(cases.multipoint.str); + + expect(wkt.type).equal('multipoint'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.multipoint.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.multipoint.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.multipoint.cmp); + }); + + it('should read basic MULTIPOINT string without wrapped vertices', function() { + wkt.read(cases.multipoint2.str); + + expect(wkt.type).equal('multipoint'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.multipoint2.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.multipoint2.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.multipoint2.cmp); + }); + + it('should read basic MULTILINESTRING string', function() { + wkt.read(cases.multilinestring.str); + + expect(wkt.type).equal('multilinestring'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.multilinestring.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.multilinestring.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.multilinestring.cmp); + }); + + it('should read basic MULTIPOLYGON string', function() { + wkt.read(cases.multipolygon.str); + + expect(wkt.type).equal('multipolygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.multipolygon.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.multipolygon.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.multipolygon.cmp); + }); + + it('should read basic MULTIPOLYGON string with two (2) polygons, one with one (1) hole', function() { + wkt.read(cases.multipolygon2.str); + + expect(wkt.type).equal('multipolygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(cases.multipolygon2.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.multipolygon2.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.multipolygon2.cmp); + }); + + it('should read basic PostGIS 2DBOX string', function() { + wkt.read(cases.box.str); + + expect(wkt.type).equal('box'); + expect(wkt.isCollection()).equal(false); + expect(wkt.components).deep.equal(cases.box.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(cases.box.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(cases.box.cmp); + }); + + }); // eo describe() + + describe('Writing Well-Formed WKT Strings: ', function() { + + afterEach(function() { + wkt.wrapVertices = false; + wkt.delimiter = ' '; + }); + + it('should write basic POINT string', function() { + wkt.components = cases.point.cmp; + wkt.type = 'point'; + + expect(wkt.write()).equal(cases.point.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.point.str.replace(/ /g, '+')); + }); + + it('should write basic LINESTRING string', function() { + wkt.components = cases.linestring.cmp; + wkt.type = 'linestring'; + + expect(wkt.write()).equal(cases.linestring.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.linestring.str.replace(/ /g, '+')); + }); + + it('should write basic POLYGON string', function() { + wkt.components = cases.polygon.cmp; + wkt.type = 'polygon'; + + expect(wkt.write()).equal(cases.polygon.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.polygon.str.replace(/ /g, '+')); + }); + + it('should write basic POLYGON string with one (1) hole', function() { + wkt.components = cases.polygon2.cmp; + wkt.type = 'polygon'; + + expect(wkt.write()).equal(cases.polygon2.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.polygon2.str.replace(/ /g, '+')); + }); + + it('should write basic MULTIPOINT string with wrapped vertices', function() { + wkt.components = cases.multipoint.cmp; + wkt.type = 'multipoint'; + wkt.wrapVertices = true; + + expect(wkt.write()).equal(cases.multipoint.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.multipoint.str.replace(/ /g, '+')); + }); + + it('should write basic MULTIPOINT string without wrapped vertices', function() { + wkt.components = cases.multipoint2.cmp; + wkt.type = 'multipoint'; + wkt.wrapVertices = false; + + expect(wkt.write()).equal(cases.multipoint2.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.multipoint2.str.replace(/ /g, '+')); + }); + + it('should write basic MULTILINESTRING string', function() { + wkt.components = cases.multilinestring.cmp; + wkt.type = 'multilinestring'; + + expect(wkt.write()).equal(cases.multilinestring.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.multilinestring.str.replace(/ /g, '+')); + }); + + it('should write basic MULTIPOLYGON string', function() { + wkt.components = cases.multipolygon.cmp; + wkt.type = 'multipolygon'; + + expect(wkt.write()).equal(cases.multipolygon.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.multipolygon.str.replace(/ /g, '+')); + }); + + it('should write basic MULTIPOLYGON string with two (2) polygons, one with one (1) hole', function() { + wkt.components = cases.multipolygon2.cmp; + wkt.type = 'multipolygon'; + + expect(wkt.write()).equal(cases.multipolygon2.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.multipolygon2.str.replace(/ /g, '+')); + }); + + it('should write basic PostGIS 2DBOX string', function() { + wkt.components = cases.box.cmp; + wkt.type = 'box'; + + expect(wkt.write()).equal(cases.box.str); + + // Now try it for URLs + wkt.delimiter = '+'; + expect(wkt.write()).equal(cases.box.str.replace(/ /g, '+')); + }); + + }); + +}); // eo describe() + +describe('Arbitrary WKT Test Cases: ', function() { + var cases, wkt; + + wkt = new Wkt.Wkt(); + + function randomLat(a, b) { + var n; + + a = a || 0; + b = b || 90; + n = Math.random() * (a + (b - a)); + return (Math.random() < 0.5) ? -n : n; + }; + + function randomLng(a, b) { + var n; + + a = a || 0; + b = b || 180; + n = Math.random() * (a + (b - a)); + return (Math.random() < 0.5) ? -n : n; + }; + + function randomCoords(n, a1, b1, a2, b2) { + var i, c, cs; + + i = 0; + a1 = a1 || 0; + b1 = b1 || 180; + a2 = a2 || 0; + b2 = b2 || 90; + cs = []; + + while (i < n) { + cs.push({ + x: randomLng(a1, b1), + y: randomLat(a2, b2) + }); + i += 1; + } + + return cs; + }; + + it('should be able to read WKT strings with bizarre whitespace', function() { + wkt.read(' LINESTRING ( 30 10, 10 30, 40 40) '); + expect(wkt.write()).equal('LINESTRING(30 10,10 30,40 40)'); + }); + + it('should be able to read WKT strings with (somewhat) arbitrary precision', function() { + wkt.read('MULTIPOINT((9.12345 40),(40 30),(20 19.999999),(30 10.000001))'); + expect(wkt.write()).equal('MULTIPOINT((9.12345 40),(40 30),(20 19.999999),(30 10.000001))'); + }); + + describe('Working with Random Coordinates: ', function() { + var c; + + it('should read and write arbitrary POINT string', function() { + c = wkt.components = randomCoords(1); + wkt.type = 'point'; + + expect(wkt.read(wkt.write()).components).deep.equal(c); + }); + + it('should read and write long, arbitrary LINESTRING string', function() { + c = wkt.components = randomCoords(100); + wkt.type = 'linestring'; + + expect(wkt.read(wkt.write()).components).deep.equal(c); + }); + + it('should read and write long, arbitrary POLYGON string', function() { + c = wkt.components = [randomCoords(100)]; + wkt.type = 'polygon'; + + expect(wkt.read(wkt.write()).components).deep.equal(c); + }); + + }); +}); + +describe('Edge Cases: ', function() { + var wkt = new Wkt.Wkt(); + + afterEach(function() { + wkt.wrapVertices = false; + wkt.delimiter = ' '; + }); + + it('should read a POINT string with single-digit coordinates', function() { + var test = { + str: 'POINT(4 4)', + cmp: [{ + x: 4, + y: 4 + }] + }; + + wkt.read(test.str); + + expect(wkt.type).equal('point'); + expect(wkt.isCollection()).equal(false); + expect(wkt.components).deep.equal(test.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(test.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(test.cmp); + }); + + it('should read a LINESTRING string with single-digit coordinates', function() { + var test = { + str: 'LINESTRING(4 4,3 5,6 7)', + cmp: [{ + x: 4, + y: 4 + }, { + x: 3, + y: 5 + }, { + x: 6, + y: 7 + }] + }; + + wkt.read(test.str); + + expect(wkt.type).equal('linestring'); + expect(wkt.isCollection()).equal(false); + expect(wkt.components).deep.equal(test.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(test.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(test.cmp); + }); + + it('should read a POLYGON string with single-digit coordinates', function() { + var test = { + str: 'POLYGON((4 4,3 5,6 7,7 5,4 4))', + cmp: [ + [{ + x: 4, + y: 4 + }, { + x: 3, + y: 5 + }, { + x: 6, + y: 7 + }, { + x: 7, + y: 5 + }, { + x: 4, + y: 4 + }] + ] + }; + + wkt.read(test.str); + + expect(wkt.type).equal('polygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(test.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(test.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(test.cmp); + }); + + it('should read a POLYGON string with excess precision', function() { + var test = { + str: 'POLYGON((4.1234 4,3 5,6 7,7 5.5678,4 4))', + cmp: [ + [{ + x: 4.1234, + y: 4 + }, { + x: 3, + y: 5 + }, { + x: 6, + y: 7 + }, { + x: 7, + y: 5.5678 + }, { + x: 4, + y: 4 + }] + ] + }; + + wkt.read(test.str); + + expect(wkt.type).equal('polygon'); + expect(wkt.isCollection()).equal(true); + expect(wkt.components).deep.equal(test.cmp); + + // Now try it for URLs + wkt.delimiter = '+'; + wkt.read(test.str.replace(/ /g, '+')); + expect(wkt.components).deep.equal(test.cmp); + }); + +}); // eo describe() + +describe('Merged WKT Test Cases: ', function() { + var cases = { + + pointA: { + str: 'POINT(30 10)', + cmp: [{ + x: 30, + y: 10 + }] + }, + + pointB: { + str: 'POINT(25 45)', + cmp: [{ + x: 25, + y: 45 + }] + }, + + linestringA: { + str: 'LINESTRING(25 15,15 35,35 35)', + cmp: [{ + x: 25, + y: 15 + }, { + x: 15, + y: 35 + }, { + x: 35, + y: 35 + }] + }, + + linestringB: { + str: 'LINESTRING(30 10,10 30,40 40)', + cmp: [{ + x: 30, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 40, + y: 40 + }] + }, + + polygonA: { + str: 'POLYGON((30 10,10 20,20 40,40 40,30 10))', + cmp: [ + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 20, + y: 40 + }, { + x: 40, + y: 40 + }, { + x: 30, + y: 10 + }] + ] + }, + + polygonB: { + str: 'POLYGON((35 15,15 25,25 45,45 45,35 15))', + cmp: [ + [{ + x: 35, + y: 15 + }, { + x: 15, + y: 25 + }, { + x: 25, + y: 45 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 15 + }] + ] + }, + + polygon2A: { + str: 'POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30,35 35,30 20,20 30))', + cmp: [ + [{ + x: 35, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 15, + y: 40 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 10 + }], + [{ + x: 20, + y: 30 + }, { + x: 35, + y: 35 + }, { + x: 30, + y: 20 + }, { + x: 20, + y: 30 + }] + ] + }, + + polygon2B: { + str: 'POLYGON((135 110,110 120,115 140,145 145,135 110),(120 130,135 135,130 120,120 130))', + cmp: [ + [{ + x: 135, + y: 110 + }, { + x: 110, + y: 120 + }, { + x: 115, + y: 140 + }, { + x: 145, + y: 145 + }, { + x: 135, + y: 110 + }], + [{ + x: 120, + y: 130 + }, { + x: 135, + y: 135 + }, { + x: 130, + y: 120 + }, { + x: 120, + y: 130 + }] + ] + }, + + multipointA: { + str: 'MULTIPOINT((10 40),(40 30),(20 20),(30 10))', + cmp: [ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }] + ] + }, + + multipointB: { + str: 'MULTIPOINT((15 45),(45 35),(25 25),(35 15))', + cmp: [ + [{ + x: 15, + y: 45 + }], + [{ + x: 45, + y: 35 + }], + [{ + x: 25, + y: 25 + }], + [{ + x: 35, + y: 15 + }] + ] + }, + + multilinestringA: { + str: 'MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10))', + cmp: [ + [{ + x: 10, + y: 10 + }, { + x: 20, + y: 20 + }, { + x: 10, + y: 40 + }], + [{ + x: 40, + y: 40 + }, { + x: 30, + y: 30 + }, { + x: 40, + y: 20 + }, { + x: 30, + y: 10 + }] + ] + }, + + multilinestringB: { + str: 'MULTILINESTRING((15 15,25 25,15 45),(45 45,35 35,45 25,35 15))', + cmp: [ + [{ + x: 15, + y: 15 + }, { + x: 25, + y: 25 + }, { + x: 15, + y: 45 + }], + [{ + x: 45, + y: 45 + }, { + x: 35, + y: 35 + }, { + x: 45, + y: 25 + }, { + x: 35, + y: 15 + }] + ] + }, + + multipolygonA: { + str: 'MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)))', + cmp: [ + [ + [{ + x: 30, + y: 20 + }, { + x: 10, + y: 40 + }, { + x: 45, + y: 40 + }, { + x: 30, + y: 20 + }, ] + ], + [ + [{ + x: 15, + y: 5 + }, { + x: 40, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 5, + y: 10 + }, { + x: 15, + y: 5 + }] + ] + ] + }, + + multipolygonB: { + str: 'MULTIPOLYGON(((130 120,110 140,145 140,130 120)),((115 15,140 110,110 120,15 110,115 15)))', + cmp: [ + [ + [{ + x: 130, + y: 120 + }, { + x: 110, + y: 140 + }, { + x: 145, + y: 140 + }, { + x: 130, + y: 120 + }, ] + ], + [ + [{ + x: 115, + y: 15 + }, { + x: 140, + y: 110 + }, { + x: 110, + y: 120 + }, { + x: 15, + y: 110 + }, { + x: 115, + y: 15 + }] + ] + ] + } + + }; + + it('should merge POINT strings together', function() { + var a = new Wkt.Wkt(cases.pointA.str), + b = new Wkt.Wkt(cases.pointB.str); + + a.merge(b); + expect(a.type).equal('multipoint'); + expect(b.type).equal('point'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(false); + expect(a.write()).equal('MULTIPOINT((30 10),(25 45))'); + expect(a.components).deep.equal([ + [{ + x: 30, + y: 10 + }, { + x: 25, + y: 45 + }] + ]); + + }); + + it('should merge LINESTRING strings together', function() { + var a = new Wkt.Wkt(cases.linestringA.str), + b = new Wkt.Wkt(cases.linestringB.str); + + a.merge(b); + expect(a.type).equal('multilinestring'); + expect(b.type).equal('linestring'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(false); + expect(a.write()).equal('MULTILINESTRING((25 15,15 35,35 35),(30 10,10 30,40 40))'); + expect(a.components).deep.equal([ + [{ + x: 25, + y: 15 + }, { + x: 15, + y: 35 + }, { + x: 35, + y: 35 + }], + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 40, + y: 40 + }] + ]); + + }); + + it('should merge POLYGON strings together', function() { + var a = new Wkt.Wkt(cases.polygonA.str), + b = new Wkt.Wkt(cases.polygonB.str); + + a.merge(b); + expect(a.type).equal('multipolygon'); + expect(b.type).equal('polygon'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTIPOLYGON(((30 10,10 20,20 40,40 40,30 10)),((35 15,15 25,25 45,45 45,35 15)))'); + expect(a.components).deep.equal([ + [ + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 20, + y: 40 + }, { + x: 40, + y: 40 + }, { + x: 30, + y: 10 + }] + ], + [ + [{ + x: 35, + y: 15 + }, { + x: 15, + y: 25 + }, { + x: 25, + y: 45 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 15 + }] + ] + ]); + + }); + + it('should merge POLYGON strings together even if they have holes', function() { + var a = new Wkt.Wkt(cases.polygon2A.str), + b = new Wkt.Wkt(cases.polygon2B.str); + + a.merge(b); + expect(a.type).equal('multipolygon'); + expect(b.type).equal('polygon'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTIPOLYGON(((35 10,10 20,15 40,45 45,35 10),(20 30,35 35,30 20,20 30)),((135 110,110 120,115 140,145 145,135 110),(120 130,135 135,130 120,120 130)))'); + expect(a.components).deep.equal([ + [ + [{ + x: 35, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 15, + y: 40 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 10 + }], + [{ + x: 20, + y: 30 + }, { + x: 35, + y: 35 + }, { + x: 30, + y: 20 + }, { + x: 20, + y: 30 + }] + ], + [ + [{ + x: 135, + y: 110 + }, { + x: 110, + y: 120 + }, { + x: 115, + y: 140 + }, { + x: 145, + y: 145 + }, { + x: 135, + y: 110 + }], + [{ + x: 120, + y: 130 + }, { + x: 135, + y: 135 + }, { + x: 130, + y: 120 + }, { + x: 120, + y: 130 + }] + ] + ]); + + }); + + it('should merge MULTIPOINT strings together', function() { + var a = new Wkt.Wkt(cases.multipointA.str), + b = new Wkt.Wkt(cases.multipointB.str); + + a.merge(b); + expect(a.type).equal('multipoint'); + expect(b.type).equal('multipoint'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTIPOINT((10 40),(40 30),(20 20),(30 10),(15 45),(45 35),(25 25),(35 15))'); + expect(a.components).deep.equal([ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }], + [{ + x: 15, + y: 45 + }], + [{ + x: 45, + y: 35 + }], + [{ + x: 25, + y: 25 + }], + [{ + x: 35, + y: 15 + }] + ]); + + }); + + it('should merge MULTILINESTRING strings together', function() { + var a = new Wkt.Wkt(cases.multilinestringA.str), + b = new Wkt.Wkt(cases.multilinestringB.str); + + a.merge(b); + expect(a.type).equal('multilinestring'); + expect(b.type).equal('multilinestring'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10),(15 15,25 25,15 45),(45 45,35 35,45 25,35 15))'); + expect(a.components).deep.equal([ + [{ + x: 10, + y: 10 + }, { + x: 20, + y: 20 + }, { + x: 10, + y: 40 + }], + [{ + x: 40, + y: 40 + }, { + x: 30, + y: 30 + }, { + x: 40, + y: 20 + }, { + x: 30, + y: 10 + }], + [{ + x: 15, + y: 15 + }, { + x: 25, + y: 25 + }, { + x: 15, + y: 45 + }], + [{ + x: 45, + y: 45 + }, { + x: 35, + y: 35 + }, { + x: 45, + y: 25 + }, { + x: 35, + y: 15 + }] + ]); + + }); + + it('should merge MULTIPOLYGON strings together', function() { + var a = new Wkt.Wkt(cases.multipolygonA.str), + b = new Wkt.Wkt(cases.multipolygonB.str); + + a.merge(b); + expect(a.type).equal('multipolygon'); + expect(b.type).equal('multipolygon'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)),((130 120,110 140,145 140,130 120)),((115 15,140 110,110 120,15 110,115 15)))'); + expect(a.components).deep.equal([ + [ + [{ + x: 30, + y: 20 + }, { + x: 10, + y: 40 + }, { + x: 45, + y: 40 + }, { + x: 30, + y: 20 + }, ] + ], + [ + [{ + x: 15, + y: 5 + }, { + x: 40, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 5, + y: 10 + }, { + x: 15, + y: 5 + }] + ], + [ + [{ + x: 130, + y: 120 + }, { + x: 110, + y: 140 + }, { + x: 145, + y: 140 + }, { + x: 130, + y: 120 + }, ] + ], + [ + [{ + x: 115, + y: 15 + }, { + x: 140, + y: 110 + }, { + x: 110, + y: 120 + }, { + x: 15, + y: 110 + }, { + x: 115, + y: 15 + }] + ] + ]); + + }); + + it('should merge POINT strings into MULTIPOINT strings', function() { + var a = new Wkt.Wkt(cases.multipointA.str), + b = new Wkt.Wkt(cases.pointB.str); + + a.merge(b); + expect(a.type).equal('multipoint'); + expect(b.type).equal('point'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(false); + expect(a.write()).equal('MULTIPOINT((10 40),(40 30),(20 20),(30 10),(25 45))'); + expect(a.components).deep.equal([ + [{ + x: 10, + y: 40 + }], + [{ + x: 40, + y: 30 + }], + [{ + x: 20, + y: 20 + }], + [{ + x: 30, + y: 10 + }], + [{ + x: 25, + y: 45 + }] + ]); + + }); + + it('should merge LINESTRING strings into MULTILINESTRING strings', function() { + var a = new Wkt.Wkt(cases.multilinestringA.str), + b = new Wkt.Wkt(cases.linestringB.str); + + a.merge(b); + expect(a.type).equal('multilinestring'); + expect(b.type).equal('linestring'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(false); + expect(a.write()).equal('MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10),(30 10,10 30,40 40))'); + expect(a.components).deep.equal([ + [{ + x: 10, + y: 10 + }, { + x: 20, + y: 20 + }, { + x: 10, + y: 40 + }], + [{ + x: 40, + y: 40 + }, { + x: 30, + y: 30 + }, { + x: 40, + y: 20 + }, { + x: 30, + y: 10 + }], + [{ + x: 30, + y: 10 + }, { + x: 10, + y: 30 + }, { + x: 40, + y: 40 + }] + ]); + + }); + + it('should merge POLYGON strings into MULTIPOLYGON strings', function() { + var a = new Wkt.Wkt(cases.multipolygonA.str), + b = new Wkt.Wkt(cases.polygonB.str); + + a.merge(b); + expect(a.type).equal('multipolygon'); + expect(b.type).equal('polygon'); + expect(a.isCollection()).equal(true); + expect(b.isCollection()).equal(true); + expect(a.write()).equal('MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)),((35 15,15 25,25 45,45 45,35 15)))'); + expect(a.components).deep.equal([ + [ + [{ + x: 30, + y: 20 + }, { + x: 10, + y: 40 + }, { + x: 45, + y: 40 + }, { + x: 30, + y: 20 + }, ] + ], + [ + [{ + x: 15, + y: 5 + }, { + x: 40, + y: 10 + }, { + x: 10, + y: 20 + }, { + x: 5, + y: 10 + }, { + x: 15, + y: 5 + }] + ], + [ + [{ + x: 35, + y: 15 + }, { + x: 15, + y: 25 + }, { + x: 25, + y: 45 + }, { + x: 45, + y: 45 + }, { + x: 35, + y: 15 + }] + ] + ]); + + }); + +}); + +describe('GeoJSON Cases:', function() { + var cases = { // See: http://en.wikipedia.org/wiki/GeoJSON#Geometries + + point: { + str: 'POINT(30 10)', + json: { + 'coordinates': [30, 10], + 'type': 'Point' + }, + jsonStr: '{"coordinates": [30, 10], "type": "Point"}' + }, + + linestring: { + str: 'LINESTRING(30 10,10 30,40 40)', + json: { + 'coordinates': [ + [30, 10], + [10, 30], + [40, 40] + ], + 'type': 'LineString' + }, + jsonStr: '{"coordinates": [[30, 10], [10, 30], [40, 40]], "type": "LineString"}' + }, + + polygon: { + str: 'POLYGON((30 10,10 20,20 40,40 40,30 10))', + json: { + 'coordinates': [ + [ + [30, 10], + [10, 20], + [20, 40], + [40, 40], + [30, 10] + ] + ], + 'type': 'Polygon' + }, + jsonStr: '{"coordinates": [[[30, 10], [10, 20], [20, 40], [40, 40], [30, 10]]], "type": "Polygon"}' + }, + + polygon2: { + str: 'POLYGON((35 10,45 45,15 40,10 20,35 10),(20 30,35 35,30 20,20 30))', + json: { + 'coordinates': [ + [ + [35, 10], + [45, 45], + [15, 40], + [10, 20], + [35, 10] + ], + [ + [20, 30], + [35, 35], + [30, 20], + [20, 30] + ] + ], + 'type': 'Polygon' + }, + jsonStr: '{"coordinates": [[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]], "type": "Polygon"}' + }, + + multipolygon: { + str: 'MULTIPOLYGON(((30 20,10 40,45 40,30 20)),((15 5,40 10,10 20,5 10,15 5)))', + json: { + 'coordinates': [ + [ + [ + [30, 20], + [10, 40], + [45, 40], + [30, 20] + ] + ], + [ + [ + [15, 5], + [40, 10], + [10, 20], + [5, 10], + [15, 5] + ] + ] + ], + 'type': 'MultiPolygon' + }, + jsonStr: '{"coordinates": [[[[30, 20], [10, 40], [45, 40], [30, 20]]], [[[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]]], "type": "MultiPolygon"}' + }, + + multipolygon2: { + str: 'MULTIPOLYGON(((40 40,20 45,45 30,40 40)),((20 35,10 30,10 10,30 5,45 20,20 35),(30 20,20 15,20 25,30 20)))', + json: { + 'coordinates': [ + [ + [ + [40, 40], + [20, 45], + [45, 30], + [40, 40] + ] + ], + [ + [ + [20, 35], + [10, 30], + [10, 10], + [30, 5], + [45, 20], + [20, 35] + ], + [ + [30, 20], + [20, 15], + [20, 25], + [30, 20] + ] + ] + ], + 'type': 'MultiPolygon' + }, + jsonStr: '{"coordinates": [[[[40, 40], [20, 45], [45, 30], [40, 40]]], [[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]], [[30, 20], [20, 15], [20, 25], [30, 20]]]], "type": "MultiPolygon"}' + }, + + multipoint: { + str: 'MULTIPOINT((10 40),(40 30),(20 20),(30 10))', + json: { + 'coordinates': [ + [10, 40], + [40, 30], + [20, 20], + [30, 10] + ], + 'type': 'MultiPoint' + }, + jsonStr: '{"coordinates": [[10, 40], [40, 30], [20, 20], [30, 10]], "type": "MultiPoint"}' + }, + + multilinestring: { + str: 'MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10))', + json: { + 'coordinates': [ + [ + [10, 10], + [20, 20], + [10, 40] + ], + [ + [40, 40], + [30, 30], + [40, 20], + [30, 10] + ] + ], + 'type': 'MultiLineString' + }, + jsonStr: '{"coordinates": [[[10, 10], [20, 20], [10, 40]], [[40, 40], [30, 30], [40, 20], [30, 10]]], "type": "MultiLineString"}' + }, + + box: { + str: 'BOX(0 0,20 20)', + json: { + 'coordinates': [ + [ + [0, 0], + [0, 20], + [20, 20], + [20, 0], + [0, 0] + ] + ], + 'type': 'Polygon', + 'bbox': [0, 0, 20, 20] + } + } + + }; + + describe('GeoJSON Construction:', function() { + + it('should create valid JSON for WKT Point type', function() { + var a = new Wkt.Wkt(cases.point.str); + expect(a.toJson()).deep.equal(cases.point.json); + }); + + it('should create valid JSON for WKT LineString type', function() { + var a = new Wkt.Wkt(cases.linestring.str); + expect(a.toJson()).deep.equal(cases.linestring.json); + }); + + it('should create valid JSON for WKT Polygon type', function() { + var a = new Wkt.Wkt(cases.polygon.str); + expect(a.toJson()).deep.equal(cases.polygon.json); + }); + + it('should create valid JSON for WKT Polygon type with a hole', function() { + var a = new Wkt.Wkt(cases.polygon2.str); + expect(a.toJson()).deep.equal(cases.polygon2.json); + }); + + it('should create valid JSON for WKT MultiPolygon type', function() { + var a = new Wkt.Wkt(cases.multipolygon.str); + expect(a.toJson()).deep.equal(cases.multipolygon.json); + }); + + it('should create valid JSON for WKT MultiPolygon type with a hole', function() { + var a = new Wkt.Wkt(cases.multipolygon2.str); + expect(a.toJson()).deep.equal(cases.multipolygon2.json); + }); + + it('should create valid JSON for WKT MultiPoint type', function() { + var a = new Wkt.Wkt(cases.multipoint.str); + expect(a.toJson()).deep.equal(cases.multipoint.json); + }); + + it('should create valid JSON for WKT MultiLineString type', function() { + var a = new Wkt.Wkt(cases.multilinestring.str); + expect(a.toJson()).deep.equal(cases.multilinestring.json); + }); + + it('should create valid JSON for WKT Box type', function() { + var a = new Wkt.Wkt(cases.box.str); + expect(a.toJson()).deep.equal(cases.box.json); + }); + + }); + + describe('GeoJSON Deconstruction (from Objects):', function() { + + it('should write the WKT string corresponding to a GeoJSON Point', function() { + var a = new Wkt.Wkt(cases.point.json); + expect(a.write()).deep.equal(cases.point.str); + }); + + it('should write the WKT string corresponding to a GeoJSON LineString', function() { + var a = new Wkt.Wkt(cases.linestring.json); + expect(a.write()).deep.equal(cases.linestring.str); + }); + + it('should write the WKT string corresponding to a GeoJSON Polygon', function() { + var a = new Wkt.Wkt(cases.polygon.json); + expect(a.write()).deep.equal(cases.polygon.str); + }); + + it('should write the WKT string corresponding to a GeoJSON Polygon with a hole', function() { + var a = new Wkt.Wkt(cases.polygon2.json); + expect(a.write()).deep.equal(cases.polygon2.str); + }); + + it('should write the WKT string corresponding to a GeoJSON MultiPolygon', function() { + var a = new Wkt.Wkt(cases.multipolygon.json); + expect(a.write()).deep.equal(cases.multipolygon.str); + }); + + it('should write the WKT string corresponding to a GeoJSON MultiPolygon with a hole', function() { + var a = new Wkt.Wkt(cases.multipolygon2.json); + expect(a.write()).deep.equal(cases.multipolygon2.str); + }); + + it('should write the WKT string corresponding to a GeoJSON MultiPoint', function() { + var a = new Wkt.Wkt(cases.multipoint.json); + expect(a.write()).deep.equal(cases.multipoint.str); + }); + + it('should write the WKT string corresponding to a GeoJSON MultiLineString', function() { + var a = new Wkt.Wkt(cases.multilinestring.json); + expect(a.write()).deep.equal(cases.multilinestring.str); + }); + + }); + + describe('GeoJSON Deconstruction (from Strings):', function() { + it('should provide support for JSON.parse() in the environment...', function() { + expect(typeof JSON).deep.equal('object'); + expect(typeof JSON.parse).deep.equal('function'); + }); + + it('should parse a GeoJSON Point string', function() { + var a = new Wkt.Wkt(cases.point.jsonStr); + expect(a.write()).deep.equal(cases.point.str); + }); + + it('should parse a GeoJSON LineString string', function() { + var a = new Wkt.Wkt(cases.linestring.jsonStr); + expect(a.write()).deep.equal(cases.linestring.str); + }); + + it('should parse a GeoJSON Polygon string', function() { + var a = new Wkt.Wkt(cases.polygon.jsonStr); + expect(a.write()).deep.equal(cases.polygon.str); + }); + + it('should parse a GeoJSON Polygon string with a hole', function() { + var a = new Wkt.Wkt(cases.polygon2.jsonStr); + expect(a.write()).deep.equal(cases.polygon2.str); + }); + + it('should parse a GeoJSON MultiPolygon string', function() { + var a = new Wkt.Wkt(cases.multipolygon.jsonStr); + expect(a.write()).deep.equal(cases.multipolygon.str); + }); + + it('should parse a GeoJSON MultiPolygon string with a hole', function() { + var a = new Wkt.Wkt(cases.multipolygon2.jsonStr); + expect(a.write()).deep.equal(cases.multipolygon2.str); + }); + + it('should parse a GeoJSON MultiPoint string', function() { + var a = new Wkt.Wkt(cases.multipoint.jsonStr); + expect(a.write()).deep.equal(cases.multipoint.str); + }); + + it('should parse a GeoJSON MultiLineString string', function() { + var a = new Wkt.Wkt(cases.multilinestring.jsonStr); + expect(a.write()).deep.equal(cases.multilinestring.str); + }); + + }); + +}); diff --git a/pacotes/wicket/wicket-arcgis.js b/pacotes/wicket/wicket-arcgis.js new file mode 100644 index 0000000..1c7fe44 --- /dev/null +++ b/pacotes/wicket/wicket-arcgis.js @@ -0,0 +1,392 @@ +/** @license + * + * Copyright (C) 2012 K. Arthur Endsley (kaendsle@mtu.edu) + * Michigan Tech Research Institute (MTRI) + * 3600 Green Court, Suite 100, Ann Arbor, MI, 48105 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +if (!Array.prototype.map) { + Array.prototype.map = function (fun /* thisArg? */) { + 'use strict'; + var t, len, res, thisArg; + + if (this === void 0 || this === null) { + throw new TypeError(); + } + + t = Object(this); + len = t.length >>> 0; + + if (typeof fun !== 'function') { + throw new TypeError(); + } + + res = new Array(len); + thisArg = arguments.length >= 2 ? arguments[1] : void 0; + + for (var i = 0; i < len; i++) { + // NOTE: Absolute correctness would demand Object.defineProperty + // be used. But this method is fairly new, and failure is + // possible only if Object.prototype or Array.prototype + // has a property |i| (very unlikely), so use a less-correct + // but more portable alternative. + if (i in t) { + res[i] = fun.call(thisArg, t[i], i, t); + } + } + + return res; + }; +} + +/** + * @augments Wkt.Wkt + * A framework-dependent flag, set for each Wkt.Wkt() instance, that indicates + * whether or not a closed polygon geometry should be interpreted as a rectangle. + */ +Wkt.Wkt.prototype.isRectangle = false; + +/** + * @augments Wkt.Wkt + * An object of framework-dependent construction methods used to generate + * objects belonging to the various geometry classes of the framework. + */ +Wkt.Wkt.prototype.construct = { + /** + * Creates the framework's equivalent point geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {esri.geometry.Point} + */ + point: function (config, component) { + var coord = component || this.components; + if (coord instanceof Array) { + coord = coord[0]; + } + + if (config) { + // Allow the specification of a coordinate system + coord.spatialReference = config.spatialReference || config.srs; + } + + return new esri.geometry.Point(coord); + }, + + /** + * Creates the framework's equivalent multipoint geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {esri.geometry.Multipoint} + */ + multipoint: function (config) { + config = config || {}; + if (!config.spatialReference && config.srs) { + config.spatialReference = config.srs; + } + + return new esri.geometry.Multipoint({ + // Create an Array of [x, y] coords from each point among the components + points: this.components.map(function (i) { + if (Wkt.isArray(i)) { + i = i[0]; // Unwrap coords + } + return [i.x, i.y]; + }), + spatialReference: config.spatialReference + }); + }, + + /** + * Creates the framework's equivalent linestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {esri.geometry.Polyline} + */ + linestring: function (config) { + config = config || {}; + if (!config.spatialReference && config.srs) { + config.spatialReference = config.srs; + } + + return new esri.geometry.Polyline({ + // Create an Array of paths... + paths: [ + this.components.map(function (i) { + return [i.x, i.y]; + }) + ], + spatialReference: config.spatialReference + }); + }, + + /** + * Creates the framework's equivalent multilinestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {esri.geometry.Polyline} + */ + multilinestring: function (config) { + config = config || {}; + if (!config.spatialReference && config.srs) { + config.spatialReference = config.srs; + } + + return new esri.geometry.Polyline({ + // Create an Array of paths... + paths: this.components.map(function (i) { + // ...Within which are Arrays of coordinate pairs (vertices) + return i.map(function (j) { + return [j.x, j.y]; + }); + }), + spatialReference: config.spatialReference + }); + }, + + /** + * Creates the framework's equivalent polygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {esri.geometry.Polygon} + */ + polygon: function (config) { + config = config || {}; + if (!config.spatialReference && config.srs) { + config.spatialReference = config.srs; + } + + return new esri.geometry.Polygon({ + // Create an Array of rings... + rings: this.components.map(function (i) { + // ...Within which are Arrays of coordinate pairs (vertices) + return i.map(function (j) { + return [j.x, j.y]; + }); + }), + spatialReference: config.spatialReference + }); + }, + + /** + * Creates the framework's equivalent multipolygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {esri.geometry.Polygon} + */ + multipolygon: function (config) { + var that = this; + config = config || {}; + if (!config.spatialReference && config.srs) { + config.spatialReference = config.srs; + } + + return new esri.geometry.Polygon({ + // Create an Array of rings... + rings: (function () { + var i, j, holey, newRings, rings; + + holey = false; // Assume there are no inner rings (holes) + rings = that.components.map(function (i) { + // ...Within which are Arrays of (outer) rings (polygons) + var rings = i.map(function (j) { + // ...Within which are (possibly) Arrays of (inner) rings (holes) + return j.map(function (k) { + return [k.x, k.y]; + }); + }); + + holey = (rings.length > 1); + + return rings; + }); + + if (!holey && rings[0].length > 1) { // Easy, if there are no inner rings (holes) + // But we add the second condition to check that we're not too deeply nested + return rings; + } + + newRings = []; + for (i = 0; i < rings.length; i += 1) { + if (rings[i].length > 1) { + for (j = 0; j < rings[i].length; j += 1) { + newRings.push(rings[i][j]); + } + } else { + newRings.push(rings[i][0]); + } + } + + return newRings; + + }()), + spatialReference: config.spatialReference + }); + } + +}; + +/** + * A test for determining whether one ring is an inner ring of another; tests + * to see whether the first argument (ring1) is an inner ring of the second + * (ring2) argument + * @param ring1 {Array} An Array of vertices that describe a ring in an esri.geometry.Polygon instance + * @param ring2 {Array} An Array of vertices that describe a ring in an esri.geometry.Polygon instance + * @param srs {esri.SpatialReference} The SRS to conduct this test within + * @return {Boolean} + */ +Wkt.isInnerRingOf = function (ring1, ring2, srs) { + var contained, i, ply, pnt; + + // Though less common, we assume that the first ring is an inner ring of the + // second as this is a stricter case (all vertices must be contained); + // we'll test this against the contrary where at least one vertex of the + // first ring is not contained by the second ring (ergo, not an inner ring) + contained = true; + + ply = new esri.geometry.Polygon({ // Create single polygon from second ring + rings: ring2.map(function (i) { + // ...Within which are Arrays of coordinate pairs (vertices) + return i.map(function (j) { + return [j.x, j.y]; + }); + }), + spatialReference: srs + }); + + for (i = 0; i < ring1.length; i += 1) { + // Sample a vertex of the first ring + pnt = new esri.geometry.Point(ring1[i].x, ring1[i].y, srs); + + // Now we have a test for inner rings: if the second ring does not + // contain every vertex of the first, then the first ring cannot be + // an inner ring of the second + if (!ply.contains(pnt)) { + contained = false; + break; + } + } + + return contained; +}; + +/** + * @augments Wkt.Wkt + * A framework-dependent deconstruction method used to generate internal + * geometric representations from instances of framework geometry. This method + * uses object detection to attempt to classify members of framework geometry + * classes into the standard WKT types. + * @param obj {Object} An instance of one of the framework's geometry classes + * @return {Object} A hash of the 'type' and 'components' thus derived + */ +Wkt.Wkt.prototype.deconstruct = function (obj) { + var i, j, paths, rings, verts; + + // esri.geometry.Point ///////////////////////////////////////////////////// + if (obj.constructor === esri.geometry.Point) { + + return { + type: 'point', + components: [{ + x: obj.getLongitude(), + y: obj.getLatitude() + }] + }; + + } + + // esri.geometry.Multipoint //////////////////////////////////////////////// + if (obj.constructor === esri.geometry.Multipoint) { + + verts = []; + for (i = 0; i < obj.points.length; i += 1) { + verts.push([{ + x: obj.points[i][0], + y: obj.points[i][1] + }]); + } + + return { + type: 'multipoint', + components: verts + }; + + } + + // esri.geometry.Polyline ////////////////////////////////////////////////// + if (obj.constructor === esri.geometry.Polyline) { + + paths = []; + for (i = 0; i < obj.paths.length; i += 1) { + verts = []; + for (j = 0; j < obj.paths[i].length; j += 1) { + verts.push({ + x: obj.paths[i][j][0], // First item is longitude, second is latitude + y: obj.paths[i][j][1] + }); + } + paths.push(verts); + } + + if (obj.paths.length > 1) { // More than one path means more than one linestring + return { + type: 'multilinestring', + components: paths + }; + } + + return { + type: 'linestring', + components: verts + }; + + } + + // esri.geometry.Polygon /////////////////////////////////////////////////// + if (obj.constructor === esri.geometry.Polygon) { + + rings = []; + for (i = 0; i < obj.rings.length; i += 1) { + verts = []; + + for (j = 0; j < obj.rings[i].length; j += 1) { + verts.push({ + x: obj.rings[i][j][0], // First item is longitude, second is latitude + y: obj.rings[i][j][1] + }); + } + + if (i > 0) { + if (Wkt.isInnerRingOf(verts, rings[i - 1], obj.spatialReference)) { + rings[rings.length - 1].push(verts); + } else { + rings.push([verts]); + } + } else { + rings.push([verts]); + } + + } + + if (rings.length > 1) { + return { + type: 'multipolygon', + components: rings + }; + } + + return { + type: 'polygon', + components: rings[0] + }; + + } +}; \ No newline at end of file diff --git a/pacotes/wicket/wicket-gmap3.js b/pacotes/wicket/wicket-gmap3.js index ba14b83..343af69 100644 --- a/pacotes/wicket/wicket-gmap3.js +++ b/pacotes/wicket/wicket-gmap3.js @@ -1,8 +1,729 @@ -google.maps.Marker.prototype.type="marker";google.maps.Polyline.prototype.type="polyline";google.maps.Polygon.prototype.type="polygon";google.maps.Rectangle.prototype.type="rectangle";google.maps.Circle.prototype.type="circle"; -Wkt.Wkt.prototype.construct={point:function(config,component){var c=component||this.components;config=config||{};config.position=new google.maps.LatLng(c[0].y,c[0].x);return new google.maps.Marker(config)},multipoint:function(config){var i,c,arr;c=this.components;config=config||{};arr=[];for(i=0;i1)verts=[verts];rings.push(verts)}return{type:"polygon",components:rings}}else if(obj.getBounds&&!obj.getRadius){tmp=obj.getBounds();return{type:"polygon",isRectangle:true,components:[[{x:tmp.getSouthWest().lng(),y:tmp.getNorthEast().lat()},{x:tmp.getNorthEast().lng(),y:tmp.getNorthEast().lat()},{x:tmp.getNorthEast().lng(), -y:tmp.getSouthWest().lat()},{x:tmp.getSouthWest().lng(),y:tmp.getSouthWest().lat()},{x:tmp.getSouthWest().lng(),y:tmp.getNorthEast().lat()}]]}}else if(obj.getBounds&&obj.getRadius)console.log("Deconstruction of google.maps.Circle objects is not yet supported");else console.log("The passed object does not have any recognizable properties.")};Wkt.Wkt.prototype.isRectangle=false; +/** @license + * + * Copyright (C) 2012 K. Arthur Endsley (kaendsle@mtu.edu) + * Michigan Tech Research Institute (MTRI) + * 3600 Green Court, Suite 100, Ann Arbor, MI, 48105 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +(function (Wkt) { + + /** + * @augments Wkt.Wkt + * A framework-dependent flag, set for each Wkt.Wkt() instance, that indicates + * whether or not a closed polygon geometry should be interpreted as a rectangle. + */ + Wkt.Wkt.prototype.isRectangle = false; + + /** + * @augments Wkt.Wkt + * An object of framework-dependent construction methods used to generate + * objects belonging to the various geometry classes of the framework. + */ + Wkt.Wkt.prototype.construct = { + /** + * Creates the framework's equivalent point geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {google.maps.Marker} + */ + point: function (config, component) { + var c = component || this.components; + + config = config || {}; + + config.position = new google.maps.LatLng(c[0].y, c[0].x); + + return new google.maps.Marker(config); + }, + + /** + * Creates the framework's equivalent multipoint geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {Array} Array containing multiple google.maps.Marker + */ + multipoint: function (config) { + var i, c, arr; + + c = this.components; + + config = config || {}; + + arr = []; + + for (i = 0; i < c.length; i += 1) { + arr.push(this.construct.point(config, c[i])); + } + + return arr; + }, + + /** + * Creates the framework's equivalent linestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {google.maps.Polyline} + */ + linestring: function (config, component) { + var i, c; + + c = component || this.components; + + config = config || { + editable: false + }; + + config.path = []; + + for (i = 0; i < c.length; i += 1) { + config.path.push(new google.maps.LatLng(c[i].y, c[i].x)); + } + + return new google.maps.Polyline(config); + }, + + /** + * Creates the framework's equivalent multilinestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {Array} Array containing multiple google.maps.Polyline instances + */ + multilinestring: function (config) { + var i, c, arr; + + c = this.components; + + config = config || { + editable: false + }; + + config.path = []; + + arr = []; + + for (i = 0; i < c.length; i += 1) { + arr.push(this.construct.linestring(config, c[i])); + } + + return arr; + }, + + /** + * Creates the framework's equivalent Box or Rectangle geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {google.maps.Rectangle} + */ + box: function (config, component) { + var c = component || this.components; + + config = config || {}; + + config.bounds = new google.maps.LatLngBounds( + new google.maps.LatLng(c[0].y, c[0].x), + new google.maps.LatLng(c[1].y, c[1].x)); + + return new google.maps.Rectangle(config); + }, + + /** + * Creates the framework's equivalent polygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {google.maps.Polygon} + */ + polygon: function (config, component) { + var j, k, c, rings, verts; + + c = component || this.components; + + config = config || { + editable: false // Editable geometry off by default + }; + + config.paths = []; + + rings = []; + for (j = 0; j < c.length; j += 1) { // For each ring... + + verts = []; + // NOTE: We iterate to one (1) less than the Array length to skip the last vertex + for (k = 0; k < c[j].length - 1; k += 1) { // For each vertex... + verts.push(new google.maps.LatLng(c[j][k].y, c[j][k].x)); + + } // eo for each vertex + + if (j !== 0) { // Reverse the order of coordinates in inner rings + if (config.reverseInnerPolygons == null || config.reverseInnerPolygons) { + verts.reverse(); + } + } + + rings.push(verts); + } // eo for each ring + + config.paths = config.paths.concat(rings); + + if (this.isRectangle) { + return (function () { + var bounds, v; + + bounds = new google.maps.LatLngBounds(); + + for (v in rings[0]) { // Ought to be only 1 ring in a Rectangle + if (rings[0].hasOwnProperty(v)) { + bounds.extend(rings[0][v]); + } + } + + return new google.maps.Rectangle({ + bounds: bounds + }); + }()); + } else { + return new google.maps.Polygon(config); + } + }, + + /** + * Creates the framework's equivalent multipolygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {Array} Array containing multiple google.maps.Polygon + */ + multipolygon: function (config) { + var i, c, arr; + + c = this.components; + + config = config || { + editable: false + }; + + config.path = []; + + arr = []; + + for (i = 0; i < c.length; i += 1) { + arr.push(this.construct.polygon(config, c[i])); + } + + return arr; + } + + }; + + /** + * @augments Wkt.Wkt + * A framework-dependent deconstruction method used to generate internal + * geometric representations from instances of framework geometry. This method + * uses object detection to attempt to classify members of framework geometry + * classes into the standard WKT types. + * @param obj {Object} An instance of one of the framework's geometry classes + * @param multiFlag {Boolean} If true, then the deconstructor will be forced to return a MultiGeometry (multipoint, multilinestring or multipolygon) + * @return {Object} A hash of the 'type' and 'components' thus derived, plus the WKT string of the feature. + */ + Wkt.Wkt.prototype.deconstruct = function (obj, multiFlag) { + var features, i, j, multiFlag, verts, rings, sign, tmp, response, lat, lng; + + // Shortcut to signed area function (determines clockwise vs counter-clock) + if (google.maps.geometry) { + sign = google.maps.geometry.spherical.computeSignedArea; + }; + + // google.maps.LatLng ////////////////////////////////////////////////////// + if (obj.constructor === google.maps.LatLng) { + + response = { + type: 'point', + components: [{ + x: obj.lng(), + y: obj.lat() + }] + }; + return response; + } + + // google.maps.Point ////////////////////////////////////////////////////// + if (obj.constructor === google.maps.Point) { + response = { + type: 'point', + components: [{ + x: obj.x, + y: obj.y + }] + }; + return response; + } + + // google.maps.Marker ////////////////////////////////////////////////////// + if (obj.constructor === google.maps.Marker) { + response = { + type: 'point', + components: [{ + x: obj.getPosition().lng(), + y: obj.getPosition().lat() + }] + }; + return response; + } + + // google.maps.Polyline //////////////////////////////////////////////////// + if (obj.constructor === google.maps.Polyline) { + + verts = []; + for (i = 0; i < obj.getPath().length; i += 1) { + tmp = obj.getPath().getAt(i); + verts.push({ + x: tmp.lng(), + y: tmp.lat() + }); + } + response = { + type: 'linestring', + components: verts + }; + return response; + + } + + // google.maps.Polygon ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Polygon) { + + rings = []; + + if (multiFlag === undefined) { + multiFlag = (function () { + var areas, i, l; + + l = obj.getPaths().length; + if (l <= 1) { // Trivial; this is a single polygon + return false; + } + + if (l === 2) { + // If clockwise*clockwise or counter*counter, i.e. + // (-1)*(-1) or (1)*(1), then result would be positive + if (sign(obj.getPaths().getAt(0)) * sign(obj.getPaths().getAt(1)) < 0) { + return false; // Most likely single polygon with 1 hole + } + + return true; + } + + // Must be longer than 3 polygons at this point... + areas = obj.getPaths().getArray().map(function (k) { + return sign(k) / Math.abs(sign(k)); // Unit normalization (outputs 1 or -1) + }); + + // If two clockwise or two counter-clockwise rings are found + // (at different indices)... + if (areas.indexOf(areas[0]) !== areas.lastIndexOf(areas[0])) { + multiFlag = true; // Flag for holes in one or more polygons + return true; + } + + return false; + + }()); + } + + for (i = 0; i < obj.getPaths().length; i += 1) { // For each polygon (ring)... + tmp = obj.getPaths().getAt(i); + verts = []; + for (j = 0; j < obj.getPaths().getAt(i).length; j += 1) { // For each vertex... + verts.push({ + x: tmp.getAt(j).lng(), + y: tmp.getAt(j).lat() + }); + + } + + if (!tmp.getAt(tmp.length - 1).equals(tmp.getAt(0))) { + if (i % 2 !== 0) { // In inner rings, coordinates are reversed... + verts.unshift({ // Add the first coordinate again for closure + x: tmp.getAt(tmp.length - 1).lng(), + y: tmp.getAt(tmp.length - 1).lat() + }); + + } else { + verts.push({ // Add the first coordinate again for closure + x: tmp.getAt(0).lng(), + y: tmp.getAt(0).lat() + }); + + } + + } + + if (obj.getPaths().length > 1 && i > 0) { + // If this and the last ring have the same signs... + if (sign(obj.getPaths().getAt(i)) > 0 && sign(obj.getPaths().getAt(i - 1)) > 0 || + sign(obj.getPaths().getAt(i)) < 0 && sign(obj.getPaths().getAt(i - 1)) < 0 && !multiFlag) { + // ...They must both be inner rings (or both be outer rings, in a multipolygon) + verts = [verts]; // Wrap multipolygons once more (collection) + } + + } + + //TODO This makes mistakes when a second polygon has holes; it sees them all as individual polygons + if (i % 2 !== 0) { // In inner rings, coordinates are reversed... + verts.reverse(); + } + rings.push(verts); + } + + response = { + type: (multiFlag) ? 'multipolygon' : 'polygon', + components: rings + }; + return response; + + } + + // google.maps.Circle ////////////////////////////////////////////////////// + if (obj.constructor === google.maps.Circle) { + var point = obj.getCenter(); + var radius = obj.getRadius(); + verts = []; + var d2r = Math.PI / 180; // degrees to radians + var r2d = 180 / Math.PI; // radians to degrees + radius = radius / 1609; // meters to miles + var earthsradius = 3963; // 3963 is the radius of the earth in miles + var num_seg = 32; // number of segments used to approximate a circle + var rlat = (radius / earthsradius) * r2d; + var rlng = rlat / Math.cos(point.lat() * d2r); + + for (var n = 0; n <= num_seg; n++) { + var theta = Math.PI * (n / (num_seg / 2)); + lng = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta) + lat = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta) + verts.push({ + x: lng, + y: lat + }); + } + + response = { + type: 'polygon', + components: [verts] + }; + + return response; + + } + + // google.maps.LatLngBounds /////////////////////////////////////////////////// + if (obj.constructor === google.maps.LatLngBounds) { + + tmp = obj; + verts = []; + verts.push({ // NW corner + x: tmp.getSouthWest().lng(), + y: tmp.getNorthEast().lat() + }); + + verts.push({ // NE corner + x: tmp.getNorthEast().lng(), + y: tmp.getNorthEast().lat() + }); + + verts.push({ // SE corner + x: tmp.getNorthEast().lng(), + y: tmp.getSouthWest().lat() + }); + + verts.push({ // SW corner + x: tmp.getSouthWest().lng(), + y: tmp.getSouthWest().lat() + }); + + verts.push({ // NW corner (again, for closure) + x: tmp.getSouthWest().lng(), + y: tmp.getNorthEast().lat() + }); + + + response = { + type: 'polygon', + isRectangle: true, + components: [verts] + }; + + return response; + + } + + // google.maps.Rectangle /////////////////////////////////////////////////// + if (obj.constructor === google.maps.Rectangle) { + + tmp = obj.getBounds(); + verts = []; + verts.push({ // NW corner + x: tmp.getSouthWest().lng(), + y: tmp.getNorthEast().lat() + }); + + verts.push({ // NE corner + x: tmp.getNorthEast().lng(), + y: tmp.getNorthEast().lat() + }); + + verts.push({ // SE corner + x: tmp.getNorthEast().lng(), + y: tmp.getSouthWest().lat() + }); + + verts.push({ // SW corner + x: tmp.getSouthWest().lng(), + y: tmp.getSouthWest().lat() + }); + + verts.push({ // NW corner (again, for closure) + x: tmp.getSouthWest().lng(), + y: tmp.getNorthEast().lat() + }); + + + response = { + type: 'polygon', + isRectangle: true, + components: [verts] + }; + + return response; + + } + + // google.maps.Data Geometry Types ///////////////////////////////////////////////////// + + // google.maps.Data.Feature ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.Feature) { + return this.deconstruct.call(this, obj.getGeometry()); + } + + // google.maps.Data.Point ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.Point) { + //console.log('It is a google.maps.Data.Point'); + response = { + type: 'point', + components: [{ + x: obj.get().lng(), + y: obj.get().lat() + }] + }; + return response; + } + + // google.maps.Data.LineString ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.LineString) { + verts = []; + //console.log('It is a google.maps.Data.LineString'); + for (i = 0; i < obj.getLength(); i += 1) { + vertex = obj.getAt(i); + verts.push({ + x: vertex.lng(), + y: vertex.lat() + }); + } + response = { + type: 'linestring', + components: verts + }; + return response; + } + + + + + // google.maps.Data.Polygon ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.Polygon) { + var rings = []; + //console.log('It is a google.maps.Data.Polygon'); + for (i = 0; i < obj.getLength(); i += 1) { // For each ring... + ring = obj.getAt(i); + var verts = []; + for (j = 0; j < ring.getLength(); j += 1) { // For each vertex... + vertex = ring.getAt(j); + verts.push({ + x: vertex.lng(), + y: vertex.lat() + }); + } + verts.push({ + x: ring.getAt(0).lng(), + y: ring.getAt(0).lat() + }); + + rings.push(verts); + } + response = { + type: 'polygon', + components: rings + }; + + return response; + } + + + // google.maps.Data.MultiPoint ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.MultiPoint) { + verts = []; + for (i = 0; i < obj.getLength(); i += 1) { + vertex = obj.getAt(i); + verts.push([{ + x: vertex.lng(), + y: vertex.lat() + }]); + } + response = { + type: 'multipoint', + components: verts + }; + return response; + } + + // google.maps.Data.MultiLineString ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.MultiLineString) { + linestrings = [] + for (i = 0; i < obj.getLength(); i += 1) { + verts = []; + var linestring = obj.getAt(i); + for (j = 0; j < linestring.getLength(); j += 1) { + vertex = linestring.getAt(j); + verts.push({ + x: vertex.lng(), + y: vertex.lat() + }); + } + linestrings.push(verts); + } + response = { + type: 'multilinestring', + components: linestrings + }; + return response; + } + + // google.maps.Data.MultiPolygon ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.MultiPolygon) { + + var polygons = []; + + //console.log('It is a google.maps.Data.MultiPolygon'); + for (k = 0; k < obj.getLength(); k += 1) { // For each multipolygon + var polygon = obj.getAt(k); + var rings = []; + for (i = 0; i < polygon.getLength(); i += 1) { // For each ring... + ring = polygon.getAt(i); + var verts = []; + for (j = 0; j < ring.getLength(); j += 1) { // For each vertex... + vertex = ring.getAt(j); + verts.push({ + x: vertex.lng(), + y: vertex.lat() + }); + } + verts.push({ + x: ring.getAt(0).lng(), + y: ring.getAt(0).lat() + }); + + rings.push(verts); + } + polygons.push(rings); + } + + response = { + type: 'multipolygon', + components: polygons + }; + return response; + } + + // google.maps.Data.GeometryCollection ///////////////////////////////////////////////////// + if (obj.constructor === google.maps.Data.GeometryCollection) { + + var objects = []; + for (k = 0; k < obj.getLength(); k += 1) { // For each multipolygon + var object = obj.getAt(k); + objects.push(this.deconstruct.call(this, object)); + } + //console.log('It is a google.maps.Data.GeometryCollection', objects); + response = { + type: 'geometrycollection', + components: objects + }; + return response; + } + + + // Array /////////////////////////////////////////////////////////////////// + if (Wkt.isArray(obj)) { + features = []; + + for (i = 0; i < obj.length; i += 1) { + features.push(this.deconstruct.call(this, obj[i], true)); + } + + response = { + + type: (function () { + var k, type = obj[0].constructor; + + for (k = 0; k < obj.length; k += 1) { + // Check that all items have the same constructor as the first item + if (obj[k].constructor !== type) { + // If they don't, type is heterogeneous geometry collection + return 'geometrycollection'; + } + } + + switch (type) { + case google.maps.Marker: + return 'multipoint'; + case google.maps.Polyline: + return 'multilinestring'; + case google.maps.Polygon: + return 'multipolygon'; + default: + return 'geometrycollection'; + } + + }()), + components: (function () { + // Pluck the components from each Wkt + var i, comps; + + comps = []; + for (i = 0; i < features.length; i += 1) { + if (features[i].components) { + comps.push(features[i].components); + } + } + + return { + comps: comps + }; + }()) + + }; + response.components = response.components.comps; + return response; + + } + + console.log('The passed object does not have any recognizable properties.'); + + }; +}(Wkt || require('./wicket'))); diff --git a/pacotes/wicket/wicket-leaflet.js b/pacotes/wicket/wicket-leaflet.js index 9d446ed..a87a50f 100644 --- a/pacotes/wicket/wicket-leaflet.js +++ b/pacotes/wicket/wicket-leaflet.js @@ -1,4 +1,408 @@ -Wkt.Wkt.prototype.isRectangle=false; -Wkt.Wkt.prototype.construct={point:function(config,component){var coord=component||this.components;if(coord instanceof Array)coord=coord[0];return L.marker(this.coordsToLatLng(coord),config)},multipoint:function(config){var layers=[],coords=this.components,latlng;for(var i=0,len=coords.length;i. + * + */ + +/** + * @augments Wkt.Wkt + * A framework-dependent flag, set for each Wkt.Wkt() instance, that indicates + * whether or not a closed polygon geometry should be interpreted as a rectangle. + */ +Wkt.Wkt.prototype.isRectangle = false; + +/** + * @augments Wkt.Wkt + * Truncates an Array of coordinates by the closing coordinate when it is + * equal to the first coordinate given--this is only to be used for closed + * geometries in order to provide merely an "implied" closure to Leaflet. + * @param coords {Array} An Array of x,y coordinates (objects) + * @return {Array} + */ +Wkt.Wkt.prototype.trunc = function (coords) { + var i, verts = []; + + for (i = 0; i < coords.length; i += 1) { + if (Wkt.isArray(coords[i])) { + verts.push(this.trunc(coords[i])); + + } else { + + // Add the first coord, but skip the last if it is identical + if (i === 0 || !this.sameCoords(coords[0], coords[i])) { + verts.push(coords[i]); + } + } + } + + return verts; +}; + +/** + * @augments Wkt.Wkt + * An object of framework-dependent construction methods used to generate + * objects belonging to the various geometry classes of the framework. + */ +Wkt.Wkt.prototype.construct = { + /** + * Creates the framework's equivalent point geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {L.marker} + */ + point: function (config, component) { + var coord = component || this.components; + if (coord instanceof Array) { + coord = coord[0]; + } + + return L.marker(this.coordsToLatLng(coord), config); + }, + + /** + * Creates the framework's equivalent multipoint geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {L.featureGroup} + */ + multipoint: function (config) { + var i, + layers = [], + coords = this.components; + + for (i = 0; i < coords.length; i += 1) { + layers.push(this.construct.point.call(this, config, coords[i])); + } + + return L.featureGroup(layers, config); + }, + + /** + * Creates the framework's equivalent linestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @param component {Object} An optional component to build from + * @return {L.polyline} + */ + linestring: function (config, component) { + var coords = component || this.components, + latlngs = this.coordsToLatLngs(coords); + + return L.polyline(latlngs, config); + }, + + /** + * Creates the framework's equivalent multilinestring geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {L.multiPolyline} + */ + multilinestring: function (config) { + var coords = this.components, + latlngs = this.coordsToLatLngs(coords, 1); + + return L.multiPolyline(latlngs, config); + }, + + /** + * Creates the framework's equivalent polygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {L.multiPolygon} + */ + polygon: function (config) { + // Truncate the coordinates to remove the closing coordinate + var coords = this.trunc(this.components), + latlngs = this.coordsToLatLngs(coords, 1); + return L.polygon(latlngs, config); + }, + + /** + * Creates the framework's equivalent multipolygon geometry object. + * @param config {Object} An optional properties hash the object should use + * @return {L.multiPolygon} + */ + multipolygon: function (config) { + // Truncate the coordinates to remove the closing coordinate + var coords = this.trunc(this.components), + latlngs = this.coordsToLatLngs(coords, 2); + + return L.multiPolygon(latlngs, config); + }, + + /** + * Creates the framework's equivalent collection of geometry objects. + * @param config {Object} An optional properties hash the object should use + * @return {L.featureGroup} + */ + geometrycollection: function (config) { + var comps, i, layers; + + comps = this.trunc(this.components); + layers = []; + for (i = 0; i < this.components.length; i += 1) { + layers.push(this.construct[comps[i].type].call(this, comps[i])); + } + + return L.featureGroup(layers, config); + + } +}; + +L.Util.extend(Wkt.Wkt.prototype, { + coordsToLatLngs: L.GeoJSON.coordsToLatLngs, + // TODO Why doesn't the coordsToLatLng function in L.GeoJSON already suffice? + coordsToLatLng: function (coords, reverse) { + var lat = reverse ? coords.x : coords.y, + lng = reverse ? coords.y : coords.x; + + return L.latLng(lat, lng, true); + } +}); + +/** + * @augments Wkt.Wkt + * A framework-dependent deconstruction method used to generate internal + * geometric representations from instances of framework geometry. This method + * uses object detection to attempt to classify members of framework geometry + * classes into the standard WKT types. + * @param obj {Object} An instance of one of the framework's geometry classes + * @return {Object} A hash of the 'type' and 'components' thus derived + */ +Wkt.Wkt.prototype.deconstruct = function (obj) { + var attr, coordsFromLatLngs, features, i, verts, rings, tmp; + + /** + * Accepts an Array (arr) of LatLngs from which it extracts each one as a + * vertex; calls itself recursively to deal with nested Arrays. + */ + coordsFromLatLngs = function (arr) { + var i, coords; + + coords = []; + for (i = 0; i < arr.length; i += 1) { + if (Wkt.isArray(arr[i])) { + coords.push(coordsFromLatLngs(arr[i])); + + } else { + coords.push({ + x: arr[i].lng, + y: arr[i].lat + }); + } + } + + return coords; + }; + + // L.Marker //////////////////////////////////////////////////////////////// + if (obj.constructor === L.Marker || obj.constructor === L.marker) { + return { + type: 'point', + components: [{ + x: obj.getLatLng().lng, + y: obj.getLatLng().lat + }] + }; + } + + // L.Rectangle ///////////////////////////////////////////////////////////// + if (obj.constructor === L.Rectangle || obj.constructor === L.rectangle) { + tmp = obj.getBounds(); // L.LatLngBounds instance + return { + type: 'polygon', + isRectangle: true, + components: [ + [ + { // NW corner + x: tmp.getSouthWest().lng, + y: tmp.getNorthEast().lat + }, + { // NE corner + x: tmp.getNorthEast().lng, + y: tmp.getNorthEast().lat + }, + { // SE corner + x: tmp.getNorthEast().lng, + y: tmp.getSouthWest().lat + }, + { // SW corner + x: tmp.getSouthWest().lng, + y: tmp.getSouthWest().lat + }, + { // NW corner (again, for closure) + x: tmp.getSouthWest().lng, + y: tmp.getNorthEast().lat + } + ] + ] + }; + + } + + // L.Polyline ////////////////////////////////////////////////////////////// + if (obj.constructor === L.Polyline || obj.constructor === L.polyline) { + verts = []; + tmp = obj.getLatLngs(); + + if (!tmp[0].equals(tmp[tmp.length - 1])) { + + for (i = 0; i < tmp.length; i += 1) { + verts.push({ + x: tmp[i].lng, + y: tmp[i].lat + }); + } + + return { + type: 'linestring', + components: verts + }; + + } + } + + // L.Polygon /////////////////////////////////////////////////////////////// + + if (obj.constructor === L.Polygon || obj.constructor === L.polygon) { + rings = []; + verts = []; + tmp = obj.getLatLngs(); + + // First, we deal with the boundary points + for (i = 0; i < obj._latlngs.length; i += 1) { + verts.push({ // Add the first coordinate again for closure + x: tmp[i].lng, + y: tmp[i].lat + }); + } + + verts.push({ // Add the first coordinate again for closure + x: tmp[0].lng, + y: tmp[0].lat + }); + + rings.push(verts); + + // Now, any holes + if (obj._holes && obj._holes.length > 0) { + // Reworked to support holes properly + verts = coordsFromLatLngs(obj._holes); + for (i=0; i < verts.length;i++) { + verts[i].push(verts[i][0]); // Copy the beginning coords again for closure + rings.push(verts[i]); + } + } + + return { + type: 'polygon', + components: rings + }; + + } + + // L.MultiPolyline ///////////////////////////////////////////////////////// + // L.MultiPolygon ////////////////////////////////////////////////////////// + // L.LayerGroup //////////////////////////////////////////////////////////// + // L.FeatureGroup ////////////////////////////////////////////////////////// + if (obj.constructor === L.MultiPolyline || obj.constructor === L.MultiPolygon + || obj.constructor === L.LayerGroup || obj.constructor === L.FeatureGroup) { + + features = []; + tmp = obj._layers; + + for (attr in tmp) { + if (tmp.hasOwnProperty(attr)) { + if (tmp[attr].getLatLngs || tmp[attr].getLatLng) { + // Recursively deconstruct each layer + features.push(this.deconstruct(tmp[attr])); + } + } + } + + return { + + type: (function () { + switch (obj.constructor) { + case L.MultiPolyline: + return 'multilinestring'; + case L.MultiPolygon: + return 'multipolygon'; + case L.FeatureGroup: + return (function () { + var i, mpgon, mpline, mpoint; + + // Assume that all layers are of one type (any one type) + mpgon = true; + mpline = true; + mpoint = true; + + for (i in obj._layers) { + if (obj._layers.hasOwnProperty(i)) { + if (obj._layers[i].constructor !== L.Marker) { + mpoint = false; + } + if (obj._layers[i].constructor !== L.Polyline) { + mpline = false; + } + if (obj._layers[i].constructor !== L.Polygon) { + mpgon = false; + } + } + } + + if (mpoint) { + return 'multipoint'; + } + if (mpline) { + return 'multilinestring'; + } + if (mpgon) { + return 'multipolygon'; + } + return 'geometrycollection'; + + }()); + default: + return 'geometrycollection'; + } + }()), + + components: (function () { + // Pluck the components from each Wkt + var i, comps; + + comps = []; + for (i = 0; i < features.length; i += 1) { + if (features[i].components) { + comps.push(features[i].components); + } + } + + return comps; + }()) + + }; + + } + + // L.Circle //////////////////////////////////////////////////////////////// + if (obj.constructor === L.Rectangle || obj.constructor === L.rectangle) { + console.log('Deconstruction of L.Circle objects is not yet supported'); + + } else { + console.log('The passed object does not have any recognizable properties.'); + } + +}; \ No newline at end of file diff --git a/pacotes/wicket/wicket.js b/pacotes/wicket/wicket.js index 21874ea..bd94074 100644 --- a/pacotes/wicket/wicket.js +++ b/pacotes/wicket/wicket.js @@ -1,18 +1,868 @@ -var Wkt=function(){return{delimiter:" ",isArray:function(obj){return!!(obj&&obj.constructor==Array)},Wkt:function(initializer){var beginsWith,endsWith,trim;beginsWith=function(str,sub){return str.substring(0,sub.length)===sub};endsWith=function(str,sub){return str.substring(str.length-sub.length)===sub};trim=function(str,sub){sub=sub||" ";while(beginsWith(str,sub))str=str.substring(1);while(endsWith(str,sub))str=str.substring(0,str.length-1);return str};this.delimiter=Wkt.delimiter;this.regExes={typeStr:/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/, -spaces:/\s+|\+/,numeric:/-*\d+\.*\d+/,comma:/\s*,\s*/,parenComma:/\)\s*,\s*\(/,doubleParenComma:/\)\s*\)\s*,\s*\(\s*\(/,trimParens:/^\s*\(?(.*?)\)?\s*$/};this.isCollection=function(){switch(this.type.slice(0,5)){case "multi":return true;case "polyg":return true;default:return false}};this.components=undefined;this.fromObject=function(obj){var result=this.deconstruct.call(this,obj);this.components=result.components;this.isRectangle=result.isRectangle||false;this.type=result.type;return this};this.toObject= -function(config){return this.construct[this.type].call(this,config)};this.read=function(wkt){var matches;matches=this.regExes.typeStr.exec(wkt);if(matches){this.type=matches[1].toLowerCase();this.base=matches[2];if(this.ingest[this.type])this.components=this.ingest[this.type].apply(this,[this.base])}else{console.log("Invalid WKT string provided to read()");throw{name:"WKTError",message:"Invalid WKT string provided to read()"};}return this.components};this.write=function(components){var i,pieces,data; -components=components||this.components;pieces=[];pieces.push(this.type.toUpperCase()+"(");for(i=0;i0)pieces.push(",");if(!this.extract[this.type])return null; -//alterado por edmar moretti - if(components[i].length == 1){ - data = this.extract[this.type].apply(this, [components[i][0]]); - } - else{ - data = this.extract[this.type].apply(this, [components[i]]); - } - -if(this.isCollection())pieces.push("("+data+")");else{pieces.push(data);if(i!==components.length-1)pieces.push(",")}}pieces.push(")");return pieces.join("")};this.extract={point:function(point){return point.x+this.delimiter+point.y},multipoint:function(multipoint){var i, -parts=[];for(i=0;i. + * + */ + +(function (global) { + var beginsWith, endsWith, root, Wkt; + + // Establish the root object, window in the browser, or exports on the server + root = this; + + /** + * @desc The Wkt namespace. + * @property {String} delimiter - The default delimiter for separating components of atomic geometry (coordinates) + * @namespace + * @global + */ + Wkt = function (obj) { + if (obj instanceof Wkt) return obj; + if (!(this instanceof Wkt)) return new Wkt(obj); + this._wrapped = obj; + }; + + // Following Underscore module pattern (http://underscorejs.org/docs/underscore.html) + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = Wkt; + } + exports.Wkt = Wkt; + } else { + root.Wkt = Wkt; + } + + /** + * Returns true if the substring is found at the beginning of the string. + * @param str {String} The String to search + * @param sub {String} The substring of interest + * @return {Boolean} + * @private + */ + beginsWith = function (str, sub) { + return str.substring(0, sub.length) === sub; + }; + + /** + * Returns true if the substring is found at the end of the string. + * @param str {String} The String to search + * @param sub {String} The substring of interest + * @return {Boolean} + * @private + */ + endsWith = function (str, sub) { + return str.substring(str.length - sub.length) === sub; + }; + + /** + * The default delimiter for separating components of atomic geometry (coordinates) + * @ignore + */ + Wkt.delimiter = ' '; + + /** + * Determines whether or not the passed Object is an Array. + * @param obj {Object} The Object in question + * @return {Boolean} + * @member Wkt.isArray + * @method + */ + Wkt.isArray = function (obj) { + return !!(obj && obj.constructor === Array); + }; + + /** + * Removes given character String(s) from a String. + * @param str {String} The String to search + * @param sub {String} The String character(s) to trim + * @return {String} The trimmed string + * @member Wkt.trim + * @method + */ + Wkt.trim = function (str, sub) { + sub = sub || ' '; // Defaults to trimming spaces + // Trim beginning spaces + while (beginsWith(str, sub)) { + str = str.substring(1); + } + // Trim ending spaces + while (endsWith(str, sub)) { + str = str.substring(0, str.length - 1); + } + return str; + }; + + /** + * An object for reading WKT strings and writing geographic features + * @constructor this.Wkt.Wkt + * @param initializer {String} An optional WKT string for immediate read + * @property {Array} components - Holder for atomic geometry objects (internal representation of geometric components) + * @property {String} delimiter - The default delimiter for separating components of atomic geometry (coordinates) + * @property {Object} regExes - Some regular expressions copied from OpenLayers.Format.WKT.js + * @property {String} type - The Well-Known Text name (e.g. 'point') of the geometry + * @property {Boolean} wrapVerticies - True to wrap vertices in MULTIPOINT geometries; If true: MULTIPOINT((30 10),(10 30),(40 40)); If false: MULTIPOINT(30 10,10 30,40 40) + * @return {this.Wkt.Wkt} + * @memberof Wkt + */ + Wkt.Wkt = function (initializer) { + + /** + * The default delimiter between X and Y coordinates. + * @ignore + */ + this.delimiter = Wkt.delimiter || ' '; + + /** + * Configuration parameter for controlling how Wicket seralizes + * MULTIPOINT strings. Examples; both are valid WKT: + * If true: MULTIPOINT((30 10),(10 30),(40 40)) + * If false: MULTIPOINT(30 10,10 30,40 40) + * @ignore + */ + this.wrapVertices = true; + + /** + * Some regular expressions copied from OpenLayers.Format.WKT.js + * @ignore + */ + this.regExes = { + 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/, + 'spaces': /\s+|\+/, // Matches the '+' or the empty space + 'numeric': /-*\d+(\.*\d+)?/, + 'comma': /\s*,\s*/, + 'parenComma': /\)\s*,\s*\(/, + 'coord': /-*\d+\.*\d+ -*\d+\.*\d+/, // e.g. "24 -14" + 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, + 'trimParens': /^\s*\(?(.*?)\)?\s*$/, + 'ogcTypes': /^(multi)?(point|line|polygon|box)?(string)?$/i, // Captures e.g. "Multi","Line","String" + 'crudeJson': /^{.*"(type|coordinates|geometries|features)":.*}$/ // Attempts to recognize JSON strings + }; + + /** + * The internal representation of geometry--the "components" of geometry. + * @ignore + */ + this.components = undefined; + + // An initial WKT string may be provided + if (initializer && typeof initializer === 'string') { + this.read(initializer); + } else if (initializer && typeof initializer !== undefined) { + this.fromObject(initializer); + } + + }; + + global.Wkt = Wkt; + + /** + * Returns true if the internal geometry is a collection of geometries. + * @return {Boolean} Returns true when it is a collection + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.isCollection = function () { + switch (this.type.slice(0, 5)) { + case 'multi': + // Trivial; any multi-geometry is a collection + return true; + case 'polyg': + // Polygons with holes are "collections" of rings + return true; + default: + // Any other geometry is not a collection + return false; + } + }; + + /** + * Compares two x,y coordinates for equality. + * @param a {Object} An object with x and y properties + * @param b {Object} An object with x and y properties + * @return {Boolean} + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.sameCoords = function (a, b) { + return (a.x === b.x && a.y === b.y); + }; + + /** + * Sets internal geometry (components) from framework geometry (e.g. + * Google Polygon objects or google.maps.Polygon). + * @param obj {Object} The framework-dependent geometry representation + * @return {this.Wkt.Wkt} The object itself + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.fromObject = function (obj) { + var result; + + if (obj.hasOwnProperty('type') && obj.hasOwnProperty('coordinates')) { + result = this.fromJson(obj); + } else { + result = this.deconstruct.call(this, obj); + } + + this.components = result.components; + this.isRectangle = result.isRectangle || false; + this.type = result.type; + return this; + }; + + /** + * Creates external geometry objects based on a plug-in framework's + * construction methods and available geometry classes. + * @param config {Object} An optional framework-dependent properties specification + * @return {Object} The framework-dependent geometry representation + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.toObject = function (config) { + var obj = this.construct[this.type].call(this, config); + // Don't assign the "properties" property to an Array + if (typeof obj === 'object' && !Wkt.isArray(obj)) { + obj.properties = this.properties; + } + return obj; + }; + + /** + * Returns the WKT string representation; the same as the write() method. + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.toString = function (config) { + return this.write(); + }; + + /** + * Parses a JSON representation as an Object. + * @param obj {Object} An Object with the GeoJSON schema + * @return {this.Wkt.Wkt} The object itself + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.fromJson = function (obj) { + var i, j, k, coords, iring, oring; + + this.type = obj.type.toLowerCase(); + this.components = []; + if (obj.hasOwnProperty('geometry')) { //Feature + this.fromJson(obj.geometry); + this.properties = obj.properties; + return this; + } + coords = obj.coordinates; + + if (!Wkt.isArray(coords[0])) { // Point + this.components.push({ + x: coords[0], + y: coords[1] + }); + + } else { + + for (i in coords) { + if (coords.hasOwnProperty(i)) { + + if (!Wkt.isArray(coords[i][0])) { // LineString + + if (this.type === 'multipoint') { // MultiPoint + this.components.push([{ + x: coords[i][0], + y: coords[i][1] + }]); + + } else { + this.components.push({ + x: coords[i][0], + y: coords[i][1] + }); + + } + + } else { + + oring = []; + for (j in coords[i]) { + if (coords[i].hasOwnProperty(j)) { + + if (!Wkt.isArray(coords[i][j][0])) { + oring.push({ + x: coords[i][j][0], + y: coords[i][j][1] + }); + + } else { + + iring = []; + for (k in coords[i][j]) { + if (coords[i][j].hasOwnProperty(k)) { + + iring.push({ + x: coords[i][j][k][0], + y: coords[i][j][k][1] + }); + + } + } + + oring.push(iring); + + } + + } + } + + this.components.push(oring); + } + } + } + + } + + return this; + }; + + /** + * Creates a JSON representation, with the GeoJSON schema, of the geometry. + * @return {Object} The corresponding GeoJSON representation + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.toJson = function () { + var cs, json, i, j, k, ring, rings; + + cs = this.components; + json = { + coordinates: [], + type: (function () { + var i, type, s; + + type = this.regExes.ogcTypes.exec(this.type).slice(1); + s = []; + + for (i in type) { + if (type.hasOwnProperty(i)) { + if (type[i] !== undefined) { + s.push(type[i].toLowerCase().slice(0, 1).toUpperCase() + type[i].toLowerCase().slice(1)); + } + } + } + + return s; + }.call(this)).join('') + } + + // Wkt BOX type gets a special bbox property in GeoJSON + if (this.type.toLowerCase() === 'box') { + json.type = 'Polygon'; + json.bbox = []; + + for (i in cs) { + if (cs.hasOwnProperty(i)) { + json.bbox = json.bbox.concat([cs[i].x, cs[i].y]); + } + } + + json.coordinates = [ + [ + [cs[0].x, cs[0].y], + [cs[0].x, cs[1].y], + [cs[1].x, cs[1].y], + [cs[1].x, cs[0].y], + [cs[0].x, cs[0].y] + ] + ]; + + return json; + } + + // For the coordinates of most simple features + for (i in cs) { + if (cs.hasOwnProperty(i)) { + + // For those nested structures + if (Wkt.isArray(cs[i])) { + rings = []; + + for (j in cs[i]) { + if (cs[i].hasOwnProperty(j)) { + + if (Wkt.isArray(cs[i][j])) { // MULTIPOLYGONS + ring = []; + + for (k in cs[i][j]) { + if (cs[i][j].hasOwnProperty(k)) { + ring.push([cs[i][j][k].x, cs[i][j][k].y]); + } + } + + rings.push(ring); + + } else { // POLYGONS and MULTILINESTRINGS + + if (cs[i].length > 1) { + rings.push([cs[i][j].x, cs[i][j].y]); + + } else { // MULTIPOINTS + rings = rings.concat([cs[i][j].x, cs[i][j].y]); + } + } + } + } + + json.coordinates.push(rings); + + } else { + if (cs.length > 1) { // For LINESTRING type + json.coordinates.push([cs[i].x, cs[i].y]); + + } else { // For POINT type + json.coordinates = json.coordinates.concat([cs[i].x, cs[i].y]); + } + } + + } + } + + return json; + }; + + /** + * Absorbs the geometry of another this.Wkt.Wkt instance, merging it with its own, + * creating a collection (MULTI-geometry) based on their types, which must agree. + * For example, creates a MULTIPOLYGON from a POLYGON type merged with another + * POLYGON type, or adds a POLYGON instance to a MULTIPOLYGON instance. + * @param wkt {String} A Wkt.Wkt object + * @return {this.Wkt.Wkt} The object itself + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.merge = function (wkt) { + var prefix = this.type.slice(0, 5); + + if (this.type !== wkt.type) { + if (this.type.slice(5, this.type.length) !== wkt.type) { + throw TypeError('The input geometry types must agree or the calling this.Wkt.Wkt instance must be a multigeometry of the other'); + } + } + + switch (prefix) { + + case 'point': + this.components = [this.components.concat(wkt.components)]; + break; + + case 'multi': + this.components = this.components.concat((wkt.type.slice(0, 5) === 'multi') ? wkt.components : [wkt.components]); + break; + + default: + this.components = [ + this.components, + wkt.components + ]; + break; + + } + + if (prefix !== 'multi') { + this.type = 'multi' + this.type; + } + return this; + }; + + /** + * Reads a WKT string, validating and incorporating it. + * @param str {String} A WKT or GeoJSON string + * @return {this.Wkt.Wkt} The object itself + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.read = function (str) { + var matches; + matches = this.regExes.typeStr.exec(str); + if (matches) { + this.type = matches[1].toLowerCase(); + this.base = matches[2]; + if (this.ingest[this.type]) { + this.components = this.ingest[this.type].apply(this, [this.base]); + } + + } else { + if (this.regExes.crudeJson.test(str)) { + if (typeof JSON === 'object' && typeof JSON.parse === 'function') { + this.fromJson(JSON.parse(str)); + + } else { + console.log('JSON.parse() is not available; cannot parse GeoJSON strings'); + throw { + name: 'JSONError', + message: 'JSON.parse() is not available; cannot parse GeoJSON strings' + }; + } + + } else { + console.log('Invalid WKT string provided to read()'); + throw { + name: 'WKTError', + message: 'Invalid WKT string provided to read()' + }; + } + } + + return this; + }; // eo readWkt + + /** + * Writes a WKT string. + * @param components {Array} An Array of internal geometry objects + * @return {String} The corresponding WKT representation + * @memberof this.Wkt.Wkt + * @method + */ + Wkt.Wkt.prototype.write = function (components) { + var i, pieces, data; + + components = components || this.components; + + pieces = []; + + pieces.push(this.type.toUpperCase() + '('); + + for (i = 0; i < components.length; i += 1) { + if (this.isCollection() && i > 0) { + pieces.push(','); + } + + // There should be an extract function for the named type + if (!this.extract[this.type]) { + return null; + } + + data = this.extract[this.type].apply(this, [components[i]]); + if (this.isCollection() && this.type !== 'multipoint') { + pieces.push('(' + data + ')'); + + } else { + pieces.push(data); + + // If not at the end of the components, add a comma + if (i !== (components.length - 1) && this.type !== 'multipoint') { + pieces.push(','); + } + + } + } + + pieces.push(')'); + + return pieces.join(''); + }; + + /** + * This object contains functions as property names that extract WKT + * strings from the internal representation. + * @memberof this.Wkt.Wkt + * @namespace this.Wkt.Wkt.extract + * @instance + */ + Wkt.Wkt.prototype.extract = { + /** + * Return a WKT string representing atomic (point) geometry + * @param point {Object} An object with x and y properties + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + point: function (point) { + return String(point.x) + this.delimiter + String(point.y); + }, + + /** + * Return a WKT string representing multiple atoms (points) + * @param multipoint {Array} Multiple x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + multipoint: function (multipoint) { + var i, parts = [], + s; + + for (i = 0; i < multipoint.length; i += 1) { + s = this.extract.point.apply(this, [multipoint[i]]); + + if (this.wrapVertices) { + s = '(' + s + ')'; + } + + parts.push(s); + } + + return parts.join(','); + }, + + /** + * Return a WKT string representing a chain (linestring) of atoms + * @param linestring {Array} Multiple x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + linestring: function (linestring) { + // Extraction of linestrings is the same as for points + return this.extract.point.apply(this, [linestring]); + }, + + /** + * Return a WKT string representing multiple chains (multilinestring) of atoms + * @param multilinestring {Array} Multiple of multiple x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + multilinestring: function (multilinestring) { + var i, parts = []; + + for (i = 0; i < multilinestring.length; i += 1) { + parts.push(this.extract.linestring.apply(this, [multilinestring[i]])); + } + + return parts.join(','); + }, + + /** + * Return a WKT string representing multiple atoms in closed series (polygon) + * @param polygon {Array} Collection of ordered x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + polygon: function (polygon) { + // Extraction of polygons is the same as for multilinestrings + return this.extract.multilinestring.apply(this, [polygon]); + }, + + /** + * Return a WKT string representing multiple closed series (multipolygons) of multiple atoms + * @param multipolygon {Array} Collection of ordered x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + multipolygon: function (multipolygon) { + var i, parts = []; + for (i = 0; i < multipolygon.length; i += 1) { + parts.push('(' + this.extract.polygon.apply(this, [multipolygon[i]]) + ')'); + } + return parts.join(','); + }, + + /** + * Return a WKT string representing a 2DBox + * @param multipolygon {Array} Collection of ordered x-and-y objects + * @return {String} The WKT representation + * @memberof this.Wkt.Wkt.extract + * @instance + */ + box: function (box) { + return this.extract.linestring.apply(this, [box]); + }, + + geometrycollection: function (str) { + console.log('The geometrycollection WKT type is not yet supported.'); + } + }; + + /** + * This object contains functions as property names that ingest WKT + * strings into the internal representation. + * @memberof this.Wkt.Wkt + * @namespace this.Wkt.Wkt.ingest + * @instance + */ + Wkt.Wkt.prototype.ingest = { + + /** + * Return point feature given a point WKT fragment. + * @param str {String} A WKT fragment representing the point + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + point: function (str) { + var coords = Wkt.trim(str).split(this.regExes.spaces); + // In case a parenthetical group of coordinates is passed... + return [{ // ...Search for numeric substrings + x: parseFloat(this.regExes.numeric.exec(coords[0])[0]), + y: parseFloat(this.regExes.numeric.exec(coords[1])[0]) + }]; + }, + + /** + * Return a multipoint feature given a multipoint WKT fragment. + * @param str {String} A WKT fragment representing the multipoint + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + multipoint: function (str) { + var i, components, points; + components = []; + points = Wkt.trim(str).split(this.regExes.comma); + for (i = 0; i < points.length; i += 1) { + components.push(this.ingest.point.apply(this, [points[i]])); + } + return components; + }, + + /** + * Return a linestring feature given a linestring WKT fragment. + * @param str {String} A WKT fragment representing the linestring + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + linestring: function (str) { + var i, multipoints, components; + + // In our x-and-y representation of components, parsing + // multipoints is the same as parsing linestrings + multipoints = this.ingest.multipoint.apply(this, [str]); + + // However, the points need to be joined + components = []; + for (i = 0; i < multipoints.length; i += 1) { + components = components.concat(multipoints[i]); + } + return components; + }, + + /** + * Return a multilinestring feature given a multilinestring WKT fragment. + * @param str {String} A WKT fragment representing the multilinestring + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + multilinestring: function (str) { + var i, components, line, lines; + components = []; + + lines = Wkt.trim(str).split(this.regExes.doubleParenComma); + if (lines.length === 1) { // If that didn't work... + lines = Wkt.trim(str).split(this.regExes.parenComma); + } + + for (i = 0; i < lines.length; i += 1) { + line = lines[i].replace(this.regExes.trimParens, '$1'); + components.push(this.ingest.linestring.apply(this, [line])); + } + + return components; + }, + + /** + * Return a polygon feature given a polygon WKT fragment. + * @param str {String} A WKT fragment representing the polygon + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + polygon: function (str) { + var i, j, components, subcomponents, ring, rings; + rings = Wkt.trim(str).split(this.regExes.parenComma); + components = []; // Holds one or more rings + for (i = 0; i < rings.length; i += 1) { + ring = rings[i].replace(this.regExes.trimParens, '$1').split(this.regExes.comma); + subcomponents = []; // Holds the outer ring and any inner rings (holes) + for (j = 0; j < ring.length; j += 1) { + // Split on the empty space or '+' character (between coordinates) + var split=ring[j].split(this.regExes.spaces); + if(split.length>2){ + //remove the elements which are blanks + split = split.filter(function(n){ return n != "" }); + } + if(split.length===2){ + var x_cord=split[0]; + var y_cord=split[1]; + + //now push + subcomponents.push({ + x: parseFloat(x_cord), + y: parseFloat(y_cord) + }); + } + } + components.push(subcomponents); + } + return components; + }, + + /** + * Return box vertices (which would become the Rectangle bounds) given a Box WKT fragment. + * @param str {String} A WKT fragment representing the box + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + box: function (str) { + var i, multipoints, components; + + // In our x-and-y representation of components, parsing + // multipoints is the same as parsing linestrings + multipoints = this.ingest.multipoint.apply(this, [str]); + + // However, the points need to be joined + components = []; + for (i = 0; i < multipoints.length; i += 1) { + components = components.concat(multipoints[i]); + } + + return components; + }, + + /** + * Return a multipolygon feature given a multipolygon WKT fragment. + * @param str {String} A WKT fragment representing the multipolygon + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + multipolygon: function (str) { + var i, components, polygon, polygons; + components = []; + polygons = Wkt.trim(str).split(this.regExes.doubleParenComma); + for (i = 0; i < polygons.length; i += 1) { + polygon = polygons[i].replace(this.regExes.trimParens, '$1'); + components.push(this.ingest.polygon.apply(this, [polygon])); + } + return components; + }, + + /** + * Return an array of features given a geometrycollection WKT fragment. + * @param str {String} A WKT fragment representing the geometry collection + * @memberof this.Wkt.Wkt.ingest + * @instance + */ + geometrycollection: function (str) { + console.log('The geometrycollection WKT type is not yet supported.'); + } + + }; // eo ingest + + return this; +}(this)); + -- libgit2 0.21.2