Commit | Line | Data |
---|---|---|
188cb5f8 | 1 | #!/usr/bin/php5-cgi |
2 | <?php | |
3 | ||
4 | /** | |
5 | * staticMapLite 0.03 | |
6 | * modded for RRZE settings -unrz191 2012-06-10 | |
7 | * | |
8 | * Copyright 2009 Gerhard Koch | |
9 | * | |
10 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
11 | * you may not use this file except in compliance with the License. | |
12 | * You may obtain a copy of the License at | |
13 | * | |
14 | * http://www.apache.org/licenses/LICENSE-2.0 | |
15 | * | |
16 | * Unless required by applicable law or agreed to in writing, software | |
17 | * distributed under the License is distributed on an "AS IS" BASIS, | |
18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
19 | * See the License for the specific language governing permissions and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @author Gerhard Koch <gerhard.koch AT ymail.com> | |
23 | * | |
24 | * USAGE: | |
25 | * | |
26 | * staticmap.php?center=40.714728,-73.998672&zoom=14&size=512x512&maptype=mapnik&markers=40.702147,-74.015794,blues|40.711614,-74.012318,greeng|40.718217,-73.998284,redc | |
27 | * | |
28 | */ | |
29 | ||
30 | error_reporting(0); | |
31 | ini_set('display_errors','off'); | |
32 | ||
33 | Class staticMapLite { | |
34 | ||
35 | protected $maxWidth = 2048; | |
36 | protected $maxHeight = 2048; | |
37 | ||
38 | protected $tileSize = 256; | |
39 | protected $tileSrcUrl = array( 'osmorg' => 'http://osm.rrze.fau.de/tiles/{Z}/{X}/{Y}.png', | |
668561ff UO |
40 | 'osmde' => 'http://osm.rrze.fau.de/osmde/{Z}/{X}/{Y}.png', |
41 | 'osmorglowzoom' => 'http://osm.rrze.fau.de/lowzoom/{Z}/{X}/{Y}.png', | |
42 | 'luftbilderl' => 'http://osm.rrze.fau.de/luftbilderl/{Z}/{X}/{Y}.png' | |
188cb5f8 | 43 | ); |
44 | ||
45 | protected $tileDefaultSrc = 'osmde'; | |
46 | protected $markerBaseDir = '/var/www/staticmaplite/images/markers'; | |
47 | protected $osmLogo = '/var/www/staticmaplite/images/osm_logo.png'; | |
48 | ||
49 | protected $markerPrototypes = array(// found at http://www.mapito.net/map-marker-icons.html | |
50 | 'lighblue' => array('regex'=>'/^lightblue([0-9]+)$/', | |
51 | 'extension'=>'.png', | |
52 | 'shadow'=>false, | |
53 | 'offsetImage'=>'0,-19', | |
54 | 'offsetShadow'=>false | |
55 | ), | |
56 | // openlayers std markers | |
57 | 'ol-marker'=> array('regex'=>'/^ol-marker(|-blue|-gold|-green)+$/', | |
58 | 'extension'=>'.png', | |
59 | 'shadow'=>'../marker_shadow.png', | |
60 | 'offsetImage'=>'-10,-25', | |
61 | 'offsetShadow'=>'-1,-13' | |
62 | ), | |
63 | // taken from http://www.visual-case.it/cgi-bin/vc/GMapsIcons.pl | |
64 | 'ylw'=> array('regex'=>'/^(pink|purple|red|ltblu|ylw)-pushpin$/', | |
65 | 'extension'=>'.png', | |
66 | 'shadow'=>'../marker_shadow.png', | |
67 | 'offsetImage'=>'-10,-32', | |
68 | 'offsetShadow'=>'-1,-13' | |
69 | ) | |
70 | ||
71 | ); | |
72 | ||
73 | ||
74 | ||
75 | # No point in caching - our source is localhost | |
76 | protected $useTileCache = false; | |
77 | protected $tileCacheBaseDir = 'cache/tiles'; | |
78 | ||
79 | protected $useMapCache = false; | |
80 | protected $mapCacheBaseDir = 'cache/maps'; | |
81 | protected $mapCacheID = ''; | |
82 | protected $mapCacheFile = ''; | |
83 | protected $mapCacheExtension = 'png'; | |
84 | ||
85 | protected $zoom, $lat, $lon, $width, $height, $markers, $image, $maptype; | |
86 | protected $centerX, $centerY, $offsetX, $offsetY; | |
87 | ||
88 | public function __construct(){ | |
89 | $this->zoom = 0; | |
90 | $this->lat = 0; | |
91 | $this->lon = 0; | |
92 | $this->width = 500; | |
93 | $this->height = 350; | |
94 | $this->markers = array(); | |
95 | $this->maptype = $this->tileDefaultSrc; | |
96 | } | |
97 | ||
98 | public function parseParams(){ | |
99 | global $_GET; | |
100 | ||
101 | // get zoom from GET paramter | |
102 | $this->zoom = $_GET['zoom']?intval($_GET['zoom']):0; | |
103 | if($this->zoom>18)$this->zoom = 18; | |
104 | ||
105 | // get lat and lon from GET paramter | |
106 | list($this->lat,$this->lon) = split(',',$_GET['center']); | |
107 | $this->lat = floatval($this->lat); | |
108 | $this->lon = floatval($this->lon); | |
109 | ||
110 | // get zoom from GET paramter | |
111 | if($_GET['size']){ | |
112 | list($this->width, $this->height) = split('x',$_GET['size']); | |
113 | $this->width = intval($this->width); | |
114 | if($this->width > $this->maxWidth) $this->width = $this->maxWidth; | |
115 | $this->height = intval($this->height); | |
116 | if($this->height > $this->maxHeight) $this->height = $this->maxHeight; | |
117 | } | |
118 | if($_GET['markers']){ | |
119 | $markers = split('%7C|\|',$_GET['markers']); | |
120 | foreach($markers as $marker){ | |
121 | list($markerLat, $markerLon, $markerType) = split(',',$marker); | |
122 | $markerLat = floatval($markerLat); | |
123 | $markerLon = floatval($markerLon); | |
124 | $markerType = basename($markerType); | |
125 | $this->markers[] = array('lat'=>$markerLat, 'lon'=>$markerLon, 'type'=>$markerType); | |
126 | } | |
127 | ||
128 | } | |
129 | if($_GET['maptype']){ | |
130 | if(array_key_exists($_GET['maptype'],$this->tileSrcUrl)) $this->maptype = $_GET['maptype']; | |
131 | } | |
132 | } | |
133 | ||
134 | public function lonToTile($long, $zoom){ | |
135 | return (($long + 180) / 360) * pow(2, $zoom); | |
136 | } | |
137 | ||
138 | public function latToTile($lat, $zoom){ | |
139 | return (1 - log(tan($lat * pi()/180) + 1 / cos($lat* pi()/180)) / pi()) /2 * pow(2, $zoom); | |
140 | } | |
141 | ||
142 | public function initCoords(){ | |
143 | $this->centerX = $this->lonToTile($this->lon, $this->zoom); | |
144 | $this->centerY = $this->latToTile($this->lat, $this->zoom); | |
145 | $this->offsetX = floor((floor($this->centerX)-$this->centerX)*$this->tileSize); | |
146 | $this->offsetY = floor((floor($this->centerY)-$this->centerY)*$this->tileSize); | |
147 | } | |
148 | ||
149 | public function createBaseMap(){ | |
150 | $this->image = imagecreatetruecolor($this->width, $this->height); | |
151 | $startX = floor($this->centerX-($this->width/$this->tileSize)/2); | |
152 | $startY = floor($this->centerY-($this->height/$this->tileSize)/2); | |
153 | $endX = ceil($this->centerX+($this->width/$this->tileSize)/2); | |
154 | $endY = ceil($this->centerY+($this->height/$this->tileSize)/2); | |
155 | $this->offsetX = -floor(($this->centerX-floor($this->centerX))*$this->tileSize); | |
156 | $this->offsetY = -floor(($this->centerY-floor($this->centerY))*$this->tileSize); | |
157 | $this->offsetX += floor($this->width/2); | |
158 | $this->offsetY += floor($this->height/2); | |
159 | $this->offsetX += floor($startX-floor($this->centerX))*$this->tileSize; | |
160 | $this->offsetY += floor($startY-floor($this->centerY))*$this->tileSize; | |
161 | ||
162 | for($x=$startX; $x<=$endX; $x++){ | |
163 | for($y=$startY; $y<=$endY; $y++){ | |
164 | $url = str_replace(array('{Z}','{X}','{Y}'),array($this->zoom, $x, $y), $this->tileSrcUrl[$this->maptype]); | |
165 | $tileData = $this->fetchTile($url); | |
166 | if($tileData){ | |
167 | $tileImage = imagecreatefromstring($tileData); | |
168 | } else { | |
169 | $tileImage = imagecreate($this->tileSize,$this->tileSize); | |
170 | $color = imagecolorallocate($tileImage, 255, 255, 255); | |
171 | @imagestring($tileImage,1,127,127,'err',$color); | |
172 | } | |
173 | $destX = ($x-$startX)*$this->tileSize+$this->offsetX; | |
174 | $destY = ($y-$startY)*$this->tileSize+$this->offsetY; | |
175 | imagecopy($this->image, $tileImage, $destX, $destY, 0, 0, $this->tileSize, $this->tileSize); | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | ||
181 | public function placeMarkers(){ | |
182 | // loop thru marker array | |
183 | foreach($this->markers as $marker){ | |
184 | // set some local variables | |
185 | $markerLat = $marker['lat']; | |
186 | $markerLon = $marker['lon']; | |
187 | $markerType = $marker['type']; | |
188 | // clear variables from previous loops | |
189 | $markerFilename = ''; | |
190 | $markerShadow = ''; | |
191 | $matches = false; | |
192 | // check for marker type, get settings from markerPrototypes | |
193 | if($markerType){ | |
194 | foreach($this->markerPrototypes as $markerPrototype){ | |
195 | if(preg_match($markerPrototype['regex'],$markerType,$matches)){ | |
196 | $markerFilename = $matches[0].$markerPrototype['extension']; | |
197 | if($markerPrototype['offsetImage']){ | |
198 | list($markerImageOffsetX, $markerImageOffsetY) = split(",",$markerPrototype['offsetImage']); | |
199 | } | |
200 | $markerShadow = $markerPrototype['shadow']; | |
201 | if($markerShadow){ | |
202 | list($markerShadowOffsetX, $markerShadowOffsetY) = split(",",$markerPrototype['offsetShadow']); | |
203 | } | |
204 | } | |
205 | } | |
206 | } | |
207 | ||
208 | // check required files or set default | |
209 | if($markerFilename == '' || !file_exists($this->markerBaseDir.'/'.$markerFilename)){ | |
210 | $markerIndex++; | |
211 | $markerFilename = 'lightblue'.$markerIndex.'.png'; | |
212 | $markerImageOffsetX = 0; | |
213 | $markerImageOffsetY = -19; } | |
214 | ||
215 | // create img resource | |
216 | if(file_exists($this->markerBaseDir.'/'.$markerFilename)){ | |
217 | $markerImg = imagecreatefrompng($this->markerBaseDir.'/'.$markerFilename); | |
218 | } else { | |
219 | $markerImg = imagecreatefrompng($this->markerBaseDir.'/lightblue1.png'); | |
220 | } | |
221 | ||
222 | // check for shadow + create shadow recource | |
223 | if($markerShadow && file_exists($this->markerBaseDir.'/'.$markerShadow)){ | |
224 | $markerShadowImg = imagecreatefrompng($this->markerBaseDir.'/'.$markerShadow); | |
225 | } | |
226 | ||
227 | // calc position | |
228 | $destX = floor(($this->width/2)-$this->tileSize*($this->centerX-$this->lonToTile($markerLon, $this->zoom))); | |
229 | $destY = floor(($this->height/2)-$this->tileSize*($this->centerY-$this->latToTile($markerLat, $this->zoom))); | |
230 | ||
231 | // copy shadow on basemap | |
232 | if($markerShadow && $markerShadowImg){ | |
233 | imagecopy($this->image, $markerShadowImg, $destX+intval($markerShadowOffsetX), $destY+intval($markerShadowOffsetY), | |
234 | 0, 0, imagesx($markerShadowImg), imagesy($markerShadowImg)); | |
235 | } | |
236 | ||
237 | // copy marker on basemap above shadow | |
238 | imagecopy($this->image, $markerImg, $destX+intval($markerImageOffsetX), $destY+intval($markerImageOffsetY), | |
239 | 0, 0, imagesx($markerImg), imagesy($markerImg)); | |
240 | ||
241 | }; | |
242 | } | |
243 | ||
244 | ||
245 | ||
246 | public function tileUrlToFilename($url){ | |
247 | return $this->tileCacheBaseDir."/".str_replace(array('http://'),'',$url); | |
248 | } | |
249 | ||
250 | public function checkTileCache($url){ | |
251 | $filename = $this->tileUrlToFilename($url); | |
252 | if(file_exists($filename)){ | |
253 | return file_get_contents($filename); | |
254 | } | |
255 | } | |
256 | ||
257 | public function checkMapCache(){ | |
258 | $this->mapCacheID = md5($this->serializeParams()); | |
259 | $filename = $this->mapCacheIDToFilename(); | |
260 | if(file_exists($filename)) return true; | |
261 | } | |
262 | ||
263 | public function serializeParams(){ | |
264 | return join("&",array($this->zoom,$this->lat,$this->lon,$this->width,$this->height, serialize($this->markers),$this->maptype)); | |
265 | } | |
266 | ||
267 | public function mapCacheIDToFilename(){ | |
268 | if(!$this->mapCacheFile){ | |
269 | $this->mapCacheFile = $this->mapCacheBaseDir."/".$this->maptype."/".$this->zoom."/cache_".substr($this->mapCacheID,0,2)."/".substr($this->mapCacheID,2,2)."/".substr($this->mapCacheID,4); | |
270 | } | |
271 | return $this->mapCacheFile.".".$this->mapCacheExtension; | |
272 | } | |
273 | ||
274 | ||
275 | ||
276 | public function mkdir_recursive($pathname, $mode){ | |
277 | is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); | |
278 | return is_dir($pathname) || @mkdir($pathname, $mode); | |
279 | } | |
280 | public function writeTileToCache($url, $data){ | |
281 | $filename = $this->tileUrlToFilename($url); | |
282 | $this->mkdir_recursive(dirname($filename),0777); | |
283 | file_put_contents($filename, $data); | |
284 | } | |
285 | ||
286 | public function fetchTile($url){ | |
287 | if($this->useTileCache && ($cached = $this->checkTileCache($url))) return $cached; | |
288 | $ch = curl_init(); | |
289 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
290 | curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0"); | |
291 | curl_setopt($ch, CURLOPT_URL, $url); | |
292 | $tile = curl_exec($ch); | |
293 | curl_close($ch); | |
294 | if($tile && $this->useTileCache){ | |
295 | $this->writeTileToCache($url,$tile); | |
296 | } | |
297 | return $tile; | |
298 | ||
299 | } | |
300 | ||
301 | public function copyrightNotice(){ | |
302 | $logoImg = imagecreatefrompng($this->osmLogo); | |
303 | imagecopy($this->image, $logoImg, imagesx($this->image)-imagesx($logoImg), imagesy($this->image)-imagesy($logoImg), 0, 0, imagesx($logoImg), imagesy($logoImg)); | |
304 | ||
305 | } | |
306 | ||
307 | public function sendHeader(){ | |
308 | header('Content-Type: image/png'); | |
309 | $expires = 60*60*24*14; | |
310 | header("Pragma: public"); | |
311 | header("Cache-Control: maxage=".$expires); | |
312 | header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$expires) . ' GMT'); | |
313 | } | |
314 | ||
315 | public function makeMap(){ | |
316 | $this->initCoords(); | |
317 | $this->createBaseMap(); | |
318 | if(count($this->markers))$this->placeMarkers(); | |
319 | if($this->osmLogo) $this->copyrightNotice(); | |
320 | } | |
321 | ||
322 | public function showMap(){ | |
323 | $this->parseParams(); | |
324 | if($this->useMapCache){ | |
325 | // use map cache, so check cache for map | |
326 | if(!$this->checkMapCache()){ | |
327 | // map is not in cache, needs to be build | |
328 | $this->makeMap(); | |
329 | $this->mkdir_recursive(dirname($this->mapCacheIDToFilename()),0777); | |
330 | imagepng($this->image,$this->mapCacheIDToFilename(),9); | |
331 | $this->sendHeader(); | |
332 | if(file_exists($this->mapCacheIDToFilename())){ | |
333 | return file_get_contents($this->mapCacheIDToFilename()); | |
334 | } else { | |
335 | return imagepng($this->image); | |
336 | } | |
337 | } else { | |
338 | // map is in cache | |
339 | $this->sendHeader(); | |
340 | return file_get_contents($this->mapCacheIDToFilename()); | |
341 | } | |
342 | ||
343 | } else { | |
344 | // no cache, make map, send headers and deliver png | |
345 | $this->makeMap(); | |
346 | $this->sendHeader(); | |
347 | return imagepng($this->image); | |
348 | ||
349 | } | |
350 | } | |
351 | ||
352 | } | |
353 | ||
354 | $map = new staticMapLite(); | |
355 | print $map->showMap(); | |
356 | ||
357 | ?> |