dev-util/idea-* minor fixes
[anomen-overlay.git] / www-apps / pmwiki / cookbook / Geobox / geobox.php
blobcd98daf3158bd972d23124d26cedb9e63fe09f90
1 <?php if (!defined('PmWiki')) exit();
3 /*
4 This script adds support for gps coordinates conversion and displaying at maps
5 - add (:geo [args] coords :) tag functionality
7 Copyright 2006-2011 Anomen (ludek_h@seznam.cz)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 TODO:
14 * GPX export (see sourceblock for howto)
18 $RecipeInfo['Geobox']['Version'] = '2012-09-07';
21 Markup('geo','fulltext','/\(:geo\s+((?:[dmsDMS,.]+:\s+)?(?:[a-z]+=\S+\s+)*)?(.*?)\s*:\)/e',
22 "geobox_maps(strtolower('$1'),'$2')");
24 SDV($GeoBoxDefaultFormat,'dm');
26 SDVA($GeoBoxLinks, array(
27 'maps.google.com'=>'http://maps.google.com/?q=$N%20$E',
28 'mapy.cz'=>'http://www.mapy.cz/?query=$N$LAT%20$E$LON',
29 'geocaching.com/maps'=>'http://www.geocaching.com/map/default.aspx?lat=$N&amp;lng=$E',
30 'geocaching.com/near'=>'http://www.geocaching.com/seek/nearest.aspx?lat=$N&amp;lng=$E&amp;f=1'
31 ));
33 function geobox_asint($m, $index)
35 $res = 0;
36 if (isset($m[$index])) {
37 $res = strtr($m[$index], ',', '.');
39 return $res;
42 function geobox_p()
44 global $Charset;
45 if (strtolower($Charset) == 'utf-8') {
46 $pat[0] = '°|˚|º|\*';
47 $pat[1] = '\'|’|′';
48 $pat[2] = '\'\'|\"|“|″|”|’’|';
49 } else {
50 $pat[0] = chr(0xB0) . '|\*';
51 $pat[1] = '\'';
52 $pat[2] = '\'\'|\"|';
54 return $pat;
56 function geobox_parse_coords($coords)
58 $pat = geobox_p();
59 $p0 = $pat[0];
60 $p1 = $pat[1];
61 $p2 = $pat[2];
62 $re_num = "\d+(?:[.,]\d*)?";
63 $re_coord="
64 ([-+]?${re_num})
65 \s*
66 (?:$p0||
67 (?:
68 (?:$p0)
69 \s*
70 (${re_num})
71 \s*
72 (?:$p1| |
73 (?:
74 (?:$p1)
75 \s*
76 (${re_num})
77 \s*
78 (?:$p2)
82 )?";
83 $regex_pre = "(N|S|)\s*(${re_coord})\s*;?\s*(E|W|)\s*(${re_coord})";
84 $regex_post = "()(${re_coord})\s*(N|S)\s*\;?s*(${re_coord})\s*(E|W)";
85 $m[] = array();
86 if (preg_match("/^\s*${regex_pre}\s*\$/xi", $coords, $m)) {
87 $res['result'] = 'PRE';
88 $res['pattern'] = $regex_pre;
90 else if (preg_match("/^\s*${regex_post}\s*\$/xi", $coords, $m)) {
91 $res['result'] = 'POST';
92 $res['pattern'] = $regex_post;
93 $m[1]=$m[6];$m[6]=$m[11]; // move directions
95 else {
96 $res['result'] = "";
99 $res[0] = abs(geobox_asint($m, 3)) + geobox_asint($m, 4)/60 + geobox_asint($m, 5)/(60*60);
100 $res[1] = abs(geobox_asint($m, 8)) + geobox_asint($m, 9)/60 + geobox_asint($m, 10)/(60*60);
102 if (geobox_asint($m, 3) < 0) { $res[0] = -$res[0]; }
103 if (geobox_asint($m, 8) < 0) { $res[1] = -$res[1]; }
105 if (strtoupper($m[1]) == 'S') { $res[0] = -$res[0]; }
106 if (strtoupper($m[6]) == 'W') { $res[1] = -$res[1]; }
109 return $res;
112 function geobox_floor0($foo)
114 if($foo > 0) { return floor($foo); }
115 else { return ceil($foo); }
118 function geobox_sign($foo)
120 return ($foo < 0) ? "-" : "";
123 function geobox_atan2($y, $x)
125 if ($y == 0) {
126 return ($x >= 0) ? 0 : pi();
128 return 2 * atan((sqrt($x*$x+$y*$y)-$x)/$y);
133 function geobox_convert_coords($c)
135 $c['LAT'] = ($c[0] > 0) ? "N" : "S";
136 $c['LON'] = ($c[1] > 0) ? "E" : "W";
138 $c['NSig'] = geobox_sign($c[0]);
139 $c['ESig'] = geobox_sign($c[1]);
141 $c['N'] = sprintf("%'08.5f",$c[0]);
142 $c['E'] = sprintf("%'08.5f",$c[1]);
143 $c['W'] = sprintf("%'08.5f",-$c[1]);
144 $c['S'] = sprintf("%'08.5f",-$c[0]);
145 $c['Nd'] = sprintf("%'08.5f",abs($c[0]));
146 $c['Ed'] = sprintf("%'08.5f",abs($c[1]));
148 // convert to [Ndi]°[Nmi]'[Ns]" and [Ndi]°[Nm]'
149 $c['Ndi'] = sprintf("%'02.0f",floor($c['Nd']));
150 $c['Ni'] = $c['NSig'] . $c['Ndi'];
151 $c['Nm'] = sprintf("%'06.3f",($c['Nd']-$c['Ndi'])*60);
152 $c['Nmi'] = sprintf("%'02.0f",floor($c['Nm']));
153 $s = ($c['Nd']*60);
154 $c['Ns'] = sprintf("%'06.3f",($s-floor($s))*60);
155 $c['Nsi'] = sprintf("%'02.0f",floor($c['Ns']));
157 $c['Edi'] = sprintf("%'03.0f",floor($c['Ed']));
158 $c['Ei'] = $c['ESig'] . $c['Edi'];
159 $c['Em'] = sprintf("%'06.3f",($c['Ed']-$c['Edi'])*60);
160 $c['Emi'] = sprintf("%'02.0f",floor($c['Em']));
161 $s = ($c['Ed']*60);
162 $c['Es'] = sprintf("%'06.3f",($s-floor($s))*60);
163 $c['Esi'] = sprintf("%'02.0f",floor($c['Es']));
165 return $c;
169 * Parses parameters and returns them in array.
171 * If parameter is specified by uniquely distinguishable substring of known
172 * parameter (e.g.: dist=10),
173 * full parameter value is also returned (e.g.: distance=10).
175 function geobox_parse_params($param)
177 $known_params = array('format', 'azimuth', 'distance');
179 $params = array('param' => $param);
181 $pairs = preg_split("/\s+/", $param, -1, PREG_SPLIT_NO_EMPTY);
182 foreach ($pairs as $p) {
183 $tokens=explode('=', $p);
184 if (strpos($tokens[0],":") !== false) {
185 $params['format'] = $tokens[0];
186 } else {
187 $params[$tokens[0]] = $tokens[1];
188 foreach ($known_params as $k) {
189 if (strpos($k, $tokens[0]) === 0) {
190 $params[$k] = $tokens[1];
196 return $params;
199 function geobox_build_link($link, $c)
201 return preg_replace('/\\$([A-Za-z]+)/e', '$c[\'$1\']', $link);
204 function geobox_maps($param, $coords_param)
206 global $GeoBoxDefaultFormat, $GeoBoxLinks;
208 $c = geobox_parse_coords($coords_param);
210 if (empty($c['result'])) {
211 return "[Invalid \"$coords_param\"]";
214 $params = geobox_parse_params($param);
215 $cformat = $params['format'];
217 if (!empty($params['azimuth']) || !empty($params['distance'])) {
218 if (is_numeric($params['azimuth']) && is_numeric($params['distance'])) {
219 $c = geobox_projection($c[0], $c[1], $params['azimuth'], $params['distance']);
220 } else {
221 return "[Invalid azimuth \"${params['azimuth']}\" or distance \"${params['distance']}\"]";
224 $c = geobox_convert_coords($c);
226 if (empty($cformat)) {
227 $cformat = $GeoBoxDefaultFormat;
229 if (strpos($cformat, "s") !== false) {
230 $COORDS=geobox_build_link('$NSig$Ndi&#176;$Nmi\'$Ns" $ESig$Edi&#176;$Emi\'$Es"', $c);// DMS
232 else if (strpos($cformat, "m") !== false) {
233 $COORDS=geobox_build_link('$NSig$Ndi&#176;$Nm\' $ESig$Edi&#176;$Em\'', $c);// DM
235 else {
236 $COORDS=geobox_build_link('$NSig$Nd&#176; $ESig$Ed&#176;', $c);//
239 $result = "$COORDS";
241 if (is_array($GeoBoxLinks) && !empty($GeoBoxLinks)) {
242 $result .= " - ";
243 foreach ($GeoBoxLinks as $t=>$l) {
244 $l = geobox_build_link($l, $c);
245 $result .= " [[$l | $t]]";
249 return $result;
253 * Calculates coordinates of point given by starting coordinates, azimuth and distance (meters).
254 * All angles are in degrees.
256 function geobox_projection($latitude_deg, $longtitude_deg, $azimuth_deg, $distance) {
258 //source: geocaching_tool2.xls
259 $ro = pi() / 180.0;
260 $R = 1.0/6378000;
261 $DR = $distance*$R;
262 $azimuth = $azimuth_deg*$ro;
263 $latitude = $latitude_deg*$ro;
265 $fi2 = sin($latitude)*cos($DR)+cos($latitude)*sin($DR)*cos($azimuth);
266 //echo "fi2=$fi2";
267 $lat = asin($fi2);
268 //echo "lat=$lat";
270 $x = (cos($DR)-sin($latitude)*sin($lat))/(cos($latitude)*cos($lat));
271 //echo "x=$x";
272 $y = sin($DR)*sin($azimuth)/cos($lat);
273 //echo "y=$y";
274 $la2 = geobox_atan2($y, $x);
275 //echo "la2=$la2";
276 $lon = $longtitude_deg + $la2/$ro;
277 //echo "lon=$lon";
279 $ret = array();
280 $ret[0] = $lat / $ro;
281 $ret[1] = $lon;
282 return $ret;