├── 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).''.$this->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 .= ''.$this->nss.'trkseg>'.$this->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().''.$this->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 .= ''.$this->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 .= ''.$this->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 .= ''.$this->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().''.$this->nss.'coordinates>'.$this->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 .= ''.$this->nss.'coordinates>';
229 | }
230 |
231 | $str .= ''. $this->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') . ''.$this->nss.'outerBoundaryIs>';
240 | foreach (array_slice($components, 1) as $comp) {
241 | $str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . ''.$this->nss.'innerBoundaryIs>';
242 | }
243 | }
244 |
245 | return '<'.$this->nss.'Polygon>'. $str .''.$this->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 .''.$this->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 |
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 | ?>
--------------------------------------------------------------------------------