1 <?php
declare(strict_types
=1);
4 * This file is part of the Rapsys PackBundle package.
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Rapsys\PackBundle\Util
;
14 use Symfony\Component\Routing\RouterInterface
;
21 * The cycle tile server
23 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
25 const cycle
= 'http://a.tile.thunderforest.com/cycle/{Z}/{X}/{Y}.png';
40 const highFill
= '#c3c3f9';
45 const highFontSize
= 30;
48 * The high radius size
53 * The high stroke color
55 const highStroke
= '#3333c3';
58 * The high stroke size
60 const highStrokeWidth
= 4;
70 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
72 const osm
= 'https://tile.openstreetmap.org/{Z}/{X}/{Y}.png';
82 const stroke
= '#00c3f9';
87 const strokeWidth
= 2;
90 * The transport tile server
92 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
94 const transport
= 'http://a.tile.thunderforest.com/transport/{Z}/{X}/{Y}.png';
107 * The RouterInterface instance
109 protected RouterInterface
$router;
112 * The SluggerUtil instance
114 protected SluggerUtil
$slugger;
124 public int $fontSize;
127 * The high fill color
129 public string $highFill;
134 public int $highFontSize;
139 public int $highRadius;
142 * The high stroke color
144 public string $highStroke;
149 public int $highStrokeWidth;
154 public string $stroke;
159 public int $strokeWidth;
167 * Creates a new map util
169 * @param RouterInterface $router The RouterInterface instance
170 * @param SluggerUtil $slugger The SluggerUtil instance
172 function __construct(RouterInterface
$router, SluggerUtil
$slugger, string $fill = self
::fill
, int $fontSize = self
::fontSize
, string $highFill = self
::highFill
, int $highFontSize = self
::highFontSize
, int $highRadius = self
::highRadius
, string $highStroke = self
::highStroke
, int $highStrokeWidth = self
::highStrokeWidth
, int $radius = self
::radius
, string $stroke = self
::stroke
, int $strokeWidth = self
::strokeWidth
) {
174 $this->router
= $router;
177 $this->slugger
= $slugger;
183 $this->fontSize
= $fontSize;
186 $this->highFill
= $highFill;
189 $this->highFontSize
= $highFontSize;
191 //Set high radius size
192 $this->highRadius
= $highRadius;
195 $this->highStroke
= $highStroke;
197 //Set high stroke size
198 $this->highStrokeWidth
= $highStrokeWidth;
201 $this->radius
= $radius;
204 $this->stroke
= $stroke;
207 $this->strokeWidth
= $strokeWidth;
213 * @param string $caption The caption
214 * @param int $updated The updated timestamp
215 * @param float $latitude The latitude
216 * @param float $longitude The longitude
217 * @param int $zoom The zoom
218 * @param int $width The width
219 * @param int $height The height
220 * @return int The zoom
222 public function mapUrl(string $caption, int $updated, float $latitude, float $longitude, int $zoom = self
::zoom
, int $width = self
::length
, int $height = self
::length
): array {
224 $link = $this->slugger
->serialize([$updated, $latitude, $longitude, $zoom +
1, $width * 2, $height * 2]);
227 $src = $this->slugger
->serialize([$updated, $latitude, $longitude, $zoom, $width, $height]);
231 'caption' => $caption,
232 'link' => $this->router
->generate('rapsys_pack_map', ['hash' => $link, 'updated' => $updated, 'latitude' => $latitude, 'longitude' => $longitude, 'zoom' => $zoom +
1, 'width' => $width * 2, 'height' => $height * 2]),
233 'src' => $this->router
->generate('rapsys_pack_map', ['hash' => $src, 'updated' => $updated, 'latitude' => $latitude, 'longitude' => $longitude, 'zoom' => $zoom, 'width' => $width, 'height' => $height]),
240 * Return multi map url
242 * @param string $caption The caption
243 * @param int $updated The updated timestamp
244 * @param float $latitude The latitude
245 * @param float $longitude The longitude
246 * @param array $coordinates The coordinates array
247 * @param int $zoom The zoom
248 * @param int $width The width
249 * @param int $height The height
250 * @return int The zoom
252 public function multiMapUrl(string $caption, int $updated, float $latitude, float $longitude, $coordinates = [], int $zoom = self
::zoom
, int $width = self
::length
, int $height = self
::length
): array {
254 $coordinate = implode('-', array_map(function ($v) { return $v
['latitude'].','.$v
['longitude']; }, $coordinates));
256 //Set coordinate hash
257 $hash = $this->slugger
->hash($coordinate);
260 $link = $this->slugger
->serialize([$updated, $latitude, $longitude, $hash, $zoom +
1, $width * 2, $height * 2]);
263 $src = $this->slugger
->serialize([$updated, $latitude, $longitude, $hash, $zoom, $width, $height]);
267 'caption' => $caption,
268 'link' => $this->router
->generate('rapsys_pack_multimap', ['hash' => $link, 'updated' => $updated, 'latitude' => $latitude, 'longitude' => $longitude, 'coordinates' => $coordinate, 'zoom' => $zoom +
1, 'width' => $width * 2, 'height' => $height * 2]),
269 'src' => $this->router
->generate('rapsys_pack_multimap', ['hash' => $src, 'updated' => $updated, 'latitude' => $latitude, 'longitude' => $longitude, 'coordinates' => $coordinate, 'zoom' => $zoom, 'width' => $width, 'height' => $height]),
276 * Return multi map zoom
278 * Compute a zoom to have all coordinates on multi map
279 * Multi map visible only from -($width / 2) until ($width / 2) and from -($height / 2) until ($height / 2)
281 * @see Wether we need to take in consideration circle radius in coordinates comparisons, likely +/-(radius / self::tz)
283 * @param float $latitude The latitude
284 * @param float $longitude The longitude
285 * @param array $coordinates The coordinates array
286 * @param int $zoom The zoom
287 * @param int $width The width
288 * @param int $height The height
289 * @return int The zoom
291 public function multiMapZoom(float $latitude, float $longitude, array $coordinates = [], int $zoom = self
::zoom
, int $width = self
::length
, int $height = self
::length
): int {
292 //Iterate on each zoom
293 for ($i = $zoom; $i >= 1; $i--) {
295 $centerX = self
::longitudeToX($longitude, $i);
296 $centerY = self
::latitudeToY($latitude, $i);
299 $startX = floor($centerX - $width / 2 / self
::tz
);
300 $startY = floor($centerY - $height / 2 / self
::tz
);
303 $endX = ceil($centerX +
$width / 2 / self
::tz
);
304 $endY = ceil($centerY +
$height / 2 / self
::tz
);
306 //Iterate on each coordinates
307 foreach($coordinates as $k => $coordinate) {
309 $destX = self
::longitudeToX($coordinate['longitude'], $i);
312 if ($startX >= $destX || $endX <= $destX) {
318 $destY = self
::latitudeToY($coordinate['latitude'], $i);
321 if ($startY >= $destY || $endY <= $destY) {
336 * Convert longitude to tile x number
338 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_5
340 * @param float $longitude The longitude
341 * @param int $zoom The zoom
343 * @return float The tile x
345 public static function longitudeToX(float $longitude, int $zoom): float {
346 return (($longitude +
180) / 360) * pow(2, $zoom);
350 * Convert latitude to tile y number
352 * @see https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_5
354 * @param $latitude The latitude
355 * @param $zoom The zoom
357 * @return float The tile y
359 public static function latitudeToY(float $latitude, int $zoom): float {
360 return (1 - log(tan(deg2rad($latitude)) +
1 / cos(deg2rad($latitude))) / pi()) / 2 * pow(2, $zoom);
364 * Convert tile x to longitude
366 * @param float $x The tile x
367 * @param int $zoom The zoom
369 * @return float The longitude
371 public static function xToLongitude(float $x, int $zoom): float {
372 return $x / pow(2, $zoom) * 360.0 - 180.0;
376 * Convert tile y to latitude
378 * @param float $y The tile y
379 * @param int $zoom The zoom
381 * @return float The latitude
383 public static function yToLatitude(float $y, int $zoom): float {
384 return rad2deg(atan(sinh(pi() * (1 - 2 * $y / pow(2, $zoom)))));
388 * Convert decimal latitude to sexagesimal
390 * @param float $latitude The decimal latitude
392 * @return string The sexagesimal longitude
394 public static function latitudeToSexagesimal(float $latitude): string {
396 $degree = $latitude %
60;
399 $minute = ($latitude - $degree) * 60 %
60;
402 $second = ($latitude - $degree - $minute / 60) * 3600 %
3600;
404 //Return sexagesimal longitude
405 return $degree.'°'.$minute.'\''.$second.'"'.($latitude >= 0 ? 'N' : 'S');
409 * Convert decimal longitude to sexagesimal
411 * @param float $longitude The decimal longitude
413 * @return string The sexagesimal longitude
415 public static function longitudeToSexagesimal(float $longitude): string {
417 $degree = $longitude %
60;
420 $minute = ($longitude - $degree) * 60 %
60;
423 $second = ($longitude - $degree - $minute / 60) * 3600 %
3600;
425 //Return sexagesimal longitude
426 return $degree.'°'.$minute.'\''.$second.'"'.($longitude >= 0 ? 'E' : 'W');