From 31ab97dc839a7513e695a593eab662b1a9c06803 Mon Sep 17 00:00:00 2001 From: Pieter Frenssen Date: Wed, 14 Mar 2012 01:54:33 +0100 Subject: [PATCH 1/2] Deleted GeoPHP submodule. --- geoPHP | 1 - 1 file changed, 1 deletion(-) delete mode 160000 geoPHP diff --git a/geoPHP b/geoPHP deleted file mode 160000 index faa33dd..0000000 --- a/geoPHP +++ /dev/null @@ -1 +0,0 @@ -Subproject commit faa33ddc4e716c3290b3da4fc3b7ce7ecd41c7b7 -- 1.7.9.2 From f263ac9a275f9b7b9eba66191c8945d08cadffa7 Mon Sep 17 00:00:00 2001 From: Pieter Frenssen Date: Wed, 14 Mar 2012 02:04:53 +0100 Subject: [PATCH 2/2] Installed geoPHP 0.7. --- geoPHP/LICENSE | 370 ++++++++ geoPHP/README.md | 72 ++ geoPHP/geoPHP.inc | 181 ++++ geoPHP/lib/adapters/GPX.class.php | 173 ++++ geoPHP/lib/adapters/GeoAdapter.class.php | 31 + geoPHP/lib/adapters/GeoJSON.class.php | 155 ++++ geoPHP/lib/adapters/GeoRSS.class.php | 224 +++++ geoPHP/lib/adapters/GoogleGeocode.class.php | 158 ++++ geoPHP/lib/adapters/KML.class.php | 240 +++++ geoPHP/lib/adapters/WKB.class.php | 216 +++++ geoPHP/lib/adapters/WKT.class.php | 195 ++++ geoPHP/lib/geometry/Collection.class.php | 196 ++++ geoPHP/lib/geometry/Geometry.class.php | 338 +++++++ geoPHP/lib/geometry/GeometryCollection.class.php | 29 + geoPHP/lib/geometry/LineString.class.php | 66 ++ geoPHP/lib/geometry/MultiLineString.class.php | 33 + geoPHP/lib/geometry/MultiPoint.class.php | 9 + geoPHP/lib/geometry/MultiPolygon.class.php | 8 + geoPHP/lib/geometry/Point.class.php | 128 +++ geoPHP/lib/geometry/Polygon.class.php | 95 ++ geoPHP/tests/input/barret_spur.gpx | 219 +++++ geoPHP/tests/input/big_n_ugly.kml | 915 ++++++++++++++++++ geoPHP/tests/input/box.georss | 1 + geoPHP/tests/input/cdata.kml | 19 + geoPHP/tests/input/circle.georss | 1 + geoPHP/tests/input/fells_loop.gpx | 1077 ++++++++++++++++++++++ geoPHP/tests/input/geometrycollection.georss | 29 + geoPHP/tests/input/geometrycollection.wkt | 1 + geoPHP/tests/input/line.georss | 1 + geoPHP/tests/input/linestring.wkt | 1 + geoPHP/tests/input/multilinestring.wkt | 1 + geoPHP/tests/input/multipolygon.wkb | Bin 0 -> 179 bytes geoPHP/tests/input/multipolygon.wkt | 1 + geoPHP/tests/input/multipolygon2.wkt | 1 + geoPHP/tests/input/multipolygon_big.wkt | 1 + geoPHP/tests/input/path.kml | 40 + geoPHP/tests/input/pentagon.kml | 34 + geoPHP/tests/input/point.georss | 21 + geoPHP/tests/input/point.kml | 11 + geoPHP/tests/input/point.wkt | 1 + geoPHP/tests/input/polygon.georss | 3 + geoPHP/tests/input/polygon.wkt | 1 + geoPHP/tests/input/polygon2.wkt | 1 + geoPHP/tests/input/polygon3.wkt | 1 + geoPHP/tests/input/track.gpx | 28 + geoPHP/tests/test.php | 221 +++++ 46 files changed, 5547 insertions(+) create mode 100644 geoPHP/LICENSE create mode 100644 geoPHP/README.md create mode 100644 geoPHP/geoPHP.inc create mode 100644 geoPHP/lib/adapters/GPX.class.php create mode 100644 geoPHP/lib/adapters/GeoAdapter.class.php create mode 100644 geoPHP/lib/adapters/GeoJSON.class.php create mode 100644 geoPHP/lib/adapters/GeoRSS.class.php create mode 100644 geoPHP/lib/adapters/GoogleGeocode.class.php create mode 100644 geoPHP/lib/adapters/KML.class.php create mode 100644 geoPHP/lib/adapters/WKB.class.php create mode 100644 geoPHP/lib/adapters/WKT.class.php create mode 100644 geoPHP/lib/geometry/Collection.class.php create mode 100644 geoPHP/lib/geometry/Geometry.class.php create mode 100644 geoPHP/lib/geometry/GeometryCollection.class.php create mode 100644 geoPHP/lib/geometry/LineString.class.php create mode 100644 geoPHP/lib/geometry/MultiLineString.class.php create mode 100644 geoPHP/lib/geometry/MultiPoint.class.php create mode 100644 geoPHP/lib/geometry/MultiPolygon.class.php create mode 100644 geoPHP/lib/geometry/Point.class.php create mode 100644 geoPHP/lib/geometry/Polygon.class.php create mode 100644 geoPHP/tests/input/barret_spur.gpx create mode 100644 geoPHP/tests/input/big_n_ugly.kml create mode 100644 geoPHP/tests/input/box.georss create mode 100644 geoPHP/tests/input/cdata.kml create mode 100644 geoPHP/tests/input/circle.georss create mode 100644 geoPHP/tests/input/fells_loop.gpx create mode 100644 geoPHP/tests/input/geometrycollection.georss create mode 100644 geoPHP/tests/input/geometrycollection.wkt create mode 100644 geoPHP/tests/input/line.georss create mode 100644 geoPHP/tests/input/linestring.wkt create mode 100644 geoPHP/tests/input/multilinestring.wkt create mode 100644 geoPHP/tests/input/multipolygon.wkb create mode 100644 geoPHP/tests/input/multipolygon.wkt create mode 100644 geoPHP/tests/input/multipolygon2.wkt create mode 100644 geoPHP/tests/input/multipolygon_big.wkt create mode 100644 geoPHP/tests/input/path.kml create mode 100644 geoPHP/tests/input/pentagon.kml create mode 100644 geoPHP/tests/input/point.georss create mode 100644 geoPHP/tests/input/point.kml create mode 100644 geoPHP/tests/input/point.wkt create mode 100644 geoPHP/tests/input/polygon.georss create mode 100644 geoPHP/tests/input/polygon.wkt create mode 100644 geoPHP/tests/input/polygon2.wkt create mode 100644 geoPHP/tests/input/polygon3.wkt create mode 100644 geoPHP/tests/input/track.gpx create mode 100644 geoPHP/tests/test.php diff --git a/geoPHP/LICENSE b/geoPHP/LICENSE new file mode 100644 index 0000000..9593990 --- /dev/null +++ b/geoPHP/LICENSE @@ -0,0 +1,370 @@ +Copyright (c) 2011, Patrick Hayes and contributors + +This program is dual-licensed under both the GPL version 2 (or later) and +Modified BSD License. Either license may be used at your option. + +------------------------------------------------------------------------------ +Modified BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of the contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/geoPHP/README.md b/geoPHP/README.md new file mode 100644 index 0000000..00f5991 --- /dev/null +++ b/geoPHP/README.md @@ -0,0 +1,72 @@ +GeoPHP is a open-source native PHP library for doing geometry operations. It is written entirely in PHP and +can therefore run on shared hosts. It can read and write a wide variety of formats (WKT, WKB, GeoJSON, +KML, GPX, GeoRSS). It works with all Simple-Feature geometries (Point, LineString, Polygon, GeometryCollection etc.) +and can be used to get centroids, bounding-boxes, area, and a wide variety of other useful information. + +geoPHP also helpfully wraps the GEOS php extension so that applications can get a transparent performance +increase when GEOS is installed on the server. When GEOS is installed, geoPHP also becomes +fully compliant with the OpenGISĀ® Implementation Standard for Geographic information. With GEOS you get the +full-set of openGIS functions in PHP like Union, IsWithin, Touches etc. This means that applications +get a useful "core-set" of geometry operations that work in all environments, and an "extended-set"of operations +for environments that have GEOS installed. + +See the 'getting started' section below for references and examples of everything that geoPHP can do. + +This project is currently looking for co-maintainers. If you think you can help out, please send me a +message. Forks are also welcome, please issue pull requests and I will merge them into the main branch. + +Getting Started +----------------------- + + * The lastest stable version can always be downloaded at: + * Read the API Reference at: + * Examples + * Using geoPHP as a GIS format converter: + * Other Interesting Links: + * Learn about GEOS integration at: + +Example usage +------------------------------------------------- + +```php +getArea(); +$centroid = $polygon->getCentroid(); +$centX = $centroid->getX(); +$centY = $centroid->getY(); + +print "This polygon has an area of ".$area." and a centroid with X=".$centX." and Y=".$centY; + +// MultiPoint json example +print "
"; +$json = +'{ + "type": "MultiPoint", + "coordinates": [ + [100.0, 0.0], [101.0, 1.0] + ] +}'; + +$multipoint = geoPHP::load($json, 'json'); +$multipoint_points = $multipoint->getComponents(); +$first_wkt = $multipoint_points[0]->out('wkt'); + +print "This multipolygon has ".$multipoint->numGeometries()." points. The first point has a wkt representation of ".$first_wkt; +``` + +Credit +------------------------------------------------- + +Maintainer: Patrick Hayes + +Code From: + + * CIS by GeoMemes Research + * gisconverter.php by Arnaud Renevier + * Dave Tarc + +This library is open-source and dual-licensed under both the Modified BSD License and GPLv2. Either license may be used at your option. diff --git a/geoPHP/geoPHP.inc b/geoPHP/geoPHP.inc new file mode 100644 index 0000000..6ba8987 --- /dev/null +++ b/geoPHP/geoPHP.inc @@ -0,0 +1,181 @@ + 'WKT', + 'wkb' => 'WKB', + 'json' => 'GeoJSON', + 'kml' => 'KML', + 'gpx' => 'GPX', + 'georss' => 'GeoRSS', + 'google_geocode' => 'GoogleGeocode', + ); + } + + static function geometryList() { + return array( + 'point' => 'Point', + 'linestring' => 'LineString', + 'polygon' => 'Polygon', + 'multipoint' => 'MultiPoint', + 'multilinestring' => 'MultiLineString', + 'multipolygon' => 'MultiPolygon', + 'geometrycollection' => 'GeometryCollection', + ); + } + + static function geosInstalled($force = NULL) { + static $geos_installed = NULL; + if ($force !== NULL) $geos_installed = $force; + if ($geos_installed !== NULL) { + return $geos_installed; + } + $geos_installed = class_exists('GEOSGeometry'); + return $geos_installed; + } + + static function geosToGeometry($geos) { + if (!geoPHP::geosInstalled()) { + return NULL; + } + $wkb_writer = new GEOSWKBWriter(); + $wkb = $wkb_writer->writeHEX($geos); + $geometry = geoPHP::load($wkb,'wkb',TRUE); + //@@TODO: We no longer need to check this once we have Empty geometries + if ($geometry) { + $geometry->setGeos($geos); + return $geometry; + } + } + + // Reduce a geometry, or an array of geometries, into their 'lowest' available common geometry. + // For example a GeometryCollection of only points will become a MultiPoint + // A multi-point containing a single point will return a point. + // An array of geometries can be passed and they will be compiled into a single geometry + static function geometryReduce($geometry) { + // If it's an array of one, then just parse the one + if (is_array($geometry)) { + if (count($geometry) == 1) return geoPHP::geometryReduce($geometry[0]); + } + + // If the geometry cannot even theoretically be reduced more, then pass it back + if (gettype($geometry) == 'object') { + $passbacks = array('Point','LineString','Polygon'); + if (in_array($geometry->geometryType(),$passbacks)) { + return $geometry; + } + } + + // If it is a mutlti-geometry, check to see if it just has one member + // If it does, then pass the member, if not, then just pass back the geometry + if (gettype($geometry) == 'object') { + $simple_collections = array('MultiPoint','MultiLineString','MultiPolygon'); + if (in_array(get_class($geometry),$passbacks)) { + $components = $geometry->getComponents(); + if (count($components) == 1) { + return $components[0]; + } + else { + return $geometry; + } + } + } + + // So now we either have an array of geometries, a GeometryCollection, or an array of GeometryCollections + if (!is_array($geometry)) { + $geometry = array($geometry); + } + + $geometries = array(); + $geom_types = array(); + + $collections = array('MultiPoint','MultiLineString','MultiPolygon','GeometryCollection'); + + foreach ($geometry as $item) { + if (in_array(get_class($item), $collections)) { + foreach ($item->getComponents() as $component) { + $geometries[] = $component; + $geom_types[] = $component->geometryType(); + } + } + else { + $geometries[] = $item; + $geom_types[] = $item->geometryType(); + } + } + + $geom_types = array_unique($geom_types); + + if (count($geom_types) == 1) { + $class = 'Multi'.$geom_types[0]; + return new $class($geometries); + } + else { + return new GeometryCollection($geometries); + } + } +} diff --git a/geoPHP/lib/adapters/GPX.class.php b/geoPHP/lib/adapters/GPX.class.php new file mode 100644 index 0000000..8aa7cb5 --- /dev/null +++ b/geoPHP/lib/adapters/GPX.class.php @@ -0,0 +1,173 @@ +geomFromText($gpx); + } + + /** + * Serialize geometries into a GPX string. + * + * @param Geometry $geometry + * + * @return string The GPX string representation of the input geometries + */ + public function write(Geometry $geometry) { + return ''.$this->geometryToGPX($geometry).''; + } + + public function geomFromText($text) { + // Change to lower-case and strip all CDATA + $text = strtolower($text); + $text = preg_replace('//s','',$text); + + // Load into DOMDOcument + $xmlobj = new DOMDocument(); + $xmlobj->loadXML($text); + if ($xmlobj === false) { + throw new Exception("Invalid GPX: ". $text); + } + + $this->xmlobj = $xmlobj; + try { + $geom = $this->geomFromXML(); + } catch(InvalidText $e) { + throw new Exception("Cannot Read Geometry From GPX: ". $text); + } catch(Exception $e) { + throw $e; + } + + return $geom; + } + + protected function geomFromXML() { + $geometries = array(); + $geometries = array_merge($geometries, $this->parseWaypoints()); + $geometries = array_merge($geometries, $this->parseTracks()); + $geometries = array_merge($geometries, $this->parseRoutes()); + + if (empty($geometries)) { + throw new Exception("Invalid / Empty GPX"); + } + + return geoPHP::geometryReduce($geometries); + } + + protected function childElements($xml, $nodename = '') { + $children = array(); + foreach ($xml->childNodes as $child) { + if ($child->nodeName == $nodename) { + $children[] = $child; + } + } + return $children; + } + + protected function parseWaypoints() { + $points = array(); + $wpt_elements = $this->xmlobj->getElementsByTagName('wpt'); + foreach ($wpt_elements as $wpt) { + $lat = $wpt->attributes->getNamedItem("lat")->nodeValue; + $lon = $wpt->attributes->getNamedItem("lon")->nodeValue; + $points[] = new Point($lon, $lat); + } + return $points; + } + + protected function parseTracks() { + $lines = array(); + $trk_elements = $this->xmlobj->getElementsByTagName('trk'); + foreach ($trk_elements as $trk) { + $components = array(); + foreach ($this->childElements($trk, 'trkseg') as $trkseg) { + foreach ($this->childElements($trkseg, 'trkpt') as $trkpt) { + $lat = $trkpt->attributes->getNamedItem("lat")->nodeValue; + $lon = $trkpt->attributes->getNamedItem("lon")->nodeValue; + $components[] = new Point($lon, $lat); + } + } + if ($components) {$lines[] = new LineString($components);} + } + return $lines; + } + + protected function parseRoutes() { + $lines = array(); + $rte_elements = $this->xmlobj->getElementsByTagName('rte'); + foreach ($rte_elements as $rte) { + $components = array(); + foreach ($this->childElements($rte, 'rtept') as $rtept) { + $lat = $rtept->attributes->getNamedItem("lat")->nodeValue; + $lon = $rtept->attributes->getNamedItem("lon")->nodeValue; + $components[] = new Point($lon, $lat); + } + $lines[] = new LineString($components); + } + return $lines; + } + + protected function geometryToGPX($geom) { + $type = strtolower($geom->getGeomType()); + switch ($type) { + case 'point': + return $this->pointToGPX($geom); + break; + case 'linestring': + return $this->linestringToGPX($geom); + break; + case 'polygon': + case 'multipoint': + case 'multilinestring': + case 'multipolygon': + case 'geometrycollection': + return $this->collectionToGPX($geom); + break; + } + } + + private function pointToGPX($geom) { + return ''; + } + + private function linestringToGPX($geom) { + $gpx = ''; + + foreach ($geom->getComponents() as $comp) { + $gpx .= ''; + } + + $gpx .= ''; + + return $gpx; + } + + public function collectionToGPX($geom) { + $gpx = ''; + $components = $geom->getComponents(); + foreach ($geom->getComponents() as $comp) { + $gpx .= $this->geometryToGPX($comp); + } + + return $gpx; + } + +} diff --git a/geoPHP/lib/adapters/GeoAdapter.class.php b/geoPHP/lib/adapters/GeoAdapter.class.php new file mode 100644 index 0000000..7217130 --- /dev/null +++ b/geoPHP/lib/adapters/GeoAdapter.class.php @@ -0,0 +1,31 @@ +type)) { + throw new Exception('Invalid JSON'); + } + + // Check to see if it's a FeatureCollection + if ($input->type == 'FeatureCollection') { + $geoms = array(); + foreach ($input->features as $feature) { + $geoms[] = $this->read($feature); + } + return geoPHP::geometryReduce($geoms); + } + + // Check to see if it's a Feature + if ($input->type == 'Feature') { + return $this->read($feature->geometry); + } + + // It's a geometry - process it + return $this->objToGeom($input); + } + + private function objToGeom($obj) { + $type = $obj->type; + + if ($type == 'GeometryCollection') { + return $this->objToGeometryCollection($obj); + } + else { + if (empty($obj->coordinates)) { + throw new Exception ('Invalid GeoJSON: missing coordinates'); + } + $method = 'arrayTo' . $type; + return $this->$method($obj->coordinates); + } + } + + private function arrayToPoint($array) { + return new Point($array[0], $array[1]); + } + + private function arrayToLineString($array) { + $points = array(); + foreach ($array as $comp_array) { + $points[] = $this->arrayToPoint($comp_array); + } + return new LineString($points); + } + + private function arrayToPolygon($array) { + $lines = array(); + foreach ($array as $comp_array) { + $lines[] = $this->arrayToLineString($comp_array); + } + return new Polygon($lines); + } + + private function arrayToMultiPoint($array) { + $points = array(); + foreach ($array as $comp_array) { + $points[] = $this->arrayToPoint($comp_array); + } + return new MultiPoint($points); + } + + private function arrayToMultiLineString($array) { + $lines = array(); + foreach ($array as $comp_array) { + $lines[] = $this->arrayToLineString($comp_array); + } + return new MultiLineString($lines); + } + + private function arrayToMultiPolygon($array) { + $polys = array(); + foreach ($array as $comp_array) { + $polys[] = $this->arrayToPolygon($comp_array); + } + return new MultiPolygon($polys); + } + + private function objToGeometryCollection($obj) { + $geoms = array(); + if (empty($obj->geometries)) { + throw new Exception('Invalid GeoJSON: GeometryCollection with no component geometries'); + } + foreach ($obj->geometries as $comp_object) { + $geoms[] = $this->objToGeom($comp_object); + } + return new GeometryCollection($geoms); + } + + /** + * Serializes an object into a geojson string + * + * + * @param Geometry $obj The object to serialize + * + * @return string The GeoJSON string + */ + public function write(Geometry $geometry, $return_array = FALSE) { + if ($return_array) { + return $this->getArray($geometry); + } + else { + return json_encode($this->getArray($geometry)); + } + } + + public function getArray($geometry) { + if ($geometry->getGeomType() == 'GeometryCollection') { + $component_array = array(); + foreach ($geometry->components as $component) { + $component_array[] = array( + 'type' => $component->geometryType(), + 'coordinates' => $component->asArray(), + ); + } + return array( + 'type'=> 'GeometryCollection', + 'geometries'=> $component_array, + ); + } + else return array( + 'type'=> $geometry->getGeomType(), + 'coordinates'=> $geometry->asArray(), + ); + } +} + + diff --git a/geoPHP/lib/adapters/GeoRSS.class.php b/geoPHP/lib/adapters/GeoRSS.class.php new file mode 100644 index 0000000..e496fff --- /dev/null +++ b/geoPHP/lib/adapters/GeoRSS.class.php @@ -0,0 +1,224 @@ +geomFromText($gpx); + } + + /** + * Serialize geometries into a GeoRSS string. + * + * @param Geometry $geometry + * + * @return string The georss string representation of the input geometries + */ + public function write(Geometry $geometry, $namespace = FALSE) { + if ($namespace) { + $this->namespace = $namespace; + $this->nss = $namespace.':'; + } + return $this->geometryToGeoRSS($geometry); + } + + public function geomFromText($text) { + // Change to lower-case, strip all CDATA, and de-namespace + $text = strtolower($text); + $text = preg_replace('//s','',$text); + $text = str_replace('georss:','',$text); + + // Load into DOMDOcument + $xmlobj = new DOMDocument(); + $xmlobj->loadXML($text); + if ($xmlobj === false) { + throw new Exception("Invalid GeoRSS: ". $text); + } + + $this->xmlobj = $xmlobj; + try { + $geom = $this->geomFromXML(); + } catch(InvalidText $e) { + throw new Exception("Cannot Read Geometry From GeoRSS: ". $text); + } catch(Exception $e) { + throw $e; + } + + return $geom; + } + + protected function geomFromXML() { + $geometries = array(); + $geometries = array_merge($geometries, $this->parsePoints()); + $geometries = array_merge($geometries, $this->parseLines()); + $geometries = array_merge($geometries, $this->parsePolygons()); + $geometries = array_merge($geometries, $this->parseBoxes()); + $geometries = array_merge($geometries, $this->parseCircles()); + + if (empty($geometries)) { + throw new Exception("Invalid / Empty GeoRSS"); + } + + return geoPHP::geometryReduce($geometries); + } + + protected function getPointsFromCoords($string) { + $coords = array(); + $latlon = explode(' ',$string); + foreach ($latlon as $key => $item) { + if (!($key % 2)) { + // It's a latitude + $lat = $item; + } + else { + // It's a longitude + $lon = $item; + $coords[] = new Point($lon, $lat); + } + } + return $coords; + } + + protected function parsePoints() { + $points = array(); + $pt_elements = $this->xmlobj->getElementsByTagName('point'); + foreach ($pt_elements as $pt) { + $point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue)); + $points[] = $point_array[0]; + } + return $points; + } + + protected function parseLines() { + $lines = array(); + $line_elements = $this->xmlobj->getElementsByTagName('line'); + foreach ($line_elements as $line) { + $components = $this->getPointsFromCoords(trim($line->firstChild->nodeValue)); + $lines[] = new LineString($components); + } + return $lines; + } + + protected function parsePolygons() { + $polygons = array(); + $poly_elements = $this->xmlobj->getElementsByTagName('polygon'); + foreach ($poly_elements as $poly) { + $points = $this->getPointsFromCoords(trim($poly->firstChild->nodeValue)); + $exterior_ring = new LineString($points); + $polygons[] = new Polygon(array($exterior_ring)); + } + return $polygons; + } + + // Boxes are rendered into polygons + protected function parseBoxes() { + $polygons = array(); + $box_elements = $this->xmlobj->getElementsByTagName('box'); + foreach ($box_elements as $box) { + $parts = explode(' ',trim($box->firstChild->nodeValue)); + $components = array( + new Point($parts[3], $parts[2]), + new Point($parts[3], $parts[0]), + new Point($parts[1], $parts[0]), + new Point($parts[1], $parts[2]), + new Point($parts[3], $parts[2]), + ); + $exterior_ring = new LineString($components); + $polygons[] = new Polygon(array($exterior_ring)); + } + return $polygons; + } + + // Circles are rendered into points + // @@TODO: Add good support once we have circular-string geometry support + protected function parseCircles() { + $points = array(); + $circle_elements = $this->xmlobj->getElementsByTagName('circle'); + foreach ($circle_elements as $circle) { + $parts = explode(' ',trim($circle->firstChild->nodeValue)); + $points[] = new Point($parts[1], $parts[0]); + } + return $points; + } + + protected function geometryToGeoRSS($geom) { + $type = strtolower($geom->getGeomType()); + switch ($type) { + case 'point': + return $this->pointToGeoRSS($geom); + break; + case 'linestring': + return $this->linestringToGeoRSS($geom); + break; + case 'polygon': + return $this->PolygonToGeoRSS($geom); + break; + case 'multipoint': + case 'multilinestring': + case 'multipolygon': + case 'geometrycollection': + return $this->collectionToGeoRSS($geom); + break; + } + return $output; + } + + private function pointToGeoRSS($geom) { + return '<'.$this->nss.'point>'.$geom->getY().' '.$geom->getX().'nss.'point>'; + } + + + private function linestringToGeoRSS($geom) { + $output = '<'.$this->nss.'line>'; + foreach ($geom->getComponents() as $k => $point) { + $output .= $point->getY().' '.$point->getX(); + if ($k < ($geom->numGeometries() -1)) $output .= ' '; + } + $output .= 'nss.'line>'; + return $output; + } + + private function polygonToGeoRSS($geom) { + $output = '<'.$this->nss.'polygon>'; + $exterior_ring = $geom->exteriorRing(); + foreach ($exterior_ring->getComponents() as $k => $point) { + $output .= $point->getY().' '.$point->getX(); + if ($k < ($exterior_ring->numGeometries() -1)) $output .= ' '; + } + $output .= 'nss.'polygon>'; + return $output; + } + + public function collectionToGeoRSS($geom) { + $georss = '<'.$this->nss.'where>'; + $components = $geom->getComponents(); + foreach ($geom->getComponents() as $comp) { + $georss .= $this->geometryToGeoRSS($comp); + } + + $georss .= 'nss.'where>'; + + return $georss; + } + +} diff --git a/geoPHP/lib/adapters/GoogleGeocode.class.php b/geoPHP/lib/adapters/GoogleGeocode.class.php new file mode 100644 index 0000000..4b40870 --- /dev/null +++ b/geoPHP/lib/adapters/GoogleGeocode.class.php @@ -0,0 +1,158 @@ + + * (c) Patrick Hayes + * + * This code is open-source and licenced under the Modified BSD License. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * PHP Google Geocoder Adapter + * + * + * @package geoPHP + * @author Patrick Hayes + */ +class GoogleGeocode extends GeoAdapter +{ + + /** + * Read an address string or array geometry objects + * + * @param string - Address to geocode + * @param string - Type of Geometry to return. Can either be 'points' or 'bounds' (polygon) + * @param Geometry|bounds-array - Limit the search area to within this region. For example + * by default geocoding "Cairo" will return the location of Cairo Egypt. + * If you pass a polygon of illinois, it will return Cairo IL. + * @param return_multiple - Return all results in a multipoint or multipolygon + * @return Geometry|GeometryCollection + */ + public function read($address, $return_type = 'point', $bounds = FALSE, $return_multiple = FALSE) { + if (is_array($address)) $address = join(',', $address); + + if (gettype($bounds) == 'object') { + $bounds = $bounds->getBBox(); + } + if (gettype($bounds) == 'array') { + $bounds_string = '&bounds='.$bounds['miny'].','.$bounds['minx'].'|'.$bounds['maxy'].','.$bounds['maxx']; + } + else { + $bounds_string = ''; + } + + $url = "http://maps.googleapis.com/maps/api/geocode/json"; + $url .= '?address='. urlencode($address); + $url .= $bounds_string; + $url .= '&sensor=false'; + $this->result = json_decode(@file_get_contents($url)); + + if ($this->result->status == 'OK') { + if ($return_multiple == FALSE) { + if ($return_type == 'point') { + return $this->getPoint(); + } + if ($return_type == 'bounds' || $return_type == 'polygon') { + return $this->getPolygon(); + } + } + if ($return_multiple == TRUE) { + if ($return_type == 'point') { + $points = array(); + foreach ($this->result->results as $delta => $item) { + $points[] = $this->getPoint($delta); + } + return new MultiPoint($points); + } + if ($return_type == 'bounds' || $return_type == 'polygon') { + $polygons = array(); + foreach ($this->result->results as $delta => $item) { + $polygons[] = $this->getPolygon($delta); + } + return new MultiPolygon($polygons); + } + } + } + else { + if ($this->result->status) throw new Exception('Error in Google Geocoder: '.$this->result->status); + else throw new Exception('Unknown error in Google Geocoder'); + return FALSE; + } + } + + /** + * Serialize geometries into a WKT string. + * + * @param Geometry $geometry + * @param string $return_type Should be either 'string' or 'array' + * + * @return string Does a reverse geocode of the geometry + */ + public function write(Geometry $geometry, $return_type = 'string') { + $centroid = $geometry->getCentroid(); + $lat = $centroid->getY(); + $lon = $centroid->getX(); + + $url = "http://maps.googleapis.com/maps/api/geocode/json"; + $url .= '?latlng='.$lat.','.$lon; + $url .= '&sensor=false'; + $this->result = json_decode(@file_get_contents($url)); + + if ($this->result->status == 'OK') { + if ($return_type == 'string') { + return $this->result->results[0]->formatted_address; + } + if ($return_type == 'array') { + return $this->result->results[0]->address_components; + } + } + else { + if ($this->result->status) throw new Exception('Error in Google Reverse Geocoder: '.$this->result->status); + else throw new Exception('Unknown error in Google Reverse Geocoder'); + return FALSE; + } + } + + private function getPoint($delta = 0) { + $lat = $this->result->results[$delta]->geometry->location->lat; + $lon = $this->result->results[$delta]->geometry->location->lng; + return new Point($lon, $lat); + } + + private function getPolygon($delta = 0) { + $points = array ( + $this->getTopLeft($delta), + $this->getTopRight($delta), + $this->getBottomRight($delta), + $this->getBottomLeft($delta), + $this->getTopLeft($delta), + ); + $outer_ring = new LineString($points); + return new Polygon(array($outer_ring)); + } + + private function getTopLeft($delta = 0) { + $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat; + $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng; + return new Point($lon, $lat); + } + + private function getTopRight($delta = 0) { + $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat; + $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng; + return new Point($lon, $lat); + } + + private function getBottomLeft($delta = 0) { + $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat; + $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng; + return new Point($lon, $lat); + } + + private function getBottomRight($delta = 0) { + $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat; + $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng; + return new Point($lon, $lat); + } +} diff --git a/geoPHP/lib/adapters/KML.class.php b/geoPHP/lib/adapters/KML.class.php new file mode 100644 index 0000000..70a859e --- /dev/null +++ b/geoPHP/lib/adapters/KML.class.php @@ -0,0 +1,240 @@ + + */ +class KML extends GeoAdapter +{ + + /** + * Read KML string into geometry objects + * + * @param string $kml A KML string + * + * @return Geometry|GeometryCollection + */ + public function read($kml) { + return $this->geomFromText($kml); + } + + /** + * Serialize geometries into a KML string. + * + * @param Geometry $geometry + * + * @return string The KML string representation of the input geometries + */ + public function write(Geometry $geometry) { + return $this->geometryToKML($geometry); + } + + public function geomFromText($text) { + + // Change to lower-case and strip all CDATA + $text = mb_strtolower($text, mb_detect_encoding($text)); + $text = preg_replace('//s','',$text); + + // Load into DOMDOcument + $xmlobj = new DOMDocument(); + @$xmlobj->loadXML($text); + if ($xmlobj === false) { + throw new Exception("Invalid KML: ". $text); + } + + $this->xmlobj = $xmlobj; + try { + $geom = $this->geomFromXML(); + } catch(InvalidText $e) { + throw new Exception("Cannot Read Geometry From KML: ". $text); + } catch(Exception $e) { + throw $e; + } + + return $geom; + } + + protected function geomFromXML() { + $geometries = array(); + $geom_types = geoPHP::geometryList(); + $placemark_elements = $this->xmlobj->getElementsByTagName('placemark'); + if ($placemark_elements->length) { + foreach ($placemark_elements as $placemark) { + foreach ($placemark->childNodes as $child) { + // Node names are all the same, except for MultiGeometry, which maps to GeometryCollection + $node_name = $child->nodeName == 'multigeometry' ? 'geometrycollection' : $child->nodeName; + if (array_key_exists($node_name, $geom_types)) { + $function = 'parse'.$geom_types[$node_name]; + $geometries[] = $this->$function($child); + } + } + } + } + else { + // The document does not have a placemark, try to create a valid geometry from the root element + $node_name = $this->xmlobj->documentElement->nodeName == 'multigeometry' ? 'geometrycollection' : $this->xmlobj->documentElement->nodeName; + if (array_key_exists($node_name, $geom_types)) { + $function = 'parse'.$geom_types[$node_name]; + $geometries[] = $this->$function($this->xmlobj->documentElement); + } + } + return geoPHP::geometryReduce($geometries); + } + + protected function childElements($xml, $nodename = '') { + $children = array(); + foreach ($xml->childNodes as $child) { + if ($child->nodeName == $nodename) { + $children[] = $child; + } + } + return $children; + } + + protected function parsePoint($xml) { + $coordinates = $this->_extractCoordinates($xml); + return new Point($coordinates[0][0],$coordinates[0][1]); + } + + protected function parseLineString($xml) { + $coordinates = $this->_extractCoordinates($xml); + $point_array = array(); + foreach ($coordinates as $set) { + $point_array[] = new Point($set[0],$set[1]); + } + return new LineString($point_array); + } + + protected function parsePolygon($xml) { + $components = array(); + + $outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis'); + $outer_boundary_element = $outer_boundary_element_a[0]; + $outer_ring_element_a = $this->childElements($outer_boundary_element, 'linearring'); + $outer_ring_element = $outer_ring_element_a[0]; + $components[] = $this->parseLineString($outer_ring_element); + + if (count($components) != 1) { + throw new Exception("Invalid KML"); + } + + $inner_boundary_element_a = $this->childElements($xml, 'innerboundaryis'); + if (count($inner_boundary_element_a)) { + foreach ($inner_boundary_element_a as $inner_boundary_element) { + foreach ($this->childElements($inner_boundary_element, 'linearring') as $inner_ring_element) { + $components[] = $this->parseLineString($inner_ring_element); + } + } + } + + return new Polygon($components); + } + + protected function parseGeometryCollection($xml) { + $components = array(); + $geom_types = geoPHP::geometryList(); + foreach ($xml->childNodes as $child) { + $nodeName = ($child->nodeName == 'linearring') ? 'linestring' : $child->nodeName; + $function = 'parse'.$geom_types[$nodeName]; + $components[] = $this->$function($child); + } + return new GeometryCollection($components); + } + + protected function _extractCoordinates($xml) { + $coord_elements = $this->childElements($xml, 'coordinates'); + if (!count($coord_elements)) { + throw new Exception('Bad KML: Missing coordinate element'); + } + $coordinates = array(); + $coord_sets = explode(' ',$coord_elements[0]->nodeValue); + foreach ($coord_sets as $set_string) { + $set_string = trim($set_string); + if ($set_string) { + $set_array = explode(',',$set_string); + if (count($set_array) >= 2) { + $coordinates[] = $set_array; + } + } + } + + return $coordinates; + } + + private function geometryToKML($geom) { + $type = strtolower($geom->getGeomType()); + switch ($type) { + case 'point': + return $this->pointToKML($geom); + break; + case 'linestring': + return $this->linestringToKML($geom); + break; + case 'polygon': + return $this->polygonToKML($geom); + break; + case 'multipoint': + case 'multilinestring': + case 'multipolygon': + case 'geometrycollection': + return $this->collectionToKML($geom); + break; + } + } + + private function pointToKML($geom) { + return "".$geom->getX().",".$geom->getY().""; + } + + private function linestringToKML($geom, $type = FALSE) { + if (!$type) { + $type = $geom->getGeomType(); + } + + $str = '<'. $type .'>'; + $i=0; + foreach ($geom->getComponents() as $comp) { + if ($i != 0) $str .= ' '; + $str .= $comp->getX() .','. $comp->getY(); + $i++; + } + + return $str .''; + } + + public function polygonToKML($geom) { + $components = $geom->getComponents(); + $str = '' . $this->linestringToKML($components[0], 'LinearRing') . ''; + foreach (array_slice($components, 1) as $comp) { + $str .= '' . $this->linestringToKML($comp) . ''; + } + + return ''. $str .''; + } + + public function collectionToKML($geom) { + $components = $geom->getComponents(); + $str = ''; + foreach ($geom->getComponents() as $comp) { + $sub_adapter = new KML(); + $str .= $sub_adapter->write($comp); + } + + return $str .''; + } + +} diff --git a/geoPHP/lib/adapters/WKB.class.php b/geoPHP/lib/adapters/WKB.class.php new file mode 100644 index 0000000..3185960 --- /dev/null +++ b/geoPHP/lib/adapters/WKB.class.php @@ -0,0 +1,216 @@ +getGeometry($mem); + fclose($mem); + return $geometry; + } + + function getGeometry(&$mem) { + $base_info = unpack("corder/Ltype", fread($mem, 5)); + if ($base_info['order'] !== 1) { + throw new Exception('Only NDR (little endian) SKB format is supported at the moment'); + } + switch ($base_info['type']) { + case 1: + return $this->getPoint($mem); + case 2: + return $this->getLinstring($mem); + case 3: + return $this->getPolygon($mem); + case 4: + return $this->getMulti($mem,'point'); + case 5: + return $this->getMulti($mem,'line'); + case 6: + return $this->getMulti($mem,'polygon'); + case 7: + return $this->getMulti($mem,'geometry'); + } + } + + function getPoint(&$mem) { + $point_coords = unpack("d*", fread($mem,16)); + return new Point($point_coords[1],$point_coords[2]); + } + + function getLinstring(&$mem) { + // Get the number of points expected in this string out of the first 4 bytes + $line_length = unpack('L',fread($mem,4)); + + // Read the nubmer of points x2 (each point is two coords) into decimal-floats + $line_coords = unpack('d'.$line_length[1]*2, fread($mem,$line_length[1]*16)); + + // We have our coords, build up the linestring + $components = array(); + $i = 1; + $num_coords = count($line_coords); + while ($i <= $num_coords) { + $components[] = new Point($line_coords[$i],$line_coords[$i+1]); + $i += 2; + } + return new LineString($components); + } + + function getPolygon(&$mem) { + // Get the number of linestring expected in this poly out of the first 4 bytes + $poly_length = unpack('L',fread($mem,4)); + + $components = array(); + $i = 1; + while ($i <= $poly_length[1]) { + $components[] = $this->getLinstring($mem); + $i++; + } + return new Polygon($components); + } + + function getMulti(&$mem, $type) { + // Get the number of items expected in this multi out of the first 4 bytes + $multi_length = unpack('L',fread($mem,4)); + + //@@TODO: create an EMPTY geometry instead of returning null + if (!$multi_length[1]) return NULL; + + $components = array(); + $i = 1; + while ($i <= $multi_length[1]) { + $components[] = $this->getGeometry($mem); + $i++; + } + switch ($type) { + case 'point': + return new MultiPoint($components); + case 'line': + return new MultiLineString($components); + case 'polygon': + return new MultiPolygon($components); + case 'geometry': + return new GeometryCollection($components); + } + } + + /** + * Serialize geometries into WKB string. + * + * @param Geometry $geometry + * + * @return string The WKB string representation of the input geometries + */ + public function write(Geometry $geometry, $write_as_hex = FALSE) { + // We always write into NDR (little endian) + $wkb = pack('c',1); + + switch ($geometry->getGeomType()) { + case 'Point'; + $wkb .= pack('L',1); + $wkb .= $this->writePoint($geometry); + break; + case 'LineString'; + $wkb .= pack('L',2); + $wkb .= $this->writeLineString($geometry); + break; + case 'Polygon'; + $wkb .= pack('L',3); + $wkb .= $this->writePolygon($geometry); + break; + case 'MultiPoint'; + $wkb .= pack('L',4); + $wkb .= $this->writeMulti($geometry); + break; + case 'MultiLineString'; + $wkb .= pack('L',5); + $wkb .= $this->writeMulti($geometry); + break; + case 'MultiPolygon'; + $wkb .= pack('L',6); + $wkb .= $this->writeMulti($geometry); + break; + case 'GeometryCollection'; + $wkb .= pack('L',7); + $wkb .= $this->writeMulti($geometry); + break; + } + + if ($write_as_hex) { + $unpacked = unpack('H*',$wkb); + return $unpacked[1]; + } + else { + return $wkb; + } + } + + function writePoint($point) { + // Set the coords + $wkb = pack('dd',$point->x(), $point->y()); + + return $wkb; + } + + function writeLineString($line) { + // Set the number of points in this line + $wkb = pack('L',$line->numPoints()); + + // Set the coords + foreach ($line->getComponents() as $point) { + $wkb .= pack('dd',$point->x(), $point->y()); + } + + return $wkb; + } + + function writePolygon($poly) { + // Set the number of lines in this poly + $wkb = pack('L',$poly->numGeometries()); + + // Write the lines + foreach ($poly->getComponents() as $line) { + $wkb .= $this->writeLineString($line); + } + + return $wkb; + } + + function writeMulti($geometry) { + // Set the number of components + $wkb = pack('L',$geometry->numGeometries()); + + // Write the components + foreach ($geometry->getComponents() as $component) { + $wkb .= $this->write($component); + } + + return $wkb; + } + +} diff --git a/geoPHP/lib/adapters/WKT.class.php b/geoPHP/lib/adapters/WKT.class.php new file mode 100644 index 0000000..a050c50 --- /dev/null +++ b/geoPHP/lib/adapters/WKT.class.php @@ -0,0 +1,195 @@ +read($wkt)); + } + $wkt = str_replace(', ', ',', $wkt); + + // For each geometry type, check to see if we have a match at the + // beggining of the string. If we do, then parse using that type + foreach (geoPHP::geometryList() as $geom_type) { + $wkt_geom = strtoupper($geom_type); + if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) { + $data_string = $this->getDataString($wkt, $wkt_geom); + $method = 'parse'.$geom_type; + return $this->$method($data_string); + } + } + } + + private function parsePoint($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode(' ',$data_string); + return new Point($parts[0], $parts[1]); + } + + private function parseLineString($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode(',',$data_string); + $points = array(); + foreach ($parts as $part) { + $points[] = $this->parsePoint($part); + } + return new LineString($points); + } + + private function parsePolygon($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode('),(',$data_string); + $lines = array(); + foreach ($parts as $part) { + if (!$this->beginsWith($part,'(')) $part = '(' . $part; + if (!$this->endsWith($part,')')) $part = $part . ')'; + $lines[] = $this->parseLineString($part); + } + return new Polygon($lines); + } + + private function parseMultiPoint($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode(',',$data_string); + $points = array(); + foreach ($parts as $part) { + $points[] = $this->parsePoint($part); + } + return new MultiPoint($points); + } + + private function parseMultiLineString($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode('),(',$data_string); + $lines = array(); + foreach ($parts as $part) { + // Repair the string if the explode broke it + if (!$this->beginsWith($part,'(')) $part = '(' . $part; + if (!$this->endsWith($part,')')) $part = $part . ')'; + $lines[] = $this->parseLineString($part); + } + return new MultiLineString($lines); + } + + private function parseMultiPolygon($data_string) { + $data_string = $this->trimParens($data_string); + $parts = explode(')),((',$data_string); + $polys = array(); + foreach ($parts as $part) { + // Repair the string if the explode broke it + if (!$this->beginsWith($part,'((')) $part = '((' . $part; + if (!$this->endsWith($part,'))')) $part = $part . '))'; + $polys[] = $this->parsePolygon($part); + } + return new MultiPolygon($polys); + } + + private function parseGeometryCollection($data_string) { + $data_string = $this->trimParens($data_string); + $geometries = array(); + $matches = array(); + $data_pattern = "( |,|[0-9]|\.|-|\)|\()+"; + $pattern = "/[A-Z]+$data_pattern/"; + preg_match_all($pattern, $data_string, $matches); + + foreach ($matches[0] as $item) { + if ($item) { + $geometries[] = $this->read(trim($item, ',')); + } + } + return new GeometryCollection($geometries); + } + + protected function getDataString($wkt, $type) { + return substr($wkt, strlen($type)); + } + + /** + * Trim the parenthesis and spaces + */ + protected function trimParens($str) { + $str = trim($str); + + // We want to only strip off one set of parenthesis + if ($this->beginsWith($str, '(')) { + return substr($str,1,-1); + } + else return $str; + } + + protected function beginsWith($str, $char) { + if (substr($str,0,strlen($char)) == $char) return TRUE; + else return FALSE; + } + + protected function endsWith($str, $char) { + if (substr($str,(0 - strlen($char))) == $char) return TRUE; + else return FALSE; + } + + /** + * Serialize geometries into a WKT string. + * + * @param Geometry $geometry + * + * @return string The WKT string representation of the input geometries + */ + public function write(Geometry $geometry) { + // If geos is installed, then we take a shortcut and let it write the WKT + if (geoPHP::geosInstalled()) { + $writer = new GEOSWKTWriter(); + return $writer->write($geometry->geos()); + } + + if ($data = $this->extractData($geometry)) { + return strtoupper($geometry->geometryType()).' ('.$data.')'; + } + } + + /** + * Extract geometry to a WKT string + * + * @param Geometry $geometry A Geometry object + * + * @return strin + */ + public function extractData($geometry) { + $parts = array(); + switch ($geometry->geometryType()) { + case 'Point': + return $geometry->getX().' '.$geometry->getY(); + case 'LineString': + foreach ($geometry->getComponents() as $component) { + $parts[] = $this->extractData($component); + } + return implode(', ', $parts); + case 'Polygon': + case 'MultiPoint': + case 'MultiLineString': + case 'MultiPolygon': + foreach ($geometry->getComponents() as $component) { + $parts[] = '('.$this->extractData($component).')'; + } + return implode(', ', $parts); + case 'GeometryCollection': + foreach ($geometry->getComponents() as $component) { + $parts[] = strtoupper($component->geometryType()).' ('.$this->extractData($component).')'; + } + return implode(', ', $parts); + } + } +} diff --git a/geoPHP/lib/geometry/Collection.class.php b/geoPHP/lib/geometry/Collection.class.php new file mode 100644 index 0000000..64eedf8 --- /dev/null +++ b/geoPHP/lib/geometry/Collection.class.php @@ -0,0 +1,196 @@ +components[] = $component; + } + else { + throw new Exception("Cannot create empty collection"); + } + } + + if (empty($this->components)) { + throw new Exception("Cannot create empty ".get_called_class()); + } + } + + /** + * Returns Collection component geometries + * + * @return array + */ + public function getComponents() { + return $this->components; + } + + public function centroid() { + if ($this->geos()) { + $geos_centroid = $this->geos()->centroid(); + if ($geos_centroid->typeName() == 'Point') { + return geoPHP::geosToGeometry($this->geos()->centroid()); + } + } + + // As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope + // @@TODO: Make this the centroid of the convexHull + // Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is + $centroid = $this->envelope()->centroid(); + + return $centroid; + } + + public function getBBox() { + if ($this->geos()) { + $envelope = $this->geos()->envelope(); + if ($envelope->typeName() == 'Point') { + return geoPHP::geosToGeometry($envelope)->getBBOX(); + } + + $geos_ring = $envelope->exteriorRing(); + return array( + 'maxy' => $geos_ring->pointN(3)->getY(), + 'miny' => $geos_ring->pointN(1)->getY(), + 'maxx' => $geos_ring->pointN(1)->getX(), + 'minx' => $geos_ring->pointN(3)->getX(), + ); + } + + // Go through each component and get the max and min x and y + $i = 0; + foreach ($this->components as $component) { + $component_bbox = $component->getBBox(); + + // On the first run through, set the bbox to the component bbox + if ($i == 0) { + $maxx = $component_bbox['maxx']; + $maxy = $component_bbox['maxy']; + $minx = $component_bbox['minx']; + $miny = $component_bbox['miny']; + } + + // Do a check and replace on each boundary, slowly growing the bbox + $maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx; + $maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy; + $minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx; + $miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny; + $i++; + } + + return array( + 'maxy' => $maxy, + 'miny' => $miny, + 'maxx' => $maxx, + 'minx' => $minx, + ); + } + + public function asArray() { + $array = array(); + foreach ($this->components as $component) { + $array[] = $component->asArray(); + } + return $array; + } + + public function area() { + if ($this->geos()) { + return $this->geos()->area(); + } + + $area = 0; + foreach ($this->components as $component) { + $area += $component->area(); + } + return $area; + } + + // By default, the boundary of a collection is the boundary of it's components + public function boundary() { + if ($this->geos()) { + return $this->geos()->boundary(); + } + + $components_boundaries = array(); + foreach ($this->components as $component) { + $components_boundaries[] = $component->boundary(); + } + return geoPHP::geometryReduce($components_boundaries); + } + + public function numGeometries() { + return count($this->components); + } + + // Note that the standard is 1 based indexing + public function geometryN($n) { + $n = intval($n); + if (array_key_exists($n-1, $this->components)) { + return $this->components[$n-1]; + } + else { + return NULL; + } + } + + public function length() { + if ($this->geos()) { + return $this->geos()->length(); + } + + $length = 0; + foreach ($this->components as $delta => $point) { + $next_point = $this->geometryN($delta); + if ($next_point) { + // Pythagorean Theorem + $distance = sqrt(($next_point->getX() - $point->getX())^2+($next_point->getY()- $point->getY())^2); + $length += $distance; + } + } + return $length; + } + + public function dimension() { + $dimension = 0; + foreach ($this->components as $component) { + if ($component->dimension() > $dimension) { + $dimension = $component->dimension(); + } + } + return $dimension; + } + + + // Not valid for this geometry type + // -------------------------------- + public function x() { return NULL; } + public function y() { return NULL; } + public function startPoint() { return NULL; } + public function endPoint() { return NULL; } + public function isRing() { return NULL; } + public function isClosed() { return NULL; } + public function numPoints() { return NULL; } + public function pointN($n) { return NULL; } + public function exteriorRing() { return NULL; } + public function numInteriorRings() { return NULL; } + public function interiorRingN($n) { return NULL; } + public function pointOnSurface() { return NULL; } +} + diff --git a/geoPHP/lib/geometry/Geometry.class.php b/geoPHP/lib/geometry/Geometry.class.php new file mode 100644 index 0000000..fd423d2 --- /dev/null +++ b/geoPHP/lib/geometry/Geometry.class.php @@ -0,0 +1,338 @@ +srid; + } + + public function setSRID($srid) { + if ($this->geos()) { + $this->geos()->setSRID($srid); + } + $this->srid = $srid; + } + + public function envelope() { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->envelope()); + } + + $bbox = $this->getBBox(); + $points = array ( + new Point($bbox['maxx'],$bbox['miny']), + new Point($bbox['maxx'],$bbox['maxy']), + new Point($bbox['minx'],$bbox['maxy']), + new Point($bbox['minx'],$bbox['miny']), + new Point($bbox['maxx'],$bbox['miny']), + ); + + $outer_boundary = new LineString($points); + return new Polygon(array($outer_boundary)); + } + + public function geometryType() { + return $this->geom_type; + } + + // Public: Non-Standard -- Common to all geometries + // ------------------------------------------------ + + // $this->out($format, $other_args); + public function out() { + $args = func_get_args(); + + $format = array_shift($args); + $type_map = geoPHP::getAdapterMap(); + $processor_type = $type_map[$format]; + $processor = new $processor_type(); + + array_unshift($args, $this); + $result = call_user_func_array(array($processor, 'write'), $args); + + return $result; + } + + + // Public: Aliases + // --------------- + public function getCentroid() { + return $this->centroid(); + } + + public function getArea() { + return $this->area(); + } + + public function getX() { + return $this->x(); + } + + public function getY() { + return $this->y(); + } + + public function getGeos() { + return $this->geos(); + } + + public function getGeomType() { + return $this->geometryType(); + } + + public function getSRID() { + return $this->SRID(); + } + + public function asText() { + return $this->out('wkt'); + } + + public function asBinary() { + return $this->out('wkb'); + } + + // Public: GEOS Only Functions + // --------------------------- + public function geos() { + // If it's already been set, just return it + if ($this->geos && geoPHP::geosInstalled()) { + return $this->geos; + } + // It hasn't been set yet, generate it + if (geoPHP::geosInstalled()) { + $reader = new GEOSWKBReader(); + $this->geos = $reader->readHEX($this->out('wkb',TRUE)); + } + else { + $this->geos = FALSE; + } + return $this->geos; + } + + public function setGeos($geos) { + $this->geos = $geos; + } + + public function pointOnSurface() { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->pointOnSurface()); + } + } + + public function equals($geometry) { + if ($this->geos()) { + return $this->geos()->equals($geometry->geos()); + } + } + + public function equalsExact($geometry) { + if ($this->geos()) { + return $this->geos()->equalsExact($geometry->geos()); + } + } + + public function relate($geometry) { + //@@TODO: Deal with second "pattern" parameter + if ($this->geos()) { + return $this->geos()->relate($geometry->geos()); + } + } + + public function checkValidity() { + if ($this->geos()) { + return $this->geos()->checkValidity(); + } + } + + public function isSimple() { + if ($this->geos()) { + return $this->geos()->isSimple(); + } + } + + public function buffer($distance) { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->buffer($distance)); + } + } + + public function intersection($geometry) { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->intersection($geometry->geos())); + } + } + + public function convexHull() { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->convexHull()); + } + } + + public function difference($geometry) { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->difference($geometry->geos())); + } + } + + public function symDifference($geometry) { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->symDifference($geometry->geos())); + } + } + + public function union($geometry) { + //@@TODO: also does union cascade + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->union($geometry->geos())); + } + } + + public function simplify($tolerance, $preserveTopology = FALSE) { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->simplify($tolerance, $preserveTopology)); + } + } + + public function disjoint($geometry) { + if ($this->geos()) { + return $this->geos()->disjoint($geometry->geos()); + } + } + + public function touches($geometry) { + if ($this->geos()) { + return $this->geos()->touches($geometry->geos()); + } + } + + public function intersects($geometry) { + if ($this->geos()) { + return $this->geos()->intersects($geometry->geos()); + } + } + + public function crosses($geometry) { + if ($this->geos()) { + return $this->geos()->crosses($geometry->geos()); + } + } + + public function within($geometry) { + if ($this->geos()) { + return $this->geos()->within($geometry->geos()); + } + } + + public function contains($geometry) { + if ($this->geos()) { + return $this->geos()->contains($geometry->geos()); + } + } + + public function overlaps($geometry) { + if ($this->geos()) { + return $this->geos()->overlaps($geometry->geos()); + } + } + + public function covers($geometry) { + if ($this->geos()) { + return $this->geos()->covers($geometry->geos()); + } + } + + public function coveredBy($geometry) { + if ($this->geos()) { + return $this->geos()->coveredBy($geometry->geos()); + } + } + + public function distance($geometry) { + if ($this->geos()) { + return $this->geos()->distance($geometry->geos()); + } + } + + public function hausdorffDistance($geometry) { + if ($this->geos()) { + return $this->geos()->hausdorffDistance($geometry->geos()); + } + } + + + // Public - Placeholders + // --------------------- + public function hasZ() { + // geoPHP does not support Z values at the moment + return FALSE; + } + + public function is3D() { + // geoPHP does not support 3D geometries at the moment + return FALSE; + } + + public function isMeasured() { + // geoPHP does not yet support M values + return FALSE; + } + + public function isEmpty() { + // geoPHP does not yet support empty geometries + return FALSE; + } + + public function coordinateDimension() { + // geoPHP only supports 2-dimentional space + return 2; + } + + public function z() { + // geoPHP only supports 2-dimentional space + return NULL; + } + + public function m() { + // geoPHP only supports 2-dimentional space + return NULL; + } + +} diff --git a/geoPHP/lib/geometry/GeometryCollection.class.php b/geoPHP/lib/geometry/GeometryCollection.class.php new file mode 100644 index 0000000..4d71119 --- /dev/null +++ b/geoPHP/lib/geometry/GeometryCollection.class.php @@ -0,0 +1,29 @@ +components as $component) { + $array[] = array( + 'type' => $component->geometryType(), + 'components' => $component->asArray(), + ); + } + return $array; + } + + // Not valid for this geomettry + public function boundary() { return NULL; } + public function isSimple() { return NULL; } +} + diff --git a/geoPHP/lib/geometry/LineString.class.php b/geoPHP/lib/geometry/LineString.class.php new file mode 100644 index 0000000..d14506f --- /dev/null +++ b/geoPHP/lib/geometry/LineString.class.php @@ -0,0 +1,66 @@ +pointN(1); + } + + public function endPoint() { + $last_n = $this->numPoints(); + return $this->pointN($last_n); + } + + public function isClosed() { + //@@TODO: Need to complete equal() first; + #return ($this->startPoint->equal($this->endPoint())); + } + + public function isRing() { + //@@TODO: need to complete isSimple first + #return ($this->isClosed() && $this->isSimple()); + } + + public function numPoints() { + return $this->numGeometries(); + } + + public function pointN($n) { + return $this->geometryN($n); + } + + public function dimension() { + return 1; + } + + public function area() { + return 0; + } + +} + diff --git a/geoPHP/lib/geometry/MultiLineString.class.php b/geoPHP/lib/geometry/MultiLineString.class.php new file mode 100644 index 0000000..208c199 --- /dev/null +++ b/geoPHP/lib/geometry/MultiLineString.class.php @@ -0,0 +1,33 @@ +geos()) { + return $this->geos()->length(); + } + + $length = 0; + foreach ($this->components as $line) { + $length += $line->length(); + } + return $length; + } + + // MultiLineString is closed if all it's components are closed + public function isClosed() { + foreach ($this->components as $line) { + if (!$line->isClosed()) { + return FALSE; + } + } + return TRUE; + } + +} + diff --git a/geoPHP/lib/geometry/MultiPoint.class.php b/geoPHP/lib/geometry/MultiPoint.class.php new file mode 100644 index 0000000..90b785d --- /dev/null +++ b/geoPHP/lib/geometry/MultiPoint.class.php @@ -0,0 +1,9 @@ +dimention = 3; + } + + // Convert to floatval in case they are passed in as a string or integer etc. + $x = floatval($x); + $y = floatval($y); + $z = floatval($z); + + // Add poitional elements + if ($this->dimention == 2) { + $this->coords = array($x, $y); + } + if ($this->dimention == 3) { + $this->coords = array($x, $y, $z); + } + } + + /** + * Get X (longitude) coordinate + * + * @return float The X coordinate + */ + public function x() { + return $this->coords[0]; + } + + /** + * Returns Y (latitude) coordinate + * + * @return float The Y coordinate + */ + public function y() { + return $this->coords[1]; + } + + /** + * Returns Z (altitude) coordinate + * + * @return float The Z coordinate or NULL is not a 3D point + */ + public function z() { + if ($this->dimention == 3) { + return $this->coords[2]; + } + else return NULL; + } + + // A point's centroid is itself + public function centroid() { + return $this; + } + + public function getBBox() { + return array( + 'maxy' => $this->getY(), + 'miny' => $this->getY(), + 'maxx' => $this->getX(), + 'minx' => $this->getX(), + ); + } + + public function asArray($assoc = FALSE) { + return $this->coords; + } + + public function area() { + return 0; + } + + public function length() { + return 0; + } + + // The bounadry of a point is itself + public function boundary() { + return $this; + } + + public function dimension() { + return 0; + } + + // Not valid for this geometry type + public function numGeometries() { return NULL; } + public function geometryN($n) { return NULL; } + public function startPoint() { return NULL; } + public function endPoint() { return NULL; } + public function isRing() { return NULL; } + public function isClosed() { return NULL; } + public function numPoints() { return NULL; } + public function pointN($n) { return NULL; } + public function exteriorRing() { return NULL; } + public function numInteriorRings() { return NULL; } + public function interiorRingN($n) { return NULL; } + public function pointOnSurface() { return NULL; } + +} + diff --git a/geoPHP/lib/geometry/Polygon.class.php b/geoPHP/lib/geometry/Polygon.class.php new file mode 100644 index 0000000..8cca643 --- /dev/null +++ b/geoPHP/lib/geometry/Polygon.class.php @@ -0,0 +1,95 @@ +geos() && $exterior_only == FALSE) { + return $this->geos()->area(); + } + + $exterior_ring = $this->components[0]; + $pts = $exterior_ring->getComponents(); + + $c = count($pts); + if((int)$c == '0') return NULL; + $a = '0'; + foreach($pts as $k => $p){ + $j = ($k + 1) % $c; + $a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX()); + } + + if ($signed) $area = ($a / 2); + else $area = abs(($a / 2)); + + if ($exterior_only == TRUE) { + return $area; + } + foreach ($this->components as $delta => $component) { + if ($delta != 0) { + $inner_poly = new Polygon(array($component)); + $area -= $inner_poly->area(); + } + } + return $area; + } + + public function centroid() { + if ($this->geos()) { + return geoPHP::geosToGeometry($this->geos()->centroid()); + } + + $exterior_ring = $this->components[0]; + $pts = $exterior_ring->getComponents(); + + $c = count($pts); + if((int)$c == '0') return NULL; + $cn = array('x' => '0', 'y' => '0'); + $a = $this->area(TRUE, TRUE); + + // If this is a polygon with no area. Just return the first point. + if ($a == 0) { + return $this->exteriorRing()->pointN(1); + } + + foreach($pts as $k => $p){ + $j = ($k + 1) % $c; + $P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX()); + $cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P; + $cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P; + } + + $cn['x'] = $cn['x'] / ( 6 * $a); + $cn['y'] = $cn['y'] / ( 6 * $a); + + $centroid = new Point($cn['x'], $cn['y']); + return $centroid; + } + + public function exteriorRing() { + return $this->components[0]; + } + + public function numInteriorRings() { + return $this->numGeometries()-1; + } + + public function interiorRingN($n) { + return $this->geometryN($n+1); + } + + public function dimension() { + return 2; + } + + // Not valid for this geometry type + // -------------------------------- + public function length() { return NULL; } + +} + diff --git a/geoPHP/tests/input/barret_spur.gpx b/geoPHP/tests/input/barret_spur.gpx new file mode 100644 index 0000000..9d48160 --- /dev/null +++ b/geoPHP/tests/input/barret_spur.gpx @@ -0,0 +1,219 @@ + + 1374Vista Ridge TrailheadTrail Head + 1777Wy'East Basin + 1823Dollar Lake + 2394Barrett SpurSummit + + Barrett Spur 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Barrett Spur 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/geoPHP/tests/input/big_n_ugly.kml b/geoPHP/tests/input/big_n_ugly.kml new file mode 100644 index 0000000..59ae0a3 --- /dev/null +++ b/geoPHP/tests/input/big_n_ugly.kml @@ -0,0 +1,915 @@ + + + + KML Samples + 1 + Unleash your creativity with the help of these examples! + + + + + + + + + + + + + + Placemarks + These are just some of the different kinds of placemarks with + which you can mark your favorite places + + -122.0839597145766 + 37.42222904525232 + 0 + -148.4122922628044 + 40.5575073395506 + 500.6566641072245 + + + Simple placemark + Attached to the ground. Intelligently places itself at the + height of the underlying terrain. + + -122.0822035425683,37.42228990140251,0 + + + + Floating placemark + 0 + Floats a defined distance above the ground. + + -122.0839597145766 + 37.42222904525232 + 0 + -148.4122922628044 + 40.5575073395506 + 500.6566641072245 + + #downArrowIcon + + relativeToGround + -122.084075,37.4220033612141,50 + + + + Extruded placemark + 0 + Tethered to the ground by a customizable + "tail" + + -122.0845787421525 + 37.42215078737763 + 0 + -148.4126684946234 + 40.55750733918048 + 365.2646606980322 + + #globeIcon + + 1 + relativeToGround + -122.0857667006183,37.42156927867553,50 + + + + + Styles and Markup + 0 + With KML it is easy to create rich, descriptive markup to + annotate and enrich your placemarks + + -122.0845787422371 + 37.42215078726837 + 0 + -148.4126777488172 + 40.55750733930874 + 365.2646826292919 + + #noDrivingDirections + + Highlighted Icon + 0 + Place your mouse over the icon to see it display the new + icon + + -122.0856552124024 + 37.4224281311035 + 0 + 0 + 0 + 265.8520424250024 + + + + + + normal + #normalPlacemark + + + highlight + #highlightPlacemark + + + + Roll over this icon + 0 + #exampleStyleMap + + -122.0856545755255,37.42243077405461,0 + + + + + Descriptive HTML + 0 +
+Placemark descriptions can be enriched by using many standard HTML tags.
+For example: +
+Styles:
+Italics, +Bold, +Underlined, +Strike Out, +subscriptsubscript, +superscriptsuperscript, +Big, +Small, +Typewriter, +Emphasized, +Strong, +Code +
+Fonts:
+red by name, +leaf green by hexadecimal RGB +
+size 1, +size 2, +size 3, +size 4, +size 5, +size 6, +size 7 +
+Times, +Verdana, +Arial
+
+Links: +
+Google Earth! +
+ or: Check out our website at www.google.com +
+Alignment:
+

left

+

center

+

right

+
+Ordered Lists:
+
  1. First
  2. Second
  3. Third
+
  1. First
  2. Second
  3. Third
+
  1. First
  2. Second
  3. Third
+
+Unordered Lists:
+
  • A
  • B
  • C
+
  • A
  • B
  • C
+
  • A
  • B
  • C
+
+Definitions:
+
+
Google:
The best thing since sliced bread
+
+
+Centered:
+Time present and time past
+Are both perhaps present in time future,
+And time future contained in time past.
+If all time is eternally present
+All time is unredeemable.
+
+
+Block Quote: +
+
+We shall not cease from exploration
+And the end of all our exploring
+Will be to arrive where we started
+And know the place for the first time.
+-- T.S. Eliot +
+
+
+Headings:
+

Header 1

+

Header 2

+

Header 3

+

Header 4

+

Header 5

+
+Images:
+Remote image
+
+Scaled image
+
+
+Simple Tables:
+ + + +
12345
abcde
+
+[Did you notice that double-clicking on the placemark doesn't cause the viewer to take you anywhere? This is because it is possible to directly author a "placeless placemark". If you look at the code for this example, you will see that it has neither a point coordinate nor a LookAt element.]]]>
+
+
+ + Ground Overlays + 0 + Examples of ground overlays + + Large-scale overlay on terrain + 0 + Overlay shows Mount Etna erupting on July 13th, 2001. + + 15.02468937557116 + 37.67395167941667 + 0 + -16.5581842842829 + 58.31228652890705 + 30350.36838438907 + + + http://code.google.com/apis/kml/documentation/etna.jpg + + + 37.91904192681665 + 37.46543388598137 + 15.35832653742206 + 14.60128369746704 + -0.1556640799496235 + + + + + Screen Overlays + 0 + Screen overlays have to be authored directly in KML. These + examples illustrate absolute and dynamic positioning in screen space. + + Simple crosshairs + 0 + This screen overlay uses fractional positioning to put the + image in the exact center of the screen + + http://code.google.com/apis/kml/documentation/crosshairs.png + + + + + + + + Absolute Positioning: Top left + 0 + + http://code.google.com/apis/kml/documentation/top_left.jpg + + + + + + + + Absolute Positioning: Top right + 0 + + http://code.google.com/apis/kml/documentation/top_right.jpg + + + + + + + + Absolute Positioning: Bottom left + 0 + + http://code.google.com/apis/kml/documentation/bottom_left.jpg + + + + + + + + Absolute Positioning: Bottom right + 0 + + http://code.google.com/apis/kml/documentation/bottom_right.jpg + + + + + + + + Dynamic Positioning: Top of screen + 0 + + http://code.google.com/apis/kml/documentation/dynamic_screenoverlay.jpg + + + + + + + + Dynamic Positioning: Right of screen + 0 + + http://code.google.com/apis/kml/documentation/dynamic_right.jpg + + + + + + + + + Paths + 0 + Examples of paths. Note that the tessellate tag is by default + set to 0. If you want to create tessellated lines, they must be authored + (or edited) directly in KML. + + Tessellated + 0 + tag has a value of 1, the line will contour to the underlying terrain]]> + + -112.0822680013139 + 36.09825589333556 + 0 + 103.8120432044965 + 62.04855796276328 + 2889.145007690472 + + + 1 + -112.0814237830345,36.10677870477137,0 + -112.0870267752693,36.0905099328766,0 + + + + Untessellated + 0 + tag has a value of 0, the line follow a simple straight-line path from point to point]]> + + -112.0822680013139 + 36.09825589333556 + 0 + 103.8120432044965 + 62.04855796276328 + 2889.145007690472 + + + 0 + -112.080622229595,36.10673460007995,0 + -112.085242575315,36.09049598612422,0 + + + + Absolute + 0 + Transparent purple line + + -112.2719329043177 + 36.08890633450894 + 0 + -106.8161545998597 + 44.60763714063257 + 2569.386744398339 + + #transPurpleLineGreenPoly + + 1 + absolute + -112.265654928602,36.09447672602546,2357 + -112.2660384528238,36.09342608838671,2357 + -112.2668139013453,36.09251058776881,2357 + -112.2677826834445,36.09189827357996,2357 + -112.2688557510952,36.0913137941187,2357 + -112.2694810717219,36.0903677207521,2357 + -112.2695268555611,36.08932171487285,2357 + -112.2690144567276,36.08850916060472,2357 + -112.2681528815339,36.08753813597956,2357 + -112.2670588176031,36.08682685262568,2357 + -112.2657374587321,36.08646312301303,2357 + + + + Absolute Extruded + 0 + Transparent green wall with yellow outlines + + -112.2643334742529 + 36.08563154742419 + 0 + -125.7518698668815 + 44.61038665812578 + 4451.842204068102 + + #yellowLineGreenPoly + + 1 + 1 + absolute + -112.2550785337791,36.07954952145647,2357 + -112.2549277039738,36.08117083492122,2357 + -112.2552505069063,36.08260761307279,2357 + -112.2564540158376,36.08395660588506,2357 + -112.2580238976449,36.08511401044813,2357 + -112.2595218489022,36.08584355239394,2357 + -112.2608216347552,36.08612634548589,2357 + -112.262073428656,36.08626019085147,2357 + -112.2633204928495,36.08621519860091,2357 + -112.2644963846444,36.08627897945274,2357 + -112.2656969554589,36.08649599090644,2357 + + + + Relative + 0 + Black line (10 pixels wide), height tracks terrain + + -112.2580438551384 + 36.1072674824385 + 0 + 4.947421249553717 + 44.61324882043339 + 2927.61105910266 + + #thickBlackLine + + 1 + relativeToGround + -112.2532845153347,36.09886943729116,645 + -112.2540466121145,36.09919570465255,645 + -112.254734666947,36.09984998366178,645 + -112.255493345654,36.10051310621746,645 + -112.2563157098468,36.10108441943419,645 + -112.2568033076439,36.10159722088088,645 + -112.257494011321,36.10204323542867,645 + -112.2584106072308,36.10229131995655,645 + -112.2596588987972,36.10240001286358,645 + -112.2610581199487,36.10213176873407,645 + -112.2626285262793,36.10157011437219,645 + + + + Relative Extruded + 0 + Opaque blue walls with red outline, height tracks terrain + + -112.2683594333433 + 36.09884362144909 + 0 + -72.24271551768405 + 44.60855445139561 + 2184.193522571467 + + #redLineBluePoly + + 1 + 1 + relativeToGround + -112.2656634181359,36.09445214722695,630 + -112.2652238941097,36.09520916122063,630 + -112.2645079986395,36.09580763864907,630 + -112.2638827428817,36.09628572284063,630 + -112.2635746835406,36.09679275951239,630 + -112.2635711822407,36.09740038871899,630 + -112.2640296531825,36.09804913435539,630 + -112.264327720538,36.09880337400301,630 + -112.2642436562271,36.09963644790288,630 + -112.2639148687042,36.10055381117246,630 + -112.2626894973474,36.10149062823369,630 + + + + + Polygons + 0 + Examples of polygon shapes + + Google Campus + 0 + A collection showing how easy it is to create 3-dimensional + buildings + + -122.084120030116 + 37.42174011925477 + 0 + -34.82469740081282 + 53.454348562403 + 276.7870053764046 + + + Building 40 + 0 + #transRedPoly + + 1 + relativeToGround + + + -122.0848938459612,37.42257124044786,17 + -122.0849580979198,37.42211922626856,17 + -122.0847469573047,37.42207183952619,17 + -122.0845725380962,37.42209006729676,17 + -122.0845954886723,37.42215932700895,17 + -122.0838521118269,37.42227278564371,17 + -122.083792243335,37.42203539112084,17 + -122.0835076656616,37.42209006957106,17 + -122.0834709464152,37.42200987395161,17 + -122.0831221085748,37.4221046494946,17 + -122.0829247374572,37.42226503990386,17 + -122.0829339169385,37.42231242843094,17 + -122.0833837359737,37.42225046087618,17 + -122.0833607854248,37.42234159228745,17 + -122.0834204551642,37.42237075460644,17 + -122.083659133885,37.42251292011001,17 + -122.0839758438952,37.42265873093781,17 + -122.0842374743331,37.42265143972521,17 + -122.0845036949503,37.4226514386435,17 + -122.0848020460801,37.42261133916315,17 + -122.0847882750515,37.42256395055121,17 + -122.0848938459612,37.42257124044786,17 + + + + + + Building 41 + 0 + #transBluePoly + + 1 + relativeToGround + + + -122.0857412771483,37.42227033155257,17 + -122.0858169768481,37.42231408832346,17 + -122.085852582875,37.42230337469744,17 + -122.0858799945639,37.42225686138789,17 + -122.0858860101409,37.4222311076138,17 + -122.0858069157288,37.42220250173855,17 + -122.0858379542653,37.42214027058678,17 + -122.0856732640519,37.42208690214408,17 + -122.0856022926407,37.42214885429042,17 + -122.0855902778436,37.422128290487,17 + -122.0855841672237,37.42208171967246,17 + -122.0854852065741,37.42210455874995,17 + -122.0855067264352,37.42214267949824,17 + -122.0854430712915,37.42212783846172,17 + -122.0850990714904,37.42251282407603,17 + -122.0856769818632,37.42281815323651,17 + -122.0860162273783,37.42244918858722,17 + -122.0857260327004,37.42229239604253,17 + -122.0857412771483,37.42227033155257,17 + + + + + + Building 42 + 0 + #transGreenPoly + + 1 + relativeToGround + + + -122.0857862287242,37.42136208886969,25 + -122.0857312990603,37.42136935989481,25 + -122.0857312992918,37.42140934910903,25 + -122.0856077073679,37.42138390166565,25 + -122.0855802426516,37.42137299550869,25 + -122.0852186221971,37.42137299504316,25 + -122.0852277765639,37.42161656508265,25 + -122.0852598189347,37.42160565894403,25 + -122.0852598185499,37.42168200156,25 + -122.0852369311478,37.42170017860346,25 + -122.0852643957828,37.42176197982575,25 + -122.0853239032746,37.42176198013907,25 + -122.0853559454324,37.421852864452,25 + -122.0854108752463,37.42188921823734,25 + -122.0854795379357,37.42189285337048,25 + -122.0855436229819,37.42188921797546,25 + -122.0856260178042,37.42186013499926,25 + -122.085937287963,37.42186013453605,25 + -122.0859428718666,37.42160898590042,25 + -122.0859655469861,37.42157992759144,25 + -122.0858640462341,37.42147115002957,25 + -122.0858548911215,37.42140571326184,25 + -122.0858091162768,37.4214057134039,25 + -122.0857862287242,37.42136208886969,25 + + + + + + Building 43 + 0 + #transYellowPoly + + 1 + relativeToGround + + + -122.0844371128284,37.42177253003091,19 + -122.0845118855746,37.42191111542896,19 + -122.0850470999805,37.42178755121535,19 + -122.0850719913391,37.42143663023161,19 + -122.084916406232,37.42137237822116,19 + -122.0842193868167,37.42137237801626,19 + -122.08421938659,37.42147617161496,19 + -122.0838086419991,37.4214613409357,19 + -122.0837899728564,37.42131306410796,19 + -122.0832796534698,37.42129328840593,19 + -122.0832609819207,37.42139213944298,19 + -122.0829373621737,37.42137236399876,19 + -122.0829062425667,37.42151569778871,19 + -122.0828502269665,37.42176282576465,19 + -122.0829435788635,37.42176776969635,19 + -122.083217411188,37.42179248552686,19 + -122.0835970430103,37.4217480074456,19 + -122.0839455556771,37.42169364237603,19 + -122.0840077894637,37.42176283815853,19 + -122.084113587521,37.42174801104392,19 + -122.0840762473784,37.42171341292375,19 + -122.0841447047739,37.42167881534569,19 + -122.084144704223,37.42181720660197,19 + -122.0842503333074,37.4218170700446,19 + -122.0844371128284,37.42177253003091,19 + + + + + + + Extruded Polygon + A simple way to model a building + + The Pentagon + + -77.05580139178142 + 38.870832443487 + 59.88865561738225 + 48.09646074797388 + 742.0552506670548 + + + 1 + relativeToGround + + + -77.05788457660967,38.87253259892824,100 + -77.05465973756702,38.87291016281703,100 + -77.05315536854791,38.87053267794386,100 + -77.05552622493516,38.868757801256,100 + -77.05844056290393,38.86996206506943,100 + -77.05788457660967,38.87253259892824,100 + + + + + -77.05668055019126,38.87154239798456,100 + -77.05542625960818,38.87167890344077,100 + -77.05485125901024,38.87076535397792,100 + -77.05577677433152,38.87008686581446,100 + -77.05691162017543,38.87054446963351,100 + -77.05668055019126,38.87154239798456,100 + + + + + + + Absolute and Relative + 0 + Four structures whose roofs meet exactly. Turn on/off + terrain to see the difference between relative and absolute + positioning. + + -112.3348969157552 + 36.14845533214919 + 0 + -86.91235037566909 + 49.30695423894192 + 990.6761201087104 + + + Absolute + 0 + #transBluePoly + + 1 + absolute + + + -112.3382510731295,36.14888505105318,1784 + -112.3356128688403,36.14781540589019,1784 + -112.3368169371048,36.14658677734382,1784 + -112.3374408457543,36.14762778914076,1784 + -112.3382510731295,36.14888505105318,1784 + + + + + + Absolute Extruded + 0 + #transRedPoly + + 1 + 1 + absolute + + + -112.3396586818843,36.14637618647505,1784 + -112.3380597654315,36.14531751871353,1784 + -112.3368254237788,36.14659596244607,1784 + -112.3384555043203,36.14762621763982,1784 + -112.3396586818843,36.14637618647505,1784 + + + + + + Relative + 0 + + -112.3350152490417 + 36.14943123077423 + 0 + -118.9214100848499 + 37.92486261093203 + 345.5169113679813 + + #transGreenPoly + + 1 + relativeToGround + + + -112.3349463145932,36.14988705767721,100 + -112.3354019540677,36.14941108398372,100 + -112.3344428289146,36.14878490381308,100 + -112.3331289492913,36.14780840132443,100 + -112.3317019516947,36.14680755678357,100 + -112.331131440106,36.1474173426228,100 + -112.332616324338,36.14845453364654,100 + -112.3339876620524,36.14926570522069,100 + -112.3349463145932,36.14988705767721,100 + + + + + + Relative Extruded + 0 + + -112.3351587892382 + 36.14979247129029 + 0 + -55.42811560891606 + 56.10280503739589 + 401.0997279712519 + + #transYellowPoly + + 1 + 1 + relativeToGround + + + -112.3348783983763,36.1514008468736,100 + -112.3372535345629,36.14888517553886,100 + -112.3356068927954,36.14781612679284,100 + -112.3350034807972,36.14846469024177,100 + -112.3358353861232,36.1489624162954,100 + -112.3345888301373,36.15026229372507,100 + -112.3337937856278,36.14978096026463,100 + -112.3331798208424,36.1504472788618,100 + -112.3348783983763,36.1514008468736,100 + + + + + + +
+
diff --git a/geoPHP/tests/input/box.georss b/geoPHP/tests/input/box.georss new file mode 100644 index 0000000..4c1bddf --- /dev/null +++ b/geoPHP/tests/input/box.georss @@ -0,0 +1 @@ +42.943 -71.032 43.039 -69.856 \ No newline at end of file diff --git a/geoPHP/tests/input/cdata.kml b/geoPHP/tests/input/cdata.kml new file mode 100644 index 0000000..f5bbe74 --- /dev/null +++ b/geoPHP/tests/input/cdata.kml @@ -0,0 +1,19 @@ + + + + + CDATA example + + CDATA Tags are useful! +

Text is more readable and + easier to write when you can avoid using entity + references.

+ ]]> +
+ + 102.595626,14.996729 + +
+
+
diff --git a/geoPHP/tests/input/circle.georss b/geoPHP/tests/input/circle.georss new file mode 100644 index 0000000..4d7055b --- /dev/null +++ b/geoPHP/tests/input/circle.georss @@ -0,0 +1 @@ +42.943 -71.032 500 \ No newline at end of file diff --git a/geoPHP/tests/input/fells_loop.gpx b/geoPHP/tests/input/fells_loop.gpx new file mode 100644 index 0000000..d8a1df5 --- /dev/null +++ b/geoPHP/tests/input/fells_loop.gpx @@ -0,0 +1,1077 @@ + + + + + + 44.586548 + + 5066 + + Crossing + + + + 57.607200 + + 5067 + + Dot + + + + 44.826904 + + 5096 + + Dot + + + + 50.594727 + + 5142 + + Dot + + + + 127.711200 + + 5156 + + Dot + + + + 96.926400 + + 5224 + + Dot + + + + 82.600800 + + 5229 + + Dot + + + + 82.905600 + + 5237 + + Dot + + + + 66.696655 + + 5254 + + Dot + + + + 74.627442 + + 5258 + + Dot + + + + 65.254761 + + 5264 + + Dot + + + + 77.419200 + + 526708 + + Dot + + + + 74.676000 + + 526750 + + Dot + + + + 78.713135 + + 527614 + + Dot + + + + 78.713135 + + 527631 + + Dot + + + + 68.275200 + + 5278 + + Dot + + + + 64.008000 + + 5289 + + Dot + + + + 52.997925 + + 5374FIRE + + Dot + + + + 56.388000 + + 5376 + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 46.028564 + + 6006BLUE + + Dot + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 56.388000 + + 6029 + + Dot + + + + 50.292000 + + 6053 + + Dot + + + + 25.603200 + + 6066 + + Dot + + + + 34.442400 + + 6067 + + Dot + + + + 30.480000 + + 6071 + + Dot + + + + 15.240000 + + 6073 + + Dot + + + + 37.795200 + + 6084 + + Dot + + + + 64.008000 + + 6130 + + Dot + + + + 64.008000 + + 6131 + + Dot + + + + 62.788800 + + 6153 + + Dot + + + + 55.473600 + + 6171 + + Dot + + + + 62.484000 + + 6176 + + Dot + + + + 62.179200 + + 6177 + + Dot + + + + 69.799200 + + 6272 + + Dot + + + + 73.152000 + + 6272 + + Dot + + + + 70.104000 + + 6278 + + Dot + + + + 57.564209 + + 6280 + + Dot + + + + 66.696655 + + 6283 + + Dot + + + + 72.945191 + + 6289 + + Dot + + + + 72.847200 + + 6297 + + Dot + + + + 53.644800 + + 6328 + + Dot + + + + 43.891200 + + 6354 + + Dot + + + + 48.768000 + + 635722 + + Dot + + + + 49.072800 + + 635783 + + Dot + + + + 62.484000 + + 6373 + + Dot + + + + 3.962400 + + 6634 + + Dot + + + + 13.411200 + + 6979 + + Dot + + + + 34.012085 + + 6997 + + Dot + + + + 87.782400 + + BEAR HILL + BEAR HILL TOWER + + Tall Tower + + + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + 43.384766 + + 6016 + + Trailhead + + + + 89.916000 + + 5236BRIDGE + + Bridge + + + + 55.473600 + + 5376BRIDGE + + Bridge + + + + 52.730400 + + 6181CROSS + + Crossing + + + + 45.110400 + + 6042CROSS + + Crossing + + + + DARKHOLLPO + + Fishing Area + + + 56.083200 + + 6121DEAD + + Danger Area + + + + 117.043200 + + 5179DEAD + + Danger Area + + + + 69.494400 + + 5299DEAD + + Danger Area + + + + 56.997600 + + 5376DEAD + + Danger Area + + + + 46.939200 + + 6353DEAD + + Danger Area + + + + 61.264800 + + 6155DEAD + + Danger Area + + + + 110.947200 + + GATE14 + + Truck Stop + + + + 77.724000 + + GATE16 + + Truck Stop + + + + 65.836800 + + GATE17 + + Truck Stop + + + + 57.302400 + + GATE19 + + Truck Stop + + + + 49.377600 + + GATE21 + + Truck Stop + + + + 81.076800 + + GATE24 + + Truck Stop + + + + 21.515015 + + GATE5 + + Truck Stop + + + + 26.561890 + + GATE6 + + Trailhead + + + + 32.004000 + + 6077LOGS + + Amusement Park + + + + 119.809082 + + 5148NANEPA + + Trailhead + + + + 73.761600 + + 5267OBSTAC + + Amusement Park + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 77.992066 + + 5252PURPLE + + Summit + + + + 67.970400 + + 5287WATER + + Swimming Area + + + + 81.076800 + + 5239ROAD + + Truck Stop + + + + 67.360800 + + 5278ROAD + + Truck Stop + + + + 53.949600 + + 5058ROAD + ROAD CROSSING + + Dot + + + + 69.799200 + + SHEEPFOLD + + Parking Area + + + + 64.008000 + + SOAPBOX + + Cemetery + + + + 64.533692 + + 5376STREAM + + Bridge + + + + 61.649902 + + 5144SUMMIT + + Summit + + + + 67.360800 + + 5150TANK + WATER TANK + + Museum + + + + BELLEVUE + + 1 + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + 26.561890 + + GATE6 + + Trailhead + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 46.028564 + + 6006BLUE + + Dot + + + + 44.826904 + + 5096 + + Dot + + + + 44.586548 + + 5066 + + Crossing + + + + 57.607200 + + 5067 + + Dot + + + + 53.949600 + + 5058ROAD + ROAD CROSSING + + Dot + + + + 67.360800 + + 5150TANK + WATER TANK + + Museum + + + + 50.594727 + + 5142 + + Dot + + + + 61.649902 + + 5144SUMMIT + + Summit + + + + 127.711200 + + 5156 + + Dot + + + + 119.809082 + + 5148NANEPA + + Trailhead + + + + 74.627442 + + 5258 + + Dot + + + + 77.992066 + + 5252PURPLE + + Summit + + + + 78.713135 + + 527631 + + Dot + + + + 78.713135 + + 527614 + + Dot + + + + 73.761600 + + 5267OBSTAC + + Amusement Park + + + + 68.275200 + + 5278 + + Dot + + + + 64.008000 + + 5289 + + Dot + + + + 52.997925 + + 5374FIRE + + Dot + + + + 56.388000 + + 5376 + + Dot + + + + 64.533692 + + 5376STREAM + + Bridge + + + + 53.644800 + + 6328 + + Dot + + + + 48.768000 + + 635722 + + Dot + + + + 49.072800 + + 635783 + + Dot + + + + 62.484000 + + 6373 + + Dot + + + + 87.782400 + + BEAR HILL + BEAR HILL TOWER + + Tall Tower + + + + 72.945191 + + 6289 + + Dot + + + + 72.847200 + + 6297 + + Dot + + + + 66.696655 + + 6283 + + Dot + + + + 57.564209 + + 6280 + + Dot + + + + 62.179200 + + 6177 + + Dot + + + + 62.484000 + + 6176 + + Dot + + + + 62.788800 + + 6153 + + Dot + + + + 55.473600 + + 6171 + + Dot + + + + 64.008000 + + 6131 + + Dot + + + + 64.008000 + + 6130 + + Dot + + + + 56.388000 + + 6029 + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 26.561890 + + GATE6 + + Trailhead + + + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + \ No newline at end of file diff --git a/geoPHP/tests/input/geometrycollection.georss b/geoPHP/tests/input/geometrycollection.georss new file mode 100644 index 0000000..92bf895 --- /dev/null +++ b/geoPHP/tests/input/geometrycollection.georss @@ -0,0 +1,29 @@ + + + Earthquakes + International earthquake observation labs + + 2005-12-13T18:30:02Z + + Dr. Thaddeus Remor + tremor@quakelab.edu + + urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 + + This has multiple georss entries in it + + urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + 2005-08-17T07:02:32Z + We just had a big one. + 45.256 -71.92 + 42.256 -69.92 + 45.256 -110.45 46.46 -109.48 43.84 -109.86 + 45.256 -110.45 46.46 -109.48 43.84 -109.86 45.256 -110.45 + + + Another Entryd + Another point. + 46.256 -70.92 + + \ No newline at end of file diff --git a/geoPHP/tests/input/geometrycollection.wkt b/geoPHP/tests/input/geometrycollection.wkt new file mode 100644 index 0000000..ef2fee5 --- /dev/null +++ b/geoPHP/tests/input/geometrycollection.wkt @@ -0,0 +1 @@ +GEOMETRYCOLLECTION (POINT (4 6), LINESTRING (4 6,7 10)) diff --git a/geoPHP/tests/input/line.georss b/geoPHP/tests/input/line.georss new file mode 100644 index 0000000..7dbeb12 --- /dev/null +++ b/geoPHP/tests/input/line.georss @@ -0,0 +1 @@ +45.256 -110.45 46.46 -109.48 43.84 -109.86 \ No newline at end of file diff --git a/geoPHP/tests/input/linestring.wkt b/geoPHP/tests/input/linestring.wkt new file mode 100644 index 0000000..cc54277 --- /dev/null +++ b/geoPHP/tests/input/linestring.wkt @@ -0,0 +1 @@ +LINESTRING (30 10, 10 30, 40 40) diff --git a/geoPHP/tests/input/multilinestring.wkt b/geoPHP/tests/input/multilinestring.wkt new file mode 100644 index 0000000..f21a403 --- /dev/null +++ b/geoPHP/tests/input/multilinestring.wkt @@ -0,0 +1 @@ +MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10)) diff --git a/geoPHP/tests/input/multipolygon.wkb b/geoPHP/tests/input/multipolygon.wkb new file mode 100644 index 0000000000000000000000000000000000000000..f8e9b826b1c639061284bff9c38267b8ffb0b51b GIT binary patch literal 179 zcmZQ%V_;xl0%AsH5COz2KnwwP4iMS|N~=I=7YNnqY>) NXqaU%bue*+egL_d2yXxY literal 0 HcmV?d00001 diff --git a/geoPHP/tests/input/multipolygon.wkt b/geoPHP/tests/input/multipolygon.wkt new file mode 100644 index 0000000..ddd06bf --- /dev/null +++ b/geoPHP/tests/input/multipolygon.wkt @@ -0,0 +1 @@ +MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5))) diff --git a/geoPHP/tests/input/multipolygon2.wkt b/geoPHP/tests/input/multipolygon2.wkt new file mode 100644 index 0000000..8a8e30a --- /dev/null +++ b/geoPHP/tests/input/multipolygon2.wkt @@ -0,0 +1 @@ +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))) \ No newline at end of file diff --git a/geoPHP/tests/input/multipolygon_big.wkt b/geoPHP/tests/input/multipolygon_big.wkt new file mode 100644 index 0000000..3105141 --- /dev/null +++ b/geoPHP/tests/input/multipolygon_big.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((-111.557386371065249 56.684410828632991,-111.544980383084948 56.682722495117694,-111.547288554185783 56.682722128260217,-111.560588075947805 56.682719181298069,-111.557386371065249 56.684410828632991)),((-110.655582437704567 56.807505664432796,-110.647218116177612 56.80671710810411,-110.643673148613047 56.80670703768957,-110.634661802700208 56.806680985279918,-110.626296209431871 56.806082076023685,-110.619789771966879 56.80561606125984,-110.5970409749429 56.80197278849441,-110.567745946116929 56.801874761074451,-110.548280302758144 56.796448204044054,-110.528820744389193 56.791018371914532,-110.50936637365119 56.785585752864272,-110.499103824807818 56.779870244503989,-110.493664505516506 56.779682321259727,-110.459232293195328 56.774966230302333,-110.452380964820449 56.7553437574648,-110.460973901640784 56.73644164816924,-110.468543133012872 56.733989511060045,-110.468734744069124 56.733927426379722,-110.49081191233563 56.726770760707375,-110.504939293196699 56.730725178028258,-110.51009929403682 56.7293322843976,-110.517293546198189 56.726409894398806,-110.51740142820934 56.726366064822571,-110.518497304347093 56.725920828546457,-110.524819818539541 56.72135261004626,-110.53298393373845 56.717811508104461,-110.539501382430203 56.716050024775306,-110.551205211566966 56.715021179989229,-110.557051038337889 56.715042093200836,-110.580468421403637 56.711908263778916,-110.586313787793046 56.711927803774849,-110.598015077092683 56.710894559920987,-110.605335181932546 56.709578597305672,-110.627292440376905 56.705627879873539,-110.663393794830597 56.705730623582014,-110.663538147305005 56.705731013412404,-110.685733407778628 56.705788963215937,-110.700206118150547 56.708482132316114,-110.70716012535172 56.706590221683513,-110.712865090422667 56.705037800495646,-110.716703851889847 56.703324734967815,-110.741711396878614 56.692276649666439,-110.755996054226088 56.685774597223499,-110.763555924376149 56.682561807037608,-110.786065807609532 56.682658062055957,-110.786291755103306 56.682659007614262,-110.792653432098987 56.682685462107784,-110.792784153484533 56.682686002294886,-110.798848751416898 56.682710912543328,-110.799139846187586 56.6827121007843,-110.803154094737508 56.682728417465995,-110.803395644126624 56.682729395163207,-110.878371475521206 56.682749524228022,-110.842601133057414 56.691138787132822,-110.804527596605666 56.709371183118691,-110.804444377663174 56.709418115779826,-110.812386805922699 56.711617602716046,-110.829909318254479 56.716467059924653,-110.83864107900483 56.726127500382901,-110.843008838106513 56.73095737621427,-110.845618246469144 56.736749787830583,-110.856118433775805 56.745446286568786,-110.84554700937008 56.754117568824391,-110.842888085499581 56.759903378999716,-110.837223940619438 56.764031364102792,-110.829680334301614 56.767122561766321,-110.822135486908806 56.77021329996947,-110.816467511436898 56.774340333187212,-110.809129122886475 56.777545645401091,-110.803262239232467 56.779144471662335,-110.793369460953144 56.78003318215687,-110.792463649253023 56.781020234103892,-110.787553339424136 56.786369548702815,-110.772863045554871 56.794380158043118,-110.763083078717614 56.797040882218859,-110.743518547797734 56.802359777655127,-110.714222753358612 56.802296133135961,-110.692218066552414 56.806262050811284,-110.684882143536583 56.807583078045376,-110.655582437704567 56.807505664432796)),((-113.229119892737344 57.017440289033701,-113.225737165173769 57.016295214053798,-113.21708768328989 57.013366567110353,-113.211072678087248 57.01132938513755,-113.2092476894736 57.010711206063391,-113.207790520939668 57.010217584717289,-113.202051170124278 57.008273063384891,-113.198901798741744 57.006986889924526,-113.195750789844126 57.005699878010773,-113.194945446664846 57.005370912866049,-113.193664258781425 57.004847552670519,-113.193267941600581 57.004594355164357,-113.192644632579302 57.004196128419622,-113.192559085669927 57.004141472321301,-113.191800755343039 57.003656963814564,-113.189039854555844 57.001892836272205,-113.188906517620751 57.001807632383461,-113.186861633570743 57.0005008597197,-113.186472060246842 57.000203066002193,-113.185191133772506 56.999223870409665,-113.185154382128928 56.999195774897977,-113.181880641550833 56.996692883817275,-113.180693703009695 56.995785321481947,-113.176582401977441 56.992641538091178,-113.168362335220493 56.986353538708485,-113.159910801255208 56.979885623788924,-113.159784583097064 56.979789008068693,-113.156037217818778 56.976920237067326,-113.149414439823445 56.964172534646195,-113.147759358486127 56.960985608523025,-113.14644547542386 56.956414617390578,-113.146049760688939 56.949531447781538,-113.144386534557967 56.94496643003567,-113.144284334630797 56.94318654385075,-113.144280210654969 56.943114717479766,-113.144118180130235 56.940292402007948,-113.144114038820348 56.940220260145864,-113.143464734220686 56.928905144337101,-113.144600261487469 56.924292097213957,-113.144205370561025 56.917408883705278,-113.144990803753913 56.912801828279413,-113.14627460595392 56.909564400709307,-113.146391482792083 56.909269606873913,-113.146874653338415 56.90805087584333,-113.151407194327703 56.896614320881795,-113.151823310997443 56.895564022581375,-113.151851958309521 56.895491713244368,-113.1554629413112 56.886374923444301,-113.155491361003229 56.886303153626116,-113.156536335385539 56.883664032121146,-113.157818198359436 56.880426486510345,-113.161847704751906 56.873925978981816,-113.163006892733065 56.871404865312876,-113.163603520424147 56.870696238971618,-113.163664572834378 56.87062372418314,-113.172162276555696 56.860527615475149,-113.173689370936771 56.85720349888409,-113.173735755015301 56.857102522635223,-113.173777259010734 56.857012169664074,-113.173979212332995 56.856572516997801,-113.177951742237028 56.847922203810981,-113.206316490765232 56.831346507011489,-113.234656195696175 56.814764517624035,-113.24946788156501 56.814498342116977,-113.249760987900729 56.814493057035797,-113.261759778885704 56.814276111460693,-113.262855083231756 56.81425625010565,-113.285306352952887 56.813847014867058,-113.285569900529723 56.813842186965431,-113.286229005540733 56.813830110445735,-113.286417509766466 56.813826655916273,-113.293221241761501 56.813701779693311,-113.307183084084315 56.815971396557714,-113.307998534798202 56.816103898023691,-113.309875851856901 56.816408916774385,-113.31053034924706 56.816515248976813,-113.31542979992075 56.817311104127306,-113.321885803281376 56.818359385095647,-113.322053055565306 56.818386537119203,-113.322833576147971 56.818513244674229,-113.334813899909093 56.822577322158914,-113.340190544732323 56.824400476766286,-113.340308183996157 56.824440362195645,-113.352789079655977 56.828670871626237,-113.358641991615968 56.833142427388346,-113.358718430806235 56.833200817030978,-113.365113457498964 56.838084967863374,-113.369051158123639 56.841091529410825,-113.369127672402101 56.841149944438847,-113.373333005650579 56.84436016002163,-113.377444040484917 56.847497538265408,-113.381711945853297 56.850754187540275,-113.381802615923519 56.850823366013721,-113.3818040267588 56.850824442435162,-113.381880579221033 56.850882849350192,-113.383611561732494 56.852203467879932,-113.386753000523996 56.854985616618343,-113.386882165138289 56.855099997818499,-113.389044294374116 56.857014537063328,-113.389230939357844 56.857179797827868,-113.389266311475708 56.857211117105884,-113.390912320380778 56.858219380661012,-113.391031403823888 56.85829232229775,-113.393894440870625 56.860045884079931,-113.395509864875578 56.861670869584479,-113.395573740134978 56.861735119527623,-113.400623223981754 56.866813407986534,-113.412084459160738 56.870184827219205,-113.41220610449578 56.870220601258232,-113.431796004364458 56.875979236146641,-113.439010204487886 56.879472789335601,-113.439109412859352 56.879520824513925,-113.452743667678973 56.886120379360172,-113.452892101789232 56.886192206508852,-113.461492257941529 56.890353034874607,-113.461590818396346 56.890400710365725,-113.462425000207716 56.890804211265262,-113.473367967011882 56.898978687222908,-113.473447300124676 56.899037932849616,-113.476478263594117 56.901301262379818,-113.476995545819008 56.901687500414432,-113.483839962276051 56.906797039736752,-113.484237061676183 56.907093429857376,-113.49208263187387 56.912948026943795,-113.495332125761536 56.915299786891993,-113.513923764294304 56.928747716235968,-113.520930806864385 56.935752263178436,-113.521885065426403 56.936705943966111,-113.526459078494099 56.944372743673206,-113.528586000028113 56.947936654294224,-113.52661019289998 56.954609476493196,-113.526588884178878 56.954681429107723,-113.525922386883224 56.95693183821497,-113.525581080566852 56.958084147749865,-113.524957903123166 56.960187925921275,-113.516709800481905 56.970096534756038,-113.510819447686444 56.973328489001425,-113.509186602856516 56.974224261161162,-113.508908443175713 56.974376852093229,-113.508468142903482 56.974618385215798,-113.508247989798221 56.974739151666505,-113.507807684313164 56.974980680691019,-113.497879825719636 56.980425363984395,-113.497660096487849 56.980545842266856,-113.497550229746366 56.980606082140568,-113.496700769871836 56.981071830777204,-113.495202115798918 56.981893482712671,-113.469331947124161 56.995396432866407,-113.467626195352068 56.996105346728783,-113.466131274143464 56.996726597979048,-113.44612325078225 57.005037737663955,-113.445523263230882 57.00528686078804,-113.444716227583584 57.0056219434192,-113.433093764522027 57.008261922236969,-113.432962369822107 57.008291759553238,-113.419479826274369 57.011352414148071,-113.417752304808573 57.011744435877461,-113.409524838933038 57.013611033865104,-113.402748147923191 57.014398614286073,-113.401770609056726 57.014512189959731,-113.384413093216438 57.016527495765708,-113.370873104493057 57.015781115379944,-113.370741785839229 57.015773869220361,-113.353656465464496 57.014829900659798,-113.352770329761725 57.015176810297703,-113.347650497446821 57.017180805393615,-113.344041028015567 57.0185933632483,-113.343222390896585 57.018913705865977,-113.341869914502752 57.019442922602892,-113.341193208110255 57.019707703112594,-113.335510000195924 57.02193112777671,-113.306065359747507 57.022477103749587,-113.299701775111558 57.023596615106271,-113.299558641120498 57.023621791424901,-113.283382119391959 57.026465865133176,-113.276865223651299 57.027031064893592,-113.270926430469174 57.026335027041874,-113.260482756141187 57.025110393770646,-113.258660550450045 57.02489662269371,-113.247172976310026 57.023548294783239,-113.234972877159535 57.019421072381711,-113.234837437321531 57.019375241971133,-113.229119892737344 57.017440289033701)),((-111.165388373977493 58.035068864753036,-111.16538533521944 57.991634713891315,-111.163367802223675 57.991635955929446,-111.163202530188926 57.991636056256837,-111.152531767337834 57.99164207949314,-111.152376572076477 57.991642160492347,-111.13720363107349 57.991649165585031,-111.136752376665967 57.991649346215119,-111.135648040531336 57.991649781512955,-111.135472094368978 57.991649849980682,-111.119491612205465 57.991655054025699,-111.119235605671193 57.991655121059722,-111.07015984168703 57.991658457494133,-111.070003046478988 57.991658437818856,-111.061630236556027 57.991657106513117,-111.061444982751553 57.991657070826825,-111.053910904241775 57.991655390960979,-111.053771748879157 57.991655355737592,-111.053033170088128 57.991655166239056,-111.052671485240651 57.99165507187702,-111.05260912707287 57.991688704852173,-111.037069173083111 58.00006728054818,-111.036971257365266 58.000120054674049,-111.0365480615324 58.000348143998359,-111.036418910895534 58.000417751294648,-111.035032382493398 58.001165012211615,-111.034921125707569 58.001224971361431,-111.027127843449918 58.00542422997232,-111.027030836290649 58.005476491174612,-111.024326675372706 58.00693322748397,-111.02422990084689 58.006985356829254,-111.003012922001417 58.018408821726844,-111.002908515952186 58.018465008352671,-110.996230941079489 58.022058033157826,-110.996134001549038 58.022110185832886,-110.98777538710489 58.026606202180204,-110.987667671947563 58.026664130136851,-110.983992179794441 58.028640599841566,-110.98388966260255 58.028695723074826,-110.98123559373191 58.030122721221503,-110.980973373045515 58.030263698738793,-110.962304038702158 58.040296632814865,-110.958722255673578 58.042220532242013,-110.958844684558642 58.042350586270885,-110.958899552106402 58.042408870746279,-110.958975179637662 58.042489207702026,-110.960923799917467 58.044559031005356,-110.9610063627686 58.044646723261302,-110.9612374624067 58.044892177915592,-110.961305184903892 58.044964106353724,-110.961559043790885 58.045233728380829,-110.96158308684528 58.045259264129641,-110.961852425986748 58.045408854247,-110.961963364293567 58.045470468505755,-110.962183197399142 58.04559256116157,-110.962702978550865 58.045881236515584,-110.962815563605659 58.045943762956853,-110.963355881007772 58.04624383498151,-110.963523278420226 58.04633679973918,-110.963673304253589 58.046420116529269,-110.963322309512932 58.0463136340801,-110.962999223328993 58.046215616926588,-110.962693511378134 58.046122869478651,-110.96257353084907 58.046086469235114,-110.959469341846159 58.045144641042256,-110.959023506287465 58.045009361762752,-110.958669007345151 58.044901794783613,-110.958431543071228 58.044829739170396,-110.958403294402501 58.044821167410561,-110.958250154085988 58.044774698419587,-110.957055886672222 58.044412298722499,-110.955494954624243 58.043997775045952,-110.954941480370337 58.043850786609603,-110.95428791784714 58.043677212664164,-110.94979115146451 58.042207393142242,-110.936718136798049 58.037576902741705,-110.919292413282434 58.031400981459065,-110.906227288001062 58.026767354895199,-110.90219637389572 58.025051443848341,-110.898971743109215 58.023678764289521,-110.886076137046416 58.018186756079366,-110.86996207358267 58.011320021453649,-110.856327039760913 58.00314422569911,-110.84679235365725 57.995878739164397,-110.841008843025946 57.990733095214715,-110.832742402669268 57.984849931642763,-110.826544680763078 57.980437203441078,-110.82470274109599 57.978862587025155,-110.820419482114175 57.978629007673383,-110.808147423000193 57.977161413430267,-110.808011258067438 57.977145122387618,-110.799656766742658 57.976145267359513,-110.799520497965602 57.976128953873669,-110.795686656218223 57.975669917656099,-110.765941003160222 57.975618661208827,-110.765805691049721 57.975618412151348,-110.765439671134288 57.975617737727802,-110.757440616938638 57.974387245327392,-110.757304288762242 57.974366268908916,-110.741940186277674 57.97200114602898,-110.740476170760246 57.971900883091124,-110.74034046683046 57.971891588541098,-110.735222424675669 57.971540937543615,-110.731954724037408 57.971099565837143,-110.731818553076153 57.971081171027016,-110.72686023900286 57.970411259361683,-110.726377673646837 57.970346048899231,-110.725151693478779 57.970180369328013,-110.723585177177938 57.969968671722249,-110.723449345001669 57.969950314457392,-110.717095196819557 57.969091389473093,-110.706579689243028 57.96766908214412,-110.706443563910611 57.967650663654986,-110.705012063955508 57.967456964051244,-110.694034535538393 57.965239720722224,-110.674844965280769 57.959348404998956,-110.663953351863029 57.957387108535414,-110.663817189794926 57.957362582027123,-110.655401462381136 57.955846331629537,-110.655265361949048 57.955821804968117,-110.652209149382102 57.955270997665778,-110.644665024353799 57.953910926467877,-110.642845383547765 57.953258640201106,-110.642651089494919 57.953188988712974,-110.632617698526644 57.949591398523481,-110.62113993075576 57.945474081072767,-110.621002863900728 57.945424900335951,-110.614551686877206 57.943109844455982,-110.612569055641757 57.942043404582144,-110.612430514242163 57.941968880861616,-110.601071074828866 57.935856883844146,-110.600940025476788 57.935786354100323,-110.584518344076855 57.926945071969378,-110.577981310837515 57.919879729819648,-110.577841617328218 57.919728712632256,-110.576392914991288 57.918162493438103,-110.576327214232137 57.91809145949582,-110.574576716282706 57.916198751135113,-110.569607894862884 57.91082523428318,-110.569733724666875 57.900298262524885,-110.569734583483012 57.900226388232589,-110.569991781734231 57.878685973644934,-110.567052321092504 57.872247829435182,-110.55510769447163 57.862564346158607,-110.555305840076073 57.84649464502742,-110.537305335232602 57.840002097678607,-110.513243141475456 57.836698039419261,-110.498367306413826 57.831324224295521,-110.498176619871344 57.829046625569021,-110.498779213933744 57.829109145828561,-110.506735274631993 57.826794759455531,-110.508522030907727 57.826274848172972,-110.520104159539642 57.826977931204588,-110.52782453329371 57.827446021884768,-110.54387659610066 57.833213762264641,-110.543909877018521 57.833213188720407,-110.551316464925776 57.833063186855085,-110.566978514770383 57.83274461881841,-110.581832199140052 57.828303129544089,-110.58518216127122 57.827301082965228,-110.592521034591826 57.826516690963565,-110.594465936186182 57.826308665650501,-110.601806570030433 57.825523411003942,-110.608116155925956 57.822715704535199,-110.611343443197697 57.817661252954899,-110.610809430852512 57.816238033802414,-110.608955330021061 57.811294527473677,-110.613937306038565 57.807361596139302,-110.617207346210193 57.807702537089085,-110.623817553345631 57.808391580500391,-110.628067226275903 57.804145975449579,-110.6332855567248 57.798931099045092,-110.637919676819038 57.796799115933091,-110.642944293026503 57.794486984442379,-110.65046322293631 57.793646717532987,-110.666785513361958 57.791820787076738,-110.683814905951451 57.789913255598535,-110.683956896624252 57.789826900810326,-110.689474248362956 57.786469924782864,-110.692993059975095 57.784328447194888,-110.696609443627622 57.778808564734085,-110.695242967010259 57.775910131961545,-110.693017752690778 57.771189837839039,-110.692863491509172 57.770862558470277,-110.693609995324834 57.765097949257367,-110.693839999268363 57.763320938694839,-110.688174500680319 57.756514286719103,-110.687379478203567 57.755558766775579,-110.682129554230244 57.749248608881771,-110.677665699862757 57.743881194794888,-110.679970746622374 57.741665881667643,-110.682272225600968 57.739453662217876,-110.687522968180005 57.734405495886165,-110.68956271424095 57.733386815919474,-110.694778658319123 57.730781167259984,-110.695472614352283 57.730434487675026,-110.710807858210615 57.729564669795607,-110.712252257800245 57.729227038881625,-110.72401512499448 57.726476696725484,-110.725181608620801 57.726203902313699,-110.738942839329354 57.725423537568076,-110.745620751174897 57.725044259846499,-110.754267494953297 57.719994125437523,-110.755195559215167 57.719451979356258,-110.761205948290339 57.71706239061907,-110.765470516862649 57.715366646011752,-110.769766502785743 57.713657925498225,-110.775329545190701 57.711444869569839,-110.775636753375991 57.708653044628832,-110.776241181585064 57.703160122276486,-110.776863219946961 57.697505940688487,-110.780998226725274 57.694484639865635,-110.782828482550741 57.694109216271556,-110.791581772073741 57.692312771483962,-110.807429991440358 57.689058430829576,-110.810577408898041 57.688411633975818,-110.815246745984794 57.684393104429887,-110.818382387645173 57.681694039691607,-110.820835325792345 57.680659147273978,-110.825073383784442 57.678871213774237,-110.818572919431958 57.676437392926978,-110.818233100817295 57.676422001000844,-110.812426212219762 57.676159639325171,-110.806062995708729 57.675871779402428,-110.798927396446061 57.675548511364127,-110.791572612762195 57.673126213205983,-110.789765979765221 57.673079667516383,-110.767677362828337 57.672508226269343,-110.76693641878677 57.672424904847404,-110.757582421913071 57.671372155953655,-110.747551149354422 57.670242247768329,-110.747464325512254 57.670191676616795,-110.744491679406792 57.668453225953733,-110.732496010311607 57.671106131124112,-110.731399569651217 57.671348570144261,-110.715458593023953 57.671195649993059,-110.70023515881411 57.671047574095738,-110.699424602227111 57.671039610561358,-110.691443771899031 57.674151388026758,-110.690971740804116 57.674335438407738,-110.684326151642836 57.67692568542568,-110.682529212042851 57.676835658972003,-110.674455578270582 57.676430811382076,-110.673217645240626 57.676368681642145,-110.667443114193077 57.68012241953101,-110.662330064489893 57.683445122638162,-110.658287145494569 57.686071873919886,-110.654169450627634 57.686113429861336,-110.652922395587154 57.686126013306023,-110.651335710191546 57.686141903186545,-110.650050973264044 57.686154843476274,-110.649958210729849 57.686155784768111,-110.635160426311231 57.68616331230831,-110.621313613174507 57.686168832204672,-110.607804058339255 57.686172732173368,-110.59395719354039 57.686175378834392,-110.580447827955794 57.686176270302624,-110.566600654776323 57.686175794238459,-110.553091028584817 57.6861739448739,-110.539244051518409 57.68617048599306,-110.52573437350118 57.686165816671419,-110.511887673956437 57.686160683222923,-110.498376093567217 57.686154293871468,-110.498375577788252 57.642451045338845,-110.498375464539464 57.635222488569511,-110.498375294596215 57.627998026339633,-110.498374830219134 57.620773535434566,-110.498374507836218 57.613639160616181,-110.49837435636654 57.613368313805786,-110.498374244149105 57.606143823440902,-110.498373747492948 57.598919109962949,-110.498373420838618 57.591694538860168,-110.498373178995891 57.587109129724567,-110.498373172278136 57.586982605313004,-110.49837304319972 57.584560183115236,-110.498373107197764 57.584289294912523,-110.498372949630209 57.581203825725886,-110.498708480126666 57.581115370176335,-110.500769711609578 57.581123530780438,-110.50092230590802 57.58112413357842,-110.51483347379488 57.581178313063326,-110.515059424768197 57.581179180428173,-110.559186246253716 57.581340826371566,-110.55932527029195 57.581341311293166,-110.603422881595023 57.581487406094666,-110.618466368154671 57.573498201411432,-110.64837870823952 57.573584990338944,-110.648519411005338 57.558985065341446,-110.648520105572587 57.558912959114323,-110.64853357691652 57.557514368731077,-110.645904552229155 57.555370575368521,-110.645678902579434 57.555186558913647,-110.636670073984135 57.547838045909849,-110.633745257208616 57.541401248776154,-110.627388168246355 57.53679079215167,-110.610385730072622 57.529852042005658,-110.605046222155565 57.525975669373004,-110.604965517679929 57.525917071541521,-110.597683069895922 57.520628451961045,-110.580693796877739 57.513685701552326,-110.568004241108738 57.504459120167901,-110.559612132864856 57.492950721020648,-110.543120124973257 57.485749293281003,-110.529972564065446 57.476772429581331,-110.516318105806249 57.468066883719899,-110.507814072030882 57.460616493968708,-110.504980010646193 57.458132983722017,-110.500432248441044 57.455230397016443,-110.490568518772989 57.449833608716105,-110.480707237616983 57.444436293411904,-110.475778142678905 57.441737225941409,-110.470849315326333 57.439038208268052,-110.460994297883502 57.433639108492791,-110.451141725827441 57.428239482142658,-110.446216984168416 57.425539258895178,-110.441292507625008 57.422839087485322,-110.431446194651414 57.41743767964433,-110.421602322262288 57.412035746546863,-110.416296524334584 57.409538827724418,-110.411740337405433 57.407972172209938,-110.39906359621294 57.402746479049611,-110.382167045902577 57.395776827347085,-110.366266932011911 57.388280191299508,-110.352613417675613 57.383574561278046,-110.348393205367643 57.381830746768721,-110.342766726351613 57.379505603174785,-110.332946074195775 57.374096763611348,-110.330260213477402 57.372616948098738,-110.32312877085333 57.36868691636456,-110.318606459061357 57.365777792581099,-110.313314350613453 57.363276551763242,-110.303502366490648 57.357865421674347,-110.29369372802654 57.352453285434031,-110.288790257965616 57.349747175895445,-110.283887969326315 57.347040633262594,-110.274084643817787 57.34162721602403,-110.264284659116882 57.33621279595085,-110.259385517167416 57.333505544540948,-110.254487554181296 57.33079786048939,-110.253633166008726 57.330088018624998,-110.2139045470215 57.327528874272566,-110.186821031354739 57.316268815577509,-110.16601628278211 57.299870228429057,-110.165977848549602 57.293232403940763,-110.249156791961482 57.293364888969052,-110.317037475897337 57.293432240146302,-110.32975335775086 57.29344078233175,-110.330253607992631 57.293440402811697,-110.330253608150358 57.293424362506791,-110.33025367379021 57.286215529851887,-110.330253639375059 57.278990632748183,-110.330253505566006 57.271765608239733,-110.330253822963314 57.26463093771585,-110.330253604504477 57.264359922554419,-110.330253796226657 57.257135066461828,-110.330253474061962 57.249910009409994,-110.33025348688895 57.242685257930965,-110.330253704718544 57.235550734060254,-110.330253699104361 57.235279781891457,-110.33025370276107 57.231000598943211,-110.347463779642737 57.232567225630966,-110.361729690044172 57.239867140280793,-110.37289331896865 57.241440096413605,-110.3847230818469 57.243105887448841,-110.3945600832336 57.245832434888229,-110.421882212382073 57.253398721948756,-110.422021324419518 57.253437222974057,-110.433923566083948 57.256730452728739,-110.443767847624997 57.259453155665625,-110.452847182844209 57.2625837582396,-110.473309885606483 57.267616403438133,-110.491019405636223 57.274118030982031,-110.502843359759126 57.277379921750899,-110.511296736506438 57.279249648190884,-110.532433250662066 57.283922091958061,-110.552152830518992 57.289351069019034,-110.562014573498743 57.292064520602281,-110.57278300550395 57.294293238347578,-110.583177874362065 57.295580293894687,-110.59164459899003 57.296985804421141,-110.596586792349228 57.297537348523441,-110.646015073645358 57.303043579918366,-110.650517302931632 57.303543921284046,-110.650671281596019 57.287299469652559,-110.653670062074184 57.280942324927793,-110.653699946767645 57.277759441384212,-110.655718031307302 57.271399535134933,-110.656041527935912 57.27037957458549,-110.657158771324291 57.266856546052765,-110.665653924035269 57.255512464191689,-110.665797967866695 57.239598921087094,-110.675674384242996 57.229015416970803,-110.680610689923128 57.223723486719813,-110.686935659696559 57.219192452546352,-110.695410676388178 57.207846252629864,-110.696347494762094 57.206343474350092,-110.696459153270837 57.206164350947581,-110.699826805491668 57.20076107156455,-110.699977760036177 57.200518831012666,-110.702837852702785 57.195928531048885,-110.705312363050794 57.191955852849503,-110.713178713555465 57.185608546144913,-110.724972508234259 57.176086402371872,-110.726637036220211 57.172969688732174,-110.72675041855787 57.172757368135159,-110.726820445732415 57.172626233459773,-110.726858696548078 57.172554603594349,-110.73157354787709 57.163723177410048,-110.734852987232898 57.160193572695057,-110.742707522701053 57.153844374302771,-110.7544836094945 57.144319393697806,-110.761879017856998 57.132398034307492,-110.7643429464474 57.128424144808427,-110.772185696587641 57.122073059955554,-110.776118693149058 57.118886837053857,-110.777073342198193 57.11811334951264,-110.777151079613986 57.118050362397739,-110.783944120830014 57.112545252598068,-110.784387907730576 57.112305323631958,-110.782763605089656 57.107812578003632,-110.78285759151585 57.091740571367843,-110.788854038380052 57.07567860596285,-110.792812666481552 57.071399348751157,-110.800715702881178 57.064983120284225,-110.804666199004018 57.061774938648853,-110.806643974559975 57.059635071030463,-110.810746374852783 57.055933157012817,-110.815533410882821 57.051612337583641,-110.830316045437868 57.043597088396432,-110.843960914798672 57.034960416355958,-110.851087109640005 57.031645114028002,-110.859862222988411 57.02756131782013,-110.875491066741532 57.02001449434821,-110.889373418755596 57.014732942697599,-110.89305973647707 57.013530767835725,-110.899202920244264 57.011526819039844,-110.91148775748286 57.007518015997427,-110.918857301915153 57.005112251010566,-110.922138932306851 57.004219460351386,-110.922376722587273 57.004154762820853,-110.930645219092014 57.001904664793308,-110.939904748643301 57.000072811916809,-110.94832225595502 56.998163166940969,-110.952004344770558 56.997494868515126,-110.963049819221894 56.995489567252307,-110.971707347914673 56.99360212504498,-110.97356861320786 56.993196244263366,-110.977775588241897 56.992278617691667,-110.986189198185656 56.990902040051168,-110.995443265825756 56.989066075987544,-111.007219830579615 56.987458612018678,-111.019837014918963 56.986309252993657,-111.024883760557969 56.985849006582541,-111.036658565667921 56.984774633979917,-111.045251280042464 56.984380962506542,-111.045395065910199 56.984374369930286,-111.045716323704255 56.984359639667765,-111.05955270103621 56.982980199197996,-111.062760594519943 56.982803399248745,-111.063583212039759 56.982758047962818,-111.066094004356827 56.982619592695833,-111.071445885433263 56.982324564511195,-111.08180578745646 56.982318221491219,-111.104726903254885 56.969767232199438,-111.104820999820461 56.969715681339324,-111.105291361057624 56.969457990451318,-111.115855425467785 56.95932114715891,-111.119809257808342 56.953530371422652,-111.123761863694156 56.947739466758414,-111.127261519954132 56.944377976253264,-111.134314783722715 56.937601034045137,-111.134314565616648 56.937540347932114,-111.134314174915502 56.937431638164178,-111.134260816818895 56.922577910339911,-111.1342604406493 56.92247314202784,-111.134200507496203 56.905771826117508,-111.128866717744472 56.892756391429629,-111.128328354857487 56.889863267962433,-111.127669876189358 56.886327223046713,-111.127662682389143 56.88421715581466,-111.127650576770861 56.880665713639644,-111.127639740387053 56.877485933563776,-111.126820565265902 56.873950041353105,-111.12242999535205 56.864405446301554,-111.119844542492956 56.85878331938553,-111.119503898095914 56.858042449950929,-111.119356152776888 56.857827765961595,-111.118944147465257 56.857229080276213,-111.118815720486339 56.857042458590456,-111.117221459220673 56.854725616049706,-111.116923537941389 56.854292631101906,-111.115524402586161 56.852259048931508,-111.108034869877216 56.845104212938686,-111.107925805285277 56.844999998724361,-111.106428062316255 56.843568795715278,-111.106331393365906 56.843476417075252,-111.104933702385523 56.842140698266093,-111.104929609571528 56.840677651406075,-111.104929406113214 56.840604918127831,-111.104908085762034 56.832981308662333,-111.104907883080514 56.832908816880341,-111.104882599814189 56.823863239088119,-111.104882397501981 56.823790836562367,-111.104872833177012 56.820367614227962,-111.104871785057639 56.8199924295768,-111.104860313399612 56.815885440143994,-111.104859864575431 56.815724733542545,-111.104858767862765 56.815332036056994,-111.104857513422203 56.814882849005699,-111.104856903323309 56.814664381539011,-111.104856702600031 56.814592504774382,-111.10483847916332 56.808065501827016,-111.10483827854479 56.807993631816267,-111.104818178908431 56.800791401153035,-111.104817978369113 56.800719525667738,-111.104800338907566 56.794396039810835,-111.105847600649966 56.793531097964696,-111.105922026997632 56.793469626795563,-111.108297042456059 56.791507894228772,-111.108384528545642 56.791435627047733,-111.11637141861921 56.78483668848699,-111.123683404863257 56.778793384828958,-111.123771408070724 56.778720636345987,-111.124082646560723 56.778463346053272,-111.12415372823763 56.778384934590882,-111.124785612815444 56.777687875285494,-111.127291413361604 56.774923331418421,-111.133717453324522 56.770495869680381,-111.139496377372879 56.765714975133648,-111.143348180190827 56.762527641982281,-111.151050267268815 56.756152614446904,-111.155948333506842 56.752096770107592,-111.156027444243989 56.75203125368526,-111.158290254942187 56.750157164239852,-111.158833412148965 56.749707280388968,-111.162597846427218 56.74658893022989,-111.176673618334178 56.741405005074441,-111.184542445194609 56.734880842937514,-111.190810979632616 56.730549611542465,-111.190917221823923 56.730476192394903,-111.196744542057743 56.726448618462939,-111.197186570288736 56.726253067241856,-111.197313208139178 56.726197042586008,-111.212010888476769 56.71969277238091,-111.228499857338534 56.713605960821951,-111.238139150996389 56.710045451669011,-111.238271448925957 56.709996574316186,-111.239489259876109 56.709546642582538,-111.245597396751691 56.707852218780204,-111.247645280198057 56.707525993022507,-111.247787592571854 56.707503321345165,-111.26698857046955 56.704442687596419,-111.268880459149486 56.70417819619928,-111.269010214380231 56.704160054861958,-111.286004602522198 56.701782717048232,-111.286006910997045 56.701781756754343,-111.288796371476082 56.700620736348135,-111.288900624089649 56.700577342057308,-111.290357609984781 56.699970864103584,-111.287230802670919 56.699266091105933,-111.287007076445718 56.699215659861864,-111.278005035551587 56.697186019122476,-111.277860699913219 56.697153469471672,-111.261218997960285 56.693399039271526,-111.226451698668484 56.692132708396699,-111.184411988739626 56.690867654377648,-111.164703987187139 56.691131035895133,-111.163887709717528 56.691141877472184,-111.147231692280513 56.691361928973301,-111.129441101941737 56.689157733343194,-111.120187480566798 56.688148909054554,-111.118883498799974 56.688006690128141,-111.109227922153636 56.686953145271985,-111.082259189729868 56.682734833315713,-111.095641434463118 56.682729167349528,-111.118481760301066 56.682716487891689,-111.119774347512816 56.682715645129917,-111.12204640779629 56.682714131248623,-111.122211097813292 56.682714019904452,-111.122216347221311 56.682714014754616,-111.148796332983906 56.682725610993955,-111.175378477684077 56.682731893185085,-111.20196047986768 56.682732413567571,-111.228542465646981 56.682727261823651,-111.255125232660021 56.682716345571045,-111.281708903505958 56.682699486123695,-111.28171065329083 56.682699482166853,-111.293533151765956 56.682706037360759,-111.304092417022957 56.682710943556032,-111.30809240156168 56.682712568340783,-111.308312337230461 56.682712653953011,-111.314629454601445 56.682714949485664,-111.327128690675863 56.687924521100825,-111.329728938103031 56.687200463679687,-111.330654476896711 56.687096036576811,-111.331101284457091 56.687045621306993,-111.333376809490289 56.686788836823176,-111.333528654362951 56.68677170009417,-111.334644179925476 56.686645799279596,-111.346392437177485 56.685319206114315,-111.351622008065988 56.684728305599137,-111.355086483906859 56.684336835052662,-111.356000438794808 56.684233544754576,-111.361841245767025 56.683894945034581,-111.37100320513207 56.682950291437628,-111.371140863577239 56.682936092518965,-111.373226660775856 56.682720931003701,-111.380520298614854 56.682719726098192,-111.381175238533885 56.682719597007321,-111.381455527828393 56.682719540709421,-111.382774828877956 56.682719267248167,-111.388015425219905 56.682718043006304,-111.391871885807063 56.682717053205174,-111.40274636223387 56.68376941622288,-111.40859363469032 56.684072147213023,-111.413377833909749 56.684319391183735,-111.423032058987189 56.684286981614846,-111.423220378385736 56.68428634198019,-111.42972759693464 56.68426406506228,-111.429886721579919 56.684263516054678,-111.430111720466726 56.684262739422415,-111.434895576606849 56.684465430450466,-111.438407347900878 56.684935669884879,-111.442062391960533 56.685652543678628,-111.442219341418522 56.685683323589515,-111.445371917237566 56.686301533748484,-111.445495139223794 56.686325695156121,-111.448072523109914 56.686831034358605,-111.457489925883891 56.688864369565117,-111.461257010203482 56.689677547750001,-111.463937412884277 56.690256028259896,-111.472953632910063 56.688772049691778,-111.48382351545655 56.684723442006231,-111.484608056046923 56.684431160895095,-111.485019968273718 56.684277698934622,-111.487491587890972 56.682717780069247,-111.491630535174195 56.68271904742916,-111.503239198545657 56.68272164556295,-111.520711375881248 56.682723761564731,-111.520944737427172 56.682723773242323,-111.529884139099039 56.682723839689437,-111.516033165252423 56.686297012140159,-111.498394870636716 56.698861753900609,-111.505245611608288 56.701085682429238,-111.510750801989275 56.702872411370748,-111.513951460584678 56.703910938063835,-111.514054246921091 56.703944287118546,-111.514068511443284 56.703949692790552,-111.526501751027908 56.708660169227365,-111.54053006441849 56.715411015826795,-111.567065548410923 56.729766498140606,-111.577077010012871 56.738766413564363,-111.583086349399778 56.744165965406452,-111.585240590615498 56.746483742686955,-111.590679469460667 56.748832764550379,-111.603695179558201 56.757612120842992,-111.612052931907684 56.761218485568605,-111.612909796582002 56.761588151127206,-111.614354382027855 56.762211339234554,-111.614501518419459 56.762274811151698,-111.619906920080666 56.76460633162651,-111.627447641383057 56.769686776875368,-111.632934915415376 56.773382588413597,-111.639718195469655 56.77630585108907,-111.651215860683081 56.774135273758581,-111.658510466182534 56.772757612453368,-111.674702919244481 56.76969743340134,-111.680391051980948 56.768621827977412,-111.715243259504931 56.768426845961102,-111.715404476833641 56.768425921393124,-111.725324797703763 56.768368628207284,-111.725783964938216 56.768365957254048,-111.738926030991408 56.768288793846295,-111.744133300820863 56.769679995056528,-111.745536402706122 56.770054800095444,-111.74674277218493 56.770377034143067,-111.758545595754001 56.773528783870759,-111.778170165285204 56.778765917464568,-111.784139283609974 56.780357857450632,-111.784294249780274 56.780399180692882,-111.797800621723539 56.783999695028797,-111.810944197343673 56.788687537549897,-111.811244885256642 56.788794752158651,-111.815507604307271 56.790314541753801,-111.817560010646631 56.791961239131368,-111.817648133890728 56.792031938618514,-111.818421148593643 56.792652098433393,-111.818495538967767 56.792711777613398,-111.8393649553975 56.809444829937057,-111.845514505246399 56.822261971538808,-111.850254264853675 56.826057669412499,-111.850334493119405 56.826121909659577,-111.85426075692753 56.829265407203444,-111.854393638804851 56.829371785405698,-111.85745798600901 56.831824731675091,-111.857825447771106 56.847895724472259,-111.854011847614018 56.851116825726599,-111.853880180081916 56.851228024835372,-111.84795817913907 56.856228595529601,-111.847867392103737 56.856305244071876,-111.847005218808761 56.857033130088574,-111.846790853730369 56.857214101564786,-111.846311873454582 56.85761845909127,-111.840732670550281 56.870514684128466,-111.838517418907543 56.872383699885738,-111.838432196136026 56.872455598144462,-111.829207749144174 56.880235839730204,-111.82951283960756 56.894009174674949,-111.82951443120055 56.894080994970082,-111.829563760962955 56.896306823876685,-111.836277920317414 56.901675270733882,-111.836370610491073 56.901749369712206,-111.84152698826766 56.905870940165855,-111.843676464856117 56.910339608793166,-111.843793590238036 56.910583075235728,-111.844726548655046 56.912522280641397,-111.844794317882346 56.912663134498686,-111.845741525470174 56.914631726441122,-111.845775658822049 56.914702662106649,-111.847693441429797 56.918687729873092,-111.854140853148266 56.923836864159512,-111.854176807188992 56.923865573403738,-111.854268202913673 56.923938552497617,-111.85442856214604 56.924066597800511,-111.854897769117372 56.924441248786835,-111.854923327633301 56.924461656406606,-111.859668504784864 56.928250041707891,-111.863315164474542 56.930194300238774,-111.863446219512483 56.930264167962825,-111.863811189599772 56.930458737763622,-111.863945910264803 56.930530558132482,-111.879717139733955 56.938935366523076,-111.879850162952081 56.939006232628586,-111.886543956358395 56.942571717072461,-111.886675604735672 56.942641829803904,-111.889442128963765 56.944115120045353,-111.911505411809543 56.943956264908131,-111.911652310149151 56.943955194196256,-111.932048092510669 56.943804857998899,-111.932179579388858 56.943803878022621,-111.953836678604333 56.943640579832717,-111.954752790745786 56.943217439065847,-111.956834178431805 56.942122983485277,-111.956933947057863 56.942070519697126,-111.964142332043238 56.938279358096651,-111.964281616586433 56.938206091455001,-111.966270854603763 56.937159661624577,-111.966397276676645 56.937093154810121,-111.980731994144449 56.929549735305969,-111.994283468460921 56.924128414698949,-111.994463486089458 56.924056377506204,-112.006779686534827 56.91912656261124,-112.03040757545952 56.913825950962078,-112.034030635624376 56.914322511258426,-112.03416481043412 56.914340898379407,-112.05208065614039 56.916794601435612,-112.052266326435543 56.916820015153142,-112.05597499315104 56.917327575701044,-112.071617916561536 56.916145469790287,-112.087828605354801 56.9149183163277,-112.09293391869781 56.914313348914646,-112.093467019788818 56.914250164574753,-112.093606818772216 56.914233594873949,-112.093752998950947 56.914216268657931,-112.125896907327572 56.910401828876651,-112.154607580098528 56.905496109118758,-112.167947457687745 56.900831750067233,-112.176435746639015 56.897862430913477,-112.180786989573335 56.894778412523124,-112.180886967965492 56.894707543388911,-112.19303277040342 56.886095474948661,-112.203699616372603 56.8748479023591,-112.229524822663848 56.860664731569628,-112.234455886917303 56.857185022723762,-112.234727766202425 56.856993141042366,-112.253543032838252 56.843707879178957,-112.275188749329203 56.832343233177625,-112.292307732361039 56.829545702639557,-112.292434629213275 56.829524955248729,-112.305513167479162 56.82738582605193,-112.320786708986716 56.828153950750888,-112.345125362714512 56.821856854323471,-112.365918053086986 56.811414190226479,-112.405122115058887 56.795653520333573,-112.429427284187682 56.784790975314188,-112.439237361970598 56.780403513105348,-112.459890786826634 56.767624344129352,-112.485838635827648 56.760816067121951,-112.489035404069057 56.760484096245385,-112.489166113010498 56.760470520808077,-112.511099813437951 56.758190409273119,-112.532545337072122 56.755374355138699,-112.555360531593593 56.755091832666622,-112.581477196382252 56.752905599872001,-112.61010550072308 56.750217032832417,-112.623262918888628 56.74168668719669,-112.660678703869507 56.727725262838398,-112.683060114156561 56.719927804787602,-112.68321710889731 56.719873083898626,-112.693950889910681 56.71613095629457,-112.727883384501283 56.719380549707417,-112.751668983309159 56.721940268202886,-112.751799514737243 56.721954301998345,-112.758444810312298 56.722668561211371,-112.793166346266872 56.724495983579104,-112.810354679576605 56.72816262694564,-112.810485954447316 56.728190618793057,-112.829872672966744 56.73232248082229,-112.851703187350054 56.734049083889921,-112.851837683116671 56.734059708966917,-112.859562698483501 56.734669726019256,-112.859920334129242 56.73471447954369,-112.860049456025351 56.734730637217474,-112.892727385928524 56.738815031951368,-112.915410138110559 56.736146210038029,-112.93112059717447 56.729401315226646,-112.944125444464191 56.719445386737384,-112.959317776945284 56.719207407994183,-112.960019528542048 56.719406123668676,-112.960153271308769 56.719443995046177,-112.966075780612996 56.721120825481215,-112.966205907829647 56.721157663321904,-112.984184940347973 56.72624535382031,-112.991585992995866 56.722411538768043,-113.008244507862074 56.717963924551746,-113.018431326646834 56.716334628471827,-113.019829773031219 56.716110882929556,-113.0299922852642 56.714484374005025,-113.030221867788669 56.714447618184771,-113.030856016513653 56.714346089355516,-113.058703197934435 56.713889027999116,-113.06420329631662 56.706366380116364,-113.065483724617252 56.698913507680544,-113.048260531385367 56.692695264684474,-113.031711243500141 56.683212367230702,-113.028765654227996 56.681846027536686,-113.036168077494793 56.681840725924914,-113.039819313567833 56.681842578319959,-113.041054393496836 56.681843180685227,-113.045728336710454 56.68184534933448,-113.045858799013274 56.68184540735048,-113.053577663595007 56.681848596618877,-113.05378863621803 56.681848677070619,-113.068939367644688 56.681853520086207,-113.068017725915993 56.683543653894048,-113.08350204180762 56.688859305493821,-113.089790642059882 56.695721155208396,-113.089927968156076 56.698198472103485,-113.089933062801492 56.698290370168991,-113.090330969400711 56.705466188560045,-113.085834191227605 56.715760124335119,-113.083265299892119 56.723584452640559,-113.083241898269705 56.723655714629402,-113.080772968617168 56.731172545570914,-113.055547456704701 56.733449104231255,-113.035259399146398 56.73331762642821,-113.030492700585299 56.734004702342766,-113.029506846544678 56.734146778358614,-113.013456540667505 56.736458618391978,-113.010186615351301 56.738889498287037,-113.010084480605215 56.738965419416331,-113.004514382573504 56.743105326065653,-112.989484548378428 56.746597402949668,-112.970635610568308 56.741787716970222,-112.966236773398052 56.740430210003652,-112.966106050442306 56.740389864232839,-112.966010507940126 56.740360376263439,-112.965793606911177 56.740293432093054,-112.961601924346567 56.738999592629042,-112.961468221354608 56.738958318946786,-112.957750592086882 56.737810604471861,-112.954027708684791 56.740633566647176,-112.953928783868008 56.740708571437288,-112.949618734427375 56.743976087159638,-112.942616472319187 56.755696940397293,-112.919055412517707 56.757919685616109,-112.891056662378261 56.756025246876185,-112.861393877913741 56.754613850775755,-112.857289777672406 56.754675060906408,-112.857158043536785 56.754677023399509,-112.844971801766278 56.75485796372854,-112.844828085970121 56.754860090494148,-112.841962053120227 56.754902468596953,-112.803608472475204 56.748496538275468,-112.764684248404095 56.747660298485336,-112.751505748001236 56.74590135080841,-112.75137517590062 56.745883915403816,-112.735741827115248 56.743795272512649,-112.733214542795395 56.743457416253591,-112.730913654185969 56.742389518208931,-112.717671612074497 56.736241547324724,-112.698578201379163 56.739320516654345,-112.698449396627765 56.739341275866472,-112.6947889935402 56.739931150891039,-112.684711676732604 56.74302251611973,-112.664672420441889 56.749165938041131,-112.650527794147564 56.756417134784627,-112.634847760861476 56.765452590074005,-112.615907994761116 56.773645400975703,-112.593445750307339 56.774817293974884,-112.570945161849053 56.775102739286531,-112.546800625823693 56.774521651341132,-112.526050214106263 56.778308741184631,-112.497187502723392 56.78042425989328,-112.490666066690608 56.784789901781814,-112.490557195453334 56.784862771961215,-112.47838350405226 56.793008551653763,-112.476852212076992 56.793698644392265,-112.476692335470815 56.793770691920749,-112.456247093100515 56.802980280244164,-112.421361126292638 56.816625226411794,-112.391115197636594 56.825794413062091,-112.383360481766431 56.833826128279803,-112.378402542582606 56.836655770372886,-112.37827672907963 56.836727567765273,-112.35811387083244 56.848228641871678,-112.32760806684395 56.851205186679827,-112.29706678027884 56.853291793792344,-112.291537492185142 56.857012327207563,-112.29127804177341 56.857186881488992,-112.288751516819616 56.858886576229324,-112.288612013039369 56.858980420065137,-112.279740194778526 56.864947189429778,-112.26088021046337 56.879264021730798,-112.249036723085624 56.887923331210033,-112.248957839344655 56.887980989563331,-112.238839236693238 56.895375084426469,-112.23627599512713 56.89709504443325,-112.236177684801291 56.897161007438434,-112.230723620642152 56.900820022033223,-112.221475110657011 56.907022477892887,-112.201728505715138 56.915281155333126,-112.191219332295034 56.91967368521091,-112.178981658564751 56.927233256072995,-112.173801385651984 56.930431985522851,-112.166076272358751 56.931446720120711,-112.165564291569694 56.931513952727393,-112.144854741743472 56.934231544681175,-112.140705458909977 56.934458815005151,-112.140566595073537 56.934466418622264,-112.125509362294622 56.935289958589692,-112.107908115103314 56.940743858210681,-112.10410557038324 56.941241156037954,-112.103540365068241 56.941315062755493,-112.098463676654944 56.941978767299268,-112.078946616153516 56.944528208571938,-112.051544466017447 56.946527165305767,-112.039173532797392 56.948869414562715,-112.039045253432221 56.948893694385312,-112.027413710636267 56.951094554609327,-112.036678144778875 56.951018110902673,-112.039391697073555 56.951365004507011,-112.039526311646114 56.951382211587394,-112.048486173597325 56.952527142119642,-112.084150088671279 56.965081825291648,-112.098468680949168 56.966905096375974,-112.107779718473452 56.968089749316704,-112.125626017955753 56.974359840663098,-112.14407775569731 56.984105883125054,-112.144215183777234 56.984178441906614,-112.155548786464962 56.990160816011681,-112.157660825644427 56.991828310984189,-112.157735860946829 56.991887549350047,-112.167625468261519 56.999693072165158,-112.170521277192918 57.005583177804837,-112.170555536167413 57.005652849181594,-112.170772008894801 57.006093076475146,-112.170910490954498 57.010500697070761,-112.170924603408992 57.010949798583184,-112.171079032222266 57.015863337584278,-112.171101070221084 57.016564403368903,-112.17157264832511 57.031558422820545,-112.171574614859068 57.031620918899961,-112.171574909733948 57.031630289944353,-112.17178265642525 57.0382310022935,-112.169036811641362 57.044686018872177,-112.169137786582667 57.047899997563718,-112.167373938076736 57.054345793346712,-112.165042557048238 57.058385894317631,-112.159958493127277 57.067192445964494,-112.160748596441962 57.067185129175357,-112.182259633518797 57.062122886142781,-112.197444599880285 57.068575931182437,-112.206516894298389 57.075333575229088,-112.207569858460218 57.076117689139245,-112.205825264448208 57.07724306020598,-112.192266035585305 57.08598646211815,-112.16973697390705 57.08949734532257,-112.150742787992172 57.089785613775767,-112.146870204632407 57.089844032976799,-112.139362422884744 57.102824111620194,-112.137025011540445 57.106863683479787,-112.134695484625865 57.110888464257066,-112.140280874727765 57.13268105837443,-112.13956552341925 57.137931396119264,-112.141741720741791 57.143942943233768,-112.141767886688172 57.1440152119375,-112.141790255259082 57.144076992296107,-112.141952718692181 57.144525697996606,-112.143552991761439 57.14894486794126,-112.160639860370438 57.14692656507065,-112.181633367534133 57.14386450363903,-112.200550222332467 57.146550996691943,-112.220074640771614 57.144724864542091,-112.233396609142275 57.137634030800761,-112.246851080382001 57.134634892683344,-112.267438702909814 57.136074283527023,-112.28122042109392 57.132341576971257,-112.281339084819606 57.132309427703483,-112.292597649818561 57.129258410281842,-112.322425660056581 57.121167864460638,-112.352434474025813 57.118391089956795,-112.378981193871027 57.123834347180598,-112.397611682698141 57.138777993758545,-112.405731681562912 57.143340275567944,-112.405831915611714 57.143396582434676,-112.407935438322667 57.144578186109307,-112.408062957267219 57.144649813249259,-112.415504167190491 57.14882881694755,-112.415636753796718 57.148903265301172,-112.417622523681146 57.150018236719653,-112.425877980071462 57.157471339447163,-112.425957329871892 57.157542959818315,-112.429128414632444 57.160404880018511,-112.446190558938838 57.16717049977273,-112.446309466209087 57.16721763293215,-112.4515245631369 57.169284593295188,-112.463967866531675 57.174214573968136,-112.464152797333355 57.174287823394387,-112.471792748607655 57.177313444810018,-112.476424843510671 57.176687906769459,-112.476672474068877 57.176654460273397,-112.47698945351334 57.176611646293125,-112.477393084152297 57.176557127154943,-112.485689927753697 57.175436134545272,-112.493716414614084 57.174351084340564,-112.494273638174377 57.174275735419855,-112.497139969495194 57.173888100318777,-112.497280205668432 57.173869133263473,-112.499797713477165 57.173528608397746,-112.499927505579109 57.173511050833632,-112.508931948147847 57.172292611544258,-112.527961592919624 57.173551194355205,-112.530702736255932 57.173732243028326,-112.531297263950648 57.174111654114697,-112.531484019518814 57.174230834132906,-112.543215956194814 57.181715578570298,-112.543695517913079 57.182021440996351,-112.543820310539004 57.182101032063414,-112.543933013649394 57.182172912194602,-112.546345818381937 57.183711666045518,-112.550910033936248 57.186621991151227,-112.553488703297049 57.182186421741683,-112.55350028753513 57.182174378919647,-112.553569399817974 57.182102530513319,-112.558442645341813 57.177035562295337,-112.560470969755997 57.1751797927596,-112.560547253347011 57.17510999457317,-112.564664646837969 57.171342193519621,-112.57195755458109 57.168092071764072,-112.587665870856554 57.165261817949471,-112.597834581175675 57.164241018860658,-112.60123648419966 57.161123240241736,-112.601306729681895 57.161058855153001,-112.601989287628953 57.160433227594183,-112.610527397452017 57.157324914838021,-112.610719794058468 57.157254859884354,-112.61136259263418 57.157020801686649,-112.630372861703307 57.156304859953373,-112.637862253618309 57.157219299138895,-112.638387480687157 57.157283409758826,-112.640194579474937 57.157503970531664,-112.640352545310549 57.157523249278448,-112.644296637308358 57.158004530001811,-112.653980142000677 57.161640019403244,-112.655488274141717 57.161701923240322,-112.655620583301527 57.161707353218389,-112.662512763738562 57.161990013550685,-112.663792462238973 57.161259920660008,-112.666272144340482 57.159845095394701,-112.666363349299445 57.159793053857044,-112.670811466508511 57.157254702127887,-112.670938083553892 57.157182439790439,-112.688983090521134 57.146879701411919,-112.692624930575263 57.144799400042885,-112.710060493351946 57.138133026685018,-112.733547814420362 57.134595380070436,-112.750971144945098 57.127923379925711,-112.767223642354224 57.133491587991543,-112.769001038367975 57.134100304398594,-112.769497179149056 57.13416036485814,-112.786733843204232 57.136245611298015,-112.786863034132054 57.136261230623397,-112.792790630532892 57.136977725859879,-112.810831800338349 57.143148559732566,-112.812429829149139 57.14397229969822,-112.812530090138694 57.144023979568566,-112.818440731061528 57.147070239864306,-112.819133362296199 57.147427160691954,-112.821701472197219 57.14875044299756,-112.823178796388106 57.149511603684573,-112.823381661556951 57.149616121926279,-112.841179493037259 57.158782146580052,-112.844562025818519 57.163836267478736,-112.844947333796469 57.164411892808893,-112.847396569907474 57.168070439489433,-112.85184268159945 57.169622973533869,-112.851929210921995 57.169653185762144,-112.852684384312752 57.170189852688864,-112.862001794724492 57.176809634589283,-112.866891180716564 57.184854231050615,-112.863377274489167 57.190030432040217,-112.862908286869384 57.190721164427949,-112.862784272749977 57.190903809844613,-112.86597024490834 57.19413917238942,-112.868598904803434 57.195825919972805,-112.869183836053892 57.196201227523886,-112.872771849987771 57.198503164680687,-112.878412167634394 57.203533712700256,-112.880578524876171 57.206424174953618,-112.883271958526677 57.210016900033729,-112.883807538991704 57.210731209952499,-112.885345884859831 57.212782750645559,-112.886789313622216 57.215261816117753,-112.892491138287696 57.221041776788901,-112.893091392180338 57.221650134395681,-112.893734481692562 57.222301880145672,-112.89784767401477 57.225454827306088,-112.904018788831692 57.230184106461408,-112.909232008606409 57.235463376163693,-112.911838962830373 57.238103050289553,-112.921941035170605 57.248326884588003,-112.922003636654949 57.248390220140443,-112.927489452234539 57.253939383533591,-112.930099037341833 57.256578654686514,-112.933193047887457 57.259706883268819,-112.933256067453044 57.259770593400205,-112.935319774060858 57.261856772943815,-112.940172633748631 57.26734665422228,-112.943153483170505 57.269773642438359,-112.94486979710878 57.271507649914639,-112.944935121587321 57.271573644087077,-112.990227001113453 57.31726393901485,-112.993215236871052 57.31968967327844,-113.005481517388148 57.32698608113661,-113.005602904808441 57.327058265927029,-113.007389198442851 57.32812046457429,-113.013370116900788 57.332971253629871,-113.017740144888975 57.338746868304042,-113.029105251150838 57.348794139030375,-113.038100028770813 57.353373958622029,-113.038215055338284 57.353432514381019,-113.042130486613488 57.355425539608895,-113.042233023888159 57.355477728349513,-113.059715828886254 57.36437259048401,-113.068854026487898 57.375705325549411,-113.069130993429539 57.375892660471905,-113.069236733527021 57.37596418029505,-113.078756193816218 57.382401370563507,-113.020658485107347 57.382565618528432,-113.020513925513271 57.382565993776886,-113.02020889971611 57.382566785020039,-113.019040142251598 57.382569809959811,-113.008671096101295 57.382596171689677,-113.008524962643506 57.382596537109727,-112.995671597644588 57.382628014587411,-112.99553856116232 57.382628333528551,-112.965056087049717 57.382697706114101,-112.964921476743086 57.382697996096361,-112.910255073889815 57.38280386396017,-112.910114318427176 57.382804105915419,-112.860981742766398 57.382878950151294,-112.860848536887985 57.382879127005921,-112.848993109451783 57.382894302821548,-112.848859592022393 57.382894467377206,-112.782658335372219 57.382958620184709,-112.78252949584305 57.38086412826987,-112.782529470179909 57.380796468682263,-112.782529442928833 57.380724615264825,-112.782529427355428 57.380683548972947,-112.78252897994345 57.373458920256162,-112.78252902950959 57.366234226670016,-112.769153493423133 57.366227082251442,-112.768652150672253 57.366227400019298,-112.755443646827644 57.366235532820582,-112.75544321416902 57.359011026240047,-112.742067839750675 57.359017828499077,-112.741566620992799 57.359017975802928,-112.728358448562972 57.359023211338851,-112.71498322524846 57.359027145629966,-112.714983719158894 57.366251787879747,-112.714482229131704 57.366251871520035,-112.701274002212742 57.366254298171278,-112.70127450803443 57.373478844920918,-112.687899011443434 57.373479970268377,-112.687899394812675 57.380057557635418,-112.687899399125044 57.380129429909054,-112.68789943218944 57.380679031229604,-112.687899433734856 57.380704655911352,-112.690224092655512 57.380683396407868,-112.698781273739783 57.380604769240328,-112.699152748986236 57.38060134278512,-112.699734635177478 57.380595973314392,-112.699878908116588 57.380594641590676,-112.699893230985865 57.380594509373246,-112.698019779400283 57.383480886255292,-112.694651086819206 57.388669480007437,-112.694604402451205 57.388741374327623,-112.692662907962031 57.391731030966689,-112.688273297959427 57.398488634285023,-112.684502134584505 57.404291986219675,-112.683601517305178 57.405677820355123,-112.679562836588573 57.407505653410517,-112.670288305481648 57.411702028716427,-112.65884387229066 57.416877760600222,-112.652680635143341 57.418454113278301,-112.637951396881761 57.422219374096279,-112.632789681169299 57.423538166054044,-112.626863724785025 57.427528112507105,-112.617817342161061 57.43361674338373,-112.616859329508557 57.43426130045367,-112.605621328038183 57.436393769706051,-112.604057197873146 57.437598287285425,-112.602851901831329 57.438526134519662,-112.601110130385763 57.442468708523819,-112.600555219152355 57.443724952121862,-112.599337444416548 57.446480392894124,-112.598663278914813 57.448005716384039,-112.600213471042082 57.44975527605007,-112.600243979050404 57.449789705747556,-112.601036083946553 57.450683607152904,-112.608684759841339 57.4522304729933,-112.610977218368163 57.452694022122159,-112.612737202621801 57.457008968771738,-112.613189684348626 57.458118475508357,-112.618368223003401 57.461056593509873,-112.618568414966688 57.461170243792665,-112.61981967576061 57.465477003026173,-112.617881769379991 57.467353815457862,-112.617591500074866 57.467526942445808,-112.617497881933446 57.467582779161859,-112.615337031948016 57.468871509707427,-112.611721457428857 57.471027576489426,-112.606544846577407 57.474113732865916,-112.606650787296644 57.479168656310897,-112.606651024971498 57.482545362198245,-112.60665126371039 57.489769766921057,-112.606651297867074 57.496994239739429,-112.606651327477337 57.497265181913555,-112.606651670242613 57.504399209211527,-112.606651654066667 57.511623582755902,-112.606651902605279 57.51782092943688,-112.606651906623583 57.517917413060282,-112.606651945610352 57.518847893617071,-112.606652179692958 57.526072275753684,-112.606652286283691 57.526343193476777,-112.60665236143079 57.53347724887103,-112.606652359652927 57.540701455009398,-112.606652383621579 57.542193166514465,-112.606652384803837 57.542265030036006,-112.606652485864586 57.547925808073074,-112.606652613280275 57.55536454051164,-112.604921940216926 57.555365330713677,-112.604417764564388 57.555365479403974,-112.591075167713825 57.555371056740803,-112.577564047302531 57.555375063382918,-112.577060076449143 57.555375116395098,-112.563716434723986 57.555377662896241,-112.552437015737596 57.555378683168996,-112.552268281775682 57.55537869078335,-112.551359110476298 57.555378727930346,-112.551219948586549 57.555378733038623,-112.550204892799286 57.555378765659633,-112.549700972740268 57.555378798676429,-112.536357693576392 57.555378491357096,-112.52284640123473 57.555376666939317,-112.52234243046108 57.555376486910532,-112.508999293786246 57.555373360087991,-112.497812544285637 57.555369526232454,-112.49781291977699 57.5479473247172,-112.49781323133881 57.540723042909399,-112.497813472561234 57.53349880789866,-112.497813784493658 57.526093932906193,-112.497813600580955 57.522499685983881,-112.497807347197011 57.522120779386228,-112.496665620770727 57.522138999800383,-112.493759860085859 57.522185328523641,-112.492943126616282 57.522198262008672,-112.491579660444415 57.522220024063408,-112.487529921676526 57.522284359411131,-112.485531819571236 57.52231608649609,-112.48131630169398 57.522382847903692,-112.480982246553367 57.522388160572937,-112.479100178054537 57.52241793884717,-112.476600140519395 57.52245740549295,-112.474790105095295 57.522485960398406,-112.472663286089855 57.52251947601038,-112.471237161014301 57.522541901858766,-112.47123690273726 57.526084879762891,-112.471236872529587 57.526355733369279,-112.471236840363602 57.533489651933074,-112.471236648476477 57.54071396607322,-112.471236477331942 57.547938130808447,-112.471236163243546 57.555360542638851,-112.468132125314014 57.55535923821509,-112.467628130671997 57.555359610582634,-112.454286993216868 57.555367888055208,-112.454287767003507 57.562532661235821,-112.45428865527856 57.569757066921589,-112.440779380859524 57.569763885471765,-112.440780281217187 57.576988206229203,-112.440781021805833 57.58421258685803,-112.440781109687279 57.584483412662486,-112.440781575407797 57.588891795759267,-112.440781583070645 57.588963654381786,-112.440781867668846 57.591617418505436,-112.440782370950458 57.597551804869795,-112.44078237777353 57.597631016505808,-112.440782482408849 57.598841735163575,-112.440783349020521 57.606065971053432,-112.440783585768486 57.608765352377766,-112.440783594101902 57.608859703990518,-112.440784014347159 57.613561229187589,-112.426938439181242 57.613566701050196,-112.426939029604497 57.620700695571188,-112.413429843073217 57.620704596449556,-112.41343045127104 57.627928809783242,-112.412925449010515 57.62792888732033,-112.410334887749272 57.627929488046377,-112.410182131546549 57.627929521811716,-112.399584654190733 57.627931413774228,-112.386075274643972 57.627932290486079,-112.385570182273099 57.627932265055222,-112.372229879452206 57.627931821803919,-112.358721435593694 57.62792988425246,-112.358721771474521 57.63515417712874,-112.358468979034299 57.635154096178027,-112.358216707356803 57.63515401489034,-112.344876266751101 57.635150612197627,-112.344876269474071 57.635250951226809,-112.344876481426127 57.642642560342871,-112.317523236724767 57.642637727315027,-112.304015405545044 57.642633230425062,-112.304015308667786 57.649767304382245,-112.303509962397513 57.649767622173904,-112.290170765168071 57.64977554125867,-112.290170830796555 57.656999759952505,-112.290170543127559 57.664224040037581,-112.290170516020979 57.666291185051328,-112.290170515108457 57.666363072638582,-112.290170502577325 57.667366857338749,-112.290170501566479 57.667449234788137,-112.29017045568817 57.671448324761627,-112.290170484596416 57.671719227758544,-112.290170224690897 57.676563242516046,-112.290170220182844 57.676648789562634,-112.290170104999802 57.678853255554962,-112.303509082621375 57.678845272501817,-112.304014834989161 57.678844906371936,-112.31752288680326 57.678850266751979,-112.330862779800853 57.67885412714044,-112.331368551210687 57.678854240681083,-112.344877044457689 57.678858533811905,-112.344877221726108 57.671724359593064,-112.3448772141831 57.671453492535562,-112.358217330760965 57.671456339072975,-112.358217420105305 57.666516431006364,-112.358469716330646 57.666515561265115,-112.385513013174773 57.666419417561094,-112.385569270918566 57.664337583595611,-112.385572073876702 57.664233854835274,-112.385571903036023 57.660222635122445,-112.38582612277888 57.660221968776177,-112.427481234648567 57.660105884789836,-112.426941688789711 57.657001715475175,-112.426941194271066 57.649777824249533,-112.426940837848818 57.644239170094302,-112.426940828398401 57.644089420297384,-112.426940737703148 57.642644297124619,-112.42694072765714 57.642475243395388,-112.426940721609355 57.642373372520261,-112.440281369357976 57.642368120108785,-112.440280893753183 57.635143897951941,-112.440280272053855 57.627919576437243,-112.440785402071938 57.627919441246533,-112.454294600207902 57.627912564962465,-112.458266418791695 57.627910275982082,-112.458410334481925 57.627910190700433,-112.467635348353184 57.627904382341306,-112.468140259927182 57.627904085391286,-112.468141025761142 57.635128363541384,-112.468141753862625 57.642352656284075,-112.481651741091568 57.642353362218579,-112.494993611449232 57.642352819043481,-112.495498676694595 57.642352753477084,-112.498977303854517 57.642354159928921,-112.499118266711903 57.642354214904501,-112.509009270211081 57.642357680096552,-112.522351437227712 57.642361078780553,-112.522856732490936 57.642361148595995,-112.536367465566173 57.642363121206692,-112.549709788521909 57.642363732206832,-112.55021496832876 57.64236365087509,-112.563725996912538 57.642362697145195,-112.577068632709995 57.642360365473628,-112.577573747874808 57.642360229574159,-112.591084630788956 57.642356259315548,-112.604426540403566 57.642350959850681,-112.604931732484545 57.64235066961227,-112.614116929341066 57.642346207850281,-112.614312206460681 57.642346105750796,-112.618442226748314 57.642343875765008,-112.631784202241008 57.642335643880848,-112.632289470996469 57.642335199268857,-112.645798123007864 57.642339521973014,-112.645797437745074 57.635115400407535,-112.659137877027206 57.63511834289929,-112.659642979791883 57.635118494971074,-112.669700429028623 57.635122153530389,-112.669841283936094 57.635122199088258,-112.673152010551348 57.635123224715656,-112.686492869463336 57.635126521851383,-112.686998068745822 57.635126647008512,-112.697617903466579 57.635128169619172,-112.697751884386562 57.63512818313103,-112.700507194591083 57.635128429521671,-112.713848037160233 57.635128887118476,-112.714353172313494 57.635128957769155,-112.727861515036651 57.635127796646934,-112.739668933471989 57.635125723680432,-112.7398119123838 57.635125691821649,-112.741201244759523 57.635125373829787,-112.741706386200647 57.635125248723291,-112.755214468374007 57.635121402716038,-112.755214938999302 57.638619728565502,-112.755214948735173 57.638691582606782,-112.755215441141644 57.642299235146872,-112.755215447488652 57.642345402788138,-112.758967608556375 57.642344081826124,-112.768555041183902 57.642340200853077,-112.769060482085038 57.64233995567534,-112.774723805433723 57.642337288433438,-112.77485779858398 57.642337222255613,-112.782568544910134 57.642333174822831,-112.792545878521608 57.642327283388113,-112.792879805745088 57.642327072595656,-112.795908199115104 57.64232512065341,-112.796413408042952 57.642324690194009,-112.796413204070831 57.642595626460313,-112.796413772391602 57.64652983267694,-112.796413782851232 57.646601687960626,-112.79641424091362 57.649729416445723,-112.809920067905253 57.649739316342981,-112.809920855351891 57.656963217303776,-112.823258284920655 57.656971400426038,-112.823763610873115 57.656971756318249,-112.830718219794321 57.656974486956898,-112.830852306301722 57.656974535846857,-112.837269477202526 57.656976709448067,-112.843218468495962 57.656978468919924,-112.843352538082513 57.656978505348206,-112.850607006408396 57.656980264588071,-112.851112640615781 57.656980352021421,-112.864618565218379 57.656982471415148,-112.877956090732994 57.656982849229017,-112.878461623045098 57.656982992559691,-112.891973358229492 57.656981752116934,-112.905316763582206 57.656979031442035,-112.905822217900621 57.656978913628727,-112.909850008811645 57.656977807352234,-112.904793255776937 57.663748102571255,-112.876051149311323 57.689002131749334,-112.85398924063584 57.703395547289318,-112.853859900073743 57.703479885685134,-112.846180811045272 57.708486213790628,-112.839085225033372 57.71324731421192,-112.833570018278607 57.715281673645009,-112.833437264182621 57.715330636059221,-112.802753315882214 57.726640253097123,-112.802638084669454 57.726682698301445,-112.802304534357916 57.726805559796297,-112.792695740923818 57.727203879689803,-112.792561460179797 57.727209440897653,-112.747148580545158 57.729081947582834,-112.740759808339661 57.728891339002537,-112.740625549048787 57.728887329904417,-112.701182883318992 57.727703332273457,-112.695460072627768 57.727325519850687,-112.695325877152243 57.727316657240131,-112.662697532322809 57.725157443019732,-112.662470432057987 57.725142384023897,-112.657023921406179 57.724781100526208,-112.602354245941228 57.716965930825133,-112.577323127171155 57.712083253178932,-112.537202600523742 57.704244053155946,-112.536633230811717 57.704077775005935,-112.534617532125367 57.707268365278459,-112.533707476725183 57.709422432230106,-112.53219078961807 57.713012564366039,-112.529944009203817 57.720595412115571,-112.527381092785689 57.725571901696703,-112.522049849374625 57.741709021979766,-112.518048832669649 57.753811697869494,-112.516714429387562 57.757845895034087,-112.515824968938432 57.760535307052692,-112.514486805220997 57.764579529074489,-112.514445766343641 57.764703543319946,-112.513131340000314 57.76867512574217,-112.513090655573208 57.768798041273612,-112.511374367185965 57.773982525977374,-112.506920534669561 57.787429577387712,-112.506773454033819 57.787873602756186,-112.50602965362792 57.790118914420248,-112.505509534964048 57.79369679873173,-112.505881326918072 57.802621702826265,-112.505194340920738 57.806201559344679,-112.505863906410553 57.822266297194709,-112.504979712931302 57.826868962042354,-112.502868122897027 57.832529819603209,-112.502016115238121 57.838384556841156,-112.502685099554142 57.85444923604512,-112.501642916328478 57.861604909406338,-112.501717263253894 57.863389924130296,-112.500339754790858 57.870549539566795,-112.501008825027057 57.886614149130821,-112.498259721194898 57.893075634585244,-112.496426598966224 57.897383173943524,-112.494134708649781 57.902767680803109,-112.492198517338494 57.905712668961868,-112.486922559138577 57.910888519184773,-112.481645093420809 57.916064153996345,-112.479707178930497 57.919008953708158,-112.471301707861372 57.926524592531436,-112.457715851491145 57.935335441296694,-112.444650691837253 57.944413655168169,-112.428150201698941 57.951743263281507,-112.409149619307399 57.957799741661837,-112.398244777276688 57.960111722262049,-112.386216860247472 57.961850602482478,-112.378197131325464 57.963009230719749,-112.368172313004578 57.964456863198528,-112.361471417667488 57.964975243714285,-112.338092478617725 57.968794918916373,-112.314447100411982 57.965470045814193,-112.307712699136403 57.965093031903081,-112.297587629960631 57.963857408460413,-112.289487608068811 57.962868381337465,-112.277339091707049 57.961383861779694,-112.246832264859435 57.95365087944166,-112.243331413368409 57.952307862347681,-112.229327203853359 57.946933506707339,-112.211828675082245 57.940213814671282,-112.205997281503286 57.937973293372842,-112.194336670355881 57.933491560025203,-112.176850728158215 57.926766872857016,-112.165197366189048 57.922282432840717,-112.155003167933273 57.918357643311076,-112.141899338213747 57.913310306330523,-112.124433422496381 57.906578312894929,-112.114442071761985 57.904319107442532,-112.113610834064545 57.904131102861385,-112.103385635151355 57.901817818363199,-112.094005667708601 57.898808325903339,-112.085279637658246 57.895439308826113,-112.073647773428831 57.890946379946513,-112.063472383308124 57.887014167851554,-112.043730155864182 57.881959575671537,-112.043590677823772 57.881923849162675,-112.039229960675598 57.880806762818004,-112.038289805305951 57.880565894111875,-112.037901697298437 57.880466457489732,-112.037734156750233 57.88042353161692,-112.033074193416368 57.879229463820458,-112.031652351090898 57.878771964778792,-112.03150045459239 57.878723088173089,-112.028390104193818 57.877722183532505,-112.022906518357672 57.875293968878623,-112.011288900044534 57.870795271160098,-112.00257735472519 57.867420513377546,-111.991552918882121 57.86531562491934,-111.972208733439587 57.859621122922817,-111.948668372399112 57.856227884196372,-111.92843500371319 57.851020417703147,-111.911510731994454 57.844000415054985,-111.88118136247725 57.836179109758952,-111.869092148117204 57.834655407850832,-111.850865085831671 57.828350513443915,-111.821109923949521 57.844617518730885,-111.791327932102519 57.860877568579482,-111.791680718486461 57.876946183355145,-111.789058874743361 57.880559785017311,-111.795190085813687 57.889987319761467,-111.795502357128726 57.9041263769642,-111.795506523899732 57.904314950462528,-111.795893294906065 57.921808538958182,-111.789519719222838 57.934224892001147,-111.788766570917701 57.937765716425744,-111.784418262153082 57.94415773094218,-111.783292168818775 57.946349148149345,-111.784054784818096 57.953192872478461,-111.77859948249116 57.960832581686468,-111.778545275677629 57.960908476530307,-111.777729649211082 57.962050392056348,-111.775004918297313 57.973090346219649,-111.762732308857849 57.9813532651918,-111.748563470641898 57.984271986611205,-111.741585556786376 57.990926804704941,-111.74102170582978 57.991380623317148,-111.726996850386286 58.002664117208724,-111.705160319125127 58.008456058869413,-111.695923370421355 58.006173268331295,-111.689890980315781 58.008355741087954,-111.677981310126356 58.012662977645775,-111.672025404245701 58.0148163012285,-111.663089967355305 58.018045583795377,-111.648170161318887 58.022100507286574,-111.63621793777547 58.024547670641908,-111.632082525232931 58.025547491725611,-111.618279208923951 58.027818460000383,-111.595824937891905 58.030312384711387,-111.58833948163813 58.031142854311135,-111.582890420269337 58.031457215401005,-111.567644659528909 58.033326732439605,-111.565254421992918 58.034874413695647,-111.560343661658365 58.038053344155493,-111.553302459355365 58.042991417768626,-111.546834991644559 58.046794258913188,-111.53329817154389 58.054086821455115,-111.525902649592084 58.057406264881912,-111.517025630128472 58.061389055879189,-111.51069025799643 58.063826285202246,-111.506164107785168 58.065567019895354,-111.493209697344014 58.069063167292718,-111.491048945884756 58.069530884588538,-111.478950329679336 58.072390569554528,-111.474215362154965 58.073509289908749,-111.465342902430606 58.076058543971705,-111.456490209551148 58.078601140597208,-111.412085757016385 58.07861102052982,-111.411574259525068 58.078611044198176,-111.366309909615666 58.078605007431712,-111.362943962962802 58.078603926898715,-111.363189588146909 58.078418747725379,-111.365499964884918 58.07674787433303,-111.248257920425146 58.073663242252245,-111.248252820860458 58.03508929268385,-111.165388373977493 58.035068864753036),(-112.546847672440251 57.216756587722735,-112.543223037823452 57.208749222454102,-112.541164697841793 57.206409944997567,-112.535720130941797 57.200220652219535,-112.532660427300769 57.196741404753055,-112.532591022034239 57.196662474128708,-112.528595840609896 57.192118342803965,-112.527961368963034 57.191967142374374,-112.516096026879865 57.189138700248705,-112.505356799991389 57.190734440821984,-112.495105069416809 57.192256761750144,-112.494896799667004 57.19228767861263,-112.493164844274304 57.192544765534159,-112.491190672837121 57.192837772933132,-112.490890802888885 57.192882276647978,-112.47816928124405 57.194769521524087,-112.464067227109751 57.193512782427113,-112.463716849617569 57.193376406289538,-112.463585620083236 57.193325327788642,-112.455951959289962 57.190353594497552,-112.454983724454465 57.189976599421151,-112.454910881874056 57.189948236579831,-112.454803739399779 57.189906518172613,-112.453677516955125 57.189467986101334,-112.45332496636091 57.189330704592862,-112.453215921383674 57.189288242593079,-112.441812377549226 57.184846647028138,-112.430856121517024 57.180577273385957,-112.415548509792956 57.17460901520851,-112.413790485602291 57.174293521047765,-112.41365782028285 57.174269711773213,-112.402116846974451 57.172197812115506,-112.401977521075352 57.17217279163151,-112.397923356380389 57.171444652072374,-112.397796449294404 57.171421856613165,-112.396678365983576 57.171221016110707,-112.396512097973101 57.171191148467422,-112.396345162651173 57.171161160680235,-112.390297867119727 57.164654926522935,-112.379559287482294 57.153094951007084,-112.378282191847291 57.145543148184892,-112.367469172818417 57.138291313584517,-112.352971762375091 57.133125632240144,-112.336811732640982 57.131701722487016,-112.32541471368387 57.135774672270863,-112.313310070184059 57.140098398379209,-112.304676398534014 57.143180982854354,-112.304556207827204 57.143223888210059,-112.293225614274903 57.147267692671832,-112.276758116378744 57.150302493585698,-112.260806608321204 57.150329284533292,-112.246721268312641 57.153851581709176,-112.22973101022535 57.158097318600305,-112.217600553891188 57.161126629874481,-112.204322110319907 57.164440716576976,-112.189741064149189 57.161803301098608,-112.171655465734673 57.158529098446671,-112.159620423752727 57.162494696003314,-112.146494698867599 57.166570300783732,-112.146739212327319 57.174467849397558,-112.145880438546612 57.1764763736563,-112.145847307362502 57.176553857374941,-112.144253996190798 57.180279737346424,-112.144343453935562 57.183173744792548,-112.142745800946187 57.188977496573763,-112.140636633169933 57.19261497738507,-112.135757478743756 57.201026203429279,-112.135385709119689 57.20184839017481,-112.132876248261653 57.206172751619562,-112.132776980259635 57.206343790924592,-112.127875429131294 57.214787143290842,-112.11765180015972 57.225366041981395,-112.106543453772176 57.235951855952223,-112.103565386992784 57.239070893461374,-112.103436003378107 57.239206388146179,-112.094606129010529 57.248450666217742,-112.089592058769469 57.251860843651343,-112.089762446054294 57.257633112182766,-112.08976733404171 57.257798671976019,-112.089950296842616 57.263994466717989,-112.087173852057091 57.270447569734202,-112.081075541927945 57.275577998785209,-112.081002281720515 57.275639621211134,-112.075590510811892 57.280191018044412,-112.076059406287399 57.296259819792105,-112.088449715917605 57.296153192767569,-112.088583395846868 57.296152035702015,-112.118530528847828 57.295889245556452,-112.118713601701074 57.295887617127505,-112.11947008387007 57.295880885408678,-112.119677483010335 57.295879039027859,-112.135423086655337 57.295737863915193,-112.147006826782629 57.299768069333304,-112.147179306654508 57.299828063599023,-112.147352349075163 57.299888253102012,-112.147516140790572 57.299945224521416,-112.153433117622811 57.302003055043393,-112.177284217891128 57.304996852975272,-112.183222238946087 57.304941131679954,-112.190089348089714 57.305494178826706,-112.190277384653356 57.305509316961356,-112.195132057431451 57.305900047133484,-112.224820664390521 57.305614440284735,-112.236659813999552 57.304427063909742,-112.241253993432338 57.303667374324903,-112.254417527666092 57.302643789189496,-112.266236321001387 57.300917930628366,-112.283962868544748 57.298327309778784,-112.28932138779679 57.297176668779954,-112.296045400269563 57.296294898586375,-112.296256193311876 57.296267249229089,-112.298197272004145 57.296012622778143,-112.298362754118628 57.295990913650492,-112.308370573863741 57.294677564569803,-112.308897890509542 57.294608338952919,-112.309433866460026 57.294537974022326,-112.309566239077597 57.294520595256522,-112.313501192638086 57.294003917129572,-112.33386838302664 57.288843830722868,-112.342944691156148 57.28726363027878,-112.353938948436465 57.283529084679074,-112.354810902230781 57.283232832669306,-112.354926795748682 57.2831934562765,-112.37107968385709 57.27770343076994,-112.371206596943978 57.27766028104277,-112.372257750707391 57.277302885964616,-112.39123810487051 57.271421304678071,-112.401615954092975 57.268942152690911,-112.411398892644044 57.266153648513658,-112.414315564427326 57.265322115179202,-112.414440380070758 57.265286528318278,-112.415598284127213 57.264956382893679,-112.415730639473807 57.264918644247871,-112.430960770832172 57.260574615239364,-112.446361441267115 57.252834273862092,-112.458757986132412 57.247913733086371,-112.458883239556314 57.247864003552635,-112.460101560464906 57.247380278523359,-112.461678816591416 57.247016801949009,-112.461811438399437 57.246986238204578,-112.464299106465205 57.246412900198713,-112.466269295501021 57.245958821148797,-112.467740243312051 57.245619777297307,-112.468694097118473 57.245399907732441,-112.469083874380331 57.245310058684069,-112.470960760910785 57.244877387393799,-112.471083827619609 57.244849015977834,-112.471219067489301 57.244817838010427,-112.471426242669523 57.244770075816582,-112.474792455560888 57.24399396362908,-112.4752257771666 57.243883411939862,-112.475357300503802 57.243849856466788,-112.484951754855246 57.241401494446116,-112.489448233077965 57.239802577090444,-112.501937735584946 57.234487261225837,-112.518584649628792 57.227398183890195,-112.519067290778253 57.227240760434945,-112.520557389306717 57.226754713688265,-112.537191853745156 57.221326750581198,-112.546847672440251 57.216756587722735),(-112.568386353278683 57.208688923410485,-112.568437018439013 57.208793640137507,-112.568756097693054 57.208689335094682,-112.568386353278683 57.208688923410485))) \ No newline at end of file diff --git a/geoPHP/tests/input/path.kml b/geoPHP/tests/input/path.kml new file mode 100644 index 0000000..0538daf --- /dev/null +++ b/geoPHP/tests/input/path.kml @@ -0,0 +1,40 @@ + + + + Paths + Examples of paths. Note that the tessellate tag is by default + set to 0. If you want to create tessellated lines, they must be authored + (or edited) directly in KML. + + + Absolute Extruded + Transparent green wall with yellow outlines + #yellowLineGreenPoly + + 1 + 1 + absolute + -112.2550785337791,36.07954952145647,2357 + -112.2549277039738,36.08117083492122,2357 + -112.2552505069063,36.08260761307279,2357 + -112.2564540158376,36.08395660588506,2357 + -112.2580238976449,36.08511401044813,2357 + -112.2595218489022,36.08584355239394,2357 + -112.2608216347552,36.08612634548589,2357 + -112.262073428656,36.08626019085147,2357 + -112.2633204928495,36.08621519860091,2357 + -112.2644963846444,36.08627897945274,2357 + -112.2656969554589,36.08649599090644,2357 + + + + + diff --git a/geoPHP/tests/input/pentagon.kml b/geoPHP/tests/input/pentagon.kml new file mode 100644 index 0000000..bdc85e3 --- /dev/null +++ b/geoPHP/tests/input/pentagon.kml @@ -0,0 +1,34 @@ + + + + The Pentagon + + 1 + relativeToGround + + + + -77.05788457660967,38.87253259892824,100 + -77.05465973756702,38.87291016281703,100 + -77.05315536854791,38.87053267794386,100 + -77.05552622493516,38.868757801256,100 + -77.05844056290393,38.86996206506943,100 + -77.05788457660967,38.87253259892824,100 + + + + + + + -77.05668055019126,38.87154239798456,100 + -77.05542625960818,38.87167890344077,100 + -77.05485125901024,38.87076535397792,100 + -77.05577677433152,38.87008686581446,100 + -77.05691162017543,38.87054446963351,100 + -77.05668055019126,38.87154239798456,100 + + + + + + diff --git a/geoPHP/tests/input/point.georss b/geoPHP/tests/input/point.georss new file mode 100644 index 0000000..3b83276 --- /dev/null +++ b/geoPHP/tests/input/point.georss @@ -0,0 +1,21 @@ + + + Earthquakes + International earthquake observation labs + + 2005-12-13T18:30:02Z + + Dr. Thaddeus Remor + tremor@quakelab.edu + + urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6 + + M 3.2, Mona Passage + + urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + 2005-08-17T07:02:32Z + We just had a big one. + 45.256 -71.92 + + \ No newline at end of file diff --git a/geoPHP/tests/input/point.kml b/geoPHP/tests/input/point.kml new file mode 100644 index 0000000..f95894f --- /dev/null +++ b/geoPHP/tests/input/point.kml @@ -0,0 +1,11 @@ + + + + Simple placemark + Attached to the ground. Intelligently places itself + at the height of the underlying terrain. + + -122.0822035425683,37.42228990140251,0 + + + diff --git a/geoPHP/tests/input/point.wkt b/geoPHP/tests/input/point.wkt new file mode 100644 index 0000000..b3be821 --- /dev/null +++ b/geoPHP/tests/input/point.wkt @@ -0,0 +1 @@ +POINT (10 12) diff --git a/geoPHP/tests/input/polygon.georss b/geoPHP/tests/input/polygon.georss new file mode 100644 index 0000000..7decd20 --- /dev/null +++ b/geoPHP/tests/input/polygon.georss @@ -0,0 +1,3 @@ + + 45.256 -110.45 46.46 -109.48 43.84 -109.86 45.256 -110.45 + \ No newline at end of file diff --git a/geoPHP/tests/input/polygon.wkt b/geoPHP/tests/input/polygon.wkt new file mode 100644 index 0000000..dc9bcab --- /dev/null +++ b/geoPHP/tests/input/polygon.wkt @@ -0,0 +1 @@ +POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)) diff --git a/geoPHP/tests/input/polygon2.wkt b/geoPHP/tests/input/polygon2.wkt new file mode 100644 index 0000000..4a75c84 --- /dev/null +++ b/geoPHP/tests/input/polygon2.wkt @@ -0,0 +1 @@ +POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10), (20 30, 35 35, 30 20, 20 30)) diff --git a/geoPHP/tests/input/polygon3.wkt b/geoPHP/tests/input/polygon3.wkt new file mode 100644 index 0000000..ac5e500 --- /dev/null +++ b/geoPHP/tests/input/polygon3.wkt @@ -0,0 +1 @@ +POLYGON ((-123.222653196 49.1529676585, -89.4726531957 49.3823707987, -81.0351531957 44.0875828344, -71.1914031957 44.3395630636, -62.0507781957 48.4583498573, -60.2929656957 45.0890334085, -78.9257781957 37.4399716272, -82.0898406957 31.3536343332, -81.3867156957 26.4312253295, -91.9335906957 29.8406412505, -98.2617156957 26.4312253295, -107.753903196 32.2499718728, -116.894528196 33.1375486348, -122.519528196 36.0313293064, -126.035153196 42.2935619329, -123.222653196 49.1529676585)) diff --git a/geoPHP/tests/input/track.gpx b/geoPHP/tests/input/track.gpx new file mode 100644 index 0000000..b2306a6 --- /dev/null +++ b/geoPHP/tests/input/track.gpx @@ -0,0 +1,28 @@ + + + + + + Garmin International + + + + + Example GPX Document + + + 4.46 + + + + 4.94 + + + + 6.87 + + + + + + diff --git a/geoPHP/tests/test.php b/geoPHP/tests/test.php new file mode 100644 index 0000000..4ea68b6 --- /dev/null +++ b/geoPHP/tests/test.php @@ -0,0 +1,221 @@ +area(); + $geometry->boundary(); + $geometry->envelope(); + $geometry->getBBox(); + $geometry->centroid(); + $geometry->length(); + $geometry->y(); + $geometry->x(); + $geometry->numGeometries(); + $geometry->geometryN(1); + $geometry->startPoint(); + $geometry->endPoint(); + $geometry->isRing(); + $geometry->isClosed(); + $geometry->numPoints(); + $geometry->pointN(1); + $geometry->exteriorRing(); + $geometry->numInteriorRings(); + $geometry->interiorRingN(1); + $geometry->dimension(); + $geometry->geometryType(); + $geometry->SRID(); + $geometry->setSRID(4326); + + // Aliases + $geometry->getCentroid(); + $geometry->getArea(); + $geometry->getX(); + $geometry->getY(); + $geometry->getGeos(); + $geometry->getGeomType(); + $geometry->getSRID(); + $geometry->asText(); + $geometry->asBinary(); + + // GEOS only functions + $geometry->geos(); + $geometry->setGeos($geometry->geos()); + $geometry->pointOnSurface(); + $geometry->equals($geometry); + $geometry->equalsExact($geometry); + $geometry->relate($geometry); + $geometry->checkValidity(); + $geometry->isSimple(); + $geometry->buffer(10); + $geometry->intersection($geometry); + $geometry->convexHull(); + $geometry->difference($geometry); + $geometry->symDifference($geometry); + $geometry->union($geometry); + $geometry->simplify(0);// @@TODO: Adjust this once we can deal with empty geometries + $geometry->disjoint($geometry); + $geometry->touches($geometry); + $geometry->intersects($geometry); + $geometry->crosses($geometry); + $geometry->within($geometry); + $geometry->contains($geometry); + $geometry->overlaps($geometry); + $geometry->covers($geometry); + $geometry->coveredBy($geometry); + $geometry->distance($geometry); + $geometry->hausdorffDistance($geometry); + + + // Place holders + $geometry->hasZ(); + $geometry->is3D(); + $geometry->isMeasured(); + $geometry->isEmpty(); + $geometry->coordinateDimension(); + $geometry->z(); + $geometry->m(); +} + +function test_adapters($geometry, $format, $input) { + // Test adapter output and input. Do a round-trip and re-test + foreach (geoPHP::getAdapterMap() as $adapter_key => $adapter_class) { + if ($adapter_key != 'google_geocode') { //Don't test google geocoder regularily. Uncomment to test + $output = $geometry->out($adapter_key); + $adapter_loader = new $adapter_class(); + $test_geom_1 = $adapter_loader->read($output); + $test_geom_2 = $adapter_loader->read($test_geom_1->out($adapter_key)); + + // Check to make sure a round-trip results in the same geometry + if ($test_geom_1->out('wkt') != $test_geom_2->out('wkt')) { + print "Mismatched adapter output in ".$adapter_class."\n"; + } + } + } + + // Test to make sure adapter work the same wether GEOS is ON or OFF + // Cannot test methods if GEOS is not intstalled + if (!geoPHP::geosInstalled()) return; + + foreach (geoPHP::getAdapterMap() as $adapter_key => $adapter_class) { + if ($adapter_key != 'google_geocode') { //Don't test google geocoder regularily. Uncomment to test + // Turn GEOS on + geoPHP::geosInstalled(TRUE); + + $output = $geometry->out($adapter_key); + $adapter_loader = new $adapter_class(); + + $test_geom_1 = $adapter_loader->read($output); + + // Turn GEOS off + geoPHP::geosInstalled(FALSE); + + $test_geom_2 = $adapter_loader->read($output); + + // Turn GEOS back On + geoPHP::geosInstalled(TRUE); + + // Check to make sure a both are the same with geos and without + if ($test_geom_1->out('wkt') != $test_geom_2->out('wkt')) { + print "Mismatched adapter output between GEOS and NORM in ".$adapter_class."\n"; + } + } + } +} + + +function test_methods($geometry) { + // Cannot test methods if GEOS is not intstalled + if (!geoPHP::geosInstalled()) return; + + $methods = array( + //'boundary', //@@TODO: Uncomment this and fix errors + 'envelope', //@@TODO: Testing reveales errors in this method -- POINT vs. POLYGON + 'getBBox', + 'x', + 'y', + 'startPoint', + 'endPoint', + 'isRing', + 'isClosed', + 'numPoints', + ); + + foreach ($methods as $method) { + // Turn GEOS on + geoPHP::geosInstalled(TRUE); + $geos_result = $geometry->$method(); + + // Turn GEOS off + geoPHP::geosInstalled(FALSE); + $norm_result = $geometry->$method(); + + // Turn GEOS back On + geoPHP::geosInstalled(TRUE); + + $geos_type = gettype($geos_result); + $norm_type = gettype($norm_result); + + if ($geos_type != $norm_type) { + print 'Type mismatch on '.$method."\n"; + var_dump($geos_type); + var_dump($norm_type); + continue; + } + + // Now check base on type + if ($geos_type == 'object') { + $haus_dist = $geos_result->hausdorffDistance(geoPHP::load($norm_result->out('wkt'),'wkt')); + + // Get the length of the diagonal of the bbox - this is used to scale the haustorff distance + // Using Pythagorean theorem + $bb = $geos_result->getBBox(); + $scale = sqrt((($bb['maxy'] - $bb['miny'])^2) + (($bb['maxx'] - $bb['minx'])^2)); + + // The difference in the output of GEOS and native-PHP methods should be less than 0.5 scaled haustorff units + if ($haus_dist / $scale > 0.5) { + print 'Output mismatch on '.$method.":\n"; + print 'GEOS : '.$geos_result->out('wkt')."\n"; + print 'NORM : '.$norm_result->out('wkt')."\n"; + continue; + } + } + + if ($geos_type == 'boolean' || $geos_type == 'string') { + if ($geos_result !== $norm_result) { + print 'Output mismatch on '.$method.":\n"; + print 'GEOS : '.(string) $geos_result."\n"; + print 'NORM : '.(string) $norm_result."\n"; + continue; + } + } + + //@@TODO: Run tests for output of types arrays and float + //@@TODO: centroid function is non-compliant for collections and strings + } +} + +print "Testing Done!"; \ No newline at end of file -- 1.7.9.2