<?php if (!defined('PmWiki')) exit(); /* Use http://www.topomap.co.nz/ to display an excerpt from a map in PmWiki + | Copyright 2013 Simon Davis | This program is free software; you can redistribute it and/or modify it under the terms of the | GNU General Public License, Version 2, as published by the Free Software Foundation. | http://www.gnu.org/copyleft/gpl.html | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + # 2013-07-15 Initial version */ # Version date $RecipeInfo['NZTopo']['Version'] = '2013-07-19'; $FmtPV['$NZTopoVersion'] = "'NZTopo version {$RecipeInfo['NZTopo']['Version']}'"; // return version as a custom page variable SDV($NZTopoZoom, 12); # set default zoom factor # declare $NZTopo for (:if enabled NZTopo:) recipe installation check global $NZTopo; $NZTopo = 1; ## Add a custom markup # (:nztopo ll=-41.293722,174.871482 :) # (:nztopo topo50=BP33912708,BP33876687 height=300 width=400 pin=1 label='destination' float=right clear=both zoom=12:) # directive arguments are # ll= -- decimal latitude,longitude # llbs = -- -- decimal latitude,longitude;latitude,longitude $vlat = '[-+]?\d{1,2}[.]\d+'; # -90 .. 90 $vlong = '[-+]?[1]?\d{1,2}[.]\d+'; # -180 .. 180 $vlatlong = $vlat . '[,]' . $vlong; # latitude,longitude $pll = 'll=' . $vlatlong; $pllbs = 'llbs=' . $vlatlong . '(?:[;]' . $vlatlong . ')+'; # two or more pairs of lat long co-ordinates # nztm $vnztm = '\d{7}[.]\d{0,3}'; # single NZTM co-ordinate $vnztm2 = $vnztm . '[,]' . $vnztm; # pair of NZTM co-ordinates, easting, northing $pnzne = 'nzne=' . $vnztm2; $pnzbs = 'nzbs=' . $vnztm2 . '(?:[;]' . $vnztm2 . ')+'; # two or more pairs of NZTM co-ordinates # topo50= -- topo50 grid coordinate, or two grid coordinates (not currently implemented in nztopomap $ptopo50 = 'topo50=[ABC][A-Z][0-4]\d{7}(?:[,][ABC][A-Z][0-4]\d{7})?'; # -- only one of topo50, ll, llbs, nzne, nzbs,, kml or gpx can be supplied $vscheme = '(?:https?|ftp):\/\/'; # $vurl = '(?:(?:\'' . $vscheme . '[^\']+\')|(?:"' . $vscheme . '[^"]+"))'; # provide for single and double quoted strings # kml= -- URL to kml file $pkml = 'kml=' . $vurl; # kml= -- URL to kml file $pgpx = 'gpx=' . $vurl; # height= -- image height in pixels $pheight = 'height=\d{1,5}'; # width= -- image width in pixels $pwidth = 'width=\d{1,5}'; # pin= -- show pin $ppin = 'pin=[01]'; # label -- tool tip label for pin $plabel = 'label=(?:(?:\'[^\']+\')|(?:"[^"]+")|(?:\w+))'; # provide for single and double quoted strings, and unquoted string # zoom= -- scale factor for map $pzoom = 'zoom=\d{1,2}'; # float= -- left or right $pfloat = 'float=(?:left|right)'; # clear= -- left, right, both $pclear = 'clear=(?:left|right|both)'; # only one location can be supplied $qlocale = '(?:' . $pll . ')|(?:' . $pllbs . ')|(?:' . $pkml . ')|(?:' . $pgpx . ')|(?:' . $pnzne . ')|(?:' . $pnzbs . ')'; # display modifications $qmods = "(" . $pheight . ")\s*|(" . $pwidth . ")\s*|(" . $ppin . ")\s*|(" . $plabel . ")\s*|(" . $pzoom . ")\s*|(" . $pfloat . ")\s*|(" . $pclear . ")\s*"; # Markup( 'NZTopo', 'directives', "/\\(:nztopo (" . $qlocale . ")\s*(?:" . $qmods . "){0,7}\s*:\\)/ei", # "Keep(NZTopo_Parse(PSS('$1'), PSS('$2'), PSS('$3'), PSS('$4'), PSS('$5'), PSS('$6'), PSS('$7'), PSS('$8'), PSS('$9')))" ); # s = dot matches all chars including newline # e = backreference substitution by expression # i = case insensitive # m = multiline # uses lazy evaluation, preserves leading and trailing white space # Keep prevents PmWiki markup being applied # $debugon = false; # debug /** Main NZTopo parser * /param arguements as documented above * /return The HTML-formatted NZTopo markup wrapped in a <div> of class "nztopo", see http://www.topomap.co.nz/. */ function NZTopo_Parse($p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9) { # global $NZTopoZoom; global $debugon; # for debug // Initialise variables $retval = ''; # return value $opt = ParseArgs($p1 . ' ' . $p2 . ' ' . $p3 . ' ' . $p4 . ' ' . $p5 . ' ' . $p6 . ' ' . $p7 . ' ' . $p8 . ' ' . $p9); $version = 2; # fixed version of nztopomap interface $newwin = 1; # open map in new window $ppcm = 80; # 80 pixels per centrimetre to provide base scale for maps $width = $opt['width']; # iframe parameter $height = $opt['height']; # iframe parameter $float = $opt['float'] ? 'float:' . $opt['float'] . ';' : ""; # div parameter $clear = $opt['clear'] ? 'clear:' . $opt['clear'] . ';' : ""; # div parameter $pdiv = $clear . $float ? ' style="' . $clear . $float . '"' : ""; // query string parameters $bllbs = (boolean) $opt['llbs']; if( $bllbs ) { # get size of map in km list ($widthkm, $heightkm, $dbgval) = llbskm($opt['llbs']); $retval .= $dbgval; $width = max ($widthkm * $ppcm, $width); # override height $height = max ($heightkm * $ppcm, $width); # override height } $query = ''; $query .= '&new=' . $newwin; $query .= $opt['ll'] ? '&ll=' . $opt['ll'] : ""; $query .= $opt['llbs'] ? '&llbs=' . $opt['llbs'] : ""; $query .= $opt['topo50'] ? '&topo50=' . $opt['topo50'] : ""; $query .= $opt['nzbs'] ? '&nzbs=' . $opt['nzbs'] : ""; $query .= $opt['nzne'] ? '&nzne=' . $opt['nzne'] : ""; $query .= $opt['kml'] ? '&kml=' . rawurlencode($opt['kml']) : ""; $query .= $opt['gpx'] ? '&gpx=' . rawurlencode($opt['gpx']) : ""; $query .= $opt['pin'] ? '&pin=' . $opt['pin'] : ""; $query .= $opt['label'] ? '&lbl=' . rawurlencode(htmlentities($opt['label'])) : ""; # double url encode unicode chars for them to work with the topo map $query .= $opt['zoom'] ? '&z=' . $opt['zoom'] : '&z=' . $NZTopoZoom; $awidth = $width ? ' width="' . $width . '"' : ""; # iframe parameter $aheight = $height ? ' height="' . $height . '"' : ""; # iframe parameter $src = 'http://www.topomap.co.nz/NZTopoMapEmbedded?&v=' . $version . $query; $retval .= '<div class="nztopo"' . $pdiv . '>' . "\n"; $retval .= '<iframe seamless frameborder="0" scrolling="no" marginheight="0" marginwidth="0"' . $awidth . $aheight . ' src="' . $src . '">'; $retval .= "\n" . '</iframe>' . $width . '+' . $height; $retval .= '</div>' . "\n"; /* example HTML for nztopomap <iframe width="300" height="300" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://www.topomap.co.nz/NZTopoMapEmbedded?v=2&ll=-41.293722,174.871482&z=15&pin=1"></iframe> */ if( $debugon ) { $retval .= '<div style="font-size:smaller;">p1=' . $p1 . ' p2=' . $p2 . ' p3=' . $p3 . ' p4=' . $p4 . ' p5=' . $p5 . ' p6=' . $p6 . ' p7=' . $p7 . ' p8=' . $p8 . ' p9=' . $p9 . '</br>' . "\n"; $retval .= 'src=' . $src . '</div>' . "\n"; } return $retval; } # NZTopo_Parse function llbskm($llbs) { global $debugon; # for debug $dbgval = ''; $latlngs = preg_split ('/[,;]/', $llbs); $lats = array_filter($latlngs, "odd"); $lngs = array_filter($latlngs, "even"); $maxlat = max ($lats); $maxlng = max ($lngs); $minlat = min ($lats); $minlng = min ($lngs); /* rectangle coordinates are (lat/long) left: right: top: max/min max/max bot: min/min min/max */ $width1 = distance ($maxlat, $minlng, $maxlat, $maxlng); $width2 = distance ($minlat, $minlng, $minlat, $maxlng); $height1 = distance ($maxlat, $minlng, $minlat, $minlng); $height2 = distance ($maxlat, $maxlng, $minlat, $maxlng); $widthkm = ceil (max ($width1, $width2)); # take largest width and round up to km $heightkm = ceil (max ($height1, $height2)); # take largest height and round up to km if( $debugon ) { $dbgval .= '<small>lats="' . var_export ($lats, TRUE) . '"</small></br>' . "\n"; $dbgval .= '<small>lngs="' . implode ('", "', $lngs) . '"</small></br>' . "\n"; $dbgval .= '<small>minlat=' . $minlat . ', maxlat=' . $maxlat . ', minlng=' . $minlng . ', maxlng=' . $maxlng . '</small></br>' . "\n"; $dbgval .= '<small>w1=' . $width1 . ', w2=' . $width2 . ', h1=' . $height1 . ', h2=' . $height2 . ', w=' . $widthkm . ', h=' . $heightkm . '</small></br>' . "\n"; } return array ($widthkm, $heightkm, $dbgval); } # http://snipplr.com/view/2531/ function distance($lat1, $lng1, $lat2, $lng2) { $pi80 = M_PI / 180; $lat1 *= $pi80; $lng1 *= $pi80; $lat2 *= $pi80; $lng2 *= $pi80; $r = 6372.797; // mean radius of Earth in km $dlat = $lat2 - $lat1; $dlng = $lng2 - $lng1; $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); $km = $r * $c; return $km; } # distance function odd($var) { // returns whether the input integer is odd return($var % 2); } # odd function even($var) { // returns whether the input integer is even return(!($var % 2)); } # even