ldc-lionor/app/Traits/Models/HasCoordinates.php
2023-02-24 15:20:58 +00:00

113 lines
3.8 KiB
PHP

<?php
namespace App\Traits\Models;
use Illuminate\Support\Str;
trait HasCoordinates
{
/**
* Convert decimal coordinate to sexagesimal
*
* @param float $value Decimal coordinate (ex : 1.209333).
* @param boolean $isLatitude Coordinates is a latitude ?.
* @return string Coordinate in sexagesimal
*/
private static function convertDecimalToDegree(float $value, bool $isLatitude): string
{
// Add cardinal point according to the axe (latitude or longitude) and the sign of the value.
$point = $isLatitude ? (($value < 0) ? 'S' : 'N') : (($value < 0) ? 'W' : 'E');
// Degrees.
list($degree, $decimal) = explode('.', \number_format($value, 10));
$degree = abs($degree);
// Minutes.
list($minute, $decimal) = explode('.', \number_format(\floatval('0.' . $decimal) * 60, 10));
$minute = \str_pad($minute, 2, "0", STR_PAD_LEFT);
// Seconds.
$second = round(\floatval('0.' . $decimal) * 60, 1, PHP_ROUND_HALF_UP);
$second = \str_pad(number_format($second, 1), 4, "0", STR_PAD_LEFT);
return "{$degree}°{$minute}'{$second}\"{$point}";
}
/**
* Convert sexagesimal coordinate to decimal
*
* @param string $value Sexagesimal coordinate (ex : 44°20'18.1"N).
* @param boolean $isLatitude Coordinate is a latitude ?.
* @return float Coordinate in decimal
* @throws \RuntimeException Not the good DMS format.
*/
private static function convertDegreeToDecimal(string $value, bool $isLatitude): float
{
// Si c'est une latitude, alors le nombre positif correspond au Nord, sinon l'Est.
$axe = $isLatitude ? 'N' : 'E';
$re = $isLatitude ?
'/^([0-8]?\d)°([0-5]?\d)\'([0-5]?\d\.\d)"(N|S)$/i' :
'/^([0-1]?[0-8]\d|\d?\d)°([0-5]?\d)\'([0-5]?\d\.\d)"(E|W|O)$/i';
preg_match($re, $value, $matches);
if (empty($matches)) {
throw new \RuntimeException("Le format DMS n'est pas conforme '{$value}'");
}
list($value, $degree, $minutes, $seconds, $point) = $matches;
// Si l'axe est Nord ou Est, alors le nombre est positif sinon i est négatif.
$degreeDecimalValue = \floatval(\sprintf(
'%s%s',
Str::upper($point) === $axe ? '' : '-',
round($degree + $minutes / 60 + $seconds / 3600, 6, PHP_ROUND_HALF_UP)
));
return !$degreeDecimalValue ? abs($degreeDecimalValue) : $degreeDecimalValue;
}
/**
* Get decimal shop's latitude and convert it to sexagesimal coordinate.
*
* @param float $value Decimal coordinate.
* @return string $sexagesimalValue Sexagesimal coordinate
*/
public function getLatitudeAttribute(float $value): string
{
return static::convertDecimalToDegree($value, true);
}
/**
* Set decimal shop's latitude from sexagesimal coordinate.
*
* @param string $value Sexagesimal coordinate.
* @return void
*/
public function setLatitudeAttribute(string $value): void
{
$this->attributes['latitude'] = static::convertDegreeToDecimal($value, true);
}
/**
* Get decimal shop's longitude and convert it to sexagesimal coordinate.
*
* @param float $value Decimal coordinate.
* @return string $sexagesimalValue Sexagesimal coordinate
*/
public function getLongitudeAttribute(float $value)
{
return static::convertDecimalToDegree($value, false);
}
/**
* Set decimal shop's longitude from sexagesimal coordinate.
*
* @param string $value Sexagesimal coordinate.
* @return void
*/
public function setLongitudeAttribute(string $value): void
{
$this->attributes['longitude'] = static::convertDegreeToDecimal($value, false);
}
}