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

CompoundPoint::asGeographicValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord;
10
11
use function cos;
12
use DateTime;
13
use DateTimeImmutable;
14
use DateTimeInterface;
15
use PHPCoord\CoordinateOperation\AutoConversion;
16
use PHPCoord\CoordinateOperation\ConvertiblePoint;
17
use PHPCoord\CoordinateReferenceSystem\Compound;
18
use PHPCoord\CoordinateReferenceSystem\Geographic3D;
19
use PHPCoord\CoordinateReferenceSystem\Vertical;
20
use PHPCoord\Exception\InvalidCoordinateReferenceSystemException;
21
use PHPCoord\UnitOfMeasure\Angle\Angle;
22
use PHPCoord\UnitOfMeasure\Length\Length;
23
use PHPCoord\UnitOfMeasure\Length\Metre;
24
use function sin;
25
use function sqrt;
26
27
/**
28
 * Coordinate representing a point expressed in 2 different CRSs (2D horizontal + 1D Vertical).
29
 */
30
class CompoundPoint extends Point implements ConvertiblePoint
31
{
32
    use AutoConversion;
33
34
    /**
35
     * Horizontal point.
36
     * @var GeographicPoint|ProjectedPoint
37
     */
38
    protected Point $horizontalPoint;
39
40
    /**
41
     * Vertical point.
42
     */
43
    protected VerticalPoint $verticalPoint;
44
45
    /**
46
     * Coordinate reference system.
47
     */
48
    protected Compound $crs;
49
50
    /**
51
     * Coordinate epoch (date for which the specified coordinates represented this point).
52
     */
53
    protected ?DateTimeImmutable $epoch;
54
55
    /**
56
     * Constructor.
57
     * @param GeographicPoint|ProjectedPoint $horizontalPoint
58
     */
59 7
    protected function __construct(Point $horizontalPoint, VerticalPoint $verticalPoint, Compound $crs, ?DateTimeInterface $epoch = null)
60
    {
61 7
        $this->horizontalPoint = $horizontalPoint;
0 ignored issues
show
Documentation Bug introduced by
$horizontalPoint is of type PHPCoord\Point, but the property $horizontalPoint was declared to be of type PHPCoord\GeographicPoint|PHPCoord\ProjectedPoint. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
62 7
        $this->verticalPoint = $verticalPoint;
63 7
        $this->crs = $crs;
64
65 7
        if ($epoch instanceof DateTime) {
66 1
            $epoch = DateTimeImmutable::createFromMutable($epoch);
67
        }
68 7
        $this->epoch = $epoch;
69 7
    }
70
71
    /**
72
     * @param GeographicPoint|ProjectedPoint $horizontalPoint
73
     */
74 7
    public static function create(Point $horizontalPoint, VerticalPoint $verticalPoint, Compound $crs, ?DateTimeInterface $epoch = null)
75
    {
76 7
        return new static($horizontalPoint, $verticalPoint, $crs, $epoch);
77
    }
78
79 6
    public function getHorizontalPoint(): Point
80
    {
81 6
        return $this->horizontalPoint;
82
    }
83
84 5
    public function getVerticalPoint(): VerticalPoint
85
    {
86 5
        return $this->verticalPoint;
87
    }
88
89 6
    public function getCRS(): Compound
90
    {
91 6
        return $this->crs;
92
    }
93
94 4
    public function getCoordinateEpoch(): ?DateTimeImmutable
95
    {
96 4
        return $this->epoch;
97
    }
98
99
    /**
100
     * Calculate distance between two points.
101
     */
102 2
    public function calculateDistance(Point $to): Length
103
    {
104
        try {
105 2
            if ($to instanceof ConvertiblePoint) {
106 2
                $to = $to->convert($this->crs);
107
            }
108
        } finally {
109 2
            if ($to->getCRS()->getSRID() !== $this->crs->getSRID()) {
110 1
                throw new InvalidCoordinateReferenceSystemException('Can only calculate distances between two points in the same CRS');
111
            }
112
113
            /* @var CompoundPoint $to */
114 1
            return $this->horizontalPoint->calculateDistance($to->horizontalPoint);
115
        }
116
    }
117
118 3
    public function __toString(): string
119
    {
120 3
        return "({$this->horizontalPoint}, {$this->verticalPoint})";
121
    }
122
123
    /**
124
     * Geographic2D with Height Offsets.
125
     * This transformation allows calculation of coordinates in the target system by adding the parameter value to the
126
     * coordinate values of the point in the source system.
127
     */
128 1
    public function geographic2DWithHeightOffsets(
129
        Geographic3D $to,
130
        Angle $latitudeOffset,
131
        Angle $longitudeOffset,
132
        Length $geoidUndulation
133
    ): GeographicPoint {
134 1
        $toLatitude = $this->getHorizontalPoint()->getLatitude()->add($latitudeOffset);
0 ignored issues
show
Bug introduced by
The method getLatitude() does not exist on PHPCoord\Point. It seems like you code against a sub-type of PHPCoord\Point such as PHPCoord\GeographicPoint. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
        $toLatitude = $this->getHorizontalPoint()->/** @scrutinizer ignore-call */ getLatitude()->add($latitudeOffset);
Loading history...
135 1
        $toLongitude = $this->getHorizontalPoint()->getLongitude()->add($longitudeOffset);
0 ignored issues
show
Bug introduced by
The method getLongitude() does not exist on PHPCoord\Point. It seems like you code against a sub-type of PHPCoord\Point such as PHPCoord\GeographicPoint. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

135
        $toLongitude = $this->getHorizontalPoint()->/** @scrutinizer ignore-call */ getLongitude()->add($longitudeOffset);
Loading history...
136 1
        $toHeight = $this->getVerticalPoint()->getHeight()->add($geoidUndulation);
137
138 1
        return GeographicPoint::create($toLatitude, $toLongitude, $toHeight, $to, $this->epoch);
139
    }
140
141
    /**
142
     * Vertical Offset and Slope
143
     * This transformation allows calculation of height in the target system by applying the parameter values to the
144
     * height value of the point in the source system.
145
     */
146 1
    public function verticalOffsetAndSlope(
147
        Compound $to,
148
        Angle $ordinate1OfEvaluationPoint,
149
        Angle $ordinate2OfEvaluationPoint,
150
        Length $verticalOffset,
151
        Angle $inclinationInLatitude,
152
        Angle $inclinationInLongitude,
153
        int $horizontalCRSCode
0 ignored issues
show
Unused Code introduced by
The parameter $horizontalCRSCode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

153
        /** @scrutinizer ignore-unused */ int $horizontalCRSCode

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
    ): self {
155 1
        $latitude = $this->horizontalPoint->getLatitude()->asRadians()->getValue();
156 1
        $longitude = $this->horizontalPoint->getLongitude()->asRadians()->getValue();
157 1
        $latitudeOrigin = $ordinate1OfEvaluationPoint->asRadians()->getValue();
158 1
        $longitudeOrigin = $ordinate2OfEvaluationPoint->asRadians()->getValue();
159 1
        $a = $this->horizontalPoint->getCRS()->getDatum()->getEllipsoid()->getSemiMajorAxis()->asMetres()->getValue();
160 1
        $e2 = $this->horizontalPoint->getCRS()->getDatum()->getEllipsoid()->getEccentricitySquared();
161
162 1
        $rhoOrigin = $a * (1 - $e2) / (1 - $e2 * sin($latitudeOrigin) ** 2) ** 1.5;
163 1
        $nuOrigin = $a / sqrt(1 - $e2 * (sin($latitudeOrigin) ** 2));
164
165 1
        $latitudeTerm = new Metre($inclinationInLatitude->asRadians()->getValue() * $rhoOrigin * ($latitude - $latitudeOrigin));
166 1
        $longitudeTerm = new Metre($inclinationInLongitude->asRadians()->getValue() * $nuOrigin * ($longitude - $longitudeOrigin) * cos($latitude));
167 1
        $newVerticalHeight = $this->verticalPoint->getHeight()->add($verticalOffset)->add($latitudeTerm)->add($longitudeTerm);
168
169 1
        $newVerticalPoint = VerticalPoint::create($newVerticalHeight, $to->getVertical());
170
171 1
        return static::create($this->horizontalPoint, $newVerticalPoint, $to);
172
    }
173
}
174