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