source: subversion/sites/other/freemap-npe/osmxml.php @ 2754

Last change on this file since 2754 was 1540, checked in by nick, 14 years ago

Freemap-NPE: initial version

File size: 10.2 KB
Line 
1<?php
2################################################################################
3# This file forms part of the Freemap source code.                             #
4# (c) 2004-06 Nick Whitelegg (Hogweed Software)                                #
5# Licenced under the Lesser GNU General Public Licence; see COPYING            #
6# for details.                                                                 #
7################################################################################
8//header("Content-type: text/xml");
9require_once('defines.php');
10//require_once('database.php');
11//define('OSM_LOGIN','NOT_NEEDED');
12
13// 15/03/06 now uses 0.3 API
14// 03/04/06 will now read local XML; takes bounding box to reject out-of-range
15// data
16
17#globals
18$inNode = $inSegment = $inWay = $inDoc =  false;
19$segments = array();
20$nodes = array();
21$ways = array();
22$curID = 0;
23$curNode = null;
24$curSeg = null;
25$curWay = null;
26$waySegs = null;
27$w = null;
28$s = null;
29$e = null;
30$n = null;
31#end globals
32
33/*
34$stuff = grabOSM(-0.75,51.02,-0.7,51.07,true);
35print_r($stuff);
36*/
37
38// $datasrc can be:
39// "osm" = grab data from OSM using the API
40// "file" = grab data from a local XML file
41// "db" = grab data from the database
42// $location is either an API URL or a local XML file
43
44function grabOSM($w0, $s0, $e0, $n0, $datasrc="db", $zoom=null, 
45                                $location="http://www.openstreetmap.org/api/0.3/map")
46{
47        $resp2=array("nodes"=>array(),"segments"=>array(),"ways"=>array());
48        // Pull out half of tiles above and to left of current tile to avoid
49        // cutting off labels
50        // Pull out half of tiles above and to left of current tile to avoid
51        // cutting off labels
52
53        // 0.5 is acceptable at zoom 13 and less
54        //$factor = ($zoom) ? 0.5 : (($zoom<13) ? 0.5 : 0.5*pow(2,$zoom-13));
55        $factor=0.5;
56
57        $w1 = $w0 - ($e0-$w0)*$factor;
58        $n1 = $n0 + ($n0-$s0)*$factor;
59        $e1= $e0 + ($e0-$w0)*$factor;
60        $s1 = $s0 - ($n0-$s0)*$factor;
61
62        switch($datasrc)
63        {
64
65                case "db": // grab from local database
66                        grab_direct_from_database($resp2,$w1,$s1,$e1,$n1);
67                        break;
68
69                case "osm": // grab from live OSM API
70                        $url = "$location?bbox=$w1,$s0,$e0,$n1";
71                        $ch=curl_init ($url);
72                        curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
73                        curl_setopt($ch,CURLOPT_HEADER,false);
74                        curl_setopt($ch,CURLOPT_USERPWD,OSM_LOGIN);
75                        $resp=curl_exec($ch);
76                        //echo $resp;
77                        curl_close($ch);
78                        $resp2 = parseOSM(explode("\n",$resp));
79                        break;
80
81                case "file": // grab from local file
82                        $resp2 = parseOSM($location,$w0,$s0,$e0,$n0);
83                        break;
84       
85        }
86        return $resp2;
87}
88
89function parseOSM($osm,$west=null,$south=null,$east=null,$north=null)
90{
91        global $segments, $nodes, $ways, $w, $s, $e, $n; 
92//      echo "parseOSM: osm = $osm<br/>";
93
94        // 030406 setup bounding box for XML
95//      echo "parseOSM: $osm $west $south $east $north<br/>";
96
97        $w=$west;
98        $s=$south;
99        $e=$east;
100        $n=$north;
101
102        $parser = xml_parser_create();
103        xml_set_element_handler($parser,"on_start_element","on_end_element");
104        xml_set_character_data_handler($parser,"on_characters");
105
106
107        if(is_array($osm))
108        {
109                foreach($osm as $line) 
110                {
111                        if (!xml_parse($parser,$line))
112                                return false;   
113                }
114        }
115        elseif(is_string($osm))
116        {
117                $fp = fopen($osm,"r");
118                $count=0;
119                while($line=fread($fp,4096))
120                {
121                        if(!xml_parse($parser,$line))
122                        {
123                                fclose($fp);
124                                return false;
125                        }
126                        $count++;
127                }
128                fclose($fp);
129        }
130
131        xml_parser_free($parser);
132
133        return array("segments"=>$segments, "nodes"=>$nodes, "ways"=>$ways);
134}
135
136#NB the PHP expat library reads in all tags as capitals - even if they're
137#lower case!!!
138function on_start_element($parser,$element,$attrs)
139{
140        global $inDoc, $inNode, $inSegment, $segments, $nodes, $curID, 
141                        $curNode, $curSeg, $inWay, $curWay, $waySegs,
142                        $w, $s, $e, $n;
143
144        if($element=="OSM" || $element=="osm")
145        {
146                $inDoc = true;
147        }
148        elseif($inDoc)
149        {
150                if($element=="NODE")
151                {
152                        $inNode=true;
153                        $curNode=null;
154                        if(include_data($attrs["LAT"],$attrs["LON"],$w,$s,$e,$n))
155                        {
156                                $curNode = array();
157                                $curNode["lat"] = $attrs["LAT"];
158                                $curNode["long"] = $attrs["LON"];
159                                $curNode['tags']=array();
160                                $curID = $attrs["ID"];
161                        }
162                }
163                elseif($element=="SEGMENT")
164                {
165                        $inSegment=true;
166                        $curSeg=null;
167                        if(isset($nodes[$attrs["FROM"]]) && isset($nodes[$attrs["TO"]]) &&
168                                (        include_data($nodes[$attrs["FROM"]]["lat"],
169                                                                  $nodes[$attrs["FROM"]]["long"],
170                                                                  $w,$s,$e,$n) || 
171                                         include_data($nodes[$attrs["TO"]]["lat"],
172                                                                  $nodes[$attrs["TO"]]["long"],
173                                                                  $w,$s,$e,$n) )
174                          )
175                        {
176                                //echo "INCLUDING SEGMENT<br/>";
177                                $curSeg = array();
178
179                                /*
180                                echo $nodes[$attrs["FROM"]]["lat"]." ";
181                                echo $nodes[$attrs["FROM"]]["long"]." ";
182                                echo $nodes[$attrs["TO"]]["long"]." ";
183                                echo $nodes[$attrs["TO"]]["long"]."<br/>";
184                                */
185
186
187                                $curSeg['from'] = $attrs["FROM"];
188                                $curSeg['to'] = $attrs["TO"];
189                                $curSeg['tags'] = array();
190                                /*
191                                $curSeg['tags']['foot'] = 'no';
192                                $curSeg['tags']['horse'] = 'no';
193                                $curSeg['tags']['bike'] = 'no';
194                                $curSeg['tags']['car'] = 'no';
195                                $curSeg['tags']['class'] = '';
196                                */
197                                $curID = $attrs["ID"];
198//                              echo "Including segment $curID\n";
199                        }
200                        else if(isset($nodes[$attrs["FROM"]]) 
201                        && isset($nodes[$attrs["TO"]]))
202                        {
203                                /*
204                                echo "NOT INCLUDING SEGMENT<br/>";
205
206                                echo $nodes[$attrs["FROM"]]["lat"]." ";
207                                echo $nodes[$attrs["FROM"]]["long"]." ";
208                                echo $nodes[$attrs["TO"]]["long"]." ";
209                                echo $nodes[$attrs["TO"]]["long"]."<br/>";
210                                */
211                        }
212                }
213                elseif($element=="WAY")
214                {
215                        $inWay = true;
216                        $waySegs = array();
217                        $curWay = array();
218                        $curWay['tags'] = array();
219                        /*
220                        $curWay['tags']['foot'] = 'no';
221                        $curWay['tags']['horse'] = 'no';
222                        $curWay['tags']['bike'] = 'no';
223                        $curWay['tags']['car'] = 'no';
224                        $curWay['tags']['class'] = '';
225                        */
226                        $curID = $attrs["ID"];
227                }
228                elseif($element=="SEG" && $inWay)
229                {
230                        $waySegs[] = $attrs["ID"];
231                }
232                       
233                // 0.3
234                elseif($element=="TAG")
235                {
236//                      echo "IN TAG<br/>";
237//                      print_r($attrs);
238//                      echo "<p></p>";
239                        // 070406 now all tags are put in the 'tags' array
240                        if($inNode && $curNode) 
241                        {
242                                //echo "Adding node<br/>";
243                                $curNode['tags'][$attrs['K']]=$attrs['V'];
244                        }
245                        elseif ($inSegment && $curSeg)
246                        {
247                                //echo "Adding segment<br/>";
248                                $curSeg['tags'][$attrs["K"]] = $attrs["V"];
249                        }
250                        elseif($inWay && $curWay)
251                        {
252                                //echo "Adding way<br/>";
253                                $curWay['tags'][$attrs["K"]] = $attrs["V"];
254                        }
255                }
256        }
257}
258
259function on_end_element($parser, $element)
260{
261        global $inNode, $nodes, $inSegment, $segments, $curSeg, $curNode, $curID,
262                        $inWay, $curWay, $ways, $waySegs;
263
264        if($element=='NODE')
265        {
266                $inNode = false;
267                if($curNode)
268                {
269                        $nodes[$curID] = $curNode; // 0.3 UID->ID
270                }
271        }
272        elseif($element=='SEGMENT')
273        {
274                $inSegment = false;
275                if($curSeg)
276                {
277                        $segments[$curID] = $curSeg;
278                }
279        }
280        elseif($element=='WAY')
281        {
282                $inWay = false;
283
284                //290306 keep a record of the IDs of the segment within a way
285                $curWay['segs'] = $waySegs;
286                # segments belonging to a way take on the way's attributes
287                # 070406 no longer done to maximise flexibility of this function
288                # In Freemap, now moved to classes.php, after we have got the data
289                /*
290                foreach($waySegs as $segID)
291                        $segments[$segID]['tags'] = $curWay['tags'];
292                        */
293                $ways[$curID] = $curWay;
294        }
295}
296
297
298function on_characters ($parser, $characters)
299{
300}
301
302function include_data($lat, $lon, $w, $s, $e, $n)
303{
304//      echo "LAT: $lat LON: $lon W:$w S:$s E:$e N:$n<br/>";
305        // Only test to include if we have a bounding box
306        if($w && $s && $e && $n)
307        {
308                return ($lat>=$s && $lat<=$n && $lon>=$w && $lon<=$e);
309                //return true;
310        }
311        return true;
312}
313
314function grab_direct_from_database (&$data, $west, $south, $east, $north)
315{
316
317        $conn=mysql_connect("localhost",DB_USERNAME,DB_PASSWORD);
318        mysql_select_db(DB_DBASE);
319
320        // Taken straight from streets.pl and dao.rb
321        $sql = "select id, latitude, longitude, visible, tags from ".
322           "nodes where latitude > $south  and latitude < $north ".
323           "and longitude > $west and longitude < $east ";
324
325        $clause=null;
326
327        $result = mysql_query($sql);
328        while ($row = mysql_fetch_array($result)) 
329        {
330
331                $curNode["lat"] = $row["latitude"];
332                $curNode["long"] = $row["longitude"];
333                $curNode["tags"] = get_tag_array($row["tags"]);
334                $data["nodes"][$row["id"]] = $curNode;
335
336                if (! $clause) 
337                {
338                        $clause .= $row["id"];
339                } 
340                else 
341                {
342                        $clause .= ',' . $row["id"];
343                }
344        }
345
346        // Also need nodes outside the bbox which belong to a segment inside
347
348        // Taken straight from streets.pl
349
350        /* 090406 Replace this call by the one below designed to get segments
351        which pass through the bounding box but with no nodes within
352        */
353       
354
355        $sql = "SELECT id, node_a, node_b, ".
356           "tags FROM segments ".
357           "where node_a IN ($clause) OR node_b IN ($clause) ".
358           "and visible = 1";
359
360        $result = mysql_query($sql);
361
362        // suppress error message
363        while($row=@mysql_fetch_array($result))
364        {
365                $curSeg["from"] = $row["node_a"];
366                $curSeg["to"] = $row["node_b"];
367                $segnodes[] = $row["node_a"];
368                $segnodes[] = $row["node_b"];
369                $curSeg["tags"] = get_tag_array($row["tags"]);
370                $data["segments"][$row["id"]] = $curSeg;
371        }
372
373        get_ways_from_segments($data,array_keys($data["segments"]));
374
375}
376
377// Adapted from same function in dao.rb
378
379function get_ways_from_segments(&$data,$segment_ids)
380{
381        if(count($segment_ids))
382        {
383        $type="way";
384        $segment_clause = "(".implode(",",$segment_ids).")";
385
386        $sql = "select id from ${type}_segments where segment_id in ".
387        "${segment_clause} group by id";
388
389        $result=mysql_query($sql) or die(mysql_error());
390        while($row=@mysql_fetch_array($result))
391        {
392                get_way($data,$row["id"]); 
393        }
394        }
395}
396
397// Adapted from same function in dao.rb
398
399function get_way(&$data,$way_id,$version=null) 
400{
401        $type="way";
402        $data["ways"][$way_id] = array();
403
404        $sql= "select k,v from ${type}_tags where id = $way_id";
405
406        // again remove version stuff and ".  "version = $version";
407
408        $result = mysql_query($sql);
409        $data["ways"][$way_id]["tags"] = array();
410        while($row=mysql_fetch_array($result))
411                $data["ways"][$way_id]["tags"][$row["k"]]=$row["v"];
412
413        // might this be quicker?  - NO
414        //$data["ways"][$way_id]["tags"] =$this->get_tag_array($row["tags"]);
415
416
417        $result = mysql_query("select segment_id as n from ${type}_segments ".
418                                "where id = $way_id");
419
420
421        $data["ways"][$way_id]["segs"]=array();
422        while($row=mysql_fetch_array($result))
423                $data["ways"][$way_id]["segs"][] = $row["n"];
424}
425
426function get_tag_array($tagstring)
427{
428        $tags=array();
429        $t = explode(";",$tagstring);
430        foreach ($t as $t1)
431        {
432                $t2 = explode("=",$t1);
433                if($t2 && $t2[0] && $t2[0]!="")
434                        $tags[$t2[0]] = $t2[1];
435        }
436        return $tags;
437}
438
439?>
Note: See TracBrowser for help on using the repository browser.