Metrical::squareByHypotenuse()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Bavix\Geo;
4
5
use Bavix\Geo\Geometry\Line;
6
use Bavix\Geo\Geometry\Quadrangle;
7
use Bavix\Geo\Unit\Distance;
8
9
class Metrical
10
{
11
12
    /**
13
     * @param Coordinate $center
14
     * @param Distance   $unit
15
     *
16
     * @return Quadrangle
17
     */
18
    public function squareByHypotenuse(Coordinate $center, Distance $unit): Quadrangle
19
    {
20
        $item = clone $unit;
21
        $item->miles /= \sqrt(2);
22
        return $this->square($center, $item);
23
    }
24
25
    /**
26
     * @param Coordinate $center
27
     * @param Distance   $unit
28
     *
29
     * @return Quadrangle
30
     */
31
    public function square(Coordinate $center, Distance $unit): Quadrangle
32
    {
33
        return $this->rectangle($center, $unit, $unit);
34
    }
35
36
    /**
37
     * @param Coordinate $center
38
     * @param Distance   $unitX
39
     * @param Distance   $unitY
40
     *
41
     * @return Quadrangle
42
     */
43
    public function rectangle(Coordinate $center, Distance $unitX, Distance $unitY): Quadrangle
44
    {
45
        $vx = \rad2deg($unitX->nauticalMiles / 60.);
46
        $vy = \rad2deg($unitY->nauticalMiles / 60.);
47
        $dx = \deg2rad(\hypot($vx, $vx) / 2.);
48
        $dy = \deg2rad(\hypot(0, $vy));
49
50
        $computedX = $center->plus($dx, 0);
51
        $computedY = $center->plus(0, $dy);
52
53
        $lineX = new Line();
54
        $lineX->push($center);
55
        $lineY = clone $lineX;
56
        $lineX->push($computedX);
57
        $lineY->push($computedY);
58
59
        $latitude = $this->axisComputed($lineX, $unitX);
60
        $longitude = $this->axisComputed($lineY, $unitY, false);
61
62
        return Quadrangle::makeWithXY(
63
            $center,
64
            $unitX->miles * $latitude,
65
            $unitY->miles * $longitude
66
        );
67
    }
68
69
    /**
70
     * @param Line     $line
71
     * @param Distance $unit
72
     * @param bool     $isAxisX
73
     *
74
     * @return float
75
     */
76
    protected function axisComputed(Line $line, Distance $unit, bool $isAxisX = true): float
77
    {
78
        $computed = $line->pop();
79
        $center = $line->pop();
80
81
        $iterator = 0;
82
        $eps = $this->computedEps($unit);
83
        $computed = $computed->plus(
84
            $eps * $isAxisX,
85
            $eps * !$isAxisX
86
        );
87
88
        while ($iterator < 256) {
89
90
            $distance = $center->distanceTo($computed);
91
            $eps += $this->computedEps($distance);
92
93
            if ($distance->compareTo($unit)->greaterThanOrEqual()) {
94
                break;
95
            }
96
97
            $computed = $computed->plus(
98
                $eps * $isAxisX,
99
                $eps * !$isAxisX
100
            );
101
102
            $iterator++;
103
104
        }
105
106
        if ($isAxisX) {
107
            $result = $center->latitude->degrees - $computed->latitude->degrees;
108
        } else {
109
            $result = $center->longitude->degrees - $computed->longitude->degrees;
110
        }
111
112
        return \abs($result) / $unit->miles;
113
    }
114
115
    /**
116
     * @param Distance $axis
117
     *
118
     * @return float
119
     */
120
    protected function computedEps(Distance $axis): float
121
    {
122
        return \max(
123
            \round($axis->miles, 5) / 1e5,
124
            1e-7
125
        );
126
    }
127
128
}
129