Passed
Push — master ( 9abb61...fb6dbd )
by Doug
08:29
created

GeographicPolygon   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Test Coverage

Coverage 75%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 32
dl 0
loc 69
ccs 27
cts 36
cp 0.75
rs 10
c 1
b 0
f 0
wmc 14

5 Methods

Rating   Name   Duplication   Size   Complexity  
A createWorld() 0 3 1
A containsPoint() 0 18 5
A createFromArray() 0 3 1
A __construct() 0 13 5
A getCentre() 0 12 2
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord\Geometry;
10
11
use function count;
12
use InvalidArgumentException;
13
use function max;
14
use function min;
15
use PHPCoord\CoordinateOperation\GeographicValue;
16
use PHPCoord\UnitOfMeasure\Angle\Degree;
17
18
class GeographicPolygon
19
{
20
    protected array $vertices;
21
22
    protected bool $crossesAntimeridian;
23
24 71
    protected function __construct(array $vertices, bool $crossesAntimeridian)
25
    {
26 71
        if (count($vertices) !== 4) {
27
            throw new InvalidArgumentException('A bounding box must have exactly 4 vertices (be rectangular)');
28
        }
29 71
        $this->vertices = $vertices;
30 71
        $this->crossesAntimeridian = $crossesAntimeridian;
31
32 71
        if ($this->crossesAntimeridian) { //convert polygon to be antimeridian based
33 7
            foreach ($this->vertices as &$vertex) {
34 7
                $vertex[0] += 180;
35 7
                if ($vertex[0] > 180) {
36 7
                    $vertex[0] -= 360;
37
                }
38
            }
39
        }
40 71
    }
41
42
    /**
43
     * @param array<Degree,Degree> $vertices [[long,lat], [long,lat]...]
44
     */
45 69
    public static function createFromArray(array $vertices, bool $crossesAntimeridian): self
46
    {
47 69
        return new self($vertices, $crossesAntimeridian);
48
    }
49
50 2
    public static function createWorld(): self
51
    {
52 2
        return new self([[-180, -90], [-180, 90], [180, 90], [180, -90]], false);
53
    }
54
55 16
    public function containsPoint(GeographicValue $point): bool
56
    {
57 16
        if ($this->crossesAntimeridian) {
58 2
            $longitude = $point->getLongitude()->add(new Degree(180));
59 2
            $point = new GeographicValue($point->getLatitude(), $longitude, $point->getHeight(), $point->getDatum());
60
        }
61
62 16
        [$lon1, $lat1] = $this->vertices[0];
63 16
        [$lon2, $lat2] = $this->vertices[2];
64 16
        $west = min($lon1, $lon2);
65 16
        $east = max($lon1, $lon2);
66 16
        $south = min($lat1, $lat2);
67 16
        $north = max($lat1, $lat2);
68
69 16
        $latitude = $point->getLatitude()->asDegrees()->getValue();
70 16
        $longitude = $point->getLongitude()->asDegrees()->getValue();
71
72 16
        return $latitude <= $north && $latitude >= $south && $longitude >= $west && $longitude <= $east;
73
    }
74
75
    public function getCentre(): array
76
    {
77
        [$west, $south] = $this->vertices[0];
78
        [$east, $north] = $this->vertices[2];
79
80
        $latitude = new Degree(($north + $south) / 2);
81
        $longitude = new Degree(($west + $east) / 2);
82
        if ($this->crossesAntimeridian) {
83
            $longitude = $longitude->subtract(new Degree(180));
84
        }
85
86
        return [$latitude, $longitude];
87
    }
88
}
89