├── README.md ├── demo ├── bicycleparking.png ├── bikeRacks_geojson.php ├── busRoutes_geojson.php ├── cdta_gis.sqlite ├── geoPHP │ ├── LICENSE │ ├── README.md │ ├── geoPHP.inc │ └── lib │ │ ├── adapters │ │ ├── EWKB.class.php │ │ ├── EWKT.class.php │ │ ├── GPX.class.php │ │ ├── GeoAdapter.class.php │ │ ├── GeoHash.class.php │ │ ├── GeoJSON.class.php │ │ ├── GeoRSS.class.php │ │ ├── GoogleGeocode.class.php │ │ ├── KML.class.php │ │ ├── WKB.class.php │ │ └── WKT.class.php │ │ └── geometry │ │ ├── Collection.class.php │ │ ├── Geometry.class.php │ │ ├── GeometryCollection.class.php │ │ ├── LineString.class.php │ │ ├── MultiLineString.class.php │ │ ├── MultiPoint.class.php │ │ ├── MultiPolygon.class.php │ │ ├── Point.class.php │ │ └── Polygon.class.php └── index.html ├── mysql_geojson.php ├── postgis_geojson.php ├── simple_points ├── csv_points_geojson.php ├── mysql_points_geojson.php ├── postgis_points_geojson.php └── sqlite_points_geojson.php └── sqlite_geojson.php /README.md: -------------------------------------------------------------------------------- 1 | PHP-Database-GeoJSON 2 | ==================== 3 | 4 | A collection of PHP scripts to query a database table or view and return the results in GeoJSON format, suitable for use in OpenLayers, Leaflet, etc. -------------------------------------------------------------------------------- /demo/bicycleparking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmcbride/PHP-Database-GeoJSON/f443c67050a5d3bb3e0e739d9e92555a504ea7b8/demo/bicycleparking.png -------------------------------------------------------------------------------- /demo/bikeRacks_geojson.php: -------------------------------------------------------------------------------- 1 | out('json'); 15 | } 16 | 17 | # Connect to SQLite database 18 | $conn = new PDO('sqlite:cdta_gis.sqlite'); 19 | 20 | # Build SQL SELECT statement and return the geometry as a GeoJSON element 21 | $sql = 'SELECT *, GEOMETRY AS wkb FROM cdta_bike_racks'; 22 | 23 | # Try query or error 24 | $rs = $conn->query($sql); 25 | if (!$rs) { 26 | echo 'An SQL error occured.\n'; 27 | exit; 28 | } 29 | 30 | # Build GeoJSON feature collection array 31 | $geojson = array( 32 | 'type' => 'FeatureCollection', 33 | 'features' => array() 34 | ); 35 | 36 | # Loop through rows to build feature arrays 37 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 38 | $properties = $row; 39 | # Remove wkb and geometry fields from properties 40 | unset($properties['wkb']); 41 | unset($properties['GEOMETRY']); 42 | $feature = array( 43 | 'type' => 'Feature', 44 | 'geometry' => json_decode(wkb_to_json($row['wkb'])), 45 | 'properties' => $properties 46 | ); 47 | # Add feature arrays to feature collection array 48 | array_push($geojson['features'], $feature); 49 | } 50 | 51 | header('Content-type: application/json'); 52 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 53 | $conn = NULL; 54 | ?> -------------------------------------------------------------------------------- /demo/busRoutes_geojson.php: -------------------------------------------------------------------------------- 1 | out('json'); 15 | } 16 | 17 | # Connect to SQLite database 18 | $conn = new PDO('sqlite:cdta_gis.sqlite'); 19 | 20 | # Build SQL SELECT statement and return the geometry as a GeoJSON element 21 | $sql = 'SELECT *, GEOMETRY AS wkb FROM cdta_routes'; 22 | 23 | # Try query or error 24 | $rs = $conn->query($sql); 25 | if (!$rs) { 26 | echo 'An SQL error occured.\n'; 27 | exit; 28 | } 29 | 30 | # Build GeoJSON feature collection array 31 | $geojson = array( 32 | 'type' => 'FeatureCollection', 33 | 'features' => array() 34 | ); 35 | 36 | # Loop through rows to build feature arrays 37 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 38 | $properties = $row; 39 | # Remove wkb and geometry fields from properties 40 | unset($properties['wkb']); 41 | unset($properties['GEOMETRY']); 42 | $feature = array( 43 | 'type' => 'Feature', 44 | 'geometry' => json_decode(wkb_to_json($row['wkb'])), 45 | 'properties' => $properties 46 | ); 47 | # Add feature arrays to feature collection array 48 | array_push($geojson['features'], $feature); 49 | } 50 | 51 | header('Content-type: application/json'); 52 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 53 | $conn = NULL; 54 | ?> -------------------------------------------------------------------------------- /demo/cdta_gis.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmcbride/PHP-Database-GeoJSON/f443c67050a5d3bb3e0e739d9e92555a504ea7b8/demo/cdta_gis.sqlite -------------------------------------------------------------------------------- /demo/geoPHP/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Patrick Hayes and contributors 2 | 3 | This program is dual-licensed under both the GPL version 2 (or later) and 4 | Modified BSD License. Either license may be used at your option. 5 | 6 | ------------------------------------------------------------------------------ 7 | Modified BSD License 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the copyright holder nor the 17 | names of the contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | ------------------------------------------------------------------------------- 32 | GNU GENERAL PUBLIC LICENSE 33 | Version 2, June 1991 34 | 35 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 36 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 37 | Everyone is permitted to copy and distribute verbatim copies 38 | of this license document, but changing it is not allowed. 39 | 40 | Preamble 41 | 42 | The licenses for most software are designed to take away your 43 | freedom to share and change it. By contrast, the GNU General Public 44 | License is intended to guarantee your freedom to share and change free 45 | software--to make sure the software is free for all its users. This 46 | General Public License applies to most of the Free Software 47 | Foundation's software and to any other program whose authors commit to 48 | using it. (Some other Free Software Foundation software is covered by 49 | the GNU Lesser General Public License instead.) You can apply it to 50 | your programs, too. 51 | 52 | When we speak of free software, we are referring to freedom, not 53 | price. Our General Public Licenses are designed to make sure that you 54 | have the freedom to distribute copies of free software (and charge for 55 | this service if you wish), that you receive source code or can get it 56 | if you want it, that you can change the software or use pieces of it 57 | in new free programs; and that you know you can do these things. 58 | 59 | To protect your rights, we need to make restrictions that forbid 60 | anyone to deny you these rights or to ask you to surrender the rights. 61 | These restrictions translate to certain responsibilities for you if you 62 | distribute copies of the software, or if you modify it. 63 | 64 | For example, if you distribute copies of such a program, whether 65 | gratis or for a fee, you must give the recipients all the rights that 66 | you have. You must make sure that they, too, receive or can get the 67 | source code. And you must show them these terms so they know their 68 | rights. 69 | 70 | We protect your rights with two steps: (1) copyright the software, and 71 | (2) offer you this license which gives you legal permission to copy, 72 | distribute and/or modify the software. 73 | 74 | Also, for each author's protection and ours, we want to make certain 75 | that everyone understands that there is no warranty for this free 76 | software. If the software is modified by someone else and passed on, we 77 | want its recipients to know that what they have is not the original, so 78 | that any problems introduced by others will not reflect on the original 79 | authors' reputations. 80 | 81 | Finally, any free program is threatened constantly by software 82 | patents. We wish to avoid the danger that redistributors of a free 83 | program will individually obtain patent licenses, in effect making the 84 | program proprietary. To prevent this, we have made it clear that any 85 | patent must be licensed for everyone's free use or not licensed at all. 86 | 87 | The precise terms and conditions for copying, distribution and 88 | modification follow. 89 | 90 | GNU GENERAL PUBLIC LICENSE 91 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 92 | 93 | 0. This License applies to any program or other work which contains 94 | a notice placed by the copyright holder saying it may be distributed 95 | under the terms of this General Public License. The "Program", below, 96 | refers to any such program or work, and a "work based on the Program" 97 | means either the Program or any derivative work under copyright law: 98 | that is to say, a work containing the Program or a portion of it, 99 | either verbatim or with modifications and/or translated into another 100 | language. (Hereinafter, translation is included without limitation in 101 | the term "modification".) Each licensee is addressed as "you". 102 | 103 | Activities other than copying, distribution and modification are not 104 | covered by this License; they are outside its scope. The act of 105 | running the Program is not restricted, and the output from the Program 106 | is covered only if its contents constitute a work based on the 107 | Program (independent of having been made by running the Program). 108 | Whether that is true depends on what the Program does. 109 | 110 | 1. You may copy and distribute verbatim copies of the Program's 111 | source code as you receive it, in any medium, provided that you 112 | conspicuously and appropriately publish on each copy an appropriate 113 | copyright notice and disclaimer of warranty; keep intact all the 114 | notices that refer to this License and to the absence of any warranty; 115 | and give any other recipients of the Program a copy of this License 116 | along with the Program. 117 | 118 | You may charge a fee for the physical act of transferring a copy, and 119 | you may at your option offer warranty protection in exchange for a fee. 120 | 121 | 2. You may modify your copy or copies of the Program or any portion 122 | of it, thus forming a work based on the Program, and copy and 123 | distribute such modifications or work under the terms of Section 1 124 | above, provided that you also meet all of these conditions: 125 | 126 | a) You must cause the modified files to carry prominent notices 127 | stating that you changed the files and the date of any change. 128 | 129 | b) You must cause any work that you distribute or publish, that in 130 | whole or in part contains or is derived from the Program or any 131 | part thereof, to be licensed as a whole at no charge to all third 132 | parties under the terms of this License. 133 | 134 | c) If the modified program normally reads commands interactively 135 | when run, you must cause it, when started running for such 136 | interactive use in the most ordinary way, to print or display an 137 | announcement including an appropriate copyright notice and a 138 | notice that there is no warranty (or else, saying that you provide 139 | a warranty) and that users may redistribute the program under 140 | these conditions, and telling the user how to view a copy of this 141 | License. (Exception: if the Program itself is interactive but 142 | does not normally print such an announcement, your work based on 143 | the Program is not required to print an announcement.) 144 | 145 | These requirements apply to the modified work as a whole. If 146 | identifiable sections of that work are not derived from the Program, 147 | and can be reasonably considered independent and separate works in 148 | themselves, then this License, and its terms, do not apply to those 149 | sections when you distribute them as separate works. But when you 150 | distribute the same sections as part of a whole which is a work based 151 | on the Program, the distribution of the whole must be on the terms of 152 | this License, whose permissions for other licensees extend to the 153 | entire whole, and thus to each and every part regardless of who wrote it. 154 | 155 | Thus, it is not the intent of this section to claim rights or contest 156 | your rights to work written entirely by you; rather, the intent is to 157 | exercise the right to control the distribution of derivative or 158 | collective works based on the Program. 159 | 160 | In addition, mere aggregation of another work not based on the Program 161 | with the Program (or with a work based on the Program) on a volume of 162 | a storage or distribution medium does not bring the other work under 163 | the scope of this License. 164 | 165 | 3. You may copy and distribute the Program (or a work based on it, 166 | under Section 2) in object code or executable form under the terms of 167 | Sections 1 and 2 above provided that you also do one of the following: 168 | 169 | a) Accompany it with the complete corresponding machine-readable 170 | source code, which must be distributed under the terms of Sections 171 | 1 and 2 above on a medium customarily used for software interchange; or, 172 | 173 | b) Accompany it with a written offer, valid for at least three 174 | years, to give any third party, for a charge no more than your 175 | cost of physically performing source distribution, a complete 176 | machine-readable copy of the corresponding source code, to be 177 | distributed under the terms of Sections 1 and 2 above on a medium 178 | customarily used for software interchange; or, 179 | 180 | c) Accompany it with the information you received as to the offer 181 | to distribute corresponding source code. (This alternative is 182 | allowed only for noncommercial distribution and only if you 183 | received the program in object code or executable form with such 184 | an offer, in accord with Subsection b above.) 185 | 186 | The source code for a work means the preferred form of the work for 187 | making modifications to it. For an executable work, complete source 188 | code means all the source code for all modules it contains, plus any 189 | associated interface definition files, plus the scripts used to 190 | control compilation and installation of the executable. However, as a 191 | special exception, the source code distributed need not include 192 | anything that is normally distributed (in either source or binary 193 | form) with the major components (compiler, kernel, and so on) of the 194 | operating system on which the executable runs, unless that component 195 | itself accompanies the executable. 196 | 197 | If distribution of executable or object code is made by offering 198 | access to copy from a designated place, then offering equivalent 199 | access to copy the source code from the same place counts as 200 | distribution of the source code, even though third parties are not 201 | compelled to copy the source along with the object code. 202 | 203 | 4. You may not copy, modify, sublicense, or distribute the Program 204 | except as expressly provided under this License. Any attempt 205 | otherwise to copy, modify, sublicense or distribute the Program is 206 | void, and will automatically terminate your rights under this License. 207 | However, parties who have received copies, or rights, from you under 208 | this License will not have their licenses terminated so long as such 209 | parties remain in full compliance. 210 | 211 | 5. You are not required to accept this License, since you have not 212 | signed it. However, nothing else grants you permission to modify or 213 | distribute the Program or its derivative works. These actions are 214 | prohibited by law if you do not accept this License. Therefore, by 215 | modifying or distributing the Program (or any work based on the 216 | Program), you indicate your acceptance of this License to do so, and 217 | all its terms and conditions for copying, distributing or modifying 218 | the Program or works based on it. 219 | 220 | 6. Each time you redistribute the Program (or any work based on the 221 | Program), the recipient automatically receives a license from the 222 | original licensor to copy, distribute or modify the Program subject to 223 | these terms and conditions. You may not impose any further 224 | restrictions on the recipients' exercise of the rights granted herein. 225 | You are not responsible for enforcing compliance by third parties to 226 | this License. 227 | 228 | 7. If, as a consequence of a court judgment or allegation of patent 229 | infringement or for any other reason (not limited to patent issues), 230 | conditions are imposed on you (whether by court order, agreement or 231 | otherwise) that contradict the conditions of this License, they do not 232 | excuse you from the conditions of this License. If you cannot 233 | distribute so as to satisfy simultaneously your obligations under this 234 | License and any other pertinent obligations, then as a consequence you 235 | may not distribute the Program at all. For example, if a patent 236 | license would not permit royalty-free redistribution of the Program by 237 | all those who receive copies directly or indirectly through you, then 238 | the only way you could satisfy both it and this License would be to 239 | refrain entirely from distribution of the Program. 240 | 241 | If any portion of this section is held invalid or unenforceable under 242 | any particular circumstance, the balance of the section is intended to 243 | apply and the section as a whole is intended to apply in other 244 | circumstances. 245 | 246 | It is not the purpose of this section to induce you to infringe any 247 | patents or other property right claims or to contest validity of any 248 | such claims; this section has the sole purpose of protecting the 249 | integrity of the free software distribution system, which is 250 | implemented by public license practices. Many people have made 251 | generous contributions to the wide range of software distributed 252 | through that system in reliance on consistent application of that 253 | system; it is up to the author/donor to decide if he or she is willing 254 | to distribute software through any other system and a licensee cannot 255 | impose that choice. 256 | 257 | This section is intended to make thoroughly clear what is believed to 258 | be a consequence of the rest of this License. 259 | 260 | 8. If the distribution and/or use of the Program is restricted in 261 | certain countries either by patents or by copyrighted interfaces, the 262 | original copyright holder who places the Program under this License 263 | may add an explicit geographical distribution limitation excluding 264 | those countries, so that distribution is permitted only in or among 265 | countries not thus excluded. In such case, this License incorporates 266 | the limitation as if written in the body of this License. 267 | 268 | 9. The Free Software Foundation may publish revised and/or new versions 269 | of the General Public License from time to time. Such new versions will 270 | be similar in spirit to the present version, but may differ in detail to 271 | address new problems or concerns. 272 | 273 | Each version is given a distinguishing version number. If the Program 274 | specifies a version number of this License which applies to it and "any 275 | later version", you have the option of following the terms and conditions 276 | either of that version or of any later version published by the Free 277 | Software Foundation. If the Program does not specify a version number of 278 | this License, you may choose any version ever published by the Free Software 279 | Foundation. 280 | 281 | 10. If you wish to incorporate parts of the Program into other free 282 | programs whose distribution conditions are different, write to the author 283 | to ask for permission. For software which is copyrighted by the Free 284 | Software Foundation, write to the Free Software Foundation; we sometimes 285 | make exceptions for this. Our decision will be guided by the two goals 286 | of preserving the free status of all derivatives of our free software and 287 | of promoting the sharing and reuse of software generally. 288 | 289 | NO WARRANTY 290 | 291 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 292 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 293 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 294 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 295 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 296 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 297 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 298 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 299 | REPAIR OR CORRECTION. 300 | 301 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 302 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 303 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 304 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 305 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 306 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 307 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 308 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 309 | POSSIBILITY OF SUCH DAMAGES. 310 | 311 | END OF TERMS AND CONDITIONS 312 | 313 | How to Apply These Terms to Your New Programs 314 | 315 | If you develop a new program, and you want it to be of the greatest 316 | possible use to the public, the best way to achieve this is to make it 317 | free software which everyone can redistribute and change under these terms. 318 | 319 | To do so, attach the following notices to the program. It is safest 320 | to attach them to the start of each source file to most effectively 321 | convey the exclusion of warranty; and each file should have at least 322 | the "copyright" line and a pointer to where the full notice is found. 323 | 324 | 325 | Copyright (C) 326 | 327 | This program is free software; you can redistribute it and/or modify 328 | it under the terms of the GNU General Public License as published by 329 | the Free Software Foundation; either version 2 of the License, or 330 | (at your option) any later version. 331 | 332 | This program is distributed in the hope that it will be useful, 333 | but WITHOUT ANY WARRANTY; without even the implied warranty of 334 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 335 | GNU General Public License for more details. 336 | 337 | You should have received a copy of the GNU General Public License along 338 | with this program; if not, write to the Free Software Foundation, Inc., 339 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 340 | 341 | Also add information on how to contact you by electronic and paper mail. 342 | 343 | If the program is interactive, make it output a short notice like this 344 | when it starts in an interactive mode: 345 | 346 | Gnomovision version 69, Copyright (C) year name of author 347 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 348 | This is free software, and you are welcome to redistribute it 349 | under certain conditions; type `show c' for details. 350 | 351 | The hypothetical commands `show w' and `show c' should show the appropriate 352 | parts of the General Public License. Of course, the commands you use may 353 | be called something other than `show w' and `show c'; they could even be 354 | mouse-clicks or menu items--whatever suits your program. 355 | 356 | You should also get your employer (if you work as a programmer) or your 357 | school, if any, to sign a "copyright disclaimer" for the program, if 358 | necessary. Here is a sample; alter the names: 359 | 360 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 361 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 362 | 363 | , 1 April 1989 364 | Ty Coon, President of Vice 365 | 366 | This General Public License does not permit incorporating your program into 367 | proprietary programs. If your program is a subroutine library, you may 368 | consider it more useful to permit linking proprietary applications with the 369 | library. If this is what you want to do, use the GNU Lesser General 370 | Public License instead of this License. 371 | -------------------------------------------------------------------------------- /demo/geoPHP/README.md: -------------------------------------------------------------------------------- 1 | GeoPHP is a open-source native PHP library for doing geometry operations. It is written entirely in PHP and 2 | can therefore run on shared hosts. It can read and write a wide variety of formats: WKT (including EWKT), WKB (including EWKB), GeoJSON, 3 | KML, GPX, GeoRSS). It works with all Simple-Feature geometries (Point, LineString, Polygon, GeometryCollection etc.) 4 | and can be used to get centroids, bounding-boxes, area, and a wide variety of other useful information. 5 | 6 | geoPHP also helpfully wraps the GEOS php extension so that applications can get a transparent performance 7 | increase when GEOS is installed on the server. When GEOS is installed, geoPHP also becomes 8 | fully compliant with the OpenGIS® Implementation Standard for Geographic information. With GEOS you get the 9 | full-set of openGIS functions in PHP like Union, IsWithin, Touches etc. This means that applications 10 | get a useful "core-set" of geometry operations that work in all environments, and an "extended-set"of operations 11 | for environments that have GEOS installed. 12 | 13 | See the 'getting started' section below for references and examples of everything that geoPHP can do. 14 | 15 | This project is currently looking for co-maintainers. If you think you can help out, please send me a 16 | message. Forks are also welcome, please issue pull requests and I will merge them into the main branch. 17 | 18 | Getting Started 19 | ----------------------- 20 | 21 | * The lastest stable version can always be downloaded at: 22 | * Read the API Reference at: 23 | * Examples 24 | * Using geoPHP as a GIS format converter: 25 | * Other Interesting Links: 26 | * Learn about GEOS integration at: 27 | 28 | Example usage 29 | ------------------------------------------------- 30 | 31 | ```php 32 | getArea(); 38 | $centroid = $polygon->getCentroid(); 39 | $centX = $centroid->getX(); 40 | $centY = $centroid->getY(); 41 | 42 | print "This polygon has an area of ".$area." and a centroid with X=".$centX." and Y=".$centY; 43 | 44 | // MultiPoint json example 45 | print "
"; 46 | $json = 47 | '{ 48 | "type": "MultiPoint", 49 | "coordinates": [ 50 | [100.0, 0.0], [101.0, 1.0] 51 | ] 52 | }'; 53 | 54 | $multipoint = geoPHP::load($json, 'json'); 55 | $multipoint_points = $multipoint->getComponents(); 56 | $first_wkt = $multipoint_points[0]->out('wkt'); 57 | 58 | print "This multipoint has ".$multipoint->numGeometries()." points. The first point has a wkt representation of ".$first_wkt; 59 | ``` 60 | ======= 61 | 62 | More Examples 63 | ------------------------------------------------- 64 | 65 | The Well Known Text (WKT) and Well Known Binary (WKB) support is ideal for integrating with MySQL's or PostGIS's spatial capability. 66 | Once you have SELECTed your data with `'AsText('geo_field')'` or `'AsBinary('geo_field')'`, you can put it straight into 67 | geoPHP (can be wkt or wkb, but must be the same as how you extracted it from your database): 68 | 69 | $geom = geoPHP::load($dbRow,'wkt'); 70 | 71 | You can collect multiple geometries into one (note that you must use wkt for this): 72 | 73 | $geom = geoPHP::load("GEOMETRYCOLLECTION(".$dbString1.",".$dbString2.")",'wkt'); 74 | 75 | Calling get components returns the sub-geometries within a geometry as an array. 76 | 77 | $geom2 = geoPHP::load("GEOMETRYCOLLECTION(LINESTRING(1 1,5 1,5 5,1 5,1 1),LINESTRING(2 2,2 3,3 3,3 2,2 2))"); 78 | $geomComponents = $geom2->getComponents(); //an array of the two linestring geometries 79 | $linestring1 = $geomComponents[0]->getComponents(); //an array of the first linestring's point geometries 80 | $linestring2 = $geomComponents[1]->getComponents(); 81 | echo $linestring1[0]->x() . ", " . $linestring1[0]->y(); //outputs '1, 1' 82 | 83 | An alternative is to use the `asArray()` method. Using the above geometry collection of two linestrings, 84 | 85 | $geometryArray = $geom2->asArray(); 86 | echo $geometryArray[0][0][0] . ", " . $geometryArray[0][0][1]; //outputs '1, 1' 87 | 88 | Clearly, more complex analysis is possible. 89 | 90 | echo $geom2->envelope()->area(); 91 | 92 | 93 | Working with PostGIS 94 | --------------------- 95 | geoPHP, through it's EWKB adapter, has good integration with postGIS. Here's an example of reading and writing postGIS geometries 96 | 97 | ```php 98 | out('ewkb')); 120 | pg_query($connection, "INSERT INTO $table ($column) values (GeomFromWKB('$insert_string'))"); 121 | } 122 | 123 | // Using a direct SELECT and INSERTs in PostGIS without using wrapping functions 124 | $result = pg_fetch_all(pg_query($connection, "SELECT $column as geom FROM $table")); 125 | foreach ($result as $item) { 126 | $wkb = pack('H*',$item['geom']); // Unpacking the hex blob 127 | $geom = geoPHP::load($wkb, 'ewkb'); // We now have a geoPHP Geometry 128 | 129 | // To insert directly into postGIS we need to unpack the WKB 130 | $unpacked = unpack('H*', $geom->out('ewkb')); 131 | $insert_string = $unpacked[1]; 132 | pg_query($connection, "INSERT INTO $table ($column) values ('$insert_string')"); 133 | } 134 | ``` 135 | 136 | 137 | Credit 138 | ------------------------------------------------- 139 | 140 | Maintainer: Patrick Hayes 141 | 142 | This library was written entirely in my free time as a volunteer. If you find it really useful, please consider making a donation by [clicking here] (https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=geomemes%40gmail%2ecom&lc=US&item_name=Patrick%20Hayes%20-%20geoPHP&no_note=0¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest). 143 | 144 | Additional Contributors: 145 | 146 | * GeoMemes Research 147 | * Arnaud Renevier (gisconverter.php) 148 | * Dave Tarc 149 | * Elliott Hunston (documentation) 150 | 151 | This library is open-source and dual-licensed under both the Modified BSD License and GPLv2. Either license may be used at your option. 152 | -------------------------------------------------------------------------------- /demo/geoPHP/geoPHP.inc: -------------------------------------------------------------------------------- 1 | 'WKT', 90 | 'ewkt' => 'EWKT', 91 | 'wkb' => 'WKB', 92 | 'ewkb' => 'EWKB', 93 | 'json' => 'GeoJSON', 94 | 'kml' => 'KML', 95 | 'gpx' => 'GPX', 96 | 'georss' => 'GeoRSS', 97 | 'google_geocode' => 'GoogleGeocode', 98 | 'geohash' => 'GeoHash', 99 | ); 100 | } 101 | 102 | static function geometryList() { 103 | return array( 104 | 'point' => 'Point', 105 | 'linestring' => 'LineString', 106 | 'polygon' => 'Polygon', 107 | 'multipoint' => 'MultiPoint', 108 | 'multilinestring' => 'MultiLineString', 109 | 'multipolygon' => 'MultiPolygon', 110 | 'geometrycollection' => 'GeometryCollection', 111 | ); 112 | } 113 | 114 | static function geosInstalled($force = NULL) { 115 | static $geos_installed = NULL; 116 | if ($force !== NULL) $geos_installed = $force; 117 | if ($geos_installed !== NULL) { 118 | return $geos_installed; 119 | } 120 | $geos_installed = class_exists('GEOSGeometry'); 121 | return $geos_installed; 122 | } 123 | 124 | static function geosToGeometry($geos) { 125 | if (!geoPHP::geosInstalled()) { 126 | return NULL; 127 | } 128 | $wkb_writer = new GEOSWKBWriter(); 129 | $wkb = $wkb_writer->writeHEX($geos); 130 | $geometry = geoPHP::load($wkb, 'wkb', TRUE); 131 | if ($geometry) { 132 | $geometry->setGeos($geos); 133 | return $geometry; 134 | } 135 | } 136 | 137 | // Reduce a geometry, or an array of geometries, into their 'lowest' available common geometry. 138 | // For example a GeometryCollection of only points will become a MultiPoint 139 | // A multi-point containing a single point will return a point. 140 | // An array of geometries can be passed and they will be compiled into a single geometry 141 | static function geometryReduce($geometry) { 142 | // If it's an array of one, then just parse the one 143 | if (is_array($geometry)) { 144 | if (count($geometry) == 1) return geoPHP::geometryReduce($geometry[0]); 145 | } 146 | 147 | // If the geometry cannot even theoretically be reduced more, then pass it back 148 | if (gettype($geometry) == 'object') { 149 | $passbacks = array('Point','LineString','Polygon'); 150 | if (in_array($geometry->geometryType(),$passbacks)) { 151 | return $geometry; 152 | } 153 | } 154 | 155 | // If it is a mutlti-geometry, check to see if it just has one member 156 | // If it does, then pass the member, if not, then just pass back the geometry 157 | if (gettype($geometry) == 'object') { 158 | $simple_collections = array('MultiPoint','MultiLineString','MultiPolygon'); 159 | if (in_array(get_class($geometry),$passbacks)) { 160 | $components = $geometry->getComponents(); 161 | if (count($components) == 1) { 162 | return $components[0]; 163 | } 164 | else { 165 | return $geometry; 166 | } 167 | } 168 | } 169 | 170 | // So now we either have an array of geometries, a GeometryCollection, or an array of GeometryCollections 171 | if (!is_array($geometry)) { 172 | $geometry = array($geometry); 173 | } 174 | 175 | $geometries = array(); 176 | $geom_types = array(); 177 | 178 | $collections = array('MultiPoint','MultiLineString','MultiPolygon','GeometryCollection'); 179 | 180 | foreach ($geometry as $item) { 181 | if (in_array(get_class($item), $collections)) { 182 | foreach ($item->getComponents() as $component) { 183 | $geometries[] = $component; 184 | $geom_types[] = $component->geometryType(); 185 | } 186 | } 187 | else { 188 | $geometries[] = $item; 189 | $geom_types[] = $item->geometryType(); 190 | } 191 | } 192 | 193 | $geom_types = array_unique($geom_types); 194 | 195 | if (count($geom_types) == 1) { 196 | if (count($geometries) == 1) { 197 | return $geometries[0]; 198 | } 199 | else { 200 | $class = 'Multi'.$geom_types[0]; 201 | return new $class($geometries); 202 | } 203 | } 204 | else { 205 | return new GeometryCollection($geometries); 206 | } 207 | } 208 | 209 | // Detect a format given a value. This function is meant to be SPEEDY. 210 | // It could make a mistake in XML detection if you are mixing or using namespaces in weird ways (ie, KML inside an RSS feed) 211 | static function detectFormat(&$input) { 212 | $mem = fopen('php://memory', 'r+'); 213 | fwrite($mem, $input, 11); // Write 11 bytes - we can detect the vast majority of formats in the first 11 bytes 214 | fseek($mem, 0); 215 | 216 | $bytes = unpack("c*", fread($mem, 11)); 217 | 218 | // If bytes is empty, then we were passed empty input 219 | if (empty($bytes)) return FALSE; 220 | 221 | // First char is a tab, space or carriage-return. trim it and try again 222 | if ($bytes[1] == 9 || $bytes[1] == 10 || $bytes[1] == 32) { 223 | return geoPHP::detectFormat(ltrim($input)); 224 | } 225 | 226 | // Detect WKB or EWKB -- first byte is 1 (little endian indicator) 227 | if ($bytes[1] == 1) { 228 | // If SRID byte is TRUE (1), it's EWKB 229 | if ($bytes[5]) return 'ewkb'; 230 | else return 'wkb'; 231 | } 232 | 233 | // Detect HEX encoded WKB or EWKB (PostGIS format) -- first byte is 48, second byte is 49 (hex '01' => first-byte = 1) 234 | if ($bytes[1] == 48 && $bytes[2] == 49) { 235 | // The shortest possible WKB string (LINESTRING EMPTY) is 18 hex-chars (9 encoded bytes) long 236 | // This differentiates it from a geohash, which is always shorter than 18 characters. 237 | if (strlen($input) >= 18) { 238 | //@@TODO: Differentiate between EWKB and WKB -- check hex-char 10 or 11 (SRID bool indicator at encoded byte 5) 239 | return 'ewkb:1'; 240 | } 241 | } 242 | 243 | // Detect GeoJSON - first char starts with { 244 | if ($bytes[1] == 123) { 245 | return 'json'; 246 | } 247 | 248 | // Detect EWKT - first char is S 249 | if ($bytes[1] == 83) { 250 | return 'ewkt'; 251 | } 252 | 253 | // Detect WKT - first char starts with P (80), L (76), M (77), or G (71) 254 | $wkt_chars = array(80, 76, 77, 71); 255 | if (in_array($bytes[1], $wkt_chars)) { 256 | return 'wkt'; 257 | } 258 | 259 | // Detect XML -- first char is < 260 | if ($bytes[1] == 60) { 261 | // grab the first 256 characters 262 | $string = substr($input, 0, 256); 263 | if (strpos($string, 'read($wkb); 36 | 37 | // If there is an SRID, add it to the geometry 38 | if ($srid) { 39 | $geom->setSRID($srid); 40 | } 41 | 42 | return $geom; 43 | } 44 | 45 | /** 46 | * Serialize geometries into an EWKB binary string. 47 | * 48 | * @param Geometry $geometry 49 | * 50 | * @return string The Extended-WKB binary string representation of the input geometries 51 | */ 52 | public function write(Geometry $geometry, $write_as_hex = FALSE) { 53 | // We always write into NDR (little endian) 54 | $wkb = pack('c',1); 55 | 56 | switch ($geometry->getGeomType()) { 57 | case 'Point'; 58 | $wkb .= pack('L',1); 59 | $wkb .= $this->writePoint($geometry); 60 | break; 61 | case 'LineString'; 62 | $wkb .= pack('L',2); 63 | $wkb .= $this->writeLineString($geometry); 64 | break; 65 | case 'Polygon'; 66 | $wkb .= pack('L',3); 67 | $wkb .= $this->writePolygon($geometry); 68 | break; 69 | case 'MultiPoint'; 70 | $wkb .= pack('L',4); 71 | $wkb .= $this->writeMulti($geometry); 72 | break; 73 | case 'MultiLineString'; 74 | $wkb .= pack('L',5); 75 | $wkb .= $this->writeMulti($geometry); 76 | break; 77 | case 'MultiPolygon'; 78 | $wkb .= pack('L',6); 79 | $wkb .= $this->writeMulti($geometry); 80 | break; 81 | case 'GeometryCollection'; 82 | $wkb .= pack('L',7); 83 | $wkb .= $this->writeMulti($geometry); 84 | break; 85 | } 86 | 87 | if ($write_as_hex) { 88 | $unpacked = unpack('H*',$wkb); 89 | return $unpacked[1]; 90 | } 91 | else { 92 | return $wkb; 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/EWKT.class.php: -------------------------------------------------------------------------------- 1 | SRID(); 17 | $wkt = ''; 18 | if ($srid) { 19 | $wkt = 'SRID=' . $srid . ';'; 20 | $wkt .= $geometry->out('wkt'); 21 | return $wkt; 22 | } 23 | else { 24 | return $geometry->out('wkt'); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/GPX.class.php: -------------------------------------------------------------------------------- 1 | geomFromText($gpx); 27 | } 28 | 29 | /** 30 | * Serialize geometries into a GPX string. 31 | * 32 | * @param Geometry $geometry 33 | * 34 | * @return string The GPX string representation of the input geometries 35 | */ 36 | public function write(Geometry $geometry, $namespace = FALSE) { 37 | if ($geometry->isEmpty()) return NULL; 38 | if ($namespace) { 39 | $this->namespace = $namespace; 40 | $this->nss = $namespace.':'; 41 | } 42 | return '<'.$this->nss.'gpx creator="geoPHP" version="1.0">'.$this->geometryToGPX($geometry).'nss.'gpx>'; 43 | } 44 | 45 | public function geomFromText($text) { 46 | // Change to lower-case and strip all CDATA 47 | $text = strtolower($text); 48 | $text = preg_replace('//s','',$text); 49 | 50 | // Load into DOMDocument 51 | $xmlobj = new DOMDocument(); 52 | @$xmlobj->loadXML($text); 53 | if ($xmlobj === false) { 54 | throw new Exception("Invalid GPX: ". $text); 55 | } 56 | 57 | $this->xmlobj = $xmlobj; 58 | try { 59 | $geom = $this->geomFromXML(); 60 | } catch(InvalidText $e) { 61 | throw new Exception("Cannot Read Geometry From GPX: ". $text); 62 | } catch(Exception $e) { 63 | throw $e; 64 | } 65 | 66 | return $geom; 67 | } 68 | 69 | protected function geomFromXML() { 70 | $geometries = array(); 71 | $geometries = array_merge($geometries, $this->parseWaypoints()); 72 | $geometries = array_merge($geometries, $this->parseTracks()); 73 | $geometries = array_merge($geometries, $this->parseRoutes()); 74 | 75 | if (empty($geometries)) { 76 | throw new Exception("Invalid / Empty GPX"); 77 | } 78 | 79 | return geoPHP::geometryReduce($geometries); 80 | } 81 | 82 | protected function childElements($xml, $nodename = '') { 83 | $children = array(); 84 | foreach ($xml->childNodes as $child) { 85 | if ($child->nodeName == $nodename) { 86 | $children[] = $child; 87 | } 88 | } 89 | return $children; 90 | } 91 | 92 | protected function parseWaypoints() { 93 | $points = array(); 94 | $wpt_elements = $this->xmlobj->getElementsByTagName('wpt'); 95 | foreach ($wpt_elements as $wpt) { 96 | $lat = $wpt->attributes->getNamedItem("lat")->nodeValue; 97 | $lon = $wpt->attributes->getNamedItem("lon")->nodeValue; 98 | $points[] = new Point($lon, $lat); 99 | } 100 | return $points; 101 | } 102 | 103 | protected function parseTracks() { 104 | $lines = array(); 105 | $trk_elements = $this->xmlobj->getElementsByTagName('trk'); 106 | foreach ($trk_elements as $trk) { 107 | $components = array(); 108 | foreach ($this->childElements($trk, 'trkseg') as $trkseg) { 109 | foreach ($this->childElements($trkseg, 'trkpt') as $trkpt) { 110 | $lat = $trkpt->attributes->getNamedItem("lat")->nodeValue; 111 | $lon = $trkpt->attributes->getNamedItem("lon")->nodeValue; 112 | $components[] = new Point($lon, $lat); 113 | } 114 | } 115 | if ($components) {$lines[] = new LineString($components);} 116 | } 117 | return $lines; 118 | } 119 | 120 | protected function parseRoutes() { 121 | $lines = array(); 122 | $rte_elements = $this->xmlobj->getElementsByTagName('rte'); 123 | foreach ($rte_elements as $rte) { 124 | $components = array(); 125 | foreach ($this->childElements($rte, 'rtept') as $rtept) { 126 | $lat = $rtept->attributes->getNamedItem("lat")->nodeValue; 127 | $lon = $rtept->attributes->getNamedItem("lon")->nodeValue; 128 | $components[] = new Point($lon, $lat); 129 | } 130 | $lines[] = new LineString($components); 131 | } 132 | return $lines; 133 | } 134 | 135 | protected function geometryToGPX($geom) { 136 | $type = strtolower($geom->getGeomType()); 137 | switch ($type) { 138 | case 'point': 139 | return $this->pointToGPX($geom); 140 | break; 141 | case 'linestring': 142 | return $this->linestringToGPX($geom); 143 | break; 144 | case 'polygon': 145 | case 'multipoint': 146 | case 'multilinestring': 147 | case 'multipolygon': 148 | case 'geometrycollection': 149 | return $this->collectionToGPX($geom); 150 | break; 151 | } 152 | } 153 | 154 | private function pointToGPX($geom) { 155 | return '<'.$this->nss.'wpt lat="'.$geom->getY().'" lon="'.$geom->getX().'" />'; 156 | } 157 | 158 | private function linestringToGPX($geom) { 159 | $gpx = '<'.$this->nss.'trk><'.$this->nss.'trkseg>'; 160 | 161 | foreach ($geom->getComponents() as $comp) { 162 | $gpx .= '<'.$this->nss.'trkpt lat="'.$comp->getY().'" lon="'.$comp->getX().'" />'; 163 | } 164 | 165 | $gpx .= 'nss.'trkseg>nss.'trk>'; 166 | 167 | return $gpx; 168 | } 169 | 170 | public function collectionToGPX($geom) { 171 | $gpx = ''; 172 | $components = $geom->getComponents(); 173 | foreach ($geom->getComponents() as $comp) { 174 | $gpx .= $this->geometryToGPX($comp); 175 | } 176 | 177 | return $gpx; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/GeoAdapter.class.php: -------------------------------------------------------------------------------- 1 | decode($hash); 20 | if (!$as_grid) { 21 | return new Point($ll['medlon'], $ll['medlat']); 22 | } 23 | else { 24 | return new Polygon(array( 25 | new LineString(array( 26 | new Point($ll['minlon'], $ll['maxlat']), 27 | new Point($ll['maxlon'], $ll['maxlat']), 28 | new Point($ll['maxlon'], $ll['minlat']), 29 | new Point($ll['minlon'], $ll['minlat']), 30 | new Point($ll['minlon'], $ll['maxlat']), 31 | )) 32 | )); 33 | } 34 | } 35 | 36 | /** 37 | * Convert the geometry to geohash. 38 | * @return string the geohash or null when the $geometry is not a Point 39 | * @param Point $geometry 40 | * @see GeoAdapter::write() 41 | */ 42 | public function write(Geometry $geometry, $precision = NULL){ 43 | if ($geometry->isEmpty()) return ''; 44 | 45 | if($geometry->geometryType() === 'Point'){ 46 | return $this->encodePoint($geometry, $precision); 47 | } 48 | else { 49 | // The geohash is the hash grid ID that fits the envelope 50 | $envelope = $geometry->envelope(); 51 | $geohashes = array(); 52 | $geohash = ''; 53 | foreach ($envelope->getPoints() as $point) { 54 | $geohashes[] = $this->encodePoint($point, 0.0000001); 55 | } 56 | $i = 0; 57 | while ($i < strlen($geohashes[0])) { 58 | $char = $geohashes[0][$i]; 59 | foreach ($geohashes as $hash) { 60 | if ($hash[$i] != $char) { 61 | return $geohash; 62 | } 63 | } 64 | $geohash .= $char; 65 | $i++; 66 | } 67 | return $geohash; 68 | } 69 | } 70 | 71 | /** 72 | * @return string geohash 73 | * @param Point $point 74 | * @author algorithm based on code by Alexander Songe 75 | * @see https://github.com/asonge/php-geohash/issues/1 76 | */ 77 | private function encodePoint($point, $precision = NULL){ 78 | if ($precision === NULL) { 79 | $lap = strlen($point->y())-strpos($point->y(),"."); 80 | $lop = strlen($point->x())-strpos($point->x(),"."); 81 | $precision = pow(10,-max($lap-1,$lop-1,0))/2; 82 | } 83 | 84 | $minlat = -90; 85 | $maxlat = 90; 86 | $minlon = -180; 87 | $maxlon = 180; 88 | $latE = 90; 89 | $lonE = 180; 90 | $i = 0; 91 | $error = 180; 92 | $hash=''; 93 | while($error>=$precision) { 94 | $chr = 0; 95 | for($b=4;$b>=0;--$b) { 96 | if((1&$b) == (1&$i)) { 97 | // even char, even bit OR odd char, odd bit...a lon 98 | $next = ($minlon+$maxlon)/2; 99 | if($point->x()>$next) { 100 | $chr |= pow(2,$b); 101 | $minlon = $next; 102 | } else { 103 | $maxlon = $next; 104 | } 105 | $lonE /= 2; 106 | } else { 107 | // odd char, even bit OR even char, odd bit...a lat 108 | $next = ($minlat+$maxlat)/2; 109 | if($point->y()>$next) { 110 | $chr |= pow(2,$b); 111 | $minlat = $next; 112 | } else { 113 | $maxlat = $next; 114 | } 115 | $latE /= 2; 116 | } 117 | } 118 | $hash .= $this->table[$chr]; 119 | $i++; 120 | $error = min($latE,$lonE); 121 | } 122 | return $hash; 123 | } 124 | 125 | /** 126 | * @param string $hash a geohash 127 | * @author algorithm based on code by Alexander Songe 128 | * @see https://github.com/asonge/php-geohash/issues/1 129 | */ 130 | private function decode($hash){ 131 | $ll = array(); 132 | $minlat = -90; 133 | $maxlat = 90; 134 | $minlon = -180; 135 | $maxlon = 180; 136 | $latE = 90; 137 | $lonE = 180; 138 | for($i=0,$c=strlen($hash);$i<$c;$i++) { 139 | $v = strpos($this->table,$hash[$i]); 140 | if(1&$i) { 141 | if(16&$v)$minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2; 142 | if(8&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2; 143 | if(4&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2; 144 | if(2&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2; 145 | if(1&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2; 146 | $latE /= 8; 147 | $lonE /= 4; 148 | } else { 149 | if(16&$v)$minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2; 150 | if(8&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2; 151 | if(4&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2; 152 | if(2&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2; 153 | if(1&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2; 154 | $latE /= 4; 155 | $lonE /= 8; 156 | } 157 | } 158 | $ll['minlat'] = $minlat; 159 | $ll['minlon'] = $minlon; 160 | $ll['maxlat'] = $maxlat; 161 | $ll['maxlon'] = $maxlon; 162 | $ll['medlat'] = round(($minlat+$maxlat)/2, max(1, -round(log10($latE)))-1); 163 | $ll['medlon'] = round(($minlon+$maxlon)/2, max(1, -round(log10($lonE)))-1); 164 | return $ll; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/GeoJSON.class.php: -------------------------------------------------------------------------------- 1 | type)) { 26 | throw new Exception('Invalid JSON'); 27 | } 28 | 29 | // Check to see if it's a FeatureCollection 30 | if ($input->type == 'FeatureCollection') { 31 | $geoms = array(); 32 | foreach ($input->features as $feature) { 33 | $geoms[] = $this->read($feature); 34 | } 35 | return geoPHP::geometryReduce($geoms); 36 | } 37 | 38 | // Check to see if it's a Feature 39 | if ($input->type == 'Feature') { 40 | return $this->read($input->geometry); 41 | } 42 | 43 | // It's a geometry - process it 44 | return $this->objToGeom($input); 45 | } 46 | 47 | private function objToGeom($obj) { 48 | $type = $obj->type; 49 | 50 | if ($type == 'GeometryCollection') { 51 | return $this->objToGeometryCollection($obj); 52 | } 53 | $method = 'arrayTo' . $type; 54 | return $this->$method($obj->coordinates); 55 | } 56 | 57 | private function arrayToPoint($array) { 58 | return new Point($array[0], $array[1]); 59 | } 60 | 61 | private function arrayToLineString($array) { 62 | $points = array(); 63 | foreach ($array as $comp_array) { 64 | $points[] = $this->arrayToPoint($comp_array); 65 | } 66 | return new LineString($points); 67 | } 68 | 69 | private function arrayToPolygon($array) { 70 | $lines = array(); 71 | foreach ($array as $comp_array) { 72 | $lines[] = $this->arrayToLineString($comp_array); 73 | } 74 | return new Polygon($lines); 75 | } 76 | 77 | private function arrayToMultiPoint($array) { 78 | $points = array(); 79 | foreach ($array as $comp_array) { 80 | $points[] = $this->arrayToPoint($comp_array); 81 | } 82 | return new MultiPoint($points); 83 | } 84 | 85 | private function arrayToMultiLineString($array) { 86 | $lines = array(); 87 | foreach ($array as $comp_array) { 88 | $lines[] = $this->arrayToLineString($comp_array); 89 | } 90 | return new MultiLineString($lines); 91 | } 92 | 93 | private function arrayToMultiPolygon($array) { 94 | $polys = array(); 95 | foreach ($array as $comp_array) { 96 | $polys[] = $this->arrayToPolygon($comp_array); 97 | } 98 | return new MultiPolygon($polys); 99 | } 100 | 101 | private function objToGeometryCollection($obj) { 102 | $geoms = array(); 103 | if (empty($obj->geometries)) { 104 | throw new Exception('Invalid GeoJSON: GeometryCollection with no component geometries'); 105 | } 106 | foreach ($obj->geometries as $comp_object) { 107 | $geoms[] = $this->objToGeom($comp_object); 108 | } 109 | return new GeometryCollection($geoms); 110 | } 111 | 112 | /** 113 | * Serializes an object into a geojson string 114 | * 115 | * 116 | * @param Geometry $obj The object to serialize 117 | * 118 | * @return string The GeoJSON string 119 | */ 120 | public function write(Geometry $geometry, $return_array = FALSE) { 121 | if ($return_array) { 122 | return $this->getArray($geometry); 123 | } 124 | else { 125 | return json_encode($this->getArray($geometry)); 126 | } 127 | } 128 | 129 | public function getArray($geometry) { 130 | if ($geometry->getGeomType() == 'GeometryCollection') { 131 | $component_array = array(); 132 | foreach ($geometry->components as $component) { 133 | $component_array[] = array( 134 | 'type' => $component->geometryType(), 135 | 'coordinates' => $component->asArray(), 136 | ); 137 | } 138 | return array( 139 | 'type'=> 'GeometryCollection', 140 | 'geometries'=> $component_array, 141 | ); 142 | } 143 | else return array( 144 | 'type'=> $geometry->getGeomType(), 145 | 'coordinates'=> $geometry->asArray(), 146 | ); 147 | } 148 | } 149 | 150 | 151 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/GeoRSS.class.php: -------------------------------------------------------------------------------- 1 | geomFromText($gpx); 27 | } 28 | 29 | /** 30 | * Serialize geometries into a GeoRSS string. 31 | * 32 | * @param Geometry $geometry 33 | * 34 | * @return string The georss string representation of the input geometries 35 | */ 36 | public function write(Geometry $geometry, $namespace = FALSE) { 37 | if ($namespace) { 38 | $this->namespace = $namespace; 39 | $this->nss = $namespace.':'; 40 | } 41 | return $this->geometryToGeoRSS($geometry); 42 | } 43 | 44 | public function geomFromText($text) { 45 | // Change to lower-case, strip all CDATA, and de-namespace 46 | $text = strtolower($text); 47 | $text = preg_replace('//s','',$text); 48 | 49 | // Load into DOMDOcument 50 | $xmlobj = new DOMDocument(); 51 | @$xmlobj->loadXML($text); 52 | if ($xmlobj === false) { 53 | throw new Exception("Invalid GeoRSS: ". $text); 54 | } 55 | 56 | $this->xmlobj = $xmlobj; 57 | try { 58 | $geom = $this->geomFromXML(); 59 | } catch(InvalidText $e) { 60 | throw new Exception("Cannot Read Geometry From GeoRSS: ". $text); 61 | } catch(Exception $e) { 62 | throw $e; 63 | } 64 | 65 | return $geom; 66 | } 67 | 68 | protected function geomFromXML() { 69 | $geometries = array(); 70 | $geometries = array_merge($geometries, $this->parsePoints()); 71 | $geometries = array_merge($geometries, $this->parseLines()); 72 | $geometries = array_merge($geometries, $this->parsePolygons()); 73 | $geometries = array_merge($geometries, $this->parseBoxes()); 74 | $geometries = array_merge($geometries, $this->parseCircles()); 75 | 76 | if (empty($geometries)) { 77 | throw new Exception("Invalid / Empty GeoRSS"); 78 | } 79 | 80 | return geoPHP::geometryReduce($geometries); 81 | } 82 | 83 | protected function getPointsFromCoords($string) { 84 | $coords = array(); 85 | $latlon = explode(' ',$string); 86 | foreach ($latlon as $key => $item) { 87 | if (!($key % 2)) { 88 | // It's a latitude 89 | $lat = $item; 90 | } 91 | else { 92 | // It's a longitude 93 | $lon = $item; 94 | $coords[] = new Point($lon, $lat); 95 | } 96 | } 97 | return $coords; 98 | } 99 | 100 | protected function parsePoints() { 101 | $points = array(); 102 | $pt_elements = $this->xmlobj->getElementsByTagName('point'); 103 | foreach ($pt_elements as $pt) { 104 | $point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue)); 105 | $points[] = $point_array[0]; 106 | } 107 | return $points; 108 | } 109 | 110 | protected function parseLines() { 111 | $lines = array(); 112 | $line_elements = $this->xmlobj->getElementsByTagName('line'); 113 | foreach ($line_elements as $line) { 114 | $components = $this->getPointsFromCoords(trim($line->firstChild->nodeValue)); 115 | $lines[] = new LineString($components); 116 | } 117 | return $lines; 118 | } 119 | 120 | protected function parsePolygons() { 121 | $polygons = array(); 122 | $poly_elements = $this->xmlobj->getElementsByTagName('polygon'); 123 | foreach ($poly_elements as $poly) { 124 | if ($poly->hasChildNodes()) { 125 | $points = $this->getPointsFromCoords(trim($poly->firstChild->nodeValue)); 126 | $exterior_ring = new LineString($points); 127 | $polygons[] = new Polygon(array($exterior_ring)); 128 | } 129 | else { 130 | // It's an EMPTY polygon 131 | $polygons[] = new Polygon(); 132 | } 133 | } 134 | return $polygons; 135 | } 136 | 137 | // Boxes are rendered into polygons 138 | protected function parseBoxes() { 139 | $polygons = array(); 140 | $box_elements = $this->xmlobj->getElementsByTagName('box'); 141 | foreach ($box_elements as $box) { 142 | $parts = explode(' ',trim($box->firstChild->nodeValue)); 143 | $components = array( 144 | new Point($parts[3], $parts[2]), 145 | new Point($parts[3], $parts[0]), 146 | new Point($parts[1], $parts[0]), 147 | new Point($parts[1], $parts[2]), 148 | new Point($parts[3], $parts[2]), 149 | ); 150 | $exterior_ring = new LineString($components); 151 | $polygons[] = new Polygon(array($exterior_ring)); 152 | } 153 | return $polygons; 154 | } 155 | 156 | // Circles are rendered into points 157 | // @@TODO: Add good support once we have circular-string geometry support 158 | protected function parseCircles() { 159 | $points = array(); 160 | $circle_elements = $this->xmlobj->getElementsByTagName('circle'); 161 | foreach ($circle_elements as $circle) { 162 | $parts = explode(' ',trim($circle->firstChild->nodeValue)); 163 | $points[] = new Point($parts[1], $parts[0]); 164 | } 165 | return $points; 166 | } 167 | 168 | protected function geometryToGeoRSS($geom) { 169 | $type = strtolower($geom->getGeomType()); 170 | switch ($type) { 171 | case 'point': 172 | return $this->pointToGeoRSS($geom); 173 | break; 174 | case 'linestring': 175 | return $this->linestringToGeoRSS($geom); 176 | break; 177 | case 'polygon': 178 | return $this->PolygonToGeoRSS($geom); 179 | break; 180 | case 'multipoint': 181 | case 'multilinestring': 182 | case 'multipolygon': 183 | case 'geometrycollection': 184 | return $this->collectionToGeoRSS($geom); 185 | break; 186 | } 187 | return $output; 188 | } 189 | 190 | private function pointToGeoRSS($geom) { 191 | return '<'.$this->nss.'point>'.$geom->getY().' '.$geom->getX().'nss.'point>'; 192 | } 193 | 194 | 195 | private function linestringToGeoRSS($geom) { 196 | $output = '<'.$this->nss.'line>'; 197 | foreach ($geom->getComponents() as $k => $point) { 198 | $output .= $point->getY().' '.$point->getX(); 199 | if ($k < ($geom->numGeometries() -1)) $output .= ' '; 200 | } 201 | $output .= 'nss.'line>'; 202 | return $output; 203 | } 204 | 205 | private function polygonToGeoRSS($geom) { 206 | $output = '<'.$this->nss.'polygon>'; 207 | $exterior_ring = $geom->exteriorRing(); 208 | foreach ($exterior_ring->getComponents() as $k => $point) { 209 | $output .= $point->getY().' '.$point->getX(); 210 | if ($k < ($exterior_ring->numGeometries() -1)) $output .= ' '; 211 | } 212 | $output .= 'nss.'polygon>'; 213 | return $output; 214 | } 215 | 216 | public function collectionToGeoRSS($geom) { 217 | $georss = '<'.$this->nss.'where>'; 218 | $components = $geom->getComponents(); 219 | foreach ($geom->getComponents() as $comp) { 220 | $georss .= $this->geometryToGeoRSS($comp); 221 | } 222 | 223 | $georss .= 'nss.'where>'; 224 | 225 | return $georss; 226 | } 227 | 228 | } 229 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/GoogleGeocode.class.php: -------------------------------------------------------------------------------- 1 | 4 | * (c) Patrick Hayes 5 | * 6 | * This code is open-source and licenced under the Modified BSD License. 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | /** 12 | * PHP Google Geocoder Adapter 13 | * 14 | * 15 | * @package geoPHP 16 | * @author Patrick Hayes 17 | */ 18 | class GoogleGeocode extends GeoAdapter 19 | { 20 | 21 | /** 22 | * Read an address string or array geometry objects 23 | * 24 | * @param string - Address to geocode 25 | * @param string - Type of Geometry to return. Can either be 'points' or 'bounds' (polygon) 26 | * @param Geometry|bounds-array - Limit the search area to within this region. For example 27 | * by default geocoding "Cairo" will return the location of Cairo Egypt. 28 | * If you pass a polygon of illinois, it will return Cairo IL. 29 | * @param return_multiple - Return all results in a multipoint or multipolygon 30 | * @return Geometry|GeometryCollection 31 | */ 32 | public function read($address, $return_type = 'point', $bounds = FALSE, $return_multiple = FALSE) { 33 | if (is_array($address)) $address = join(',', $address); 34 | 35 | if (gettype($bounds) == 'object') { 36 | $bounds = $bounds->getBBox(); 37 | } 38 | if (gettype($bounds) == 'array') { 39 | $bounds_string = '&bounds='.$bounds['miny'].','.$bounds['minx'].'|'.$bounds['maxy'].','.$bounds['maxx']; 40 | } 41 | else { 42 | $bounds_string = ''; 43 | } 44 | 45 | $url = "http://maps.googleapis.com/maps/api/geocode/json"; 46 | $url .= '?address='. urlencode($address); 47 | $url .= $bounds_string; 48 | $url .= '&sensor=false'; 49 | $this->result = json_decode(@file_get_contents($url)); 50 | 51 | if ($this->result->status == 'OK') { 52 | if ($return_multiple == FALSE) { 53 | if ($return_type == 'point') { 54 | return $this->getPoint(); 55 | } 56 | if ($return_type == 'bounds' || $return_type == 'polygon') { 57 | return $this->getPolygon(); 58 | } 59 | } 60 | if ($return_multiple == TRUE) { 61 | if ($return_type == 'point') { 62 | $points = array(); 63 | foreach ($this->result->results as $delta => $item) { 64 | $points[] = $this->getPoint($delta); 65 | } 66 | return new MultiPoint($points); 67 | } 68 | if ($return_type == 'bounds' || $return_type == 'polygon') { 69 | $polygons = array(); 70 | foreach ($this->result->results as $delta => $item) { 71 | $polygons[] = $this->getPolygon($delta); 72 | } 73 | return new MultiPolygon($polygons); 74 | } 75 | } 76 | } 77 | else { 78 | if ($this->result->status) throw new Exception('Error in Google Geocoder: '.$this->result->status); 79 | else throw new Exception('Unknown error in Google Geocoder'); 80 | return FALSE; 81 | } 82 | } 83 | 84 | /** 85 | * Serialize geometries into a WKT string. 86 | * 87 | * @param Geometry $geometry 88 | * @param string $return_type Should be either 'string' or 'array' 89 | * 90 | * @return string Does a reverse geocode of the geometry 91 | */ 92 | public function write(Geometry $geometry, $return_type = 'string') { 93 | $centroid = $geometry->getCentroid(); 94 | $lat = $centroid->getY(); 95 | $lon = $centroid->getX(); 96 | 97 | $url = "http://maps.googleapis.com/maps/api/geocode/json"; 98 | $url .= '?latlng='.$lat.','.$lon; 99 | $url .= '&sensor=false'; 100 | $this->result = json_decode(@file_get_contents($url)); 101 | 102 | if ($this->result->status == 'OK') { 103 | if ($return_type == 'string') { 104 | return $this->result->results[0]->formatted_address; 105 | } 106 | if ($return_type == 'array') { 107 | return $this->result->results[0]->address_components; 108 | } 109 | } 110 | else { 111 | if ($this->result->status) throw new Exception('Error in Google Reverse Geocoder: '.$this->result->status); 112 | else throw new Exception('Unknown error in Google Reverse Geocoder'); 113 | return FALSE; 114 | } 115 | } 116 | 117 | private function getPoint($delta = 0) { 118 | $lat = $this->result->results[$delta]->geometry->location->lat; 119 | $lon = $this->result->results[$delta]->geometry->location->lng; 120 | return new Point($lon, $lat); 121 | } 122 | 123 | private function getPolygon($delta = 0) { 124 | $points = array ( 125 | $this->getTopLeft($delta), 126 | $this->getTopRight($delta), 127 | $this->getBottomRight($delta), 128 | $this->getBottomLeft($delta), 129 | $this->getTopLeft($delta), 130 | ); 131 | $outer_ring = new LineString($points); 132 | return new Polygon(array($outer_ring)); 133 | } 134 | 135 | private function getTopLeft($delta = 0) { 136 | $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat; 137 | $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng; 138 | return new Point($lon, $lat); 139 | } 140 | 141 | private function getTopRight($delta = 0) { 142 | $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat; 143 | $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng; 144 | return new Point($lon, $lat); 145 | } 146 | 147 | private function getBottomLeft($delta = 0) { 148 | $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat; 149 | $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng; 150 | return new Point($lon, $lat); 151 | } 152 | 153 | private function getBottomRight($delta = 0) { 154 | $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat; 155 | $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng; 156 | return new Point($lon, $lat); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/KML.class.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class KML extends GeoAdapter 22 | { 23 | private $namespace = FALSE; 24 | private $nss = ''; // Name-space string. eg 'georss:' 25 | 26 | /** 27 | * Read KML string into geometry objects 28 | * 29 | * @param string $kml A KML string 30 | * 31 | * @return Geometry|GeometryCollection 32 | */ 33 | public function read($kml) { 34 | return $this->geomFromText($kml); 35 | } 36 | 37 | /** 38 | * Serialize geometries into a KML string. 39 | * 40 | * @param Geometry $geometry 41 | * 42 | * @return string The KML string representation of the input geometries 43 | */ 44 | public function write(Geometry $geometry, $namespace = FALSE) { 45 | if ($namespace) { 46 | $this->namespace = $namespace; 47 | $this->nss = $namespace.':'; 48 | } 49 | return $this->geometryToKML($geometry); 50 | } 51 | 52 | public function geomFromText($text) { 53 | 54 | // Change to lower-case and strip all CDATA 55 | $text = mb_strtolower($text, mb_detect_encoding($text)); 56 | $text = preg_replace('//s','',$text); 57 | 58 | // Load into DOMDOcument 59 | $xmlobj = new DOMDocument(); 60 | @$xmlobj->loadXML($text); 61 | if ($xmlobj === false) { 62 | throw new Exception("Invalid KML: ". $text); 63 | } 64 | 65 | $this->xmlobj = $xmlobj; 66 | try { 67 | $geom = $this->geomFromXML(); 68 | } catch(InvalidText $e) { 69 | throw new Exception("Cannot Read Geometry From KML: ". $text); 70 | } catch(Exception $e) { 71 | throw $e; 72 | } 73 | 74 | return $geom; 75 | } 76 | 77 | protected function geomFromXML() { 78 | $geometries = array(); 79 | $geom_types = geoPHP::geometryList(); 80 | $placemark_elements = $this->xmlobj->getElementsByTagName('placemark'); 81 | if ($placemark_elements->length) { 82 | foreach ($placemark_elements as $placemark) { 83 | foreach ($placemark->childNodes as $child) { 84 | // Node names are all the same, except for MultiGeometry, which maps to GeometryCollection 85 | $node_name = $child->nodeName == 'multigeometry' ? 'geometrycollection' : $child->nodeName; 86 | if (array_key_exists($node_name, $geom_types)) { 87 | $function = 'parse'.$geom_types[$node_name]; 88 | $geometries[] = $this->$function($child); 89 | } 90 | } 91 | } 92 | } 93 | else { 94 | // The document does not have a placemark, try to create a valid geometry from the root element 95 | $node_name = $this->xmlobj->documentElement->nodeName == 'multigeometry' ? 'geometrycollection' : $this->xmlobj->documentElement->nodeName; 96 | if (array_key_exists($node_name, $geom_types)) { 97 | $function = 'parse'.$geom_types[$node_name]; 98 | $geometries[] = $this->$function($this->xmlobj->documentElement); 99 | } 100 | } 101 | return geoPHP::geometryReduce($geometries); 102 | } 103 | 104 | protected function childElements($xml, $nodename = '') { 105 | $children = array(); 106 | if ($xml->childNodes) { 107 | foreach ($xml->childNodes as $child) { 108 | if ($child->nodeName == $nodename) { 109 | $children[] = $child; 110 | } 111 | } 112 | } 113 | return $children; 114 | } 115 | 116 | protected function parsePoint($xml) { 117 | $coordinates = $this->_extractCoordinates($xml); 118 | return new Point($coordinates[0][0],$coordinates[0][1]); 119 | } 120 | 121 | protected function parseLineString($xml) { 122 | $coordinates = $this->_extractCoordinates($xml); 123 | $point_array = array(); 124 | foreach ($coordinates as $set) { 125 | $point_array[] = new Point($set[0],$set[1]); 126 | } 127 | return new LineString($point_array); 128 | } 129 | 130 | protected function parsePolygon($xml) { 131 | $components = array(); 132 | 133 | $outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis'); 134 | $outer_boundary_element = $outer_boundary_element_a[0]; 135 | $outer_ring_element_a = $this->childElements($outer_boundary_element, 'linearring'); 136 | $outer_ring_element = $outer_ring_element_a[0]; 137 | $components[] = $this->parseLineString($outer_ring_element); 138 | 139 | if (count($components) != 1) { 140 | throw new Exception("Invalid KML"); 141 | } 142 | 143 | $inner_boundary_element_a = $this->childElements($xml, 'innerboundaryis'); 144 | if (count($inner_boundary_element_a)) { 145 | foreach ($inner_boundary_element_a as $inner_boundary_element) { 146 | foreach ($this->childElements($inner_boundary_element, 'linearring') as $inner_ring_element) { 147 | $components[] = $this->parseLineString($inner_ring_element); 148 | } 149 | } 150 | } 151 | 152 | return new Polygon($components); 153 | } 154 | 155 | protected function parseGeometryCollection($xml) { 156 | $components = array(); 157 | $geom_types = geoPHP::geometryList(); 158 | foreach ($xml->childNodes as $child) { 159 | $nodeName = ($child->nodeName == 'linearring') ? 'linestring' : $child->nodeName; 160 | if (array_key_exists($nodeName, $geom_types)) { 161 | $function = 'parse'.$geom_types[$nodeName]; 162 | $components[] = $this->$function($child); 163 | } 164 | } 165 | return new GeometryCollection($components); 166 | } 167 | 168 | protected function _extractCoordinates($xml) { 169 | $coord_elements = $this->childElements($xml, 'coordinates'); 170 | $coordinates = array(); 171 | if (count($coord_elements)) { 172 | $coord_sets = explode(' ', $coord_elements[0]->nodeValue); 173 | foreach ($coord_sets as $set_string) { 174 | $set_string = trim($set_string); 175 | if ($set_string) { 176 | $set_array = explode(',',$set_string); 177 | if (count($set_array) >= 2) { 178 | $coordinates[] = $set_array; 179 | } 180 | } 181 | } 182 | } 183 | 184 | return $coordinates; 185 | } 186 | 187 | private function geometryToKML($geom) { 188 | $type = strtolower($geom->getGeomType()); 189 | switch ($type) { 190 | case 'point': 191 | return $this->pointToKML($geom); 192 | break; 193 | case 'linestring': 194 | return $this->linestringToKML($geom); 195 | break; 196 | case 'polygon': 197 | return $this->polygonToKML($geom); 198 | break; 199 | case 'multipoint': 200 | case 'multilinestring': 201 | case 'multipolygon': 202 | case 'geometrycollection': 203 | return $this->collectionToKML($geom); 204 | break; 205 | } 206 | } 207 | 208 | private function pointToKML($geom) { 209 | return '<'.$this->nss.'Point><'.$this->nss.'coordinates>'.$geom->getX().",".$geom->getY().'nss.'coordinates>nss.'Point>'; 210 | } 211 | 212 | private function linestringToKML($geom, $type = FALSE) { 213 | if (!$type) { 214 | $type = $geom->getGeomType(); 215 | } 216 | 217 | $str = '<'.$this->nss . $type .'>'; 218 | 219 | if (!$geom->isEmpty()) { 220 | $str .= '<'.$this->nss.'coordinates>'; 221 | $i=0; 222 | foreach ($geom->getComponents() as $comp) { 223 | if ($i != 0) $str .= ' '; 224 | $str .= $comp->getX() .','. $comp->getY(); 225 | $i++; 226 | } 227 | 228 | $str .= 'nss.'coordinates>'; 229 | } 230 | 231 | $str .= 'nss . $type .'>'; 232 | 233 | return $str; 234 | } 235 | 236 | public function polygonToKML($geom) { 237 | $components = $geom->getComponents(); 238 | if (!empty($components)) { 239 | $str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . 'nss.'outerBoundaryIs>'; 240 | foreach (array_slice($components, 1) as $comp) { 241 | $str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . 'nss.'innerBoundaryIs>'; 242 | } 243 | } 244 | 245 | return '<'.$this->nss.'Polygon>'. $str .'nss.'Polygon>'; 246 | } 247 | 248 | public function collectionToKML($geom) { 249 | $components = $geom->getComponents(); 250 | $str = '<'.$this->nss.'MultiGeometry>'; 251 | foreach ($geom->getComponents() as $comp) { 252 | $sub_adapter = new KML(); 253 | $str .= $sub_adapter->write($comp); 254 | } 255 | 256 | return $str .'nss.'MultiGeometry>'; 257 | } 258 | 259 | } 260 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/WKB.class.php: -------------------------------------------------------------------------------- 1 | getGeometry($mem); 45 | fclose($mem); 46 | return $geometry; 47 | } 48 | 49 | function getGeometry(&$mem) { 50 | $base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5)); 51 | if ($base_info['order'] !== 1) { 52 | throw new Exception('Only NDR (little endian) SKB format is supported at the moment'); 53 | } 54 | 55 | if ($base_info['z']) { 56 | $this->dimension++; 57 | $this->z = TRUE; 58 | } 59 | if ($base_info['m']) { 60 | $this->dimension++; 61 | $this->m = TRUE; 62 | } 63 | 64 | // If there is SRID information, ignore it - use EWKB Adapter to get SRID support 65 | if ($base_info['s']) { 66 | fread($mem, 4); 67 | } 68 | 69 | switch ($base_info['type']) { 70 | case 1: 71 | return $this->getPoint($mem); 72 | case 2: 73 | return $this->getLinstring($mem); 74 | case 3: 75 | return $this->getPolygon($mem); 76 | case 4: 77 | return $this->getMulti($mem,'point'); 78 | case 5: 79 | return $this->getMulti($mem,'line'); 80 | case 6: 81 | return $this->getMulti($mem,'polygon'); 82 | case 7: 83 | return $this->getMulti($mem,'geometry'); 84 | } 85 | } 86 | 87 | function getPoint(&$mem) { 88 | $point_coords = unpack("d*", fread($mem,$this->dimension*8)); 89 | return new Point($point_coords[1],$point_coords[2]); 90 | } 91 | 92 | function getLinstring(&$mem) { 93 | // Get the number of points expected in this string out of the first 4 bytes 94 | $line_length = unpack('L',fread($mem,4)); 95 | 96 | // Return an empty linestring if there is no line-length 97 | if (!$line_length[1]) return new LineString(); 98 | 99 | // Read the nubmer of points x2 (each point is two coords) into decimal-floats 100 | $line_coords = unpack('d*', fread($mem,$line_length[1]*$this->dimension*8)); 101 | 102 | // We have our coords, build up the linestring 103 | $components = array(); 104 | $i = 1; 105 | $num_coords = count($line_coords); 106 | while ($i <= $num_coords) { 107 | $components[] = new Point($line_coords[$i],$line_coords[$i+1]); 108 | $i += 2; 109 | } 110 | return new LineString($components); 111 | } 112 | 113 | function getPolygon(&$mem) { 114 | // Get the number of linestring expected in this poly out of the first 4 bytes 115 | $poly_length = unpack('L',fread($mem,4)); 116 | 117 | $components = array(); 118 | $i = 1; 119 | while ($i <= $poly_length[1]) { 120 | $components[] = $this->getLinstring($mem); 121 | $i++; 122 | } 123 | return new Polygon($components); 124 | } 125 | 126 | function getMulti(&$mem, $type) { 127 | // Get the number of items expected in this multi out of the first 4 bytes 128 | $multi_length = unpack('L',fread($mem,4)); 129 | 130 | $components = array(); 131 | $i = 1; 132 | while ($i <= $multi_length[1]) { 133 | $components[] = $this->getGeometry($mem); 134 | $i++; 135 | } 136 | switch ($type) { 137 | case 'point': 138 | return new MultiPoint($components); 139 | case 'line': 140 | return new MultiLineString($components); 141 | case 'polygon': 142 | return new MultiPolygon($components); 143 | case 'geometry': 144 | return new GeometryCollection($components); 145 | } 146 | } 147 | 148 | /** 149 | * Serialize geometries into WKB string. 150 | * 151 | * @param Geometry $geometry 152 | * 153 | * @return string The WKB string representation of the input geometries 154 | */ 155 | public function write(Geometry $geometry, $write_as_hex = FALSE) { 156 | // We always write into NDR (little endian) 157 | $wkb = pack('c',1); 158 | 159 | switch ($geometry->getGeomType()) { 160 | case 'Point'; 161 | $wkb .= pack('L',1); 162 | $wkb .= $this->writePoint($geometry); 163 | break; 164 | case 'LineString'; 165 | $wkb .= pack('L',2); 166 | $wkb .= $this->writeLineString($geometry); 167 | break; 168 | case 'Polygon'; 169 | $wkb .= pack('L',3); 170 | $wkb .= $this->writePolygon($geometry); 171 | break; 172 | case 'MultiPoint'; 173 | $wkb .= pack('L',4); 174 | $wkb .= $this->writeMulti($geometry); 175 | break; 176 | case 'MultiLineString'; 177 | $wkb .= pack('L',5); 178 | $wkb .= $this->writeMulti($geometry); 179 | break; 180 | case 'MultiPolygon'; 181 | $wkb .= pack('L',6); 182 | $wkb .= $this->writeMulti($geometry); 183 | break; 184 | case 'GeometryCollection'; 185 | $wkb .= pack('L',7); 186 | $wkb .= $this->writeMulti($geometry); 187 | break; 188 | } 189 | 190 | if ($write_as_hex) { 191 | $unpacked = unpack('H*',$wkb); 192 | return $unpacked[1]; 193 | } 194 | else { 195 | return $wkb; 196 | } 197 | } 198 | 199 | function writePoint($point) { 200 | // Set the coords 201 | $wkb = pack('dd',$point->x(), $point->y()); 202 | 203 | return $wkb; 204 | } 205 | 206 | function writeLineString($line) { 207 | // Set the number of points in this line 208 | $wkb = pack('L',$line->numPoints()); 209 | 210 | // Set the coords 211 | foreach ($line->getComponents() as $point) { 212 | $wkb .= pack('dd',$point->x(), $point->y()); 213 | } 214 | 215 | return $wkb; 216 | } 217 | 218 | function writePolygon($poly) { 219 | // Set the number of lines in this poly 220 | $wkb = pack('L',$poly->numGeometries()); 221 | 222 | // Write the lines 223 | foreach ($poly->getComponents() as $line) { 224 | $wkb .= $this->writeLineString($line); 225 | } 226 | 227 | return $wkb; 228 | } 229 | 230 | function writeMulti($geometry) { 231 | // Set the number of components 232 | $wkb = pack('L',$geometry->numGeometries()); 233 | 234 | // Write the components 235 | foreach ($geometry->getComponents() as $component) { 236 | $wkb .= $this->write($component); 237 | } 238 | 239 | return $wkb; 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/adapters/WKT.class.php: -------------------------------------------------------------------------------- 1 | read($wkt)); 34 | $geom->setSRID($srid); 35 | return $geom; 36 | } 37 | else { 38 | return geoPHP::geosToGeometry($reader->read($wkt)); 39 | } 40 | } 41 | $wkt = str_replace(', ', ',', $wkt); 42 | 43 | // For each geometry type, check to see if we have a match at the 44 | // beggining of the string. If we do, then parse using that type 45 | foreach (geoPHP::geometryList() as $geom_type) { 46 | $wkt_geom = strtoupper($geom_type); 47 | if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) { 48 | $data_string = $this->getDataString($wkt, $wkt_geom); 49 | $method = 'parse'.$geom_type; 50 | 51 | if ($srid) { 52 | $geom = $this->$method($data_string); 53 | $geom->setSRID($srid); 54 | return $geom; 55 | } 56 | else { 57 | return $this->$method($data_string); 58 | } 59 | 60 | } 61 | } 62 | } 63 | 64 | private function parsePoint($data_string) { 65 | $data_string = $this->trimParens($data_string); 66 | $parts = explode(' ',$data_string); 67 | return new Point($parts[0], $parts[1]); 68 | } 69 | 70 | private function parseLineString($data_string) { 71 | $data_string = $this->trimParens($data_string); 72 | 73 | // If it's marked as empty, then return an empty line 74 | if ($data_string == 'EMPTY') return new LineString(); 75 | 76 | $parts = explode(',',$data_string); 77 | $points = array(); 78 | foreach ($parts as $part) { 79 | $points[] = $this->parsePoint($part); 80 | } 81 | return new LineString($points); 82 | } 83 | 84 | private function parsePolygon($data_string) { 85 | $data_string = $this->trimParens($data_string); 86 | 87 | // If it's marked as empty, then return an empty polygon 88 | if ($data_string == 'EMPTY') return new Polygon(); 89 | 90 | $parts = explode('),(',$data_string); 91 | $lines = array(); 92 | foreach ($parts as $part) { 93 | if (!$this->beginsWith($part,'(')) $part = '(' . $part; 94 | if (!$this->endsWith($part,')')) $part = $part . ')'; 95 | $lines[] = $this->parseLineString($part); 96 | } 97 | return new Polygon($lines); 98 | } 99 | 100 | private function parseMultiPoint($data_string) { 101 | $data_string = $this->trimParens($data_string); 102 | 103 | // If it's marked as empty, then return an empty MutiPoint 104 | if ($data_string == 'EMPTY') return new MultiPoint(); 105 | 106 | $parts = explode(',',$data_string); 107 | $points = array(); 108 | foreach ($parts as $part) { 109 | $points[] = $this->parsePoint($part); 110 | } 111 | return new MultiPoint($points); 112 | } 113 | 114 | private function parseMultiLineString($data_string) { 115 | $data_string = $this->trimParens($data_string); 116 | 117 | // If it's marked as empty, then return an empty multi-linestring 118 | if ($data_string == 'EMPTY') return new MultiLineString(); 119 | 120 | $parts = explode('),(',$data_string); 121 | $lines = array(); 122 | foreach ($parts as $part) { 123 | // Repair the string if the explode broke it 124 | if (!$this->beginsWith($part,'(')) $part = '(' . $part; 125 | if (!$this->endsWith($part,')')) $part = $part . ')'; 126 | $lines[] = $this->parseLineString($part); 127 | } 128 | return new MultiLineString($lines); 129 | } 130 | 131 | private function parseMultiPolygon($data_string) { 132 | $data_string = $this->trimParens($data_string); 133 | 134 | // If it's marked as empty, then return an empty multi-polygon 135 | if ($data_string == 'EMPTY') return new MultiPolygon(); 136 | 137 | $parts = explode(')),((',$data_string); 138 | $polys = array(); 139 | foreach ($parts as $part) { 140 | // Repair the string if the explode broke it 141 | if (!$this->beginsWith($part,'((')) $part = '((' . $part; 142 | if (!$this->endsWith($part,'))')) $part = $part . '))'; 143 | $polys[] = $this->parsePolygon($part); 144 | } 145 | return new MultiPolygon($polys); 146 | } 147 | 148 | private function parseGeometryCollection($data_string) { 149 | $data_string = $this->trimParens($data_string); 150 | 151 | // If it's marked as empty, then return an empty geom-collection 152 | if ($data_string == 'EMPTY') return new GeometryCollection(); 153 | 154 | $geometries = array(); 155 | $matches = array(); 156 | $str = preg_replace('/,\s*([A-Za-z])/', '|$1', $data_string); 157 | $components = explode('|', trim($str)); 158 | 159 | foreach ($components as $component) { 160 | $geometries[] = $this->read($component); 161 | } 162 | return new GeometryCollection($geometries); 163 | } 164 | 165 | protected function getDataString($wkt, $type) { 166 | return substr($wkt, strlen($type)); 167 | } 168 | 169 | /** 170 | * Trim the parenthesis and spaces 171 | */ 172 | protected function trimParens($str) { 173 | $str = trim($str); 174 | 175 | // We want to only strip off one set of parenthesis 176 | if ($this->beginsWith($str, '(')) { 177 | return substr($str,1,-1); 178 | } 179 | else return $str; 180 | } 181 | 182 | protected function beginsWith($str, $char) { 183 | if (substr($str,0,strlen($char)) == $char) return TRUE; 184 | else return FALSE; 185 | } 186 | 187 | protected function endsWith($str, $char) { 188 | if (substr($str,(0 - strlen($char))) == $char) return TRUE; 189 | else return FALSE; 190 | } 191 | 192 | /** 193 | * Serialize geometries into a WKT string. 194 | * 195 | * @param Geometry $geometry 196 | * 197 | * @return string The WKT string representation of the input geometries 198 | */ 199 | public function write(Geometry $geometry) { 200 | // If geos is installed, then we take a shortcut and let it write the WKT 201 | if (geoPHP::geosInstalled()) { 202 | $writer = new GEOSWKTWriter(); 203 | $writer->setTrim(TRUE); 204 | return $writer->write($geometry->geos()); 205 | } 206 | 207 | if ($geometry->isEmpty()) { 208 | return strtoupper($geometry->geometryType()).' EMPTY'; 209 | } 210 | else if ($data = $this->extractData($geometry)) { 211 | return strtoupper($geometry->geometryType()).' ('.$data.')'; 212 | } 213 | } 214 | 215 | /** 216 | * Extract geometry to a WKT string 217 | * 218 | * @param Geometry $geometry A Geometry object 219 | * 220 | * @return string 221 | */ 222 | public function extractData($geometry) { 223 | $parts = array(); 224 | switch ($geometry->geometryType()) { 225 | case 'Point': 226 | return $geometry->getX().' '.$geometry->getY(); 227 | case 'LineString': 228 | foreach ($geometry->getComponents() as $component) { 229 | $parts[] = $this->extractData($component); 230 | } 231 | return implode(', ', $parts); 232 | case 'Polygon': 233 | case 'MultiPoint': 234 | case 'MultiLineString': 235 | case 'MultiPolygon': 236 | foreach ($geometry->getComponents() as $component) { 237 | $parts[] = '('.$this->extractData($component).')'; 238 | } 239 | return implode(', ', $parts); 240 | case 'GeometryCollection': 241 | foreach ($geometry->getComponents() as $component) { 242 | $parts[] = strtoupper($component->geometryType()).' ('.$this->extractData($component).')'; 243 | } 244 | return implode(', ', $parts); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/Collection.class.php: -------------------------------------------------------------------------------- 1 | components[] = $component; 27 | } 28 | else { 29 | throw new Exception("Cannot create a collection with non-geometries"); 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * Returns Collection component geometries 36 | * 37 | * @return array 38 | */ 39 | public function getComponents() { 40 | return $this->components; 41 | } 42 | 43 | public function centroid() { 44 | if ($this->isEmpty()) return NULL; 45 | 46 | if ($this->geos()) { 47 | $geos_centroid = $this->geos()->centroid(); 48 | if ($geos_centroid->typeName() == 'Point') { 49 | return geoPHP::geosToGeometry($this->geos()->centroid()); 50 | } 51 | } 52 | 53 | // As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope 54 | // @@TODO: Make this the centroid of the convexHull 55 | // Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is 56 | $centroid = $this->envelope()->centroid(); 57 | 58 | return $centroid; 59 | } 60 | 61 | public function getBBox() { 62 | if ($this->isEmpty()) return NULL; 63 | 64 | if ($this->geos()) { 65 | $envelope = $this->geos()->envelope(); 66 | if ($envelope->typeName() == 'Point') { 67 | return geoPHP::geosToGeometry($envelope)->getBBOX(); 68 | } 69 | 70 | $geos_ring = $envelope->exteriorRing(); 71 | return array( 72 | 'maxy' => $geos_ring->pointN(3)->getY(), 73 | 'miny' => $geos_ring->pointN(1)->getY(), 74 | 'maxx' => $geos_ring->pointN(1)->getX(), 75 | 'minx' => $geos_ring->pointN(3)->getX(), 76 | ); 77 | } 78 | 79 | // Go through each component and get the max and min x and y 80 | $i = 0; 81 | foreach ($this->components as $component) { 82 | $component_bbox = $component->getBBox(); 83 | 84 | // On the first run through, set the bbox to the component bbox 85 | if ($i == 0) { 86 | $maxx = $component_bbox['maxx']; 87 | $maxy = $component_bbox['maxy']; 88 | $minx = $component_bbox['minx']; 89 | $miny = $component_bbox['miny']; 90 | } 91 | 92 | // Do a check and replace on each boundary, slowly growing the bbox 93 | $maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx; 94 | $maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy; 95 | $minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx; 96 | $miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny; 97 | $i++; 98 | } 99 | 100 | return array( 101 | 'maxy' => $maxy, 102 | 'miny' => $miny, 103 | 'maxx' => $maxx, 104 | 'minx' => $minx, 105 | ); 106 | } 107 | 108 | public function asArray() { 109 | $array = array(); 110 | foreach ($this->components as $component) { 111 | $array[] = $component->asArray(); 112 | } 113 | return $array; 114 | } 115 | 116 | public function area() { 117 | if ($this->geos()) { 118 | return $this->geos()->area(); 119 | } 120 | 121 | $area = 0; 122 | foreach ($this->components as $component) { 123 | $area += $component->area(); 124 | } 125 | return $area; 126 | } 127 | 128 | // By default, the boundary of a collection is the boundary of it's components 129 | public function boundary() { 130 | if ($this->isEmpty()) return new LineString(); 131 | 132 | if ($this->geos()) { 133 | return $this->geos()->boundary(); 134 | } 135 | 136 | $components_boundaries = array(); 137 | foreach ($this->components as $component) { 138 | $components_boundaries[] = $component->boundary(); 139 | } 140 | return geoPHP::geometryReduce($components_boundaries); 141 | } 142 | 143 | public function numGeometries() { 144 | return count($this->components); 145 | } 146 | 147 | // Note that the standard is 1 based indexing 148 | public function geometryN($n) { 149 | $n = intval($n); 150 | if (array_key_exists($n-1, $this->components)) { 151 | return $this->components[$n-1]; 152 | } 153 | else { 154 | return NULL; 155 | } 156 | } 157 | 158 | public function length() { 159 | $length = 0; 160 | foreach ($this->components as $delta => $component) { 161 | $length += $component->length(); 162 | } 163 | return $length; 164 | } 165 | 166 | public function greatCircleLength($radius = 6378137) { 167 | $length = 0; 168 | foreach ($this->components as $component) { 169 | $length += $component->greatCircleLength($radius); 170 | } 171 | return $length; 172 | } 173 | 174 | public function haversineLength() { 175 | $length = 0; 176 | foreach ($this->components as $component) { 177 | $length += $component->haversineLength(); 178 | } 179 | return $length; 180 | } 181 | 182 | public function dimension() { 183 | $dimension = 0; 184 | foreach ($this->components as $component) { 185 | if ($component->dimension() > $dimension) { 186 | $dimension = $component->dimension(); 187 | } 188 | } 189 | return $dimension; 190 | } 191 | 192 | // A collection is empty if it has no components OR all it's components are empty 193 | public function isEmpty() { 194 | if (!count($this->components)) { 195 | return TRUE; 196 | } 197 | else { 198 | foreach ($this->components as $component) { 199 | if (!$component->isEmpty()) return FALSE; 200 | } 201 | return TRUE; 202 | } 203 | } 204 | 205 | public function numPoints() { 206 | $num = 0; 207 | foreach ($this->components as $component) { 208 | $num += $component->numPoints(); 209 | } 210 | return $num; 211 | } 212 | 213 | public function getPoints() { 214 | $points = array(); 215 | foreach ($this->components as $component) { 216 | $points = array_merge($points, $component->getPoints()); 217 | } 218 | return $points; 219 | } 220 | 221 | public function equals($geometry) { 222 | if ($this->geos()) { 223 | return $this->geos()->equals($geometry->geos()); 224 | } 225 | 226 | // To test for equality we check to make sure that there is a matching point 227 | // in the other geometry for every point in this geometry. 228 | // This is slightly more strict than the standard, which 229 | // uses Within(A,B) = true and Within(B,A) = true 230 | // @@TODO: Eventually we could fix this by using some sort of simplification 231 | // method that strips redundant vertices (that are all in a row) 232 | 233 | $this_points = $this->getPoints(); 234 | $other_points = $geometry->getPoints(); 235 | 236 | // First do a check to make sure they have the same number of vertices 237 | if (count($this_points) != count($other_points)) { 238 | return FALSE; 239 | } 240 | 241 | foreach ($this_points as $point) { 242 | $found_match = FALSE; 243 | foreach ($other_points as $key => $test_point) { 244 | if ($point->equals($test_point)) { 245 | $found_match = TRUE; 246 | unset($other_points[$key]); 247 | break; 248 | } 249 | } 250 | if (!$found_match) { 251 | return FALSE; 252 | } 253 | } 254 | 255 | // All points match, return TRUE 256 | return TRUE; 257 | } 258 | 259 | public function isSimple() { 260 | if ($this->geos()) { 261 | return $this->geos()->isSimple(); 262 | } 263 | 264 | // A collection is simple if all it's components are simple 265 | foreach ($this->components as $component) { 266 | if (!$component->isSimple()) return FALSE; 267 | } 268 | 269 | return TRUE; 270 | } 271 | 272 | public function explode() { 273 | $parts = array(); 274 | foreach ($this->components as $component) { 275 | $parts = array_merge($parts, $component->explode()); 276 | } 277 | return $parts; 278 | } 279 | 280 | // Not valid for this geometry type 281 | // -------------------------------- 282 | public function x() { return NULL; } 283 | public function y() { return NULL; } 284 | public function startPoint() { return NULL; } 285 | public function endPoint() { return NULL; } 286 | public function isRing() { return NULL; } 287 | public function isClosed() { return NULL; } 288 | public function pointN($n) { return NULL; } 289 | public function exteriorRing() { return NULL; } 290 | public function numInteriorRings() { return NULL; } 291 | public function interiorRingN($n) { return NULL; } 292 | public function pointOnSurface() { return NULL; } 293 | } 294 | 295 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/Geometry.class.php: -------------------------------------------------------------------------------- 1 | srid; 50 | } 51 | 52 | public function setSRID($srid) { 53 | if ($this->geos()) { 54 | $this->geos()->setSRID($srid); 55 | } 56 | $this->srid = $srid; 57 | } 58 | 59 | public function envelope() { 60 | if ($this->isEmpty()) return new Polygon(); 61 | 62 | if ($this->geos()) { 63 | return geoPHP::geosToGeometry($this->geos()->envelope()); 64 | } 65 | 66 | $bbox = $this->getBBox(); 67 | $points = array ( 68 | new Point($bbox['maxx'],$bbox['miny']), 69 | new Point($bbox['maxx'],$bbox['maxy']), 70 | new Point($bbox['minx'],$bbox['maxy']), 71 | new Point($bbox['minx'],$bbox['miny']), 72 | new Point($bbox['maxx'],$bbox['miny']), 73 | ); 74 | 75 | $outer_boundary = new LineString($points); 76 | return new Polygon(array($outer_boundary)); 77 | } 78 | 79 | public function geometryType() { 80 | return $this->geom_type; 81 | } 82 | 83 | // Public: Non-Standard -- Common to all geometries 84 | // ------------------------------------------------ 85 | 86 | // $this->out($format, $other_args); 87 | public function out() { 88 | $args = func_get_args(); 89 | 90 | $format = array_shift($args); 91 | $type_map = geoPHP::getAdapterMap(); 92 | $processor_type = $type_map[$format]; 93 | $processor = new $processor_type(); 94 | 95 | array_unshift($args, $this); 96 | $result = call_user_func_array(array($processor, 'write'), $args); 97 | 98 | return $result; 99 | } 100 | 101 | 102 | // Public: Aliases 103 | // --------------- 104 | public function getCentroid() { 105 | return $this->centroid(); 106 | } 107 | 108 | public function getArea() { 109 | return $this->area(); 110 | } 111 | 112 | public function getX() { 113 | return $this->x(); 114 | } 115 | 116 | public function getY() { 117 | return $this->y(); 118 | } 119 | 120 | public function getGeos() { 121 | return $this->geos(); 122 | } 123 | 124 | public function getGeomType() { 125 | return $this->geometryType(); 126 | } 127 | 128 | public function getSRID() { 129 | return $this->SRID(); 130 | } 131 | 132 | public function asText() { 133 | return $this->out('wkt'); 134 | } 135 | 136 | public function asBinary() { 137 | return $this->out('wkb'); 138 | } 139 | 140 | // Public: GEOS Only Functions 141 | // --------------------------- 142 | public function geos() { 143 | // If it's already been set, just return it 144 | if ($this->geos && geoPHP::geosInstalled()) { 145 | return $this->geos; 146 | } 147 | // It hasn't been set yet, generate it 148 | if (geoPHP::geosInstalled()) { 149 | $reader = new GEOSWKBReader(); 150 | $this->geos = $reader->readHEX($this->out('wkb',TRUE)); 151 | } 152 | else { 153 | $this->geos = FALSE; 154 | } 155 | return $this->geos; 156 | } 157 | 158 | public function setGeos($geos) { 159 | $this->geos = $geos; 160 | } 161 | 162 | public function pointOnSurface() { 163 | if ($this->geos()) { 164 | return geoPHP::geosToGeometry($this->geos()->pointOnSurface()); 165 | } 166 | } 167 | 168 | public function equalsExact(Geometry $geometry) { 169 | if ($this->geos()) { 170 | return $this->geos()->equalsExact($geometry->geos()); 171 | } 172 | } 173 | 174 | public function relate(Geometry $geometry, $pattern = NULL) { 175 | if ($this->geos()) { 176 | if ($pattern) { 177 | return $this->geos()->relate($geometry->geos(), $pattern); 178 | } 179 | else { 180 | return $this->geos()->relate($geometry->geos()); 181 | } 182 | } 183 | } 184 | 185 | public function checkValidity() { 186 | if ($this->geos()) { 187 | return $this->geos()->checkValidity(); 188 | } 189 | } 190 | 191 | public function buffer($distance) { 192 | if ($this->geos()) { 193 | return geoPHP::geosToGeometry($this->geos()->buffer($distance)); 194 | } 195 | } 196 | 197 | public function intersection(Geometry $geometry) { 198 | if ($this->geos()) { 199 | return geoPHP::geosToGeometry($this->geos()->intersection($geometry->geos())); 200 | } 201 | } 202 | 203 | public function convexHull() { 204 | if ($this->geos()) { 205 | return geoPHP::geosToGeometry($this->geos()->convexHull()); 206 | } 207 | } 208 | 209 | public function difference(Geometry $geometry) { 210 | if ($this->geos()) { 211 | return geoPHP::geosToGeometry($this->geos()->difference($geometry->geos())); 212 | } 213 | } 214 | 215 | public function symDifference(Geometry $geometry) { 216 | if ($this->geos()) { 217 | return geoPHP::geosToGeometry($this->geos()->symDifference($geometry->geos())); 218 | } 219 | } 220 | 221 | // Can pass in a geometry or an array of geometries 222 | public function union(Geometry $geometry) { 223 | if ($this->geos()) { 224 | if (is_array($geometry)) { 225 | $geom = $this->geos(); 226 | foreach ($geometry as $item) { 227 | $geom = $geom->union($item->geos()); 228 | } 229 | return geoPHP::geosToGeometry($geos); 230 | } 231 | else { 232 | return geoPHP::geosToGeometry($this->geos()->union($geometry->geos())); 233 | } 234 | } 235 | } 236 | 237 | public function simplify($tolerance, $preserveTopology = FALSE) { 238 | if ($this->geos()) { 239 | return geoPHP::geosToGeometry($this->geos()->simplify($tolerance, $preserveTopology)); 240 | } 241 | } 242 | 243 | public function disjoint(Geometry $geometry) { 244 | if ($this->geos()) { 245 | return $this->geos()->disjoint($geometry->geos()); 246 | } 247 | } 248 | 249 | public function touches(Geometry $geometry) { 250 | if ($this->geos()) { 251 | return $this->geos()->touches($geometry->geos()); 252 | } 253 | } 254 | 255 | public function intersects(Geometry $geometry) { 256 | if ($this->geos()) { 257 | return $this->geos()->intersects($geometry->geos()); 258 | } 259 | } 260 | 261 | public function crosses(Geometry $geometry) { 262 | if ($this->geos()) { 263 | return $this->geos()->crosses($geometry->geos()); 264 | } 265 | } 266 | 267 | public function within(Geometry $geometry) { 268 | if ($this->geos()) { 269 | return $this->geos()->within($geometry->geos()); 270 | } 271 | } 272 | 273 | public function contains(Geometry $geometry) { 274 | if ($this->geos()) { 275 | return $this->geos()->contains($geometry->geos()); 276 | } 277 | } 278 | 279 | public function overlaps(Geometry $geometry) { 280 | if ($this->geos()) { 281 | return $this->geos()->overlaps($geometry->geos()); 282 | } 283 | } 284 | 285 | public function covers(Geometry $geometry) { 286 | if ($this->geos()) { 287 | return $this->geos()->covers($geometry->geos()); 288 | } 289 | } 290 | 291 | public function coveredBy(Geometry $geometry) { 292 | if ($this->geos()) { 293 | return $this->geos()->coveredBy($geometry->geos()); 294 | } 295 | } 296 | 297 | public function distance(Geometry $geometry) { 298 | if ($this->geos()) { 299 | return $this->geos()->distance($geometry->geos()); 300 | } 301 | } 302 | 303 | public function hausdorffDistance(Geometry $geometry) { 304 | if ($this->geos()) { 305 | return $this->geos()->hausdorffDistance($geometry->geos()); 306 | } 307 | } 308 | 309 | public function project(Geometry $point, $normalized = NULL) { 310 | if ($this->geos()) { 311 | return $this->geos()->project($point->geos(), $normalized); 312 | } 313 | } 314 | 315 | // Public - Placeholders 316 | // --------------------- 317 | public function hasZ() { 318 | // geoPHP does not support Z values at the moment 319 | return FALSE; 320 | } 321 | 322 | public function is3D() { 323 | // geoPHP does not support 3D geometries at the moment 324 | return FALSE; 325 | } 326 | 327 | public function isMeasured() { 328 | // geoPHP does not yet support M values 329 | return FALSE; 330 | } 331 | 332 | public function coordinateDimension() { 333 | // geoPHP only supports 2-dimentional space 334 | return 2; 335 | } 336 | 337 | public function z() { 338 | // geoPHP only supports 2-dimentional space 339 | return NULL; 340 | } 341 | 342 | public function m() { 343 | // geoPHP only supports 2-dimentional space 344 | return NULL; 345 | } 346 | 347 | } 348 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/GeometryCollection.class.php: -------------------------------------------------------------------------------- 1 | components as $component) { 17 | $array[] = array( 18 | 'type' => $component->geometryType(), 19 | 'components' => $component->asArray(), 20 | ); 21 | } 22 | return $array; 23 | } 24 | 25 | // Not valid for this geomettry 26 | public function boundary() { return NULL; } 27 | public function isSimple() { return NULL; } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/LineString.class.php: -------------------------------------------------------------------------------- 1 | pointN(1); 32 | } 33 | 34 | public function endPoint() { 35 | $last_n = $this->numPoints(); 36 | return $this->pointN($last_n); 37 | } 38 | 39 | public function isClosed() { 40 | return ($this->startPoint()->equals($this->endPoint())); 41 | } 42 | 43 | public function isRing() { 44 | return ($this->isClosed() && $this->isSimple()); 45 | } 46 | 47 | public function numPoints() { 48 | return $this->numGeometries(); 49 | } 50 | 51 | public function pointN($n) { 52 | return $this->geometryN($n); 53 | } 54 | 55 | public function dimension() { 56 | if ($this->isEmpty()) return 0; 57 | return 1; 58 | } 59 | 60 | public function area() { 61 | return 0; 62 | } 63 | 64 | public function length() { 65 | if ($this->geos()) { 66 | return $this->geos()->length(); 67 | } 68 | $length = 0; 69 | foreach ($this->getPoints() as $delta => $point) { 70 | $previous_point = $this->geometryN($delta); 71 | if ($previous_point) { 72 | $length += sqrt(pow(($previous_point->getX() - $point->getX()), 2) + pow(($previous_point->getY()- $point->getY()), 2)); 73 | } 74 | } 75 | return $length; 76 | } 77 | 78 | public function greatCircleLength($radius = 6378137) { 79 | $length = 0; 80 | $points = $this->getPoints(); 81 | for($i=0; $i<$this->numPoints()-1; $i++) { 82 | $point = $points[$i]; 83 | $next_point = $points[$i+1]; 84 | if (!is_object($next_point)) {continue;} 85 | // Great circle method 86 | $lat1 = deg2rad($point->getY()); 87 | $lat2 = deg2rad($next_point->getY()); 88 | $lon1 = deg2rad($point->getX()); 89 | $lon2 = deg2rad($next_point->getX()); 90 | $dlon = $lon2 - $lon1; 91 | $length += 92 | $radius * 93 | atan2( 94 | sqrt( 95 | pow(cos($lat2) * sin($dlon), 2) + 96 | pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dlon), 2) 97 | ) 98 | , 99 | sin($lat1) * sin($lat2) + 100 | cos($lat1) * cos($lat2) * cos($dlon) 101 | ); 102 | } 103 | // Returns length in meters. 104 | return $length; 105 | } 106 | 107 | public function haversineLength() { 108 | $degrees = 0; 109 | $points = $this->getPoints(); 110 | for($i=0; $i<$this->numPoints()-1; $i++) { 111 | $point = $points[$i]; 112 | $next_point = $points[$i+1]; 113 | if (!is_object($next_point)) {continue;} 114 | $degree = rad2deg( 115 | acos( 116 | sin(deg2rad($point->getY())) * sin(deg2rad($next_point->getY())) + 117 | cos(deg2rad($point->getY())) * cos(deg2rad($next_point->getY())) * 118 | cos(deg2rad(abs($point->getX() - $next_point->getX()))) 119 | ) 120 | ); 121 | $degrees += $degree; 122 | } 123 | // Returns degrees 124 | return $degrees; 125 | } 126 | 127 | public function explode() { 128 | $parts = array(); 129 | $points = $this->getPoints(); 130 | 131 | foreach ($points as $i => $point) { 132 | if (isset($points[$i+1])) { 133 | $parts[] = new LineString(array($point, $points[$i+1])); 134 | } 135 | } 136 | return $parts; 137 | } 138 | 139 | public function isSimple() { 140 | if ($this->geos()) { 141 | return $this->geos()->isSimple(); 142 | } 143 | 144 | $segments = $this->explode(); 145 | 146 | foreach ($segments as $i => $segment) { 147 | foreach ($segments as $j => $check_segment) { 148 | if ($i != $j) { 149 | if ($segment->lineSegmentIntersect($check_segment)) { 150 | return FALSE; 151 | } 152 | } 153 | } 154 | } 155 | return TRUE; 156 | } 157 | 158 | // Utility function to check if any line sigments intersect 159 | // Derived from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect 160 | public function lineSegmentIntersect($segment) { 161 | $p0_x = $this->startPoint()->x(); 162 | $p0_y = $this->startPoint()->y(); 163 | $p1_x = $this->endPoint()->x(); 164 | $p1_y = $this->endPoint()->y(); 165 | $p2_x = $segment->startPoint()->x(); 166 | $p2_y = $segment->startPoint()->y(); 167 | $p3_x = $segment->endPoint()->x(); 168 | $p3_y = $segment->endPoint()->y(); 169 | 170 | $s1_x = $p1_x - $p0_x; $s1_y = $p1_y - $p0_y; 171 | $s2_x = $p3_x - $p2_x; $s2_y = $p3_y - $p2_y; 172 | 173 | $fps = (-$s2_x * $s1_y) + ($s1_x * $s2_y); 174 | $fpt = (-$s2_x * $s1_y) + ($s1_x * $s2_y); 175 | 176 | if ($fps == 0 || $fpt == 0) { 177 | return FALSE; 178 | } 179 | 180 | $s = (-$s1_y * ($p0_x - $p2_x) + $s1_x * ($p0_y - $p2_y)) / $fps; 181 | $t = ( $s2_x * ($p0_y - $p2_y) - $s2_y * ($p0_x - $p2_x)) / $fpt; 182 | 183 | if ($s > 0 && $s < 1 && $t > 0 && $t < 1) { 184 | // Collision detected 185 | return TRUE; 186 | } 187 | return FALSE; 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/MultiLineString.class.php: -------------------------------------------------------------------------------- 1 | components as $line) { 12 | if (!$line->isClosed()) { 13 | return FALSE; 14 | } 15 | } 16 | return TRUE; 17 | } 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/MultiPoint.class.php: -------------------------------------------------------------------------------- 1 | numGeometries(); 11 | } 12 | 13 | public function isSimple() { 14 | return TRUE; 15 | } 16 | 17 | // Not valid for this geometry type 18 | // -------------------------------- 19 | public function explode() { return NULL; } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/MultiPolygon.class.php: -------------------------------------------------------------------------------- 1 | dimention = 3; 32 | } 33 | 34 | // Convert to floatval in case they are passed in as a string or integer etc. 35 | $x = floatval($x); 36 | $y = floatval($y); 37 | $z = floatval($z); 38 | 39 | // Add poitional elements 40 | if ($this->dimention == 2) { 41 | $this->coords = array($x, $y); 42 | } 43 | if ($this->dimention == 3) { 44 | $this->coords = array($x, $y, $z); 45 | } 46 | } 47 | 48 | /** 49 | * Get X (longitude) coordinate 50 | * 51 | * @return float The X coordinate 52 | */ 53 | public function x() { 54 | return $this->coords[0]; 55 | } 56 | 57 | /** 58 | * Returns Y (latitude) coordinate 59 | * 60 | * @return float The Y coordinate 61 | */ 62 | public function y() { 63 | return $this->coords[1]; 64 | } 65 | 66 | /** 67 | * Returns Z (altitude) coordinate 68 | * 69 | * @return float The Z coordinate or NULL is not a 3D point 70 | */ 71 | public function z() { 72 | if ($this->dimention == 3) { 73 | return $this->coords[2]; 74 | } 75 | else return NULL; 76 | } 77 | 78 | // A point's centroid is itself 79 | public function centroid() { 80 | return $this; 81 | } 82 | 83 | public function getBBox() { 84 | return array( 85 | 'maxy' => $this->getY(), 86 | 'miny' => $this->getY(), 87 | 'maxx' => $this->getX(), 88 | 'minx' => $this->getX(), 89 | ); 90 | } 91 | 92 | public function asArray($assoc = FALSE) { 93 | return $this->coords; 94 | } 95 | 96 | public function area() { 97 | return 0; 98 | } 99 | 100 | public function length() { 101 | return 0; 102 | } 103 | 104 | public function greatCircleLength() { 105 | return 0; 106 | } 107 | 108 | public function haversineLength() { 109 | return 0; 110 | } 111 | 112 | // The boundary of a point is itself 113 | public function boundary() { 114 | return $this; 115 | } 116 | 117 | public function dimension() { 118 | return 0; 119 | } 120 | 121 | public function isEmpty() { 122 | return FALSE; 123 | } 124 | 125 | public function numPoints() { 126 | return 1; 127 | } 128 | 129 | public function getPoints() { 130 | return array($this); 131 | } 132 | 133 | public function equals($geometry) { 134 | return ($this->x() == $geometry->x() && $this->y() == $geometry->y()); 135 | } 136 | 137 | public function isSimple() { 138 | return TRUE; 139 | } 140 | 141 | // Not valid for this geometry type 142 | public function numGeometries() { return NULL; } 143 | public function geometryN($n) { return NULL; } 144 | public function startPoint() { return NULL; } 145 | public function endPoint() { return NULL; } 146 | public function isRing() { return NULL; } 147 | public function isClosed() { return NULL; } 148 | public function pointN($n) { return NULL; } 149 | public function exteriorRing() { return NULL; } 150 | public function numInteriorRings() { return NULL; } 151 | public function interiorRingN($n) { return NULL; } 152 | public function pointOnSurface() { return NULL; } 153 | public function explode() { return NULL; } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /demo/geoPHP/lib/geometry/Polygon.class.php: -------------------------------------------------------------------------------- 1 | isEmpty()) return 0; 13 | 14 | if ($this->geos() && $exterior_only == FALSE) { 15 | return $this->geos()->area(); 16 | } 17 | 18 | $exterior_ring = $this->components[0]; 19 | $pts = $exterior_ring->getComponents(); 20 | 21 | $c = count($pts); 22 | if((int)$c == '0') return NULL; 23 | $a = '0'; 24 | foreach($pts as $k => $p){ 25 | $j = ($k + 1) % $c; 26 | $a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX()); 27 | } 28 | 29 | if ($signed) $area = ($a / 2); 30 | else $area = abs(($a / 2)); 31 | 32 | if ($exterior_only == TRUE) { 33 | return $area; 34 | } 35 | foreach ($this->components as $delta => $component) { 36 | if ($delta != 0) { 37 | $inner_poly = new Polygon(array($component)); 38 | $area -= $inner_poly->area(); 39 | } 40 | } 41 | return $area; 42 | } 43 | 44 | public function centroid() { 45 | if ($this->isEmpty()) return NULL; 46 | 47 | if ($this->geos()) { 48 | return geoPHP::geosToGeometry($this->geos()->centroid()); 49 | } 50 | 51 | $exterior_ring = $this->components[0]; 52 | $pts = $exterior_ring->getComponents(); 53 | 54 | $c = count($pts); 55 | if((int)$c == '0') return NULL; 56 | $cn = array('x' => '0', 'y' => '0'); 57 | $a = $this->area(TRUE, TRUE); 58 | 59 | // If this is a polygon with no area. Just return the first point. 60 | if ($a == 0) { 61 | return $this->exteriorRing()->pointN(1); 62 | } 63 | 64 | foreach($pts as $k => $p){ 65 | $j = ($k + 1) % $c; 66 | $P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX()); 67 | $cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P; 68 | $cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P; 69 | } 70 | 71 | $cn['x'] = $cn['x'] / ( 6 * $a); 72 | $cn['y'] = $cn['y'] / ( 6 * $a); 73 | 74 | $centroid = new Point($cn['x'], $cn['y']); 75 | return $centroid; 76 | } 77 | 78 | /** 79 | * Find the outermost point from the centroid 80 | * 81 | * @returns Point The outermost point 82 | */ 83 | public function outermostPoint() { 84 | $centroid = $this->getCentroid(); 85 | 86 | $max = array('length' => 0, 'point' => null); 87 | 88 | foreach($this->getPoints() as $point) { 89 | $lineString = new LineString(array($centroid, $point)); 90 | 91 | if($lineString->length() > $max['length']) { 92 | $max['length'] = $lineString->length(); 93 | $max['point'] = $point; 94 | } 95 | } 96 | 97 | return $max['point']; 98 | } 99 | 100 | public function exteriorRing() { 101 | if ($this->isEmpty()) return new LineString(); 102 | return $this->components[0]; 103 | } 104 | 105 | public function numInteriorRings() { 106 | if ($this->isEmpty()) return 0; 107 | return $this->numGeometries()-1; 108 | } 109 | 110 | public function interiorRingN($n) { 111 | return $this->geometryN($n+1); 112 | } 113 | 114 | public function dimension() { 115 | if ($this->isEmpty()) return 0; 116 | return 2; 117 | } 118 | 119 | public function isSimple() { 120 | if ($this->geos()) { 121 | return $this->geos()->isSimple(); 122 | } 123 | 124 | $segments = $this->explode(); 125 | 126 | foreach ($segments as $i => $segment) { 127 | foreach ($segments as $j => $check_segment) { 128 | if ($i != $j) { 129 | if ($segment->lineSegmentIntersect($check_segment)) { 130 | return FALSE; 131 | } 132 | } 133 | } 134 | } 135 | return TRUE; 136 | } 137 | 138 | // Not valid for this geometry type 139 | // -------------------------------- 140 | public function length() { return NULL; } 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Leaflet SQLite GeoJSON Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Fork me on GitHub 15 |
16 |

This example demonstrates the ability to view layers from an SQLite database file as GeoJSON layers.

17 |

18 |

22 |

23 | 24 | 25 | 26 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /mysql_geojson.php: -------------------------------------------------------------------------------- 1 | out('json'); 15 | } 16 | 17 | # Connect to MySQL database 18 | $conn = new PDO('mysql:host=localhost;dbname=mydatabase','myusername','mypassword'); 19 | 20 | # Build SQL SELECT statement and return the geometry as a WKB element 21 | $sql = 'SELECT *, AsWKB(SHAPE) AS wkb FROM parcels'; 22 | 23 | # Try query or error 24 | $rs = $conn->query($sql); 25 | if (!$rs) { 26 | echo 'An SQL error occured.\n'; 27 | exit; 28 | } 29 | 30 | # Build GeoJSON feature collection array 31 | $geojson = array( 32 | 'type' => 'FeatureCollection', 33 | 'features' => array() 34 | ); 35 | 36 | # Loop through rows to build feature arrays 37 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 38 | $properties = $row; 39 | # Remove wkb and geometry fields from properties 40 | unset($properties['wkb']); 41 | unset($properties['SHAPE']); 42 | $feature = array( 43 | 'type' => 'Feature', 44 | 'geometry' => json_decode(wkb_to_json($row['wkb'])), 45 | 'properties' => $properties 46 | ); 47 | # Add feature arrays to feature collection array 48 | array_push($geojson['features'], $feature); 49 | } 50 | 51 | header('Content-type: application/json'); 52 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 53 | $conn = NULL; 54 | ?> -------------------------------------------------------------------------------- /postgis_geojson.php: -------------------------------------------------------------------------------- 1 | query($sql); 28 | if (!$rs) { 29 | echo 'An SQL error occured.\n'; 30 | exit; 31 | } 32 | 33 | # Build GeoJSON feature collection array 34 | $geojson = array( 35 | 'type' => 'FeatureCollection', 36 | 'features' => array() 37 | ); 38 | 39 | # Loop through rows to build feature arrays 40 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 41 | $properties = $row; 42 | # Remove geojson and geometry fields from properties 43 | unset($properties['geojson']); 44 | unset($properties['the_geom']); 45 | $feature = array( 46 | 'type' => 'Feature', 47 | 'geometry' => json_decode($row['geojson'], true), 48 | 'properties' => $properties 49 | ); 50 | # Add feature arrays to feature collection array 51 | array_push($geojson['features'], $feature); 52 | } 53 | 54 | header('Content-type: application/json'); 55 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 56 | $conn = NULL; 57 | ?> 58 | -------------------------------------------------------------------------------- /simple_points/csv_points_geojson.php: -------------------------------------------------------------------------------- 1 | 'FeatureCollection', 17 | 'features' => array() 18 | ); 19 | 20 | # Loop through rows to build feature arrays 21 | $header = NULL; 22 | while (($row = fgetcsv($handle, 1000, ',')) !== FALSE) { 23 | if (!$header) { 24 | $header = $row; 25 | } else { 26 | $data = array_combine($header, $row); 27 | $properties = $data; 28 | # Remove x and y fields from properties (optional) 29 | unset($properties['x']); 30 | unset($properties['y']); 31 | $feature = array( 32 | 'type' => 'Feature', 33 | 'geometry' => array( 34 | 'type' => 'Point', 35 | 'coordinates' => array( 36 | $data['x'], 37 | $data['y'] 38 | ) 39 | ), 40 | 'properties' => $properties 41 | ); 42 | # Add feature arrays to feature collection array 43 | array_push($geojson['features'], $feature); 44 | } 45 | } 46 | fclose($handle); 47 | 48 | header('Content-type: application/json'); 49 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 50 | ?> 51 | -------------------------------------------------------------------------------- /simple_points/mysql_points_geojson.php: -------------------------------------------------------------------------------- 1 | = ' . $bbox[0] . ' AND y <= ' . $bbox[3] . ' AND y >= ' . $bbox[1]; 24 | } 25 | 26 | # Try query or error 27 | $rs = $conn->query($sql); 28 | if (!$rs) { 29 | echo 'An SQL error occured.\n'; 30 | exit; 31 | } 32 | 33 | # Build GeoJSON feature collection array 34 | $geojson = array( 35 | 'type' => 'FeatureCollection', 36 | 'features' => array() 37 | ); 38 | 39 | # Loop through rows to build feature arrays 40 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 41 | $properties = $row; 42 | # Remove x and y fields from properties (optional) 43 | unset($properties['x']); 44 | unset($properties['y']); 45 | $feature = array( 46 | 'type' => 'Feature', 47 | 'geometry' => array( 48 | 'type' => 'Point', 49 | 'coordinates' => array( 50 | $row['x'], 51 | $row['y'] 52 | ) 53 | ), 54 | 'properties' => $properties 55 | ); 56 | # Add feature arrays to feature collection array 57 | array_push($geojson['features'], $feature); 58 | } 59 | 60 | header('Content-type: application/json'); 61 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 62 | $conn = NULL; 63 | ?> 64 | -------------------------------------------------------------------------------- /simple_points/postgis_points_geojson.php: -------------------------------------------------------------------------------- 1 | = ' . $bbox[0] . ' AND y <= ' . $bbox[3] . ' AND y >= ' . $bbox[1]; 24 | } 25 | 26 | # Try query or error 27 | $rs = $conn->query($sql); 28 | if (!$rs) { 29 | echo 'An SQL error occured.\n'; 30 | exit; 31 | } 32 | 33 | # Build GeoJSON feature collection array 34 | $geojson = array( 35 | 'type' => 'FeatureCollection', 36 | 'features' => array() 37 | ); 38 | 39 | # Loop through rows to build feature arrays 40 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 41 | $properties = $row; 42 | # Remove x and y fields from properties (optional) 43 | unset($properties['x']); 44 | unset($properties['y']); 45 | $feature = array( 46 | 'type' => 'Feature', 47 | 'geometry' => array( 48 | 'type' => 'Point', 49 | 'coordinates' => array( 50 | $row['x'], 51 | $row['y'] 52 | ) 53 | ), 54 | 'properties' => $properties 55 | ); 56 | # Add feature arrays to feature collection array 57 | array_push($geojson['features'], $feature); 58 | } 59 | 60 | header('Content-type: application/json'); 61 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 62 | $conn = NULL; 63 | ?> -------------------------------------------------------------------------------- /simple_points/sqlite_points_geojson.php: -------------------------------------------------------------------------------- 1 | = ' . $bbox[0] . ' AND y <= ' . $bbox[3] . ' AND y >= ' . $bbox[1]; 24 | } 25 | 26 | # Try query or error 27 | $rs = $conn->query($sql); 28 | if (!$rs) { 29 | echo 'An SQL error occured.\n'; 30 | exit; 31 | } 32 | 33 | # Build GeoJSON feature collection array 34 | $geojson = array( 35 | 'type' => 'FeatureCollection', 36 | 'features' => array() 37 | ); 38 | 39 | # Loop through rows to build feature arrays 40 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 41 | $properties = $row; 42 | # Remove x and y fields from properties (optional) 43 | unset($properties['x']); 44 | unset($properties['y']); 45 | $feature = array( 46 | 'type' => 'Feature', 47 | 'geometry' => array( 48 | 'type' => 'Point', 49 | 'coordinates' => array( 50 | $row['x'], 51 | $row['y'] 52 | ) 53 | ), 54 | 'properties' => $properties 55 | ); 56 | # Add feature arrays to feature collection array 57 | array_push($geojson['features'], $feature); 58 | } 59 | 60 | header('Content-type: application/json'); 61 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 62 | $conn = NULL; 63 | ?> 64 | -------------------------------------------------------------------------------- /sqlite_geojson.php: -------------------------------------------------------------------------------- 1 | out('json'); 15 | } 16 | 17 | # Connect to SQLite database 18 | $conn = new PDO('sqlite:mydatabase.sqlite'); 19 | 20 | # Build SQL SELECT statement and return the geometry as a GeoJSON element 21 | $sql = 'SELECT *, GEOMETRY AS wkb FROM mytable'; 22 | 23 | # Try query or error 24 | $rs = $conn->query($sql); 25 | if (!$rs) { 26 | echo 'An SQL error occured.\n'; 27 | exit; 28 | } 29 | 30 | # Build GeoJSON feature collection array 31 | $geojson = array( 32 | 'type' => 'FeatureCollection', 33 | 'features' => array() 34 | ); 35 | 36 | # Loop through rows to build feature arrays 37 | while ($row = $rs->fetch(PDO::FETCH_ASSOC)) { 38 | $properties = $row; 39 | # Remove wkb and geometry fields from properties 40 | unset($properties['wkb']); 41 | unset($properties['GEOMETRY']); 42 | $feature = array( 43 | 'type' => 'Feature', 44 | 'geometry' => json_decode(wkb_to_json($row['wkb'])), 45 | 'properties' => $properties 46 | ); 47 | # Add feature arrays to feature collection array 48 | array_push($geojson['features'], $feature); 49 | } 50 | 51 | header('Content-type: application/json'); 52 | echo json_encode($geojson, JSON_NUMERIC_CHECK); 53 | $conn = NULL; 54 | ?> --------------------------------------------------------------------------------