-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathCircleToPolygon.php
61 lines (55 loc) · 1.84 KB
/
CircleToPolygon.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
/**
* The GeoJSON spec does not support circles. If you wish to create an area that represents a circle,
* your best bet is to create a polygon that roughly approximates the circle.
* In the limit of the number of edges becoming infinite, your Polygon will match a circle.
*/
class CircleToPolygon
{
/**
* @param array $center In [longitude, latitude] format
* @param int $radius In meters
* @param int $numberOfSegments Optional that defaults to 32
*/
public static function convert($center, $radius, $numberOfSegments = 32)
{
$n = $numberOfSegments;
$flatCoordinates = [];
$coordinates = [];
for ($i = 0; $i < $n; $i++) {
$flatCoordinates = array_merge($flatCoordinates, static::offset($center, $radius, 2 * pi() * $i / $n));
}
$flatCoordinates[] = $flatCoordinates[0];
$flatCoordinates[] = $flatCoordinates[1];
for ($i = 0, $j = 0; $j < count($flatCoordinates); $j += 2) {
$coordinates[$i++] = array_slice($flatCoordinates, $j, 2);
}
return [
'type' => 'Polygon',
'coordinates' => [array_reverse($coordinates)]
];
}
public static function toRadians($angleInDegrees = null)
{
return $angleInDegrees * pi() / 180;
}
public static function toDegrees($angleInRadians = null)
{
return $angleInRadians * 180 / pi();
}
public static function offset($c1, $distance, $bearing)
{
$lat1 = static::toRadians($c1[1]);
$lon1 = static::toRadians($c1[0]);
$dByR = $distance / 6378137; // distance divided by 6378137 (radius of the earth) wgs84
$lat = asin(
sin($lat1) * cos($dByR) +
cos($lat1) * sin($dByR) * cos($bearing)
);
$lon = $lon1 + atan2(
sin($bearing) * sin($dByR) * cos($lat1),
cos($dByR) - sin($lat1) * sin($lat)
);
return [static::toDegrees($lon), static::toDegrees($lat)];
}
}