diff --git a/gmap.module b/gmap.module index b31869d..b57199f 100644 --- a/gmap.module +++ b/gmap.module @@ -1178,6 +1178,12 @@ function gmap_map_cleanup(&$map) { list($map['latitude'],$map['longitude']) = explode(',',$map['latlon']); } unset($map['latlon']); + // convert gpx data to markers and polygons + if (isset($map['gpx']) && function_exists('gmap_gpx_parse_file')) { + $gpxdata = gmap_gpx_parse_file($map['gpx']); + gmap_gpx_data2map($map, $gpxdata); + unset($map['gpx']); + } } function theme_gmap_coord($element) { @@ -1369,3 +1375,6 @@ function gmap_decimal($num) { // Otherwise, cast to float, possibly losing precision. return (float) $num; } + +// we now can parse gpx files +require_once(drupal_get_path('module','gmap') .'/gmap_gpx.inc'); diff --git a/gmap_gpx.inc b/gmap_gpx.inc new file mode 100755 index 0000000..f19509e --- /dev/null +++ b/gmap_gpx.inc @@ -0,0 +1,216 @@ +data); + } + + $fp = fopen($gpxfile, "r"); + if (!$fp) return NULL; + + $data = fgets($fp, 8192); + while (!feof($fp)) { + $data .= fgets($fp, 8192); + } + fclose($fp); + + $gpxdata = gmap_gpx_parse($data); + if ($gpxdata) { + cache_set($cid, 'cache', serialize($gpxdata), CACHE_TEMPORARY); + } + + return $gpxdata; +} + +/** + * parse the data-string for gpx info + * @returns gpx data array on success, NULL on failure + */ +function gmap_gpx_parse(&$data) { + global $gmap_gpx; + + $parser = drupal_xml_parser_create($data); + xml_set_element_handler($parser, '_gmap_gpx_start_element', '_gmap_gpx_stop_element'); + xml_set_character_data_handler($parser, '_gmap_gpx_char_data'); + + $gmap_gpx = array ('stack' => array ()); + $r = xml_parse($parser, $data, true); //$buf, feof($fp)); + xml_parser_free($parser); + + if ($r) { + unset($gmap_gpx['stack']); + $r =& $gmap_gpx; + unset($gmap_gpx); + return $r; + } + + return null; +} + +function gmap_gpx_data2map(&$map, &$gpxdata) { + + $c = is_array($gpxdata['wpt']) ? count($gpxdata['wpt']) : 0; + for ($i = 0; $i <= $c; $i++) { + $wp =& $gpxdata['wpt'][$i]; + $m = array('latitude' => $wp['lat'], 'longitude' => $wp['lon']); + if ($wp['name']) $m['opts']['title'] = $wp['name']; + $map['markers'][] = $m; + // TODO: select icon from $wp['sym'] and $wp['type'] + } + + if (is_array($gpxdata['rte'])) { // 0..n routes + $c = count($gpxdata['rte']); + for ($i = 0; $i < $c; $i++) { + _gmap_gpx_add_wp_poly($map, $gpxdata['rte'][$i]); + } + } + + if (is_array($gpxdata['trk'])) { // 0..n tracks with 1..m segments + $c = count($gpxdata['trk']); + for ($i = 0; $i < $c; $i++) { + $c2 = count($gpxdata['trk'][$i]); + for ($j = 0; $j < $c; $j++) { + _gmap_gpx_add_wp_poly($map, $gpxdata['trk'][$i][$j]); + } + } + } + + // TODO: make sure we don't screw up around 180 degrees + if ($gpxdata['bounds']) { + $lat = ($gpxdata['bounds']['minlat'] + $gpxdata['bounds']['maxlat']) / 2; + $lon = ($gpxdata['bounds']['minlon'] + $gpxdata['bounds']['maxlon']) / 2; + $map['latitude'] = $lat; + $map['longitude'] = $lon; + } +} + +function _gmap_gpx_add_wp_poly(&$map, &$wpa) { + $c = count($wpa); + $s = array('type' => 'polygon', 'points' => array()); + for ($i = 0; $i < $c; $i++) { + $wp = $wpa[$i]; + $s['points'][] = array('latitude' => $wp['lat'], 'longitude' => $wp['lon']); + } + $map['shapes'][] = $s; +} + +/** + * the paths to tags representing waypoint types nodes + */ +function _gmap_gpx_wp_elements() { + static $wpa = array ( + 'GPX WPT' => 1, + 'GPX RTE RTEPT' => 1, + 'GPX TRK TRKSEG TRKPT' => 1, + ); + return $wpa; +} + +function _gmap_gpx_start_element(&$parser, $name, $attrs) { + global $gmap_gpx; + $wpa = _gmap_gpx_wp_elements(); + $path = join(' ', $gmap_gpx['stack']) . ' ' . $name; + + //if (($path == 'GPX WPT') || ($path == 'GPX RTE RTEPT') || ($path == 'GPX TRK TRKSEG TRKPT')) { + if (isset ($wpa[$path])) { + $gmap_gpx['waypoint'] = array ( + 'lat' => $attrs['LAT'], + 'lon' => $attrs['LON'], + //'lat_pretty' => _gmap_gpx_latlon_pretty($attrs['LAT'], 'N', 'S'), + //'lon_pretty' => _gmap_gpx_latlon_pretty($attrs['LON'], 'E', 'W', true), + ); + $gmap_gpx['wp_cont'] = strtolower($name); + } + elseif (isset($gmap_gpx['waypoint']) && ($name == 'EXTENSIONS')) { + $gmap_gpx['in_extension'] = true; + } + elseif ($path == 'GPX BOUNDS') { + foreach ($attrs as $key => $val) { + $gmap_gpx['bounds'][strtolower($key)] = $val; + } + } + + $gmap_gpx['char_data'] = ''; + $gmap_gpx['stack'][] = $name; +} + +function _gmap_gpx_stop_element(&$parser, $name) { + global $gmap_gpx; + $wpa = _gmap_gpx_wp_elements(); + + $path = join(' ', $gmap_gpx['stack']); + array_pop($gmap_gpx['stack']); // remove $name from stack + + $cname = $gmap_gpx['wp_cont']; + if (isset($wpa[$path])) { + $gmap_gpx[$cname][] = $gmap_gpx['waypoint']; + unset($gmap_gpx['waypoint']); + unset($gmap_gpx['wp_cont']); + } + elseif (isset($gmap_gpx['waypoint'])) { + if ($gmap_gpx['in_extension']) { + if ($name == 'EXTENSIONS') unset($gmap_gpx['in_extension']); + return; + } + if ($name == 'TIME') { + $gmap_gpx['waypoint']['time'] = strtotime($gmap_gpx['char_data']); + } + else { + $gmap_gpx['waypoint'][strtolower($name)] = $gmap_gpx['char_data']; + } + } + elseif ($path == 'GPX RTE') { + $gmap_gpx['rte'][] = $gmap_gpx['rtept']; + unset($gmap_gpx['rtept']); + } + elseif ($path == 'GPX TRK TRKSEG') { + $gmap_gpx['trkseg'][] = $gmap_gpx['trkpt']; + unset($gmap_gpx['trkpt']); + } + elseif ($path == 'GPX TRK') { + $gmap_gpx['trk'][] = $gmap_gpx['trkseg']; + unset($gmap_gpx['trkseg']); + } + + unset($gmap_gpx['char_data']); +} + +function _gmap_gpx_char_data(&$parser, $data) { + global $gmap_gpx; + $gmap_gpx['char_data'] .= $data; +} + +function _gmap_gpx_latlon_pretty($deg, $pos, $neg, $three = false) { + if ($deg > 0) { + $str = $pos; + } else { + $str = $neg; + $deg = - $deg; + } + + $d = $deg; + settype($d, 'integer'); + $deg -= $d; + if ($three && $d < 100) + $str .= '0'; + if ($d < 10) + $str .= '0'; + $str .= $d . '°'; + + $deg *= 60; + $deg *= 1000; + settype($deg, 'integer'); + $deg /= 1000; + $str .= $deg . "'"; + + return $str; +}