1628e43ccSMark Prins<?php 2628e43ccSMark Prins/* 3*d768c538SMark Prins * Copyright (c) 2012-2014 Mark C. Prins <mprins@users.sf.net> 4628e43ccSMark Prins * 5f4b9bdacSMark Prins * In part based on staticMapLite 0.03 available at http://staticmaplite.svn.sourceforge.net/viewvc/staticmaplite/ 6628e43ccSMark Prins * 7628e43ccSMark Prins * Copyright (c) 2009 Gerhard Koch <gerhard.koch AT ymail.com> 8628e43ccSMark Prins * 9628e43ccSMark Prins * Licensed under the Apache License, Version 2.0 (the "License"); 10628e43ccSMark Prins * you may not use this file except in compliance with the License. 11628e43ccSMark Prins * You may obtain a copy of the License at 12628e43ccSMark Prins * 13628e43ccSMark Prins * http://www.apache.org/licenses/LICENSE-2.0 14628e43ccSMark Prins * 15628e43ccSMark Prins * Unless required by applicable law or agreed to in writing, software 16628e43ccSMark Prins * distributed under the License is distributed on an "AS IS" BASIS, 17628e43ccSMark Prins * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18628e43ccSMark Prins * See the License for the specific language governing permissions and 19628e43ccSMark Prins * limitations under the License. 20628e43ccSMark Prins */ 21f4b9bdacSMark Prinsinclude_once(realpath(dirname(__FILE__)).'/../geophp/geoPHP/geoPHP.inc'); 22628e43ccSMark Prins/** 23628e43ccSMark Prins * @author Mark C. Prins <mprins@users.sf.net> 24628e43ccSMark Prins * @author Gerhard Koch <gerhard.koch AT ymail.com> 25628e43ccSMark Prins * 26628e43ccSMark Prins */ 27628e43ccSMark Prinsclass StaticMap { 28628e43ccSMark Prins // these should probably not be changed 29628e43ccSMark Prins protected $tileSize = 256; 30628e43ccSMark Prins 31628e43ccSMark Prins // the final output 32628e43ccSMark Prins var $doc = ''; 33628e43ccSMark Prins 34628e43ccSMark Prins protected $tileInfo = array( 35628e43ccSMark Prins // OSM sources 36628e43ccSMark Prins 'openstreetmap'=>array( 37628e43ccSMark Prins 'txt'=>'(c) OpenStreetMap CC-BY-SA', 38628e43ccSMark Prins 'logo'=>'osm_logo.png', 39628e43ccSMark Prins 'url'=>'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png'), 40628e43ccSMark Prins // cloudmade 41628e43ccSMark Prins 'cloudmade' =>array( 42628e43ccSMark Prins 'txt'=>'CloudMade tiles', 43628e43ccSMark Prins 'logo'=>'cloudmade_logo.png', 44628e43ccSMark Prins 'url'=> 'http://tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/2/256/{Z}/{X}/{Y}.png'), 45628e43ccSMark Prins 'fresh' =>array( 46628e43ccSMark Prins 'txt'=>'CloudMade tiles', 47628e43ccSMark Prins 'logo'=>'cloudmade_logo.png', 48628e43ccSMark Prins 'url'=> 'http://tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{Z}/{X}/{Y}.png'), 49628e43ccSMark Prins // OCM sources 50628e43ccSMark Prins 'cycle'=>array( 51628e43ccSMark Prins 'txt'=>'OpenCycleMap tiles', 52628e43ccSMark Prins 'logo'=>'cycle_logo.png', 53628e43ccSMark Prins 'url'=>'http://tile.opencyclemap.org/cycle/{Z}/{X}/{Y}.png'), 54628e43ccSMark Prins 'transport'=>array( 55628e43ccSMark Prins 'txt'=>'OpenCycleMap tiles', 56628e43ccSMark Prins 'logo'=>'cycle_logo.png', 57628e43ccSMark Prins 'url'=>'http://tile2.opencyclemap.org/transport/{Z}/{X}/{Y}.png'), 58628e43ccSMark Prins 'landscape'=>array( 59628e43ccSMark Prins 'txt'=>'OpenCycleMap tiles', 60628e43ccSMark Prins 'logo'=>'cycle_logo.png', 61628e43ccSMark Prins 'url'=>'http://tile3.opencyclemap.org/landscape/{Z}/{X}/{Y}.png'), 62628e43ccSMark Prins // H&B sources 63628e43ccSMark Prins 'hikeandbike'=>array( 64628e43ccSMark Prins 'txt'=>'Hike & Bike Map', 65628e43ccSMark Prins 'logo'=>'hnb_logo.png', 66628e43ccSMark Prins 'url'=>'http://toolserver.org/tiles/hikebike/{Z}/{X}/{Y}.png'), 67628e43ccSMark Prins //'piste'=>array( 68628e43ccSMark Prins // 'txt'=>'OpenPisteMap tiles', 69628e43ccSMark Prins // 'logo'=>'piste_logo.png', 70628e43ccSMark Prins // 'url'=>''), 71628e43ccSMark Prins //'sea'=>array( 72628e43ccSMark Prins // 'txt'=>'OpenSeaMap tiles', 73628e43ccSMark Prins // 'logo'=>'sea_logo.png', 74628e43ccSMark Prins // 'url'=>''), 75628e43ccSMark Prins // MapQuest 76628e43ccSMark Prins 'mapquest'=>array( 77628e43ccSMark Prins 'txt'=>'MapQuest tiles', 78628e43ccSMark Prins 'logo'=>'mq_logo.png', 797e0d6b41SMark Prins 'url'=>'http://otile3.mqcdn.com/tiles/1.0.0/map/{Z}/{X}/{Y}.png') 80628e43ccSMark Prins ); 81628e43ccSMark Prins protected $tileDefaultSrc = 'openstreetmap'; 82628e43ccSMark Prins 83628e43ccSMark Prins // set up markers 84628e43ccSMark Prins protected $markerPrototypes = array( 85628e43ccSMark Prins // found at http://www.mapito.net/map-marker-icons.html 86628e43ccSMark Prins // these are 17x19 px with a pointer at the bottom left 87628e43ccSMark Prins 'lighblue' => array('regex'=>'/^lightblue([0-9]+)$/', 88628e43ccSMark Prins 'extension'=>'.png', 89628e43ccSMark Prins 'shadow'=>false, 90628e43ccSMark Prins 'offsetImage'=>'0,-19', 91628e43ccSMark Prins 'offsetShadow'=>false 92628e43ccSMark Prins ), 93628e43ccSMark Prins // openlayers std markers are 21x25px with shadow 94628e43ccSMark Prins 'ol-marker'=> array('regex'=>'/^marker(|-blue|-gold|-green|-red)+$/', 95628e43ccSMark Prins 'extension'=>'.png', 96628e43ccSMark Prins 'shadow'=>'marker_shadow.png', 97628e43ccSMark Prins 'offsetImage'=>'-10,-25', 98628e43ccSMark Prins 'offsetShadow'=>'-1,-13' 99628e43ccSMark Prins ), 100628e43ccSMark Prins // these are 16x16 px 101628e43ccSMark Prins 'ww_icon'=> array('regex'=>'/ww_\S+$/', 102628e43ccSMark Prins 'extension'=>'.png', 103628e43ccSMark Prins 'shadow'=>false, 104628e43ccSMark Prins 'offsetImage'=>'-8,-8', 105628e43ccSMark Prins 'offsetShadow'=>false 106628e43ccSMark Prins ), 107628e43ccSMark Prins // assume these are 16x16 px 108628e43ccSMark Prins 'rest' => array('regex'=>'/^(?!lightblue([0-9]+)$)(?!(ww_\S+$))(?!marker(|-blue|-gold|-green|-red)+$)(.*)/', 109628e43ccSMark Prins 'extension'=>'.png', 110628e43ccSMark Prins 'shadow'=>'marker_shadow.png', 111628e43ccSMark Prins 'offsetImage'=>'-8,-8', 112628e43ccSMark Prins 'offsetShadow'=>'-1,-1' 113628e43ccSMark Prins ) 114628e43ccSMark Prins ); 115628e43ccSMark Prins protected $centerX, $centerY, $offsetX, $offsetY, $image; 1166914b920SMark Prins protected $zoom, $lat, $lon, $width, $height, $markers, $maptype, $kmlFileName, $gpxFileName, $geojsonFileName, $autoZoomExtent; 117628e43ccSMark Prins protected $tileCacheBaseDir, $mapCacheBaseDir, $mediaBaseDir; 118628e43ccSMark Prins protected $useTileCache = true; 119628e43ccSMark Prins protected $mapCacheID = ''; 120628e43ccSMark Prins protected $mapCacheFile = ''; 121628e43ccSMark Prins protected $mapCacheExtension = 'png'; 122628e43ccSMark Prins 123628e43ccSMark Prins /** 124f4b9bdacSMark Prins * Constructor. 1252d11d700SMark Prins * @param float $lat Latitude (x) of center of map 1262d11d700SMark Prins * @param float $lon Longitude (y) of center of map 1272d11d700SMark Prins * @param int $zoom Zoomlevel 1282d11d700SMark Prins * @param int $width Width in pixels 1292d11d700SMark Prins * @param int $height Height in pixels 1302d11d700SMark Prins * @param string $maptype Name of the map 1312d11d700SMark Prins * @param mixed $markers array of markers 1322d11d700SMark Prins * @param string $gpx GPX filename 1332d11d700SMark Prins * @param string $kml KML filename 1342d11d700SMark Prins * @param string $mediaDir Directory to store/cache maps 1352d11d700SMark Prins * @param string $tileCacheBaseDir Directory to cache map tiles 1362d11d700SMark Prins * @param boolean $autoZoomExtent Wheter or not to override zoom/lat/lon and zoom to the extent of gpx/kml and markers 137628e43ccSMark Prins */ 1386914b920SMark Prins public function __construct($lat, $lon, $zoom, $width, $height, $maptype, $markers, $gpx, $kml, $geojson, $mediaDir, $tileCacheBaseDir, $autoZoomExtent=TRUE){ 139628e43ccSMark Prins $this->zoom = $zoom; 140628e43ccSMark Prins $this->lat = $lat; 141628e43ccSMark Prins $this->lon = $lon; 142628e43ccSMark Prins $this->width = $width; 143628e43ccSMark Prins $this->height = $height; 144628e43ccSMark Prins // validate + set maptype 145628e43ccSMark Prins $this->maptype = $this->tileDefaultSrc; 146628e43ccSMark Prins if(array_key_exists($maptype,$this->tileInfo)) { 147628e43ccSMark Prins $this->maptype = $maptype; 148628e43ccSMark Prins } 1492d11d700SMark Prins $this->markers = $markers; 1502d11d700SMark Prins $this->kmlFileName = $kml; 1512d11d700SMark Prins $this->gpxFileName = $gpx; 1526914b920SMark Prins $this->geojsonFileName = $geojson; 1532d11d700SMark Prins $this->mediaBaseDir = $mediaDir; 154628e43ccSMark Prins $this->tileCacheBaseDir= $tileCacheBaseDir.'/olmaptiles'; 155628e43ccSMark Prins $this->useTileCache = $this->tileCacheBaseDir !==''; 156628e43ccSMark Prins $this->mapCacheBaseDir = $mediaDir.'/olmapmaps'; 1572d11d700SMark Prins $this->autoZoomExtent = $autoZoomExtent; 158628e43ccSMark Prins } 159628e43ccSMark Prins 160628e43ccSMark Prins /** 161628e43ccSMark Prins * 162628e43ccSMark Prins * @param number $long 163628e43ccSMark Prins * @param number $zoom 164f4b9bdacSMark Prins * @return number 165628e43ccSMark Prins */ 166628e43ccSMark Prins public function lonToTile($long, $zoom){ 167628e43ccSMark Prins return (($long + 180) / 360) * pow(2, $zoom); 168628e43ccSMark Prins } 169628e43ccSMark Prins /** 170628e43ccSMark Prins * 171628e43ccSMark Prins * @param number $lat 172628e43ccSMark Prins * @param number $zoom 173628e43ccSMark Prins * @return number 174628e43ccSMark Prins */ 175628e43ccSMark Prins public function latToTile($lat, $zoom){ 1762d11d700SMark Prins return (1 - log(tan($lat * pi()/180) + 1 / cos($lat* M_PI/180)) / M_PI) /2 * pow(2, $zoom); 177628e43ccSMark Prins } 178f4b9bdacSMark Prins 179628e43ccSMark Prins /** 180628e43ccSMark Prins * 181628e43ccSMark Prins */ 182628e43ccSMark Prins public function initCoords(){ 183628e43ccSMark Prins $this->centerX = $this->lonToTile($this->lon, $this->zoom); 184628e43ccSMark Prins $this->centerY = $this->latToTile($this->lat, $this->zoom); 185628e43ccSMark Prins $this->offsetX = floor((floor($this->centerX)-$this->centerX)*$this->tileSize); 186628e43ccSMark Prins $this->offsetY = floor((floor($this->centerY)-$this->centerY)*$this->tileSize); 187628e43ccSMark Prins } 188628e43ccSMark Prins 189628e43ccSMark Prins /** 190628e43ccSMark Prins * make basemap image. 191628e43ccSMark Prins */ 192628e43ccSMark Prins public function createBaseMap(){ 193628e43ccSMark Prins $this->image = imagecreatetruecolor($this->width, $this->height); 194628e43ccSMark Prins $startX = floor($this->centerX-($this->width/$this->tileSize)/2); 195628e43ccSMark Prins $startY = floor($this->centerY-($this->height/$this->tileSize)/2); 196628e43ccSMark Prins $endX = ceil($this->centerX+($this->width/$this->tileSize)/2); 197628e43ccSMark Prins $endY = ceil($this->centerY+($this->height/$this->tileSize)/2); 198628e43ccSMark Prins $this->offsetX = -floor(($this->centerX-floor($this->centerX))*$this->tileSize); 199628e43ccSMark Prins $this->offsetY = -floor(($this->centerY-floor($this->centerY))*$this->tileSize); 200628e43ccSMark Prins $this->offsetX += floor($this->width/2); 201628e43ccSMark Prins $this->offsetY += floor($this->height/2); 202628e43ccSMark Prins $this->offsetX += floor($startX-floor($this->centerX))*$this->tileSize; 203628e43ccSMark Prins $this->offsetY += floor($startY-floor($this->centerY))*$this->tileSize; 204628e43ccSMark Prins 205628e43ccSMark Prins for($x=$startX; $x<=$endX; $x++){ 206628e43ccSMark Prins for($y=$startY; $y<=$endY; $y++){ 207628e43ccSMark Prins $url = str_replace(array('{Z}','{X}','{Y}'),array($this->zoom, $x, $y), $this->tileInfo[$this->maptype]['url']); 208628e43ccSMark Prins $tileData = $this->fetchTile($url); 209628e43ccSMark Prins if($tileData){ 210628e43ccSMark Prins $tileImage = imagecreatefromstring($tileData); 211628e43ccSMark Prins } else { 212628e43ccSMark Prins $tileImage = imagecreate($this->tileSize,$this->tileSize); 213628e43ccSMark Prins $color = imagecolorallocate($tileImage, 255, 255, 255); 214628e43ccSMark Prins @imagestring($tileImage,1,127,127,'err',$color); 215628e43ccSMark Prins } 216628e43ccSMark Prins $destX = ($x-$startX)*$this->tileSize+$this->offsetX; 217628e43ccSMark Prins $destY = ($y-$startY)*$this->tileSize+$this->offsetY; 218628e43ccSMark Prins imagecopy($this->image, $tileImage, $destX, $destY, 0, 0, $this->tileSize, $this->tileSize); 219628e43ccSMark Prins } 220628e43ccSMark Prins } 221628e43ccSMark Prins } 222628e43ccSMark Prins 223628e43ccSMark Prins /** 224628e43ccSMark Prins * Place markers on the map and number them in the same order as they are listed in the html. 225628e43ccSMark Prins */ 226628e43ccSMark Prins public function placeMarkers(){ 227628e43ccSMark Prins $count=0; 228628e43ccSMark Prins $color=imagecolorallocate ($this->image,0,0,0 ); 229628e43ccSMark Prins $bgcolor=imagecolorallocate ($this->image,200,200,200 ); 230628e43ccSMark Prins $markerBaseDir = dirname(__FILE__).'/icons'; 231628e43ccSMark Prins // loop thru marker array 232628e43ccSMark Prins foreach($this->markers as $marker) { 233628e43ccSMark Prins // set some local variables 234628e43ccSMark Prins $markerLat = $marker['lat']; 235628e43ccSMark Prins $markerLon = $marker['lon']; 236628e43ccSMark Prins $markerType = $marker['type']; 237628e43ccSMark Prins // clear variables from previous loops 238628e43ccSMark Prins $markerFilename = ''; 239628e43ccSMark Prins $markerShadow = ''; 240628e43ccSMark Prins $matches = false; 241628e43ccSMark Prins // check for marker type, get settings from markerPrototypes 242628e43ccSMark Prins if($markerType){ 243628e43ccSMark Prins foreach($this->markerPrototypes as $markerPrototype){ 244628e43ccSMark Prins if(preg_match($markerPrototype['regex'],$markerType,$matches)){ 245628e43ccSMark Prins $markerFilename = $matches[0].$markerPrototype['extension']; 246628e43ccSMark Prins if($markerPrototype['offsetImage']){ 247628e43ccSMark Prins list($markerImageOffsetX, $markerImageOffsetY) = split(",",$markerPrototype['offsetImage']); 248628e43ccSMark Prins } 249628e43ccSMark Prins $markerShadow = $markerPrototype['shadow']; 250628e43ccSMark Prins if($markerShadow){ 251628e43ccSMark Prins list($markerShadowOffsetX, $markerShadowOffsetY) = split(",",$markerPrototype['offsetShadow']); 252628e43ccSMark Prins } 253628e43ccSMark Prins } 254628e43ccSMark Prins } 255628e43ccSMark Prins } 256628e43ccSMark Prins // create img resource 257628e43ccSMark Prins if(file_exists($markerBaseDir.'/'.$markerFilename)){ 258628e43ccSMark Prins $markerImg = imagecreatefrompng($markerBaseDir.'/'.$markerFilename); 259628e43ccSMark Prins } else { 260628e43ccSMark Prins $markerImg = imagecreatefrompng($markerBaseDir.'/marker.png'); 261628e43ccSMark Prins } 262628e43ccSMark Prins // check for shadow + create shadow recource 263628e43ccSMark Prins if($markerShadow && file_exists($markerBaseDir.'/'.$markerShadow)){ 264628e43ccSMark Prins $markerShadowImg = imagecreatefrompng($markerBaseDir.'/'.$markerShadow); 265628e43ccSMark Prins } 266628e43ccSMark Prins // calc position 267628e43ccSMark Prins $destX = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($markerLon, $this->zoom))); 268628e43ccSMark Prins $destY = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($markerLat, $this->zoom))); 269628e43ccSMark Prins // copy shadow on basemap 270628e43ccSMark Prins if($markerShadow && $markerShadowImg){ 271628e43ccSMark Prins imagecopy($this->image, $markerShadowImg, $destX+intval($markerShadowOffsetX), $destY+intval($markerShadowOffsetY), 272628e43ccSMark Prins 0, 0, imagesx($markerShadowImg), imagesy($markerShadowImg)); 273628e43ccSMark Prins } 274628e43ccSMark Prins // copy marker on basemap above shadow 275628e43ccSMark Prins imagecopy($this->image, $markerImg, $destX+intval($markerImageOffsetX), $destY+intval($markerImageOffsetY), 276628e43ccSMark Prins 0, 0, imagesx($markerImg), imagesy($markerImg)); 277628e43ccSMark Prins // add label 278628e43ccSMark Prins imagestring ($this->image , 3 , $destX-imagesx($markerImg)+1 , $destY+intval($markerImageOffsetY)+1 , ++$count , $bgcolor ); 279628e43ccSMark Prins imagestring ($this->image , 3 , $destX-imagesx($markerImg) , $destY+intval($markerImageOffsetY) , $count , $color ); 280628e43ccSMark Prins }; 281628e43ccSMark Prins } 28257e65445SMark Prins 283628e43ccSMark Prins /** 284628e43ccSMark Prins * 285628e43ccSMark Prins * @param string $url 286628e43ccSMark Prins * @return string 287628e43ccSMark Prins */ 288628e43ccSMark Prins public function tileUrlToFilename($url){ 289628e43ccSMark Prins return $this->tileCacheBaseDir."/".str_replace(array('http://'),'',$url); 290628e43ccSMark Prins } 29157e65445SMark Prins 292628e43ccSMark Prins /** 293628e43ccSMark Prins * 294628e43ccSMark Prins * @param string $url 295628e43ccSMark Prins */ 296628e43ccSMark Prins public function checkTileCache($url){ 297628e43ccSMark Prins $filename = $this->tileUrlToFilename($url); 298628e43ccSMark Prins if(file_exists($filename)){ 299628e43ccSMark Prins return file_get_contents($filename); 300628e43ccSMark Prins } 301628e43ccSMark Prins } 302628e43ccSMark Prins 303628e43ccSMark Prins public function checkMapCache(){ 304628e43ccSMark Prins $this->mapCacheID = md5($this->serializeParams()); 305628e43ccSMark Prins $filename = $this->mapCacheIDToFilename(); 306628e43ccSMark Prins if(file_exists($filename)) return true; 307628e43ccSMark Prins } 308628e43ccSMark Prins 309628e43ccSMark Prins public function serializeParams(){ 3106914b920SMark Prins return join("&",array($this->zoom,$this->lat,$this->lon,$this->width,$this->height, serialize($this->markers),$this->maptype, $this->kmlFileName, $this->gpxFileName, $this->geojsonFileName)); 311628e43ccSMark Prins } 312628e43ccSMark Prins 313628e43ccSMark Prins public function mapCacheIDToFilename(){ 314628e43ccSMark Prins if(!$this->mapCacheFile){ 315628e43ccSMark Prins $this->mapCacheFile = $this->mapCacheBaseDir."/".$this->maptype."/".$this->zoom."/cache_".substr($this->mapCacheID,0,2)."/".substr($this->mapCacheID,2,2)."/".substr($this->mapCacheID,4); 316628e43ccSMark Prins } 317628e43ccSMark Prins return $this->mapCacheFile.".".$this->mapCacheExtension; 318628e43ccSMark Prins } 31957e65445SMark Prins 3202d11d700SMark Prins /** 3212d11d700SMark Prins * Recursively create the directory. 3222d11d700SMark Prins * @param string $pathname The directory path. 3232d11d700SMark Prins * @param int $mode File access mode. For more information on modes, read the details on the chmod manpage. 3242d11d700SMark Prins */ 325628e43ccSMark Prins public function mkdir_recursive($pathname, $mode){ 326628e43ccSMark Prins is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); 327628e43ccSMark Prins return is_dir($pathname) || @mkdir($pathname, $mode); 328628e43ccSMark Prins } 329628e43ccSMark Prins 3302d11d700SMark Prins /** 3312d11d700SMark Prins * Write a tile into the cache. 3322d11d700SMark Prins * @param string $url 3332d11d700SMark Prins * @param mixed $data 3342d11d700SMark Prins */ 335628e43ccSMark Prins public function writeTileToCache($url, $data){ 336628e43ccSMark Prins $filename = $this->tileUrlToFilename($url); 337628e43ccSMark Prins $this->mkdir_recursive(dirname($filename),0777); 338628e43ccSMark Prins file_put_contents($filename, $data); 339628e43ccSMark Prins } 34057e65445SMark Prins 3412d11d700SMark Prins /** 3422d11d700SMark Prins * Fetch a tile and (if configured) store it in the cache. 3432d11d700SMark Prins * @param string $url 3442d11d700SMark Prins */ 345628e43ccSMark Prins public function fetchTile($url){ 346628e43ccSMark Prins if($this->useTileCache && ($cached = $this->checkTileCache($url))) return $cached; 347e4f115f4SMark Prins 348e4f115f4SMark Prins $_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; '.PHP_OS.')'; 349e4f115f4SMark Prins if(function_exists("curl_init")){ 350e4f115f4SMark Prins // use cUrl 351628e43ccSMark Prins $ch = curl_init(); 352628e43ccSMark Prins curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 353e4f115f4SMark Prins curl_setopt($ch, CURLOPT_USERAGENT, $_UA); 354628e43ccSMark Prins curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 355628e43ccSMark Prins curl_setopt($ch, CURLOPT_URL, $url); 356628e43ccSMark Prins $tile = curl_exec($ch); 357628e43ccSMark Prins curl_close($ch); 358e4f115f4SMark Prins } else { 359e4f115f4SMark Prins // use file_get_contents 360e4f115f4SMark Prins global $conf; 361e4f115f4SMark Prins $opts = array( 362e4f115f4SMark Prins 'http'=>array( 363e4f115f4SMark Prins 'method'=>"GET", 364e4f115f4SMark Prins 'header'=>"Accept-language: en\r\n" . 365e4f115f4SMark Prins "User-Agent: $_UA\r\n". 366e4f115f4SMark Prins "accept: image/png\r\n", 367e4f115f4SMark Prins 'proxy' => "tcp://".$conf['proxy']['host'] . ":" . $conf['proxy']['port'], 368e4f115f4SMark Prins 'request_fulluri' => true, 369e4f115f4SMark Prins ) 370e4f115f4SMark Prins ); 371e4f115f4SMark Prins $context = stream_context_create($opts); 372e4f115f4SMark Prins $tile = file_get_contents($url, false, $context); 373e4f115f4SMark Prins } 374628e43ccSMark Prins if($tile && $this->useTileCache){ 375628e43ccSMark Prins $this->writeTileToCache($url,$tile); 376628e43ccSMark Prins } 377628e43ccSMark Prins return $tile; 378628e43ccSMark Prins } 379628e43ccSMark Prins 380628e43ccSMark Prins /** 381628e43ccSMark Prins * Draw gpx trace on the map. 382628e43ccSMark Prins */ 383628e43ccSMark Prins public function drawGPX(){ 384c977deacSMark Prins $col = imagecolorallocatealpha($this->image, 0, 0, 255, .4*127); 3856c6bb022SMark Prins $gpxgeom = geoPHP::load(file_get_contents($this->gpxFileName),'gpx'); 386c977deacSMark Prins $this->drawGeometry($gpxgeom, $col); 387628e43ccSMark Prins } 388628e43ccSMark Prins 3896914b920SMark Prins /** 3906914b920SMark Prins * Draw geojson on the map. 3916914b920SMark Prins */ 3926914b920SMark Prins public function drawGeojson(){ 3936914b920SMark Prins $col = imagecolorallocatealpha($this->image, 255, 0, 255, .4*127); 3946914b920SMark Prins $gpxgeom = geoPHP::load(file_get_contents($this->geojsonFileName),'json'); 3956914b920SMark Prins $this->drawGeometry($gpxgeom, $col); 3966914b920SMark Prins } 39757e65445SMark Prins 398628e43ccSMark Prins /** 399628e43ccSMark Prins * Draw kml trace on the map. 400628e43ccSMark Prins */ 401628e43ccSMark Prins public function drawKML(){ 4022d11d700SMark Prins // TODO get colour from kml node (not currently supported in geoPHP) 403c977deacSMark Prins $col = imagecolorallocatealpha($this->image, 255, 0, 0, .4*127); 404c977deacSMark Prins $kmlgeom = geoPHP::load(file_get_contents($this->kmlFileName),'kml'); 405c977deacSMark Prins $this->drawGeometry($kmlgeom, $col); 406c977deacSMark Prins } 40757e65445SMark Prins 408c977deacSMark Prins /** 409c977deacSMark Prins * Draw geometry or geometry collection on the map. 410c977deacSMark Prins * @param Geometry $geom 411c977deacSMark Prins * @param int $colour drawing colour 412c977deacSMark Prins */ 413c977deacSMark Prins private function drawGeometry($geom, $colour){ 4146c6bb022SMark Prins switch ($geom->geometryType()) { 415c977deacSMark Prins case 'GeometryCollection': 416c977deacSMark Prins // recursively draw part of the collection 417c977deacSMark Prins for ($i = 1; $i < $geom->numGeometries()+1; $i++) { 418c977deacSMark Prins $_geom = $geom->geometryN($i); 419c977deacSMark Prins $this->drawGeometry($_geom, $colour); 420c977deacSMark Prins } 4216c6bb022SMark Prins break; 422c977deacSMark Prins case 'MultiPolygon': 423c977deacSMark Prins // TODO implement / do nothing 424c977deacSMark Prins break; 425c977deacSMark Prins case 'MultiLineString': 426c977deacSMark Prins // TODO implement / do nothing 427c977deacSMark Prins break; 428c977deacSMark Prins case 'MultiPoint': 429c977deacSMark Prins // TODO implement / do nothing 4306c6bb022SMark Prins break; 4316c6bb022SMark Prins case 'Polygon': 432c977deacSMark Prins $this->drawPolygon($geom, $colour); 433c977deacSMark Prins break; 434c977deacSMark Prins case 'LineString': 435c977deacSMark Prins $this->drawLineString($geom, $colour); 436c977deacSMark Prins break; 437c977deacSMark Prins case 'Point': 438c977deacSMark Prins $this->drawPoint($geom, $colour); 4396c6bb022SMark Prins break; 4406c6bb022SMark Prins default: 4412d11d700SMark Prins //draw nothing 4426c6bb022SMark Prins break; 4436c6bb022SMark Prins } 4446c6bb022SMark Prins } 445c977deacSMark Prins 446e61425c7SMark Prins /** 447e61425c7SMark Prins * Draw a line on the map. 448e61425c7SMark Prins * @param LineString $line 449c977deacSMark Prins * @param int $colour drawing colour 450e61425c7SMark Prins */ 451da6f229fSMark Prins private function drawLineString($line, $colour){ 452cc74a83cSMark Prins imagesetthickness($this->image,2); 453da6f229fSMark Prins for ($p = 1; $p < $line->numGeometries(); $p++) { 454da6f229fSMark Prins // get first pair of points 455da6f229fSMark Prins $p1 = $line->geometryN($p); 456da6f229fSMark Prins $p2 = $line->geometryN($p+1); 457da6f229fSMark Prins // translate to paper space 458da6f229fSMark Prins $x1 = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($p1->x(), $this->zoom))); 459da6f229fSMark Prins $y1 = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($p1->y(), $this->zoom))); 460da6f229fSMark Prins $x2 = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($p2->x(), $this->zoom))); 461da6f229fSMark Prins $y2 = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($p2->y(), $this->zoom))); 462da6f229fSMark Prins // draw to image 463da6f229fSMark Prins imageline ($this->image, $x1, $y1, $x2, $y2, $colour); 464da6f229fSMark Prins } 465e61425c7SMark Prins imagesetthickness($this->image,1); 466da6f229fSMark Prins } 467c977deacSMark Prins 468e61425c7SMark Prins /** 469e61425c7SMark Prins * Draw a point on the map. 470e61425c7SMark Prins * @param Point $point 471c977deacSMark Prins * @param int $colour drawing colour 472e61425c7SMark Prins */ 473da6f229fSMark Prins private function drawPoint($point, $colour){ 474c977deacSMark Prins imagesetthickness($this->image,2); 475da6f229fSMark Prins // translate to paper space 476da6f229fSMark Prins $cx = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($point->x(), $this->zoom))); 477da6f229fSMark Prins $cy = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($point->y(), $this->zoom))); 478cc74a83cSMark Prins $r = 5; 479da6f229fSMark Prins // draw to image 480cc74a83cSMark Prins // imageellipse($this->image, $cx, $cy,$r, $r, $colour); 481cc74a83cSMark Prins imagefilledellipse ($this->image, $cx, $cy, $r, $r, $colour); 482cc74a83cSMark Prins // don't use imageellipse because the imagesetthickness function has 483c977deacSMark Prins // no effect. So the better workaround is to use imagearc. 484cc74a83cSMark Prins imagearc($this->image, $cx, $cy, $r, $r, 0, 359, $colour); 485e61425c7SMark Prins imagesetthickness($this->image,1); 486da6f229fSMark Prins } 487c977deacSMark Prins 488e61425c7SMark Prins /** 489e61425c7SMark Prins * Draw a polygon on the map. 490e61425c7SMark Prins * @param Polygon $polygon 491c977deacSMark Prins * @param int $colour drawing colour 492e61425c7SMark Prins */ 493e61425c7SMark Prins private function drawPolygon($polygon, $colour){ 494c977deacSMark Prins // TODO implementation of drawing holes, 495c977deacSMark Prins // maybe draw the polygon to an in-memory image and use imagecopy, draw polygon in col., draw holes in bgcol? 496c977deacSMark Prins 497c977deacSMark Prins //print_r('Polygon:<br />'); 498c977deacSMark Prins //print_r($polygon); 499c977deacSMark Prins 500c977deacSMark Prins $extPoints = array(); 501c977deacSMark Prins // extring is a linestring actually.. 502c977deacSMark Prins $extRing = $polygon->exteriorRing(); 503c977deacSMark Prins 504c977deacSMark Prins for ($i = 1; $i < $extRing->numGeometries(); $i++) { 505c977deacSMark Prins $p1 = $extRing->geometryN($i); 506c977deacSMark Prins $x = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($p1->x(), $this->zoom))); 507c977deacSMark Prins $y = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($p1->y(), $this->zoom))); 508c977deacSMark Prins $extPoints[]=$x; 509c977deacSMark Prins $extPoints[]=$y; 510e61425c7SMark Prins } 511c977deacSMark Prins //print_r('points:('.($i-1).')<br />'); 512c977deacSMark Prins //print_r($extPoints); 513c977deacSMark Prins //imagepolygon ($this->image, $extPoints, $i-1, $colour ); 514c977deacSMark Prins imagefilledpolygon($this->image, $extPoints, $i-1, $colour ); 515c977deacSMark Prins } 516c977deacSMark Prins 517628e43ccSMark Prins /** 518628e43ccSMark Prins * add copyright and origin notice and icons to the map. 519628e43ccSMark Prins */ 520628e43ccSMark Prins public function drawCopyright(){ 521628e43ccSMark Prins $logoBaseDir = dirname(__FILE__).'/'.'logo/'; 522628e43ccSMark Prins $logoImg = imagecreatefrompng($logoBaseDir.$this->tileInfo['openstreetmap']['logo']); 523628e43ccSMark Prins $textcolor = imagecolorallocate($this->image, 0, 0, 0); 524628e43ccSMark Prins $bgcolor = imagecolorallocate($this->image, 200, 200, 200); 525628e43ccSMark Prins 5262d11d700SMark Prins imagecopy($this->image, $logoImg, 0, imagesy($this->image)-imagesy($logoImg), 0, 0, imagesx($logoImg), imagesy($logoImg)); 527628e43ccSMark Prins imagestring($this->image , 1, imagesx($logoImg)+2 ,imagesy($this->image)-imagesy($logoImg)+1 ,$this->tileInfo['openstreetmap']['txt'], $bgcolor ); 528628e43ccSMark Prins imagestring($this->image , 1, imagesx($logoImg)+1 ,imagesy($this->image)-imagesy($logoImg) ,$this->tileInfo['openstreetmap']['txt'] ,$textcolor ); 529628e43ccSMark Prins 530628e43ccSMark Prins // additional tile source info, ie. who created/hosted the tiles 531628e43ccSMark Prins if ($this->maptype!='openstreetmap') { 532628e43ccSMark Prins $iconImg = imagecreatefrompng($logoBaseDir.$this->tileInfo[$this->maptype]['logo']); 5332d11d700SMark Prins imagecopy($this->image, $iconImg, imagesx($logoImg)+1, imagesy($this->image)-imagesy($iconImg), 0, 0, imagesx($iconImg), imagesy($iconImg)); 534628e43ccSMark Prins imagestring($this->image, 1, imagesx($logoImg)+imagesx($iconImg)+4, imagesy($this->image)-ceil(imagesy($logoImg)/2)+1, $this->tileInfo[$this->maptype]['txt'], $bgcolor ); 535628e43ccSMark Prins imagestring($this->image, 1, imagesx($logoImg)+imagesx($iconImg)+3, imagesy($this->image)-ceil(imagesy($logoImg)/2), $this->tileInfo[$this->maptype]['txt'], $textcolor ); 536628e43ccSMark Prins } 537628e43ccSMark Prins } 538cc74a83cSMark Prins 539628e43ccSMark Prins /** 540628e43ccSMark Prins * make the map. 541628e43ccSMark Prins */ 542628e43ccSMark Prins public function makeMap(){ 543628e43ccSMark Prins $this->initCoords(); 544628e43ccSMark Prins $this->createBaseMap(); 545e4f115f4SMark Prins if(!empty($this->markers))$this->placeMarkers(); 546628e43ccSMark Prins if(file_exists($this->kmlFileName)) $this->drawKML(); 547628e43ccSMark Prins if(file_exists($this->gpxFileName)) $this->drawGPX(); 5486914b920SMark Prins if(file_exists($this->geojsonFileName)) $this->drawGeojson(); 5496914b920SMark Prins 550628e43ccSMark Prins $this->drawCopyright(); 551628e43ccSMark Prins } 552cc74a83cSMark Prins 553628e43ccSMark Prins /** 554e4f115f4SMark Prins * Calculate the lat/lon/zoom values to make sure that all of the markers and gpx/kml are on the map. 5552d11d700SMark Prins * @param float $paddingFactor buffer constant to enlarge (>1.0) the zoom level 5562d11d700SMark Prins */ 5572d11d700SMark Prins private function autoZoom($paddingFactor=1.0){ 5582d11d700SMark Prins $geoms = array(); 559e4f115f4SMark Prins $geoms[] = new Point($this->lon, $this->lat); 560e4f115f4SMark Prins if(!empty($this->markers)){ 5612d11d700SMark Prins foreach($this->markers as $marker){ 5622d11d700SMark Prins $geoms[] = new Point($marker['lon'],$marker['lat']); 5632d11d700SMark Prins } 5642d11d700SMark Prins } 5652d11d700SMark Prins if(file_exists($this->kmlFileName)){ 5662d11d700SMark Prins $geoms[] = geoPHP::load(file_get_contents($this->kmlFileName),'kml'); 5672d11d700SMark Prins } 5682d11d700SMark Prins if(file_exists($this->gpxFileName)) { 5692d11d700SMark Prins $geoms[] = geoPHP::load(file_get_contents($this->gpxFileName),'gpx'); 5702d11d700SMark Prins } 5716914b920SMark Prins if(file_exists($this->geojsonFileName)) { 5726914b920SMark Prins $geoms[] = geoPHP::load(file_get_contents($this->geojsonFileName),'geojson'); 5736914b920SMark Prins } 5746914b920SMark Prins 575e4f115f4SMark Prins if (count($geoms)<=1) return; 57653bfe4a3SMark Prins 5772d11d700SMark Prins $geom = new GeometryCollection($geoms); 5782d11d700SMark Prins $centroid=$geom->centroid(); 5792d11d700SMark Prins $bbox=$geom->getBBox(); 5802d11d700SMark Prins 5812d11d700SMark Prins // determine vertical resolution, this depends on the distance from the equator 5822d11d700SMark Prins // $vy00 = log(tan(M_PI*(0.25 + $centroid->getY()/360))); 5832d11d700SMark Prins $vy0 = log(tan(M_PI*(0.25 + $bbox['miny']/360))); 5842d11d700SMark Prins $vy1 = log(tan(M_PI*(0.25 + $bbox['maxy']/360))); 58553bfe4a3SMark Prins $zoomFactorPowered = ($this->height/2) / (40.7436654315252 * ($vy1 - $vy0)); 5862d11d700SMark Prins $resolutionVertical = 360 / ($zoomFactorPowered * $this->tileSize); 5872d11d700SMark Prins // determine horizontal resolution 5882d11d700SMark Prins $resolutionHorizontal = ($bbox['maxx']-$bbox['minx']) / $this->width; 5892d11d700SMark Prins $resolution = max($resolutionHorizontal, $resolutionVertical) * $paddingFactor; 5902d11d700SMark Prins $zoom = log(360 / ($resolution * $this->tileSize), 2); 5912d11d700SMark Prins 5922d11d700SMark Prins $this->zoom = floor($zoom); 5932d11d700SMark Prins $this->lon=$centroid->getX(); 5942d11d700SMark Prins $this->lat=$centroid->getY(); 5952d11d700SMark Prins } 5962d11d700SMark Prins 5972d11d700SMark Prins /** 598628e43ccSMark Prins * get the map, this may return a reference to a cached copy. 599628e43ccSMark Prins * @return string url relative to media dir 600628e43ccSMark Prins */ 601628e43ccSMark Prins public function getMap(){ 6022d11d700SMark Prins if($this->autoZoomExtent) $this->autoZoom() ; 6032d11d700SMark Prins 604628e43ccSMark Prins // use map cache, so check cache for map 605628e43ccSMark Prins if(!$this->checkMapCache()){ 606628e43ccSMark Prins // map is not in cache, needs to be build 607628e43ccSMark Prins $this->makeMap(); 608628e43ccSMark Prins $this->mkdir_recursive(dirname($this->mapCacheIDToFilename()),0777); 609628e43ccSMark Prins imagepng($this->image,$this->mapCacheIDToFilename(),9); 610628e43ccSMark Prins } 611628e43ccSMark Prins $this->doc =$this->mapCacheIDToFilename(); 612628e43ccSMark Prins // make url relative to media dir 613628e43ccSMark Prins return str_replace($this->mediaBaseDir, '', $this->doc); 614628e43ccSMark Prins } 615628e43ccSMark Prins} 616