Passed
Pull Request — master (#8)
by Mark
02:40
created
StaticMap.php 2 patches
Indentation   +907 added lines, -907 removed lines patch added patch discarded remove patch
@@ -34,911 +34,911 @@
 block discarded – undo
34 34
 class StaticMap
35 35
 {
36 36
 
37
-    // the final output
38
-    private $tileSize = 256;
39
-    private $tileInfo = array(
40
-        // OSM sources
41
-        'openstreetmap' => array(
42
-            'txt'  => '(c) OpenStreetMap data/ODbl',
43
-            'logo' => 'osm_logo.png',
44
-            'url'  => 'https://tile.openstreetmap.org/{Z}/{X}/{Y}.png'
45
-        ),
46
-        // OCM sources
47
-        'cycle'         => array(
48
-            'txt'  => '(c) Thunderforest maps',
49
-            'logo' => 'tf_logo.png',
50
-            'url'  => 'https://tile.thunderforest.com/cycle/{Z}/{X}/{Y}.png'
51
-        ),
52
-        'transport'     => array(
53
-            'txt'  => '(c) Thunderforest maps',
54
-            'logo' => 'tf_logo.png',
55
-            'url'  => 'https://tile.thunderforest.com/transport/{Z}/{X}/{Y}.png'
56
-        ),
57
-        'landscape'     => array(
58
-            'txt'  => '(c) Thunderforest maps',
59
-            'logo' => 'tf_logo.png',
60
-            'url'  => 'https://tile.thunderforest.com/landscape/{Z}/{X}/{Y}.png'
61
-        ),
62
-        'outdoors'      => array(
63
-            'txt'  => '(c) Thunderforest maps',
64
-            'logo' => 'tf_logo.png',
65
-            'url'  => 'https://tile.thunderforest.com/outdoors/{Z}/{X}/{Y}.png'
66
-        ),
67
-        'toner-lite'    => array(
68
-            'txt'  => 'Stamen tiles',
69
-            'logo' => 'stamen.png',
70
-            'url'  => 'https://stamen-tiles.a.ssl.fastly.net/toner/{Z}/{X}/{Y}.png'
71
-        ),
72
-        'terrain'       => array(
73
-            'txt'  => 'Stamen tiles',
74
-            'logo' => 'stamen.png',
75
-            'url'  => 'https://stamen-tiles.a.ssl.fastly.net/terrain/{Z}/{X}/{Y}.jpg'
76
-        )
77
-        //,
78
-        // 'piste'=>array(
79
-        // 'txt'=>'OpenPisteMap tiles',
80
-        // 'logo'=>'piste_logo.png',
81
-        // 'url'=>''),
82
-        // 'sea'=>array(
83
-        // 'txt'=>'OpenSeaMap tiles',
84
-        // 'logo'=>'sea_logo.png',
85
-        // 'url'=>''),
86
-        // H&B sources
87
-        //          'hikeandbike' => array (
88
-        //                  'txt' => 'Hike & Bike Map',
89
-        //                  'logo' => 'hnb_logo.png',
90
-        //                  //'url' => 'http://toolserver.org/tiles/hikebike/{Z}/{X}/{Y}.png'
91
-        //                  //moved to: https://www.toolserver.org/tiles/hikebike/12/2105/1388.png
92
-        //                  'url' => 'http://c.tiles.wmflabs.org/hikebike/{Z}/{X}/{Y}.png'
93
-        //          )
94
-    );
95
-    private $tileDefaultSrc = 'openstreetmap';
96
-
97
-    // set up markers
98
-    private $markerPrototypes = array(
99
-        // found at http://www.mapito.net/map-marker-icons.html
100
-        // these are 17x19 px with a pointer at the bottom left
101
-        'lightblue' => array(
102
-            'regex'        => '/^lightblue([0-9]+)$/',
103
-            'extension'    => '.png',
104
-            'shadow'       => false,
105
-            'offsetImage'  => '0,-19',
106
-            'offsetShadow' => false
107
-        ),
108
-        // openlayers std markers are 21x25px with shadow
109
-        'ol-marker' => array(
110
-            'regex'        => '/^marker(|-blue|-gold|-green|-red)+$/',
111
-            'extension'    => '.png',
112
-            'shadow'       => 'marker_shadow.png',
113
-            'offsetImage'  => '-10,-25',
114
-            'offsetShadow' => '-1,-13'
115
-        ),
116
-        // these are 16x16 px
117
-        'ww_icon'   => array(
118
-            'regex'        => '/ww_\S+$/',
119
-            'extension'    => '.png',
120
-            'shadow'       => false,
121
-            'offsetImage'  => '-8,-8',
122
-            'offsetShadow' => false
123
-        ),
124
-        // assume these are 16x16 px
125
-        'rest'      => array(
126
-            'regex'        => '/^(?!lightblue([0-9]+)$)(?!(ww_\S+$))(?!marker(|-blue|-gold|-green|-red)+$)(.*)/',
127
-            'extension'    => '.png',
128
-            'shadow'       => 'marker_shadow.png',
129
-            'offsetImage'  => '-8,-8',
130
-            'offsetShadow' => '-1,-1'
131
-        )
132
-    );
133
-    private $centerX;
134
-    private $centerY;
135
-    private $offsetX;
136
-    private $offsetY;
137
-    private $image;
138
-    private $zoom;
139
-    private $lat;
140
-    private $lon;
141
-    private $width;
142
-    private $height;
143
-    private $markers;
144
-    private $maptype;
145
-    private $kmlFileName;
146
-    private $gpxFileName;
147
-    private $geojsonFileName;
148
-    private $autoZoomExtent;
149
-    private $apikey;
150
-    private $tileCacheBaseDir;
151
-    private $mapCacheBaseDir;
152
-    private $mediaBaseDir;
153
-    private $useTileCache;
154
-    private $mapCacheID = '';
155
-    private $mapCacheFile = '';
156
-    private $mapCacheExtension = 'png';
157
-
158
-    /**
159
-     * Constructor.
160
-     *
161
-     * @param float  $lat
162
-     *            Latitude (x) of center of map
163
-     * @param float  $lon
164
-     *            Longitude (y) of center of map
165
-     * @param int    $zoom
166
-     *            Zoomlevel
167
-     * @param int    $width
168
-     *            Width in pixels
169
-     * @param int    $height
170
-     *            Height in pixels
171
-     * @param string $maptype
172
-     *            Name of the map
173
-     * @param array  $markers
174
-     *            array of markers
175
-     * @param string $gpx
176
-     *            GPX filename
177
-     * @param string $kml
178
-     *            KML filename
179
-     * @param string $geojson
180
-     * @param string $mediaDir
181
-     *            Directory to store/cache maps
182
-     * @param string $tileCacheBaseDir
183
-     *            Directory to cache map tiles
184
-     * @param bool   $autoZoomExtent
185
-     *            Wheter or not to override zoom/lat/lon and zoom to the extent of gpx/kml and markers
186
-     * @param string $apikey
187
-     */
188
-    public function __construct(
189
-        float $lat,
190
-        float $lon,
191
-        int $zoom,
192
-        int $width,
193
-        int $height,
194
-        string $maptype,
195
-        array $markers,
196
-        string $gpx,
197
-        string $kml,
198
-        string $geojson,
199
-        string $mediaDir,
200
-        string $tileCacheBaseDir,
201
-        bool $autoZoomExtent = true,
202
-        string $apikey = ''
203
-    ) {
204
-        $this->zoom   = $zoom;
205
-        $this->lat    = $lat;
206
-        $this->lon    = $lon;
207
-        $this->width  = $width;
208
-        $this->height = $height;
209
-        // validate + set maptype
210
-        $this->maptype = $this->tileDefaultSrc;
211
-        if (array_key_exists($maptype, $this->tileInfo)) {
212
-            $this->maptype = $maptype;
213
-        }
214
-        $this->markers          = $markers;
215
-        $this->kmlFileName      = $kml;
216
-        $this->gpxFileName      = $gpx;
217
-        $this->geojsonFileName  = $geojson;
218
-        $this->mediaBaseDir     = $mediaDir;
219
-        $this->tileCacheBaseDir = $tileCacheBaseDir . '/olmaptiles';
220
-        $this->useTileCache     = $this->tileCacheBaseDir !== '';
221
-        $this->mapCacheBaseDir  = $mediaDir . '/olmapmaps';
222
-        $this->autoZoomExtent   = $autoZoomExtent;
223
-        $this->apikey           = $apikey;
224
-    }
225
-
226
-    /**
227
-     * get the map, this may return a reference to a cached copy.
228
-     *
229
-     * @return string url relative to media dir
230
-     */
231
-    public function getMap(): string
232
-    {
233
-        try {
234
-            if ($this->autoZoomExtent) {
235
-                $this->autoZoom();
236
-            }
237
-        } catch (Exception $e) {
238
-            Logger::debug($e);
239
-        }
240
-
241
-        // use map cache, so check cache for map
242
-        if (!$this->checkMapCache()) {
243
-            // map is not in cache, needs to be build
244
-            $this->makeMap();
245
-            $this->mkdirRecursive(dirname($this->mapCacheIDToFilename()), 0777);
246
-            imagepng($this->image, $this->mapCacheIDToFilename(), 9);
247
-        }
248
-        $doc = $this->mapCacheIDToFilename();
249
-        // make url relative to media dir
250
-        return str_replace($this->mediaBaseDir, '', $doc);
251
-    }
252
-
253
-    /**
254
-     * Calculate the lat/lon/zoom values to make sure that all of the markers and gpx/kml are on the map.
255
-     * can throw an error like
256
-     * "Fatal error: Uncaught Exception: Cannot create a collection with non-geometries in
257
-     * D:\www\wild-water.nl\www\dokuwiki\lib\plugins\geophp\geoPHP\lib\geometry\Collection.class.php:29"
258
-     *
259
-     * @param float $paddingFactor
260
-     *            buffer constant to enlarge (>1.0) the zoom level
261
-     * @throws Exception
262
-     */
263
-    private function autoZoom(float $paddingFactor = 1.0): void
264
-    {
265
-        $geoms    = array();
266
-        $geoms [] = new Point ($this->lon, $this->lat);
267
-        if (!empty ($this->markers)) {
268
-            foreach ($this->markers as $marker) {
269
-                $geoms [] = new Point ($marker ['lon'], $marker ['lat']);
270
-            }
271
-        }
272
-        if (file_exists($this->kmlFileName)) {
273
-            $g = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
274
-            if ($g !== false) {
275
-                $geoms [] = $g;
276
-            }
277
-        }
278
-        if (file_exists($this->gpxFileName)) {
279
-            $g = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
280
-            if ($g !== false) {
281
-                $geoms [] = $g;
282
-            }
283
-        }
284
-        if (file_exists($this->geojsonFileName)) {
285
-            $g = geoPHP::load(file_get_contents($this->geojsonFileName), 'geojson');
286
-            if ($g !== false) {
287
-                $geoms [] = $g;
288
-            }
289
-        }
290
-
291
-        if (count($geoms) <= 1) {
292
-            Logger::debug("StaticMap::autoZoom: Skip setting autozoom options", $geoms);
293
-            return;
294
-        }
295
-
296
-        $geom     = new GeometryCollection ($geoms);
297
-        $centroid = $geom->centroid();
298
-        $bbox     = $geom->getBBox();
299
-
300
-        // determine vertical resolution, this depends on the distance from the equator
301
-        // $vy00 = log(tan(M_PI*(0.25 + $centroid->getY()/360)));
302
-        $vy0 = log(tan(M_PI * (0.25 + $bbox ['miny'] / 360)));
303
-        $vy1 = log(tan(M_PI * (0.25 + $bbox ['maxy'] / 360)));
304
-        Logger::debug("StaticMap::autoZoom: vertical resolution: $vy0, $vy1");
305
-        if ($vy1 - $vy0 === 0.0){
306
-            $resolutionVertical = 0;
307
-            Logger::debug("StaticMap::autoZoom: using $resolutionVertical");
308
-        } else {
309
-            $zoomFactorPowered  = ($this->height / 2) / (40.7436654315252 * ($vy1 - $vy0));
310
-            $resolutionVertical = 360 / ($zoomFactorPowered * $this->tileSize);
311
-        }
312
-        // determine horizontal resolution
313
-        $resolutionHorizontal = ($bbox ['maxx'] - $bbox ['minx']) / $this->width;
314
-        Logger::debug("StaticMap::autoZoom: using $resolutionHorizontal");
315
-        $resolution           = max($resolutionHorizontal, $resolutionVertical) * $paddingFactor;
316
-        $zoom                 = $this->zoom;
317
-        if ($resolution > 0){
318
-            $zoom             = log(360 / ($resolution * $this->tileSize), 2);
319
-        }
320
-
321
-        if (is_finite($zoom) && $zoom < 15 && $zoom > 2) {
322
-            $this->zoom = floor($zoom);
323
-        }
324
-        $this->lon = $centroid->getX();
325
-        $this->lat = $centroid->getY();
326
-        Logger::debug("StaticMap::autoZoom: Set autozoom options to: z: $this->zoom, lon: $this->lon, lat: $this->lat");
327
-    }
328
-
329
-    public function checkMapCache(): bool
330
-    {
331
-        // side effect: set the mapCacheID
332
-        $this->mapCacheID = md5($this->serializeParams());
333
-        $filename         = $this->mapCacheIDToFilename();
334
-        return file_exists($filename);
335
-    }
336
-
337
-    public function serializeParams(): string
338
-    {
339
-        return join(
340
-            "&", array(
341
-                   $this->zoom,
342
-                   $this->lat,
343
-                   $this->lon,
344
-                   $this->width,
345
-                   $this->height,
346
-                   serialize($this->markers),
347
-                   $this->maptype,
348
-                   $this->kmlFileName,
349
-                   $this->gpxFileName,
350
-                   $this->geojsonFileName
351
-               )
352
-        );
353
-    }
354
-
355
-    public function mapCacheIDToFilename(): string
356
-    {
357
-        if (!$this->mapCacheFile) {
358
-            $this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_"
359
-                . substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2)
360
-                . "/" . substr($this->mapCacheID, 4);
361
-        }
362
-        return $this->mapCacheFile . "." . $this->mapCacheExtension;
363
-    }
364
-
365
-    /**
366
-     * make the map.
367
-     */
368
-    public function makeMap(): void
369
-    {
370
-        $this->initCoords();
371
-        $this->createBaseMap();
372
-        if (!empty ($this->markers)) {
373
-            $this->placeMarkers();
374
-        }
375
-        if (file_exists($this->kmlFileName)) {
376
-            try {
377
-                $this->drawKML();
378
-            } catch (exception $e) {
379
-                Logger::error('failed to load KML file', $e);
380
-            }
381
-        }
382
-        if (file_exists($this->gpxFileName)) {
383
-            try {
384
-                $this->drawGPX();
385
-            } catch (exception $e) {
386
-                Logger::error('failed to load GPX file', $e);
387
-            }
388
-        }
389
-        if (file_exists($this->geojsonFileName)) {
390
-            try {
391
-                $this->drawGeojson();
392
-            } catch (exception $e) {
393
-                Logger::error('failed to load GeoJSON file', $e);
394
-            }
395
-        }
396
-
397
-        $this->drawCopyright();
398
-    }
399
-
400
-    /**
401
-     */
402
-    public function initCoords(): void
403
-    {
404
-        $this->centerX = $this->lonToTile($this->lon, $this->zoom);
405
-        $this->centerY = $this->latToTile($this->lat, $this->zoom);
406
-        $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize);
407
-        $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize);
408
-    }
409
-
410
-    /**
411
-     *
412
-     * @param float $long
413
-     * @param int   $zoom
414
-     * @return float|int
415
-     */
416
-    public function lonToTile(float $long, int $zoom)
417
-    {
418
-        return (($long + 180) / 360) * pow(2, $zoom);
419
-    }
420
-
421
-    /**
422
-     *
423
-     * @param float $lat
424
-     * @param int   $zoom
425
-     * @return float|int
426
-     */
427
-    public function latToTile(float $lat, int $zoom)
428
-    {
429
-        return (1 - log(tan($lat * pi() / 180) + 1 / cos($lat * M_PI / 180)) / M_PI) / 2 * pow(2, $zoom);
430
-    }
431
-
432
-    /**
433
-     * make basemap image.
434
-     */
435
-    public function createBaseMap(): void
436
-    {
437
-        $this->image   = imagecreatetruecolor($this->width, $this->height);
438
-        $startX        = floor($this->centerX - ($this->width / $this->tileSize) / 2);
439
-        $startY        = floor($this->centerY - ($this->height / $this->tileSize) / 2);
440
-        $endX          = ceil($this->centerX + ($this->width / $this->tileSize) / 2);
441
-        $endY          = ceil($this->centerY + ($this->height / $this->tileSize) / 2);
442
-        $this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize);
443
-        $this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize);
444
-        $this->offsetX += floor($this->width / 2);
445
-        $this->offsetY += floor($this->height / 2);
446
-        $this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize;
447
-        $this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize;
448
-
449
-        for ($x = $startX; $x <= $endX; $x++) {
450
-            for ($y = $startY; $y <= $endY; $y++) {
451
-                $url = str_replace(
452
-                    array(
453
-                        '{Z}',
454
-                        '{X}',
455
-                        '{Y}'
456
-                    ),
457
-                    array(
458
-                        $this->zoom,
459
-                        $x,
460
-                        $y
461
-                    ),
462
-                    $this->tileInfo [$this->maptype] ['url']
463
-                );
464
-
465
-                $tileData = $this->fetchTile($url);
466
-                if ($tileData) {
467
-                    $tileImage = imagecreatefromstring($tileData);
468
-                } else {
469
-                    $tileImage = imagecreate($this->tileSize, $this->tileSize);
470
-                    $color     = imagecolorallocate($tileImage, 255, 255, 255);
471
-                    @imagestring($tileImage, 1, 127, 127, 'err', $color);
472
-                }
473
-                $destX = ($x - $startX) * $this->tileSize + $this->offsetX;
474
-                $destY = ($y - $startY) * $this->tileSize + $this->offsetY;
475
-                Logger::debug("imagecopy tile into image: $destX, $destY", $this->tileSize);
476
-                imagecopy(
477
-                    $this->image,
478
-                    $tileImage,
479
-                    $destX,
480
-                    $destY,
481
-                    0,
482
-                    0,
483
-                    $this->tileSize,
484
-                    $this->tileSize
485
-                );
486
-            }
487
-        }
488
-    }
489
-
490
-    /**
491
-     * Fetch a tile and (if configured) store it in the cache.
492
-     * @param string $url
493
-     * @return bool|string
494
-     * @todo refactor this to use dokuwiki\HTTP\HTTPClient or dokuwiki\HTTP\DokuHTTPClient
495
-     *          for better proxy handling...
496
-     */
497
-    public function fetchTile(string $url)
498
-    {
499
-        if ($this->useTileCache && ($cached = $this->checkTileCache($url))) {
500
-            return $cached;
501
-        }
502
-
503
-        $_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; ' . PHP_OS . ')';
504
-        if (function_exists("curl_init")) {
505
-            // use cUrl
506
-            $ch = curl_init();
507
-            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
508
-            curl_setopt($ch, CURLOPT_USERAGENT, $_UA);
509
-            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
510
-            curl_setopt($ch, CURLOPT_URL, $url . $this->apikey);
511
-            Logger::debug("StaticMap::fetchTile: getting: $url using curl_exec");
512
-            $tile = curl_exec($ch);
513
-            curl_close($ch);
514
-        } else {
515
-            // use file_get_contents
516
-            global $conf;
517
-            $opts = array(
518
-                'http' => array(
519
-                    'method'          => "GET",
520
-                    'header'          => "Accept-language: en\r\n" . "User-Agent: $_UA\r\n" . "accept: image/png\r\n",
521
-                    'request_fulluri' => true
522
-                )
523
-            );
524
-            if (isset($conf['proxy']['host'], $conf['proxy']['port'])
525
-                && $conf['proxy']['host'] !== ''
526
-                && $conf['proxy']['port'] !== '') {
527
-                $opts['http'] += ['proxy' => "tcp://" . $conf['proxy']['host'] . ":" . $conf['proxy']['port']];
528
-            }
529
-
530
-            $context = stream_context_create($opts);
531
-            Logger::debug(
532
-                "StaticMap::fetchTile: getting: $url . $this->apikey using file_get_contents and options $opts"
533
-            );
534
-            $tile = file_get_contents($url . $this->apikey, false, $context);
535
-        }
536
-        if ($tile && $this->useTileCache) {
537
-            $this->writeTileToCache($url, $tile);
538
-        }
539
-        return $tile;
540
-    }
541
-
542
-    /**
543
-     *
544
-     * @param string $url
545
-     * @return string|false
546
-     */
547
-    public function checkTileCache(string $url)
548
-    {
549
-        $filename = $this->tileUrlToFilename($url);
550
-        if (file_exists($filename)) {
551
-            return file_get_contents($filename);
552
-        }
553
-        return false;
554
-    }
555
-
556
-    /**
557
-     *
558
-     * @param string $url
559
-     * @return string
560
-     */
561
-    public function tileUrlToFilename(string $url): string
562
-    {
563
-        return $this->tileCacheBaseDir . "/" . substr($url, strpos($url, '/') + 1);
564
-    }
565
-
566
-    /**
567
-     * Write a tile into the cache.
568
-     *
569
-     * @param string $url
570
-     * @param mixed  $data
571
-     */
572
-    public function writeTileToCache(string $url, $data): void
573
-    {
574
-        $filename = $this->tileUrlToFilename($url);
575
-        $this->mkdirRecursive(dirname($filename), 0777);
576
-        file_put_contents($filename, $data);
577
-    }
578
-
579
-    /**
580
-     * Recursively create the directory.
581
-     *
582
-     * @param string $pathname
583
-     *            The directory path.
584
-     * @param int    $mode
585
-     *            File access mode. For more information on modes, read the details on the chmod manpage.
586
-     */
587
-    public function mkdirRecursive(string $pathname, int $mode): bool
588
-    {
589
-        is_dir(dirname($pathname)) || $this->mkdirRecursive(dirname($pathname), $mode);
590
-        return is_dir($pathname) || mkdir($pathname, $mode) || is_dir($pathname);
591
-    }
592
-
593
-    /**
594
-     * Place markers on the map and number them in the same order as they are listed in the html.
595
-     */
596
-    public function placeMarkers(): void
597
-    {
598
-        $count               = 0;
599
-        $color               = imagecolorallocate($this->image, 0, 0, 0);
600
-        $bgcolor             = imagecolorallocate($this->image, 200, 200, 200);
601
-        $markerBaseDir       = __DIR__ . '/icons';
602
-        $markerImageOffsetX  = 0;
603
-        $markerImageOffsetY  = 0;
604
-        $markerShadowOffsetX = 0;
605
-        $markerShadowOffsetY = 0;
606
-        $markerShadowImg     = null;
607
-        // loop thru marker array
608
-        foreach ($this->markers as $marker) {
609
-            // set some local variables
610
-            $markerLat  = $marker ['lat'];
611
-            $markerLon  = $marker ['lon'];
612
-            $markerType = $marker ['type'];
613
-            // clear variables from previous loops
614
-            $markerFilename = '';
615
-            $markerShadow   = '';
616
-            $matches        = false;
617
-            // check for marker type, get settings from markerPrototypes
618
-            if ($markerType) {
619
-                foreach ($this->markerPrototypes as $markerPrototype) {
620
-                    if (preg_match($markerPrototype ['regex'], $markerType, $matches)) {
621
-                        $markerFilename = $matches [0] . $markerPrototype ['extension'];
622
-                        if ($markerPrototype ['offsetImage']) {
623
-                            list ($markerImageOffsetX, $markerImageOffsetY) = explode(
624
-                                ",",
625
-                                $markerPrototype ['offsetImage']
626
-                            );
627
-                        }
628
-                        $markerShadow = $markerPrototype ['shadow'];
629
-                        if ($markerShadow) {
630
-                            list ($markerShadowOffsetX, $markerShadowOffsetY) = explode(
631
-                                ",",
632
-                                $markerPrototype ['offsetShadow']
633
-                            );
634
-                        }
635
-                    }
636
-                }
637
-            }
638
-            // create img resource
639
-            if (file_exists($markerBaseDir . '/' . $markerFilename)) {
640
-                $markerImg = imagecreatefrompng($markerBaseDir . '/' . $markerFilename);
641
-            } else {
642
-                $markerImg = imagecreatefrompng($markerBaseDir . '/marker.png');
643
-            }
644
-            // check for shadow + create shadow recource
645
-            if ($markerShadow && file_exists($markerBaseDir . '/' . $markerShadow)) {
646
-                $markerShadowImg = imagecreatefrompng($markerBaseDir . '/' . $markerShadow);
647
-            }
648
-            // calc position
649
-            $destX = floor(
650
-                ($this->width / 2) -
651
-                $this->tileSize * ($this->centerX - $this->lonToTile($markerLon, $this->zoom))
652
-            );
653
-            $destY = floor(
654
-                ($this->height / 2) -
655
-                $this->tileSize * ($this->centerY - $this->latToTile($markerLat, $this->zoom))
656
-            );
657
-            // copy shadow on basemap
658
-            if ($markerShadow && $markerShadowImg) {
659
-                imagecopy(
660
-                    $this->image,
661
-                    $markerShadowImg,
662
-                    $destX + (int)$markerShadowOffsetX,
663
-                    $destY + (int)$markerShadowOffsetY,
664
-                    0,
665
-                    0,
666
-                    imagesx($markerShadowImg),
667
-                    imagesy($markerShadowImg)
668
-                );
669
-            }
670
-            // copy marker on basemap above shadow
671
-            imagecopy(
672
-                $this->image,
673
-                $markerImg,
674
-                $destX + (int)$markerImageOffsetX,
675
-                $destY + (int)$markerImageOffsetY,
676
-                0,
677
-                0,
678
-                imagesx($markerImg),
679
-                imagesy($markerImg)
680
-            );
681
-            // add label
682
-            imagestring(
683
-                $this->image,
684
-                3,
685
-                $destX - imagesx($markerImg) + 1,
686
-                $destY + (int)$markerImageOffsetY + 1,
687
-                ++$count,
688
-                $bgcolor
689
-            );
690
-            imagestring(
691
-                $this->image,
692
-                3,
693
-                $destX - imagesx($markerImg),
694
-                $destY + (int)$markerImageOffsetY,
695
-                $count,
696
-                $color
697
-            );
698
-        }
699
-    }
700
-
701
-    /**
702
-     * Draw kml trace on the map.
703
-     * @throws exception if loading the specified KML fails
704
-     */
705
-    public function drawKML(): void
706
-    {
707
-        // TODO get colour from kml node (not currently supported in geoPHP)
708
-        $col     = imagecolorallocatealpha($this->image, 255, 0, 0, .4 * 127);
709
-        $kmlgeom = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
710
-        $this->drawGeometry($kmlgeom, $col);
711
-    }
712
-
713
-    /**
714
-     * Draw geometry or geometry collection on the map.
715
-     *
716
-     * @param Geometry|GeometryCollection|MultiPolygon|MultiLineString|MultiPoint|Polygon|LineString|Point $geom
717
-     * @param int                                                                                          $colour
718
-     *            drawing colour
719
-     */
720
-    private function drawGeometry(Geometry $geom, int $colour): void
721
-    {
722
-        if (empty($geom)) {
723
-            return;
724
-        }
725
-
726
-        switch ($geom->geometryType()) {
727
-            case 'GeometryCollection' :
728
-                // recursively draw part of the collection
729
-                for ($i = 1; $i < $geom->numGeometries() + 1; $i++) {
730
-                    $_geom = $geom->geometryN($i);
731
-                    $this->drawGeometry($_geom, $colour);
732
-                }
733
-                break;
734
-            case 'MultiPolygon' :
735
-            case 'MultiLineString' :
736
-            case 'MultiPoint' :
737
-                // TODO implement / do nothing
738
-                break;
739
-            case 'Polygon' :
740
-                $this->drawPolygon($geom, $colour);
741
-                break;
742
-            case 'LineString' :
743
-                $this->drawLineString($geom, $colour);
744
-                break;
745
-            case 'Point' :
746
-                $this->drawPoint($geom, $colour);
747
-                break;
748
-            default :
749
-                // draw nothing
750
-                break;
751
-        }
752
-    }
753
-
754
-    /**
755
-     * Draw a polygon on the map.
756
-     *
757
-     * @param Polygon $polygon
758
-     * @param int     $colour
759
-     *            drawing colour
760
-     */
761
-    private function drawPolygon(Polygon $polygon, int $colour)
762
-    {
763
-        // TODO implementation of drawing holes,
764
-        // maybe draw the polygon to an in-memory image and use imagecopy, draw polygon in col., draw holes in bgcol?
765
-
766
-        // print_r('Polygon:<br />');
767
-        // print_r($polygon);
768
-        $extPoints = array();
769
-        // extring is a linestring actually..
770
-        $extRing = $polygon->exteriorRing();
771
-
772
-        for ($i = 1; $i < $extRing->numGeometries(); $i++) {
773
-            $p1           = $extRing->geometryN($i);
774
-            $x            = floor(
775
-                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
776
-            );
777
-            $y            = floor(
778
-                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
779
-            );
780
-            $extPoints [] = $x;
781
-            $extPoints [] = $y;
782
-        }
783
-        // print_r('points:('.($i-1).')<br />');
784
-        // print_r($extPoints);
785
-        // imagepolygon ($this->image, $extPoints, $i-1, $colour );
786
-        imagefilledpolygon($this->image, $extPoints, $i - 1, $colour);
787
-    }
788
-
789
-    /**
790
-     * Draw a line on the map.
791
-     *
792
-     * @param LineString $line
793
-     * @param int        $colour
794
-     *            drawing colour
795
-     */
796
-    private function drawLineString(LineString $line, int $colour)
797
-    {
798
-        imagesetthickness($this->image, 2);
799
-        for ($p = 1; $p < $line->numGeometries(); $p++) {
800
-            // get first pair of points
801
-            $p1 = $line->geometryN($p);
802
-            $p2 = $line->geometryN($p + 1);
803
-            // translate to paper space
804
-            $x1 = floor(
805
-                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
806
-            );
807
-            $y1 = floor(
808
-                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
809
-            );
810
-            $x2 = floor(
811
-                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p2->x(), $this->zoom))
812
-            );
813
-            $y2 = floor(
814
-                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p2->y(), $this->zoom))
815
-            );
816
-            // draw to image
817
-            imageline($this->image, $x1, $y1, $x2, $y2, $colour);
818
-        }
819
-        imagesetthickness($this->image, 1);
820
-    }
821
-
822
-    /**
823
-     * Draw a point on the map.
824
-     *
825
-     * @param Point $point
826
-     * @param int   $colour
827
-     *            drawing colour
828
-     */
829
-    private function drawPoint(Point $point, int $colour)
830
-    {
831
-        imagesetthickness($this->image, 2);
832
-        // translate to paper space
833
-        $cx = floor(
834
-            ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($point->x(), $this->zoom))
835
-        );
836
-        $cy = floor(
837
-            ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($point->y(), $this->zoom))
838
-        );
839
-        $r  = 5;
840
-        // draw to image
841
-        // imageellipse($this->image, $cx, $cy,$r, $r, $colour);
842
-        imagefilledellipse($this->image, $cx, $cy, $r, $r, $colour);
843
-        // don't use imageellipse because the imagesetthickness function has
844
-        // no effect. So the better workaround is to use imagearc.
845
-        imagearc($this->image, $cx, $cy, $r, $r, 0, 359, $colour);
846
-        imagesetthickness($this->image, 1);
847
-    }
848
-
849
-    /**
850
-     * Draw gpx trace on the map.
851
-     * @throws exception if loading the specified GPX fails
852
-     */
853
-    public function drawGPX()
854
-    {
855
-        $col     = imagecolorallocatealpha($this->image, 0, 0, 255, .4 * 127);
856
-        $gpxgeom = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
857
-        $this->drawGeometry($gpxgeom, $col);
858
-    }
859
-
860
-    /**
861
-     * Draw geojson on the map.
862
-     * @throws exception if loading the specified GeoJSON fails
863
-     */
864
-    public function drawGeojson()
865
-    {
866
-        $col     = imagecolorallocatealpha($this->image, 255, 0, 255, .4 * 127);
867
-        $gpxgeom = geoPHP::load(file_get_contents($this->geojsonFileName), 'json');
868
-        $this->drawGeometry($gpxgeom, $col);
869
-    }
870
-
871
-    /**
872
-     * add copyright and origin notice and icons to the map.
873
-     */
874
-    public function drawCopyright()
875
-    {
876
-        $logoBaseDir = dirname(__FILE__) . '/' . 'logo/';
877
-        $logoImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo ['openstreetmap'] ['logo']);
878
-        $textcolor   = imagecolorallocate($this->image, 0, 0, 0);
879
-        $bgcolor     = imagecolorallocate($this->image, 200, 200, 200);
880
-
881
-        imagecopy(
882
-            $this->image,
883
-            $logoImg,
884
-            0,
885
-            imagesy($this->image) - imagesy($logoImg),
886
-            0,
887
-            0,
888
-            imagesx($logoImg),
889
-            imagesy($logoImg)
890
-        );
891
-        imagestring(
892
-            $this->image,
893
-            1,
894
-            imagesx($logoImg) + 2,
895
-            imagesy($this->image) - imagesy($logoImg) + 1,
896
-            $this->tileInfo ['openstreetmap'] ['txt'],
897
-            $bgcolor
898
-        );
899
-        imagestring(
900
-            $this->image,
901
-            1,
902
-            imagesx($logoImg) + 1,
903
-            imagesy($this->image) - imagesy($logoImg),
904
-            $this->tileInfo ['openstreetmap'] ['txt'],
905
-            $textcolor
906
-        );
907
-
908
-        // additional tile source info, ie. who created/hosted the tiles
909
-        $xIconOffset = 0;
910
-        if ($this->maptype === 'openstreetmap') {
911
-            $mapAuthor = "(c) OpenStreetMap maps/CC BY-SA";
912
-        } else {
913
-            $mapAuthor   = $this->tileInfo [$this->maptype] ['txt'];
914
-            $iconImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo [$this->maptype] ['logo']);
915
-            $xIconOffset = imagesx($iconImg);
916
-            imagecopy(
917
-                $this->image,
918
-                $iconImg,
919
-                imagesx($logoImg) + 1,
920
-                imagesy($this->image) - imagesy($iconImg),
921
-                0,
922
-                0,
923
-                imagesx($iconImg),
924
-                imagesy($iconImg)
925
-            );
926
-        }
927
-        imagestring(
928
-            $this->image,
929
-            1,
930
-            imagesx($logoImg) + $xIconOffset + 4,
931
-            imagesy($this->image) - ceil(imagesy($logoImg) / 2) + 1,
932
-            $mapAuthor,
933
-            $bgcolor
934
-        );
935
-        imagestring(
936
-            $this->image,
937
-            1,
938
-            imagesx($logoImg) + $xIconOffset + 3,
939
-            imagesy($this->image) - ceil(imagesy($logoImg) / 2),
940
-            $mapAuthor,
941
-            $textcolor
942
-        );
943
-    }
37
+	// the final output
38
+	private $tileSize = 256;
39
+	private $tileInfo = array(
40
+		// OSM sources
41
+		'openstreetmap' => array(
42
+			'txt'  => '(c) OpenStreetMap data/ODbl',
43
+			'logo' => 'osm_logo.png',
44
+			'url'  => 'https://tile.openstreetmap.org/{Z}/{X}/{Y}.png'
45
+		),
46
+		// OCM sources
47
+		'cycle'         => array(
48
+			'txt'  => '(c) Thunderforest maps',
49
+			'logo' => 'tf_logo.png',
50
+			'url'  => 'https://tile.thunderforest.com/cycle/{Z}/{X}/{Y}.png'
51
+		),
52
+		'transport'     => array(
53
+			'txt'  => '(c) Thunderforest maps',
54
+			'logo' => 'tf_logo.png',
55
+			'url'  => 'https://tile.thunderforest.com/transport/{Z}/{X}/{Y}.png'
56
+		),
57
+		'landscape'     => array(
58
+			'txt'  => '(c) Thunderforest maps',
59
+			'logo' => 'tf_logo.png',
60
+			'url'  => 'https://tile.thunderforest.com/landscape/{Z}/{X}/{Y}.png'
61
+		),
62
+		'outdoors'      => array(
63
+			'txt'  => '(c) Thunderforest maps',
64
+			'logo' => 'tf_logo.png',
65
+			'url'  => 'https://tile.thunderforest.com/outdoors/{Z}/{X}/{Y}.png'
66
+		),
67
+		'toner-lite'    => array(
68
+			'txt'  => 'Stamen tiles',
69
+			'logo' => 'stamen.png',
70
+			'url'  => 'https://stamen-tiles.a.ssl.fastly.net/toner/{Z}/{X}/{Y}.png'
71
+		),
72
+		'terrain'       => array(
73
+			'txt'  => 'Stamen tiles',
74
+			'logo' => 'stamen.png',
75
+			'url'  => 'https://stamen-tiles.a.ssl.fastly.net/terrain/{Z}/{X}/{Y}.jpg'
76
+		)
77
+		//,
78
+		// 'piste'=>array(
79
+		// 'txt'=>'OpenPisteMap tiles',
80
+		// 'logo'=>'piste_logo.png',
81
+		// 'url'=>''),
82
+		// 'sea'=>array(
83
+		// 'txt'=>'OpenSeaMap tiles',
84
+		// 'logo'=>'sea_logo.png',
85
+		// 'url'=>''),
86
+		// H&B sources
87
+		//          'hikeandbike' => array (
88
+		//                  'txt' => 'Hike & Bike Map',
89
+		//                  'logo' => 'hnb_logo.png',
90
+		//                  //'url' => 'http://toolserver.org/tiles/hikebike/{Z}/{X}/{Y}.png'
91
+		//                  //moved to: https://www.toolserver.org/tiles/hikebike/12/2105/1388.png
92
+		//                  'url' => 'http://c.tiles.wmflabs.org/hikebike/{Z}/{X}/{Y}.png'
93
+		//          )
94
+	);
95
+	private $tileDefaultSrc = 'openstreetmap';
96
+
97
+	// set up markers
98
+	private $markerPrototypes = array(
99
+		// found at http://www.mapito.net/map-marker-icons.html
100
+		// these are 17x19 px with a pointer at the bottom left
101
+		'lightblue' => array(
102
+			'regex'        => '/^lightblue([0-9]+)$/',
103
+			'extension'    => '.png',
104
+			'shadow'       => false,
105
+			'offsetImage'  => '0,-19',
106
+			'offsetShadow' => false
107
+		),
108
+		// openlayers std markers are 21x25px with shadow
109
+		'ol-marker' => array(
110
+			'regex'        => '/^marker(|-blue|-gold|-green|-red)+$/',
111
+			'extension'    => '.png',
112
+			'shadow'       => 'marker_shadow.png',
113
+			'offsetImage'  => '-10,-25',
114
+			'offsetShadow' => '-1,-13'
115
+		),
116
+		// these are 16x16 px
117
+		'ww_icon'   => array(
118
+			'regex'        => '/ww_\S+$/',
119
+			'extension'    => '.png',
120
+			'shadow'       => false,
121
+			'offsetImage'  => '-8,-8',
122
+			'offsetShadow' => false
123
+		),
124
+		// assume these are 16x16 px
125
+		'rest'      => array(
126
+			'regex'        => '/^(?!lightblue([0-9]+)$)(?!(ww_\S+$))(?!marker(|-blue|-gold|-green|-red)+$)(.*)/',
127
+			'extension'    => '.png',
128
+			'shadow'       => 'marker_shadow.png',
129
+			'offsetImage'  => '-8,-8',
130
+			'offsetShadow' => '-1,-1'
131
+		)
132
+	);
133
+	private $centerX;
134
+	private $centerY;
135
+	private $offsetX;
136
+	private $offsetY;
137
+	private $image;
138
+	private $zoom;
139
+	private $lat;
140
+	private $lon;
141
+	private $width;
142
+	private $height;
143
+	private $markers;
144
+	private $maptype;
145
+	private $kmlFileName;
146
+	private $gpxFileName;
147
+	private $geojsonFileName;
148
+	private $autoZoomExtent;
149
+	private $apikey;
150
+	private $tileCacheBaseDir;
151
+	private $mapCacheBaseDir;
152
+	private $mediaBaseDir;
153
+	private $useTileCache;
154
+	private $mapCacheID = '';
155
+	private $mapCacheFile = '';
156
+	private $mapCacheExtension = 'png';
157
+
158
+	/**
159
+	 * Constructor.
160
+	 *
161
+	 * @param float  $lat
162
+	 *            Latitude (x) of center of map
163
+	 * @param float  $lon
164
+	 *            Longitude (y) of center of map
165
+	 * @param int    $zoom
166
+	 *            Zoomlevel
167
+	 * @param int    $width
168
+	 *            Width in pixels
169
+	 * @param int    $height
170
+	 *            Height in pixels
171
+	 * @param string $maptype
172
+	 *            Name of the map
173
+	 * @param array  $markers
174
+	 *            array of markers
175
+	 * @param string $gpx
176
+	 *            GPX filename
177
+	 * @param string $kml
178
+	 *            KML filename
179
+	 * @param string $geojson
180
+	 * @param string $mediaDir
181
+	 *            Directory to store/cache maps
182
+	 * @param string $tileCacheBaseDir
183
+	 *            Directory to cache map tiles
184
+	 * @param bool   $autoZoomExtent
185
+	 *            Wheter or not to override zoom/lat/lon and zoom to the extent of gpx/kml and markers
186
+	 * @param string $apikey
187
+	 */
188
+	public function __construct(
189
+		float $lat,
190
+		float $lon,
191
+		int $zoom,
192
+		int $width,
193
+		int $height,
194
+		string $maptype,
195
+		array $markers,
196
+		string $gpx,
197
+		string $kml,
198
+		string $geojson,
199
+		string $mediaDir,
200
+		string $tileCacheBaseDir,
201
+		bool $autoZoomExtent = true,
202
+		string $apikey = ''
203
+	) {
204
+		$this->zoom   = $zoom;
205
+		$this->lat    = $lat;
206
+		$this->lon    = $lon;
207
+		$this->width  = $width;
208
+		$this->height = $height;
209
+		// validate + set maptype
210
+		$this->maptype = $this->tileDefaultSrc;
211
+		if (array_key_exists($maptype, $this->tileInfo)) {
212
+			$this->maptype = $maptype;
213
+		}
214
+		$this->markers          = $markers;
215
+		$this->kmlFileName      = $kml;
216
+		$this->gpxFileName      = $gpx;
217
+		$this->geojsonFileName  = $geojson;
218
+		$this->mediaBaseDir     = $mediaDir;
219
+		$this->tileCacheBaseDir = $tileCacheBaseDir . '/olmaptiles';
220
+		$this->useTileCache     = $this->tileCacheBaseDir !== '';
221
+		$this->mapCacheBaseDir  = $mediaDir . '/olmapmaps';
222
+		$this->autoZoomExtent   = $autoZoomExtent;
223
+		$this->apikey           = $apikey;
224
+	}
225
+
226
+	/**
227
+	 * get the map, this may return a reference to a cached copy.
228
+	 *
229
+	 * @return string url relative to media dir
230
+	 */
231
+	public function getMap(): string
232
+	{
233
+		try {
234
+			if ($this->autoZoomExtent) {
235
+				$this->autoZoom();
236
+			}
237
+		} catch (Exception $e) {
238
+			Logger::debug($e);
239
+		}
240
+
241
+		// use map cache, so check cache for map
242
+		if (!$this->checkMapCache()) {
243
+			// map is not in cache, needs to be build
244
+			$this->makeMap();
245
+			$this->mkdirRecursive(dirname($this->mapCacheIDToFilename()), 0777);
246
+			imagepng($this->image, $this->mapCacheIDToFilename(), 9);
247
+		}
248
+		$doc = $this->mapCacheIDToFilename();
249
+		// make url relative to media dir
250
+		return str_replace($this->mediaBaseDir, '', $doc);
251
+	}
252
+
253
+	/**
254
+	 * Calculate the lat/lon/zoom values to make sure that all of the markers and gpx/kml are on the map.
255
+	 * can throw an error like
256
+	 * "Fatal error: Uncaught Exception: Cannot create a collection with non-geometries in
257
+	 * D:\www\wild-water.nl\www\dokuwiki\lib\plugins\geophp\geoPHP\lib\geometry\Collection.class.php:29"
258
+	 *
259
+	 * @param float $paddingFactor
260
+	 *            buffer constant to enlarge (>1.0) the zoom level
261
+	 * @throws Exception
262
+	 */
263
+	private function autoZoom(float $paddingFactor = 1.0): void
264
+	{
265
+		$geoms    = array();
266
+		$geoms [] = new Point ($this->lon, $this->lat);
267
+		if (!empty ($this->markers)) {
268
+			foreach ($this->markers as $marker) {
269
+				$geoms [] = new Point ($marker ['lon'], $marker ['lat']);
270
+			}
271
+		}
272
+		if (file_exists($this->kmlFileName)) {
273
+			$g = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
274
+			if ($g !== false) {
275
+				$geoms [] = $g;
276
+			}
277
+		}
278
+		if (file_exists($this->gpxFileName)) {
279
+			$g = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
280
+			if ($g !== false) {
281
+				$geoms [] = $g;
282
+			}
283
+		}
284
+		if (file_exists($this->geojsonFileName)) {
285
+			$g = geoPHP::load(file_get_contents($this->geojsonFileName), 'geojson');
286
+			if ($g !== false) {
287
+				$geoms [] = $g;
288
+			}
289
+		}
290
+
291
+		if (count($geoms) <= 1) {
292
+			Logger::debug("StaticMap::autoZoom: Skip setting autozoom options", $geoms);
293
+			return;
294
+		}
295
+
296
+		$geom     = new GeometryCollection ($geoms);
297
+		$centroid = $geom->centroid();
298
+		$bbox     = $geom->getBBox();
299
+
300
+		// determine vertical resolution, this depends on the distance from the equator
301
+		// $vy00 = log(tan(M_PI*(0.25 + $centroid->getY()/360)));
302
+		$vy0 = log(tan(M_PI * (0.25 + $bbox ['miny'] / 360)));
303
+		$vy1 = log(tan(M_PI * (0.25 + $bbox ['maxy'] / 360)));
304
+		Logger::debug("StaticMap::autoZoom: vertical resolution: $vy0, $vy1");
305
+		if ($vy1 - $vy0 === 0.0){
306
+			$resolutionVertical = 0;
307
+			Logger::debug("StaticMap::autoZoom: using $resolutionVertical");
308
+		} else {
309
+			$zoomFactorPowered  = ($this->height / 2) / (40.7436654315252 * ($vy1 - $vy0));
310
+			$resolutionVertical = 360 / ($zoomFactorPowered * $this->tileSize);
311
+		}
312
+		// determine horizontal resolution
313
+		$resolutionHorizontal = ($bbox ['maxx'] - $bbox ['minx']) / $this->width;
314
+		Logger::debug("StaticMap::autoZoom: using $resolutionHorizontal");
315
+		$resolution           = max($resolutionHorizontal, $resolutionVertical) * $paddingFactor;
316
+		$zoom                 = $this->zoom;
317
+		if ($resolution > 0){
318
+			$zoom             = log(360 / ($resolution * $this->tileSize), 2);
319
+		}
320
+
321
+		if (is_finite($zoom) && $zoom < 15 && $zoom > 2) {
322
+			$this->zoom = floor($zoom);
323
+		}
324
+		$this->lon = $centroid->getX();
325
+		$this->lat = $centroid->getY();
326
+		Logger::debug("StaticMap::autoZoom: Set autozoom options to: z: $this->zoom, lon: $this->lon, lat: $this->lat");
327
+	}
328
+
329
+	public function checkMapCache(): bool
330
+	{
331
+		// side effect: set the mapCacheID
332
+		$this->mapCacheID = md5($this->serializeParams());
333
+		$filename         = $this->mapCacheIDToFilename();
334
+		return file_exists($filename);
335
+	}
336
+
337
+	public function serializeParams(): string
338
+	{
339
+		return join(
340
+			"&", array(
341
+				   $this->zoom,
342
+				   $this->lat,
343
+				   $this->lon,
344
+				   $this->width,
345
+				   $this->height,
346
+				   serialize($this->markers),
347
+				   $this->maptype,
348
+				   $this->kmlFileName,
349
+				   $this->gpxFileName,
350
+				   $this->geojsonFileName
351
+			   )
352
+		);
353
+	}
354
+
355
+	public function mapCacheIDToFilename(): string
356
+	{
357
+		if (!$this->mapCacheFile) {
358
+			$this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_"
359
+				. substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2)
360
+				. "/" . substr($this->mapCacheID, 4);
361
+		}
362
+		return $this->mapCacheFile . "." . $this->mapCacheExtension;
363
+	}
364
+
365
+	/**
366
+	 * make the map.
367
+	 */
368
+	public function makeMap(): void
369
+	{
370
+		$this->initCoords();
371
+		$this->createBaseMap();
372
+		if (!empty ($this->markers)) {
373
+			$this->placeMarkers();
374
+		}
375
+		if (file_exists($this->kmlFileName)) {
376
+			try {
377
+				$this->drawKML();
378
+			} catch (exception $e) {
379
+				Logger::error('failed to load KML file', $e);
380
+			}
381
+		}
382
+		if (file_exists($this->gpxFileName)) {
383
+			try {
384
+				$this->drawGPX();
385
+			} catch (exception $e) {
386
+				Logger::error('failed to load GPX file', $e);
387
+			}
388
+		}
389
+		if (file_exists($this->geojsonFileName)) {
390
+			try {
391
+				$this->drawGeojson();
392
+			} catch (exception $e) {
393
+				Logger::error('failed to load GeoJSON file', $e);
394
+			}
395
+		}
396
+
397
+		$this->drawCopyright();
398
+	}
399
+
400
+	/**
401
+	 */
402
+	public function initCoords(): void
403
+	{
404
+		$this->centerX = $this->lonToTile($this->lon, $this->zoom);
405
+		$this->centerY = $this->latToTile($this->lat, $this->zoom);
406
+		$this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize);
407
+		$this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize);
408
+	}
409
+
410
+	/**
411
+	 *
412
+	 * @param float $long
413
+	 * @param int   $zoom
414
+	 * @return float|int
415
+	 */
416
+	public function lonToTile(float $long, int $zoom)
417
+	{
418
+		return (($long + 180) / 360) * pow(2, $zoom);
419
+	}
420
+
421
+	/**
422
+	 *
423
+	 * @param float $lat
424
+	 * @param int   $zoom
425
+	 * @return float|int
426
+	 */
427
+	public function latToTile(float $lat, int $zoom)
428
+	{
429
+		return (1 - log(tan($lat * pi() / 180) + 1 / cos($lat * M_PI / 180)) / M_PI) / 2 * pow(2, $zoom);
430
+	}
431
+
432
+	/**
433
+	 * make basemap image.
434
+	 */
435
+	public function createBaseMap(): void
436
+	{
437
+		$this->image   = imagecreatetruecolor($this->width, $this->height);
438
+		$startX        = floor($this->centerX - ($this->width / $this->tileSize) / 2);
439
+		$startY        = floor($this->centerY - ($this->height / $this->tileSize) / 2);
440
+		$endX          = ceil($this->centerX + ($this->width / $this->tileSize) / 2);
441
+		$endY          = ceil($this->centerY + ($this->height / $this->tileSize) / 2);
442
+		$this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize);
443
+		$this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize);
444
+		$this->offsetX += floor($this->width / 2);
445
+		$this->offsetY += floor($this->height / 2);
446
+		$this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize;
447
+		$this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize;
448
+
449
+		for ($x = $startX; $x <= $endX; $x++) {
450
+			for ($y = $startY; $y <= $endY; $y++) {
451
+				$url = str_replace(
452
+					array(
453
+						'{Z}',
454
+						'{X}',
455
+						'{Y}'
456
+					),
457
+					array(
458
+						$this->zoom,
459
+						$x,
460
+						$y
461
+					),
462
+					$this->tileInfo [$this->maptype] ['url']
463
+				);
464
+
465
+				$tileData = $this->fetchTile($url);
466
+				if ($tileData) {
467
+					$tileImage = imagecreatefromstring($tileData);
468
+				} else {
469
+					$tileImage = imagecreate($this->tileSize, $this->tileSize);
470
+					$color     = imagecolorallocate($tileImage, 255, 255, 255);
471
+					@imagestring($tileImage, 1, 127, 127, 'err', $color);
472
+				}
473
+				$destX = ($x - $startX) * $this->tileSize + $this->offsetX;
474
+				$destY = ($y - $startY) * $this->tileSize + $this->offsetY;
475
+				Logger::debug("imagecopy tile into image: $destX, $destY", $this->tileSize);
476
+				imagecopy(
477
+					$this->image,
478
+					$tileImage,
479
+					$destX,
480
+					$destY,
481
+					0,
482
+					0,
483
+					$this->tileSize,
484
+					$this->tileSize
485
+				);
486
+			}
487
+		}
488
+	}
489
+
490
+	/**
491
+	 * Fetch a tile and (if configured) store it in the cache.
492
+	 * @param string $url
493
+	 * @return bool|string
494
+	 * @todo refactor this to use dokuwiki\HTTP\HTTPClient or dokuwiki\HTTP\DokuHTTPClient
495
+	 *          for better proxy handling...
496
+	 */
497
+	public function fetchTile(string $url)
498
+	{
499
+		if ($this->useTileCache && ($cached = $this->checkTileCache($url))) {
500
+			return $cached;
501
+		}
502
+
503
+		$_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; ' . PHP_OS . ')';
504
+		if (function_exists("curl_init")) {
505
+			// use cUrl
506
+			$ch = curl_init();
507
+			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
508
+			curl_setopt($ch, CURLOPT_USERAGENT, $_UA);
509
+			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
510
+			curl_setopt($ch, CURLOPT_URL, $url . $this->apikey);
511
+			Logger::debug("StaticMap::fetchTile: getting: $url using curl_exec");
512
+			$tile = curl_exec($ch);
513
+			curl_close($ch);
514
+		} else {
515
+			// use file_get_contents
516
+			global $conf;
517
+			$opts = array(
518
+				'http' => array(
519
+					'method'          => "GET",
520
+					'header'          => "Accept-language: en\r\n" . "User-Agent: $_UA\r\n" . "accept: image/png\r\n",
521
+					'request_fulluri' => true
522
+				)
523
+			);
524
+			if (isset($conf['proxy']['host'], $conf['proxy']['port'])
525
+				&& $conf['proxy']['host'] !== ''
526
+				&& $conf['proxy']['port'] !== '') {
527
+				$opts['http'] += ['proxy' => "tcp://" . $conf['proxy']['host'] . ":" . $conf['proxy']['port']];
528
+			}
529
+
530
+			$context = stream_context_create($opts);
531
+			Logger::debug(
532
+				"StaticMap::fetchTile: getting: $url . $this->apikey using file_get_contents and options $opts"
533
+			);
534
+			$tile = file_get_contents($url . $this->apikey, false, $context);
535
+		}
536
+		if ($tile && $this->useTileCache) {
537
+			$this->writeTileToCache($url, $tile);
538
+		}
539
+		return $tile;
540
+	}
541
+
542
+	/**
543
+	 *
544
+	 * @param string $url
545
+	 * @return string|false
546
+	 */
547
+	public function checkTileCache(string $url)
548
+	{
549
+		$filename = $this->tileUrlToFilename($url);
550
+		if (file_exists($filename)) {
551
+			return file_get_contents($filename);
552
+		}
553
+		return false;
554
+	}
555
+
556
+	/**
557
+	 *
558
+	 * @param string $url
559
+	 * @return string
560
+	 */
561
+	public function tileUrlToFilename(string $url): string
562
+	{
563
+		return $this->tileCacheBaseDir . "/" . substr($url, strpos($url, '/') + 1);
564
+	}
565
+
566
+	/**
567
+	 * Write a tile into the cache.
568
+	 *
569
+	 * @param string $url
570
+	 * @param mixed  $data
571
+	 */
572
+	public function writeTileToCache(string $url, $data): void
573
+	{
574
+		$filename = $this->tileUrlToFilename($url);
575
+		$this->mkdirRecursive(dirname($filename), 0777);
576
+		file_put_contents($filename, $data);
577
+	}
578
+
579
+	/**
580
+	 * Recursively create the directory.
581
+	 *
582
+	 * @param string $pathname
583
+	 *            The directory path.
584
+	 * @param int    $mode
585
+	 *            File access mode. For more information on modes, read the details on the chmod manpage.
586
+	 */
587
+	public function mkdirRecursive(string $pathname, int $mode): bool
588
+	{
589
+		is_dir(dirname($pathname)) || $this->mkdirRecursive(dirname($pathname), $mode);
590
+		return is_dir($pathname) || mkdir($pathname, $mode) || is_dir($pathname);
591
+	}
592
+
593
+	/**
594
+	 * Place markers on the map and number them in the same order as they are listed in the html.
595
+	 */
596
+	public function placeMarkers(): void
597
+	{
598
+		$count               = 0;
599
+		$color               = imagecolorallocate($this->image, 0, 0, 0);
600
+		$bgcolor             = imagecolorallocate($this->image, 200, 200, 200);
601
+		$markerBaseDir       = __DIR__ . '/icons';
602
+		$markerImageOffsetX  = 0;
603
+		$markerImageOffsetY  = 0;
604
+		$markerShadowOffsetX = 0;
605
+		$markerShadowOffsetY = 0;
606
+		$markerShadowImg     = null;
607
+		// loop thru marker array
608
+		foreach ($this->markers as $marker) {
609
+			// set some local variables
610
+			$markerLat  = $marker ['lat'];
611
+			$markerLon  = $marker ['lon'];
612
+			$markerType = $marker ['type'];
613
+			// clear variables from previous loops
614
+			$markerFilename = '';
615
+			$markerShadow   = '';
616
+			$matches        = false;
617
+			// check for marker type, get settings from markerPrototypes
618
+			if ($markerType) {
619
+				foreach ($this->markerPrototypes as $markerPrototype) {
620
+					if (preg_match($markerPrototype ['regex'], $markerType, $matches)) {
621
+						$markerFilename = $matches [0] . $markerPrototype ['extension'];
622
+						if ($markerPrototype ['offsetImage']) {
623
+							list ($markerImageOffsetX, $markerImageOffsetY) = explode(
624
+								",",
625
+								$markerPrototype ['offsetImage']
626
+							);
627
+						}
628
+						$markerShadow = $markerPrototype ['shadow'];
629
+						if ($markerShadow) {
630
+							list ($markerShadowOffsetX, $markerShadowOffsetY) = explode(
631
+								",",
632
+								$markerPrototype ['offsetShadow']
633
+							);
634
+						}
635
+					}
636
+				}
637
+			}
638
+			// create img resource
639
+			if (file_exists($markerBaseDir . '/' . $markerFilename)) {
640
+				$markerImg = imagecreatefrompng($markerBaseDir . '/' . $markerFilename);
641
+			} else {
642
+				$markerImg = imagecreatefrompng($markerBaseDir . '/marker.png');
643
+			}
644
+			// check for shadow + create shadow recource
645
+			if ($markerShadow && file_exists($markerBaseDir . '/' . $markerShadow)) {
646
+				$markerShadowImg = imagecreatefrompng($markerBaseDir . '/' . $markerShadow);
647
+			}
648
+			// calc position
649
+			$destX = floor(
650
+				($this->width / 2) -
651
+				$this->tileSize * ($this->centerX - $this->lonToTile($markerLon, $this->zoom))
652
+			);
653
+			$destY = floor(
654
+				($this->height / 2) -
655
+				$this->tileSize * ($this->centerY - $this->latToTile($markerLat, $this->zoom))
656
+			);
657
+			// copy shadow on basemap
658
+			if ($markerShadow && $markerShadowImg) {
659
+				imagecopy(
660
+					$this->image,
661
+					$markerShadowImg,
662
+					$destX + (int)$markerShadowOffsetX,
663
+					$destY + (int)$markerShadowOffsetY,
664
+					0,
665
+					0,
666
+					imagesx($markerShadowImg),
667
+					imagesy($markerShadowImg)
668
+				);
669
+			}
670
+			// copy marker on basemap above shadow
671
+			imagecopy(
672
+				$this->image,
673
+				$markerImg,
674
+				$destX + (int)$markerImageOffsetX,
675
+				$destY + (int)$markerImageOffsetY,
676
+				0,
677
+				0,
678
+				imagesx($markerImg),
679
+				imagesy($markerImg)
680
+			);
681
+			// add label
682
+			imagestring(
683
+				$this->image,
684
+				3,
685
+				$destX - imagesx($markerImg) + 1,
686
+				$destY + (int)$markerImageOffsetY + 1,
687
+				++$count,
688
+				$bgcolor
689
+			);
690
+			imagestring(
691
+				$this->image,
692
+				3,
693
+				$destX - imagesx($markerImg),
694
+				$destY + (int)$markerImageOffsetY,
695
+				$count,
696
+				$color
697
+			);
698
+		}
699
+	}
700
+
701
+	/**
702
+	 * Draw kml trace on the map.
703
+	 * @throws exception if loading the specified KML fails
704
+	 */
705
+	public function drawKML(): void
706
+	{
707
+		// TODO get colour from kml node (not currently supported in geoPHP)
708
+		$col     = imagecolorallocatealpha($this->image, 255, 0, 0, .4 * 127);
709
+		$kmlgeom = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
710
+		$this->drawGeometry($kmlgeom, $col);
711
+	}
712
+
713
+	/**
714
+	 * Draw geometry or geometry collection on the map.
715
+	 *
716
+	 * @param Geometry|GeometryCollection|MultiPolygon|MultiLineString|MultiPoint|Polygon|LineString|Point $geom
717
+	 * @param int                                                                                          $colour
718
+	 *            drawing colour
719
+	 */
720
+	private function drawGeometry(Geometry $geom, int $colour): void
721
+	{
722
+		if (empty($geom)) {
723
+			return;
724
+		}
725
+
726
+		switch ($geom->geometryType()) {
727
+			case 'GeometryCollection' :
728
+				// recursively draw part of the collection
729
+				for ($i = 1; $i < $geom->numGeometries() + 1; $i++) {
730
+					$_geom = $geom->geometryN($i);
731
+					$this->drawGeometry($_geom, $colour);
732
+				}
733
+				break;
734
+			case 'MultiPolygon' :
735
+			case 'MultiLineString' :
736
+			case 'MultiPoint' :
737
+				// TODO implement / do nothing
738
+				break;
739
+			case 'Polygon' :
740
+				$this->drawPolygon($geom, $colour);
741
+				break;
742
+			case 'LineString' :
743
+				$this->drawLineString($geom, $colour);
744
+				break;
745
+			case 'Point' :
746
+				$this->drawPoint($geom, $colour);
747
+				break;
748
+			default :
749
+				// draw nothing
750
+				break;
751
+		}
752
+	}
753
+
754
+	/**
755
+	 * Draw a polygon on the map.
756
+	 *
757
+	 * @param Polygon $polygon
758
+	 * @param int     $colour
759
+	 *            drawing colour
760
+	 */
761
+	private function drawPolygon(Polygon $polygon, int $colour)
762
+	{
763
+		// TODO implementation of drawing holes,
764
+		// maybe draw the polygon to an in-memory image and use imagecopy, draw polygon in col., draw holes in bgcol?
765
+
766
+		// print_r('Polygon:<br />');
767
+		// print_r($polygon);
768
+		$extPoints = array();
769
+		// extring is a linestring actually..
770
+		$extRing = $polygon->exteriorRing();
771
+
772
+		for ($i = 1; $i < $extRing->numGeometries(); $i++) {
773
+			$p1           = $extRing->geometryN($i);
774
+			$x            = floor(
775
+				($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
776
+			);
777
+			$y            = floor(
778
+				($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
779
+			);
780
+			$extPoints [] = $x;
781
+			$extPoints [] = $y;
782
+		}
783
+		// print_r('points:('.($i-1).')<br />');
784
+		// print_r($extPoints);
785
+		// imagepolygon ($this->image, $extPoints, $i-1, $colour );
786
+		imagefilledpolygon($this->image, $extPoints, $i - 1, $colour);
787
+	}
788
+
789
+	/**
790
+	 * Draw a line on the map.
791
+	 *
792
+	 * @param LineString $line
793
+	 * @param int        $colour
794
+	 *            drawing colour
795
+	 */
796
+	private function drawLineString(LineString $line, int $colour)
797
+	{
798
+		imagesetthickness($this->image, 2);
799
+		for ($p = 1; $p < $line->numGeometries(); $p++) {
800
+			// get first pair of points
801
+			$p1 = $line->geometryN($p);
802
+			$p2 = $line->geometryN($p + 1);
803
+			// translate to paper space
804
+			$x1 = floor(
805
+				($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
806
+			);
807
+			$y1 = floor(
808
+				($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
809
+			);
810
+			$x2 = floor(
811
+				($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p2->x(), $this->zoom))
812
+			);
813
+			$y2 = floor(
814
+				($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p2->y(), $this->zoom))
815
+			);
816
+			// draw to image
817
+			imageline($this->image, $x1, $y1, $x2, $y2, $colour);
818
+		}
819
+		imagesetthickness($this->image, 1);
820
+	}
821
+
822
+	/**
823
+	 * Draw a point on the map.
824
+	 *
825
+	 * @param Point $point
826
+	 * @param int   $colour
827
+	 *            drawing colour
828
+	 */
829
+	private function drawPoint(Point $point, int $colour)
830
+	{
831
+		imagesetthickness($this->image, 2);
832
+		// translate to paper space
833
+		$cx = floor(
834
+			($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($point->x(), $this->zoom))
835
+		);
836
+		$cy = floor(
837
+			($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($point->y(), $this->zoom))
838
+		);
839
+		$r  = 5;
840
+		// draw to image
841
+		// imageellipse($this->image, $cx, $cy,$r, $r, $colour);
842
+		imagefilledellipse($this->image, $cx, $cy, $r, $r, $colour);
843
+		// don't use imageellipse because the imagesetthickness function has
844
+		// no effect. So the better workaround is to use imagearc.
845
+		imagearc($this->image, $cx, $cy, $r, $r, 0, 359, $colour);
846
+		imagesetthickness($this->image, 1);
847
+	}
848
+
849
+	/**
850
+	 * Draw gpx trace on the map.
851
+	 * @throws exception if loading the specified GPX fails
852
+	 */
853
+	public function drawGPX()
854
+	{
855
+		$col     = imagecolorallocatealpha($this->image, 0, 0, 255, .4 * 127);
856
+		$gpxgeom = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
857
+		$this->drawGeometry($gpxgeom, $col);
858
+	}
859
+
860
+	/**
861
+	 * Draw geojson on the map.
862
+	 * @throws exception if loading the specified GeoJSON fails
863
+	 */
864
+	public function drawGeojson()
865
+	{
866
+		$col     = imagecolorallocatealpha($this->image, 255, 0, 255, .4 * 127);
867
+		$gpxgeom = geoPHP::load(file_get_contents($this->geojsonFileName), 'json');
868
+		$this->drawGeometry($gpxgeom, $col);
869
+	}
870
+
871
+	/**
872
+	 * add copyright and origin notice and icons to the map.
873
+	 */
874
+	public function drawCopyright()
875
+	{
876
+		$logoBaseDir = dirname(__FILE__) . '/' . 'logo/';
877
+		$logoImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo ['openstreetmap'] ['logo']);
878
+		$textcolor   = imagecolorallocate($this->image, 0, 0, 0);
879
+		$bgcolor     = imagecolorallocate($this->image, 200, 200, 200);
880
+
881
+		imagecopy(
882
+			$this->image,
883
+			$logoImg,
884
+			0,
885
+			imagesy($this->image) - imagesy($logoImg),
886
+			0,
887
+			0,
888
+			imagesx($logoImg),
889
+			imagesy($logoImg)
890
+		);
891
+		imagestring(
892
+			$this->image,
893
+			1,
894
+			imagesx($logoImg) + 2,
895
+			imagesy($this->image) - imagesy($logoImg) + 1,
896
+			$this->tileInfo ['openstreetmap'] ['txt'],
897
+			$bgcolor
898
+		);
899
+		imagestring(
900
+			$this->image,
901
+			1,
902
+			imagesx($logoImg) + 1,
903
+			imagesy($this->image) - imagesy($logoImg),
904
+			$this->tileInfo ['openstreetmap'] ['txt'],
905
+			$textcolor
906
+		);
907
+
908
+		// additional tile source info, ie. who created/hosted the tiles
909
+		$xIconOffset = 0;
910
+		if ($this->maptype === 'openstreetmap') {
911
+			$mapAuthor = "(c) OpenStreetMap maps/CC BY-SA";
912
+		} else {
913
+			$mapAuthor   = $this->tileInfo [$this->maptype] ['txt'];
914
+			$iconImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo [$this->maptype] ['logo']);
915
+			$xIconOffset = imagesx($iconImg);
916
+			imagecopy(
917
+				$this->image,
918
+				$iconImg,
919
+				imagesx($logoImg) + 1,
920
+				imagesy($this->image) - imagesy($iconImg),
921
+				0,
922
+				0,
923
+				imagesx($iconImg),
924
+				imagesy($iconImg)
925
+			);
926
+		}
927
+		imagestring(
928
+			$this->image,
929
+			1,
930
+			imagesx($logoImg) + $xIconOffset + 4,
931
+			imagesy($this->image) - ceil(imagesy($logoImg) / 2) + 1,
932
+			$mapAuthor,
933
+			$bgcolor
934
+		);
935
+		imagestring(
936
+			$this->image,
937
+			1,
938
+			imagesx($logoImg) + $xIconOffset + 3,
939
+			imagesy($this->image) - ceil(imagesy($logoImg) / 2),
940
+			$mapAuthor,
941
+			$textcolor
942
+		);
943
+	}
944 944
 }
Please login to merge, or discard this patch.
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
 
24 24
 // phpcs:disable PSR1.Files.SideEffects
25 25
 // TODO resolve side effect
26
-include_once(realpath(__DIR__) . '/../geophp/geoPHP/geoPHP.inc');
26
+include_once(realpath(__DIR__).'/../geophp/geoPHP/geoPHP.inc');
27 27
 
28 28
 /**
29 29
  *
@@ -216,9 +216,9 @@  discard block
 block discarded – undo
216 216
         $this->gpxFileName      = $gpx;
217 217
         $this->geojsonFileName  = $geojson;
218 218
         $this->mediaBaseDir     = $mediaDir;
219
-        $this->tileCacheBaseDir = $tileCacheBaseDir . '/olmaptiles';
219
+        $this->tileCacheBaseDir = $tileCacheBaseDir.'/olmaptiles';
220 220
         $this->useTileCache     = $this->tileCacheBaseDir !== '';
221
-        $this->mapCacheBaseDir  = $mediaDir . '/olmapmaps';
221
+        $this->mapCacheBaseDir  = $mediaDir.'/olmapmaps';
222 222
         $this->autoZoomExtent   = $autoZoomExtent;
223 223
         $this->apikey           = $apikey;
224 224
     }
@@ -263,10 +263,10 @@  discard block
 block discarded – undo
263 263
     private function autoZoom(float $paddingFactor = 1.0): void
264 264
     {
265 265
         $geoms    = array();
266
-        $geoms [] = new Point ($this->lon, $this->lat);
266
+        $geoms [] = new Point($this->lon, $this->lat);
267 267
         if (!empty ($this->markers)) {
268 268
             foreach ($this->markers as $marker) {
269
-                $geoms [] = new Point ($marker ['lon'], $marker ['lat']);
269
+                $geoms [] = new Point($marker ['lon'], $marker ['lat']);
270 270
             }
271 271
         }
272 272
         if (file_exists($this->kmlFileName)) {
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
             return;
294 294
         }
295 295
 
296
-        $geom     = new GeometryCollection ($geoms);
296
+        $geom     = new GeometryCollection($geoms);
297 297
         $centroid = $geom->centroid();
298 298
         $bbox     = $geom->getBBox();
299 299
 
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
         $vy0 = log(tan(M_PI * (0.25 + $bbox ['miny'] / 360)));
303 303
         $vy1 = log(tan(M_PI * (0.25 + $bbox ['maxy'] / 360)));
304 304
         Logger::debug("StaticMap::autoZoom: vertical resolution: $vy0, $vy1");
305
-        if ($vy1 - $vy0 === 0.0){
305
+        if ($vy1 - $vy0 === 0.0) {
306 306
             $resolutionVertical = 0;
307 307
             Logger::debug("StaticMap::autoZoom: using $resolutionVertical");
308 308
         } else {
@@ -314,7 +314,7 @@  discard block
 block discarded – undo
314 314
         Logger::debug("StaticMap::autoZoom: using $resolutionHorizontal");
315 315
         $resolution           = max($resolutionHorizontal, $resolutionVertical) * $paddingFactor;
316 316
         $zoom                 = $this->zoom;
317
-        if ($resolution > 0){
317
+        if ($resolution > 0) {
318 318
             $zoom             = log(360 / ($resolution * $this->tileSize), 2);
319 319
         }
320 320
 
@@ -355,11 +355,11 @@  discard block
 block discarded – undo
355 355
     public function mapCacheIDToFilename(): string
356 356
     {
357 357
         if (!$this->mapCacheFile) {
358
-            $this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_"
359
-                . substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2)
360
-                . "/" . substr($this->mapCacheID, 4);
358
+            $this->mapCacheFile = $this->mapCacheBaseDir."/".$this->maptype."/".$this->zoom."/cache_"
359
+                . substr($this->mapCacheID, 0, 2)."/".substr($this->mapCacheID, 2, 2)
360
+                . "/".substr($this->mapCacheID, 4);
361 361
         }
362
-        return $this->mapCacheFile . "." . $this->mapCacheExtension;
362
+        return $this->mapCacheFile.".".$this->mapCacheExtension;
363 363
     }
364 364
 
365 365
     /**
@@ -500,14 +500,14 @@  discard block
 block discarded – undo
500 500
             return $cached;
501 501
         }
502 502
 
503
-        $_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; ' . PHP_OS . ')';
503
+        $_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; '.PHP_OS.')';
504 504
         if (function_exists("curl_init")) {
505 505
             // use cUrl
506 506
             $ch = curl_init();
507 507
             curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
508 508
             curl_setopt($ch, CURLOPT_USERAGENT, $_UA);
509 509
             curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
510
-            curl_setopt($ch, CURLOPT_URL, $url . $this->apikey);
510
+            curl_setopt($ch, CURLOPT_URL, $url.$this->apikey);
511 511
             Logger::debug("StaticMap::fetchTile: getting: $url using curl_exec");
512 512
             $tile = curl_exec($ch);
513 513
             curl_close($ch);
@@ -517,21 +517,21 @@  discard block
 block discarded – undo
517 517
             $opts = array(
518 518
                 'http' => array(
519 519
                     'method'          => "GET",
520
-                    'header'          => "Accept-language: en\r\n" . "User-Agent: $_UA\r\n" . "accept: image/png\r\n",
520
+                    'header'          => "Accept-language: en\r\n"."User-Agent: $_UA\r\n"."accept: image/png\r\n",
521 521
                     'request_fulluri' => true
522 522
                 )
523 523
             );
524 524
             if (isset($conf['proxy']['host'], $conf['proxy']['port'])
525 525
                 && $conf['proxy']['host'] !== ''
526 526
                 && $conf['proxy']['port'] !== '') {
527
-                $opts['http'] += ['proxy' => "tcp://" . $conf['proxy']['host'] . ":" . $conf['proxy']['port']];
527
+                $opts['http'] += ['proxy' => "tcp://".$conf['proxy']['host'].":".$conf['proxy']['port']];
528 528
             }
529 529
 
530 530
             $context = stream_context_create($opts);
531 531
             Logger::debug(
532 532
                 "StaticMap::fetchTile: getting: $url . $this->apikey using file_get_contents and options $opts"
533 533
             );
534
-            $tile = file_get_contents($url . $this->apikey, false, $context);
534
+            $tile = file_get_contents($url.$this->apikey, false, $context);
535 535
         }
536 536
         if ($tile && $this->useTileCache) {
537 537
             $this->writeTileToCache($url, $tile);
@@ -560,7 +560,7 @@  discard block
 block discarded – undo
560 560
      */
561 561
     public function tileUrlToFilename(string $url): string
562 562
     {
563
-        return $this->tileCacheBaseDir . "/" . substr($url, strpos($url, '/') + 1);
563
+        return $this->tileCacheBaseDir."/".substr($url, strpos($url, '/') + 1);
564 564
     }
565 565
 
566 566
     /**
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
         $count               = 0;
599 599
         $color               = imagecolorallocate($this->image, 0, 0, 0);
600 600
         $bgcolor             = imagecolorallocate($this->image, 200, 200, 200);
601
-        $markerBaseDir       = __DIR__ . '/icons';
601
+        $markerBaseDir       = __DIR__.'/icons';
602 602
         $markerImageOffsetX  = 0;
603 603
         $markerImageOffsetY  = 0;
604 604
         $markerShadowOffsetX = 0;
@@ -618,7 +618,7 @@  discard block
 block discarded – undo
618 618
             if ($markerType) {
619 619
                 foreach ($this->markerPrototypes as $markerPrototype) {
620 620
                     if (preg_match($markerPrototype ['regex'], $markerType, $matches)) {
621
-                        $markerFilename = $matches [0] . $markerPrototype ['extension'];
621
+                        $markerFilename = $matches [0].$markerPrototype ['extension'];
622 622
                         if ($markerPrototype ['offsetImage']) {
623 623
                             list ($markerImageOffsetX, $markerImageOffsetY) = explode(
624 624
                                 ",",
@@ -636,14 +636,14 @@  discard block
 block discarded – undo
636 636
                 }
637 637
             }
638 638
             // create img resource
639
-            if (file_exists($markerBaseDir . '/' . $markerFilename)) {
640
-                $markerImg = imagecreatefrompng($markerBaseDir . '/' . $markerFilename);
639
+            if (file_exists($markerBaseDir.'/'.$markerFilename)) {
640
+                $markerImg = imagecreatefrompng($markerBaseDir.'/'.$markerFilename);
641 641
             } else {
642
-                $markerImg = imagecreatefrompng($markerBaseDir . '/marker.png');
642
+                $markerImg = imagecreatefrompng($markerBaseDir.'/marker.png');
643 643
             }
644 644
             // check for shadow + create shadow recource
645
-            if ($markerShadow && file_exists($markerBaseDir . '/' . $markerShadow)) {
646
-                $markerShadowImg = imagecreatefrompng($markerBaseDir . '/' . $markerShadow);
645
+            if ($markerShadow && file_exists($markerBaseDir.'/'.$markerShadow)) {
646
+                $markerShadowImg = imagecreatefrompng($markerBaseDir.'/'.$markerShadow);
647 647
             }
648 648
             // calc position
649 649
             $destX = floor(
@@ -659,8 +659,8 @@  discard block
 block discarded – undo
659 659
                 imagecopy(
660 660
                     $this->image,
661 661
                     $markerShadowImg,
662
-                    $destX + (int)$markerShadowOffsetX,
663
-                    $destY + (int)$markerShadowOffsetY,
662
+                    $destX + (int) $markerShadowOffsetX,
663
+                    $destY + (int) $markerShadowOffsetY,
664 664
                     0,
665 665
                     0,
666 666
                     imagesx($markerShadowImg),
@@ -671,8 +671,8 @@  discard block
 block discarded – undo
671 671
             imagecopy(
672 672
                 $this->image,
673 673
                 $markerImg,
674
-                $destX + (int)$markerImageOffsetX,
675
-                $destY + (int)$markerImageOffsetY,
674
+                $destX + (int) $markerImageOffsetX,
675
+                $destY + (int) $markerImageOffsetY,
676 676
                 0,
677 677
                 0,
678 678
                 imagesx($markerImg),
@@ -683,7 +683,7 @@  discard block
 block discarded – undo
683 683
                 $this->image,
684 684
                 3,
685 685
                 $destX - imagesx($markerImg) + 1,
686
-                $destY + (int)$markerImageOffsetY + 1,
686
+                $destY + (int) $markerImageOffsetY + 1,
687 687
                 ++$count,
688 688
                 $bgcolor
689 689
             );
@@ -691,7 +691,7 @@  discard block
 block discarded – undo
691 691
                 $this->image,
692 692
                 3,
693 693
                 $destX - imagesx($markerImg),
694
-                $destY + (int)$markerImageOffsetY,
694
+                $destY + (int) $markerImageOffsetY,
695 695
                 $count,
696 696
                 $color
697 697
             );
@@ -873,8 +873,8 @@  discard block
 block discarded – undo
873 873
      */
874 874
     public function drawCopyright()
875 875
     {
876
-        $logoBaseDir = dirname(__FILE__) . '/' . 'logo/';
877
-        $logoImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo ['openstreetmap'] ['logo']);
876
+        $logoBaseDir = dirname(__FILE__).'/'.'logo/';
877
+        $logoImg     = imagecreatefrompng($logoBaseDir.$this->tileInfo ['openstreetmap'] ['logo']);
878 878
         $textcolor   = imagecolorallocate($this->image, 0, 0, 0);
879 879
         $bgcolor     = imagecolorallocate($this->image, 200, 200, 200);
880 880
 
@@ -911,7 +911,7 @@  discard block
 block discarded – undo
911 911
             $mapAuthor = "(c) OpenStreetMap maps/CC BY-SA";
912 912
         } else {
913 913
             $mapAuthor   = $this->tileInfo [$this->maptype] ['txt'];
914
-            $iconImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo [$this->maptype] ['logo']);
914
+            $iconImg     = imagecreatefrompng($logoBaseDir.$this->tileInfo [$this->maptype] ['logo']);
915 915
             $xIconOffset = imagesx($iconImg);
916 916
             imagecopy(
917 917
                 $this->image,
Please login to merge, or discard this patch.