Passed
Push — master ( a0122a...936f3f )
by Doug
36:42 queued 23:33
created

applyForwardAdjustment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 9
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord\CoordinateOperation;
10
11
use function abs;
12
use function assert;
13
use function explode;
14
use const PHP_MAJOR_VERSION;
15
use PHPCoord\CoordinateReferenceSystem\Geographic;
16
use PHPCoord\GeographicPoint;
17
use PHPCoord\UnitOfMeasure\Angle\Angle;
18
use PHPCoord\UnitOfMeasure\Length\Metre;
19
use function preg_replace;
20
use SplFileObject;
21
use function str_replace;
22
use function trim;
23
24
class IGNGeocentricTranslationGrid extends SplFileObject
25
{
26
    private const ITERATION_CONVERGENCE = 0.0001;
27
28
    private float $lowerLatitudeLimit;
29
    private float $upperLatitudeLimit;
30
    private float $lowerLongitudeLimit;
31
    private float $upperLongitudeLimit;
32
    private float $latitudeGridInterval;
33
    private float $longitudeGridInterval;
34
35 3
    public function __construct($filename)
36
    {
37 3
        parent::__construct($filename);
38
39 3
        $this->readHeader();
40 3
    }
41
42 2
    public function applyForwardAdjustment(GeographicPoint $point, Geographic $to): GeographicPoint
43
    {
44 2
        [$tx, $ty, $tz] = $this->getAdjustment($point->getLatitude(), $point->getLongitude());
45
46 2
        return $point->geocentricTranslation(
47 2
            $to,
48
            $tx,
49
            $ty,
50
            $tz,
51
        );
52
    }
53
54 1
    public function applyReverseAdjustment(GeographicPoint $point, Geographic $to): GeographicPoint
55
    {
56 1
        $adjustment = [new Metre(0), new Metre(0), new Metre(0)];
57 1
        $latitude = $point->getLatitude();
58 1
        $longitude = $point->getLongitude();
59
60
        do {
61 1
            $prevAdjustment = $adjustment;
62 1
            $adjustment = $this->getAdjustment($latitude, $longitude);
63 1
            $newPoint = $point->geocentricTranslation(
64 1
                $to,
65 1
                $adjustment[0]->multiply(-1),
66 1
                $adjustment[1]->multiply(-1),
67 1
                $adjustment[2]->multiply(-1),
68
            );
69
70 1
            $latitude = $newPoint->getLatitude();
71 1
            $longitude = $newPoint->getLongitude();
72 1
        } while (abs($adjustment[0]->subtract($prevAdjustment[0])->getValue()) > self::ITERATION_CONVERGENCE && abs($adjustment[1]->subtract($prevAdjustment[1])->getValue()) > self::ITERATION_CONVERGENCE && abs($adjustment[2]->subtract($prevAdjustment[2])->getValue()) > self::ITERATION_CONVERGENCE);
73
74 1
        return $newPoint;
75
    }
76
77
    /**
78
     * @return Metre[]
79
     */
80 3
    private function getAdjustment(Angle $latitude, Angle $longitude): array
81
    {
82 3
        $latitudeIndex = (int) (string) (($latitude->getValue() - $this->lowerLatitudeLimit) / $this->latitudeGridInterval);
83 3
        $longitudeIndex = (int) (string) (($longitude->getValue() - $this->lowerLongitudeLimit) / $this->longitudeGridInterval);
84
85 3
        $corner0 = $this->getRecord($latitudeIndex, $longitudeIndex);
86 3
        $corner1 = $this->getRecord($latitudeIndex + 1, $longitudeIndex);
87 3
        $corner2 = $this->getRecord($latitudeIndex + 1, $longitudeIndex + 1);
88 3
        $corner3 = $this->getRecord($latitudeIndex, $longitudeIndex + 1);
89
90 3
        $dLatitude = $latitude->getValue() - $corner0[2];
91 3
        $dLongitude = $longitude->getValue() - $corner0[1];
92
93 3
        $t = $dLatitude / $this->latitudeGridInterval;
94 3
        $u = $dLongitude / $this->longitudeGridInterval;
95
96 3
        $tx = (1 - $t) * (1 - $u) * $corner0[3] + ($t) * (1 - $u) * $corner1[3] + ($t) * ($u) * $corner2[3] + (1 - $t) * ($u) * $corner3[3];
97 3
        $ty = (1 - $t) * (1 - $u) * $corner0[4] + ($t) * (1 - $u) * $corner1[4] + ($t) * ($u) * $corner2[4] + (1 - $t) * ($u) * $corner3[4];
98 3
        $tz = (1 - $t) * (1 - $u) * $corner0[5] + ($t) * (1 - $u) * $corner1[5] + ($t) * ($u) * $corner2[5] + (1 - $t) * ($u) * $corner3[5];
99
100 3
        return [new Metre($tx), new Metre($ty), new Metre($tz)];
101
    }
102
103 3
    private function getRecord(int $latitudeIndex, int $longitudeIndex): array
104
    {
105 3
        $latitudesPerLongitude = (int) (string) (($this->upperLatitudeLimit - $this->lowerLatitudeLimit) / $this->latitudeGridInterval);
106 3
        $record = ($longitudeIndex * ($latitudesPerLongitude + 1) + $latitudeIndex + 4);
107
108
        // https://bugs.php.net/bug.php?id=62004
109 3
        if (PHP_MAJOR_VERSION < 8) {
110
            --$record;
111
        }
112
113 3
        $this->seek($record);
114
115 3
        return explode(' ', trim(preg_replace('/ +/', ' ', $this->fgets())));
116
    }
117
118 3
    private function readHeader(): void
119
    {
120 3
        $header0 = $this->fgets();
0 ignored issues
show
Unused Code introduced by
The assignment to $header0 is dead and can be removed.
Loading history...
121 3
        $header1 = $this->fgets();
122 3
        $header2 = $this->fgets();
123 3
        $header3 = $this->fgets();
0 ignored issues
show
Unused Code introduced by
The assignment to $header3 is dead and can be removed.
Loading history...
124
125 3
        $interpolationMethod = trim(str_replace('GR3D2', '', $header2));
126 3
        assert($interpolationMethod === 'INTERPOLATION BILINEAIRE');
127
128 3
        $gridDimensions = explode(' ', trim(preg_replace('/ +/', ' ', str_replace('GR3D1', '', $header1))));
129 3
        $this->lowerLongitudeLimit = (float) $gridDimensions[0];
130 3
        $this->upperLongitudeLimit = (float) $gridDimensions[1];
131 3
        $this->lowerLatitudeLimit = (float) $gridDimensions[2];
132 3
        $this->upperLatitudeLimit = (float) $gridDimensions[3];
133 3
        $this->longitudeGridInterval = (float) $gridDimensions[4];
134 3
        $this->latitudeGridInterval = (float) $gridDimensions[5];
135 3
    }
136
}
137