Passed
Push — 4.0.x ( 414ad0...5c8c8d )
by Doug
05:04 queued 12s
created

CompoundPoint::getHorizontalPoint()   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 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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\CoordinateReferenceSystem;
19
use PHPCoord\CoordinateReferenceSystem\Geographic2D;
20
use PHPCoord\CoordinateReferenceSystem\Geographic3D;
21
use PHPCoord\CoordinateReferenceSystem\Projected;
22
use PHPCoord\CoordinateReferenceSystem\Vertical;
23
use PHPCoord\Exception\InvalidCoordinateReferenceSystemException;
24
use PHPCoord\Exception\UnknownConversionException;
25
use PHPCoord\UnitOfMeasure\Angle\Angle;
26
use PHPCoord\UnitOfMeasure\Length\Length;
27
use PHPCoord\UnitOfMeasure\Length\Metre;
28
use function sin;
29
use function sqrt;
30
31
/**
32
 * Coordinate representing a point expressed in 2 different CRSs (2D horizontal + 1D Vertical).
33
 */
34
class CompoundPoint extends Point implements ConvertiblePoint
35
{
36
    use AutoConversion {
37
        convert as protected autoConvert;
38
    }
39
40
    /**
41
     * Horizontal point.
42
     * @var GeographicPoint|ProjectedPoint
43
     */
44
    protected $horizontalPoint;
45
46
    /**
47
     * Vertical point.
48
     */
49
    protected $verticalPoint;
50
51
    /**
52
     * Coordinate reference system.
53
     */
54
    protected $crs;
55
56
    /**
57
     * Coordinate epoch (date for which the specified coordinates represented this point).
58
     */
59
    protected $epoch;
60
61
    /**
62
     * Constructor.
63
     * @param GeographicPoint|ProjectedPoint $horizontalPoint
64
     */
65 8
    protected function __construct(Point $horizontalPoint, VerticalPoint $verticalPoint, Compound $crs, ?DateTimeInterface $epoch = null)
66
    {
67 8
        $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...
68 8
        $this->verticalPoint = $verticalPoint;
69 8
        $this->crs = $crs;
70
71 8
        if ($epoch instanceof DateTime) {
72 1
            $epoch = DateTimeImmutable::createFromMutable($epoch);
73
        }
74 8
        $this->epoch = $epoch;
75 8
    }
76
77
    /**
78
     * @param GeographicPoint|ProjectedPoint $horizontalPoint
79
     */
80 8
    public static function create(Point $horizontalPoint, VerticalPoint $verticalPoint, Compound $crs, ?DateTimeInterface $epoch = null)
81
    {
82 8
        return new static($horizontalPoint, $verticalPoint, $crs, $epoch);
83
    }
84
85 7
    public function getHorizontalPoint(): Point
86
    {
87 7
        return $this->horizontalPoint;
88
    }
89
90 6
    public function getVerticalPoint(): VerticalPoint
91
    {
92 6
        return $this->verticalPoint;
93
    }
94
95 7
    public function getCRS(): Compound
96
    {
97 7
        return $this->crs;
98
    }
99
100 5
    public function getCoordinateEpoch(): ?DateTimeImmutable
101
    {
102 5
        return $this->epoch;
103
    }
104
105
    /**
106
     * Calculate distance between two points.
107
     */
108 2
    public function calculateDistance(Point $to): Length
109
    {
110
        try {
111 2
            if ($to instanceof ConvertiblePoint) {
112 2
                $to = $to->convert($this->crs);
113
            }
114
        } finally {
115 2
            if ($to->getCRS()->getSRID() !== $this->crs->getSRID()) {
116 1
                throw new InvalidCoordinateReferenceSystemException('Can only calculate distances between two points in the same CRS');
117
            }
118
119
            /* @var CompoundPoint $to */
120 1
            return $this->horizontalPoint->calculateDistance($to->horizontalPoint);
121
        }
122
    }
123
124 4
    public function convert(CoordinateReferenceSystem $to, bool $ignoreBoundaryRestrictions = false): Point
125
    {
126
        try {
127 4
            return $this->autoConvert($to, $ignoreBoundaryRestrictions);
128 1
        } catch (UnknownConversionException $e) {
129 1
            if (($to instanceof Geographic2D || $to instanceof Projected) && $this->getHorizontalPoint() instanceof ConvertiblePoint) {
130
                return $this->getHorizontalPoint()->convert($to, $ignoreBoundaryRestrictions);
131
            }
132
        }
133 1
    }
134
135 3
    public function __toString(): string
136
    {
137 3
        return "({$this->horizontalPoint}, {$this->verticalPoint})";
138
    }
139
140
    /**
141
     * Geographic2D with Height Offsets.
142
     * This transformation allows calculation of coordinates in the target system by adding the parameter value to the
143
     * coordinate values of the point in the source system.
144
     */
145 2
    public function geographic2DWithHeightOffsets(
146
        Geographic3D $to,
147
        Angle $latitudeOffset,
148
        Angle $longitudeOffset,
149
        Length $geoidUndulation
150
    ): GeographicPoint {
151 2
        $toLatitude = $this->getHorizontalPoint()->getLatitude()->add($latitudeOffset);
0 ignored issues
show
Bug introduced by
The method getLatitude() does not exist on PHPCoord\ProjectedPoint. ( Ignorable by Annotation )

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

151
        $toLatitude = $this->getHorizontalPoint()->/** @scrutinizer ignore-call */ getLatitude()->add($latitudeOffset);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
152 2
        $toLongitude = $this->getHorizontalPoint()->getLongitude()->add($longitudeOffset);
0 ignored issues
show
Bug introduced by
The method getLongitude() does not exist on PHPCoord\ProjectedPoint. ( Ignorable by Annotation )

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

152
        $toLongitude = $this->getHorizontalPoint()->/** @scrutinizer ignore-call */ getLongitude()->add($longitudeOffset);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
153 2
        $toHeight = $this->getVerticalPoint()->getHeight()->add($geoidUndulation);
154
155 2
        return GeographicPoint::create($toLatitude, $toLongitude, $toHeight, $to, $this->epoch);
156
    }
157
158
    /**
159
     * Vertical Offset and Slope
160
     * This transformation allows calculation of height in the target system by applying the parameter values to the
161
     * height value of the point in the source system.
162
     */
163 1
    public function verticalOffsetAndSlope(
164
        Compound $to,
165
        Angle $ordinate1OfEvaluationPoint,
166
        Angle $ordinate2OfEvaluationPoint,
167
        Length $verticalOffset,
168
        Angle $inclinationInLatitude,
169
        Angle $inclinationInLongitude
170
    ): self {
171 1
        $latitude = $this->horizontalPoint->getLatitude()->asRadians()->getValue();
172 1
        $longitude = $this->horizontalPoint->getLongitude()->asRadians()->getValue();
173 1
        $latitudeOrigin = $ordinate1OfEvaluationPoint->asRadians()->getValue();
174 1
        $longitudeOrigin = $ordinate2OfEvaluationPoint->asRadians()->getValue();
175 1
        $a = $this->horizontalPoint->getCRS()->getDatum()->getEllipsoid()->getSemiMajorAxis()->asMetres()->getValue();
176 1
        $e2 = $this->horizontalPoint->getCRS()->getDatum()->getEllipsoid()->getEccentricitySquared();
177
178 1
        $rhoOrigin = $a * (1 - $e2) / (1 - $e2 * sin($latitudeOrigin) ** 2) ** 1.5;
179 1
        $nuOrigin = $a / sqrt(1 - $e2 * (sin($latitudeOrigin) ** 2));
180
181 1
        $latitudeTerm = new Metre($inclinationInLatitude->asRadians()->getValue() * $rhoOrigin * ($latitude - $latitudeOrigin));
182 1
        $longitudeTerm = new Metre($inclinationInLongitude->asRadians()->getValue() * $nuOrigin * ($longitude - $longitudeOrigin) * cos($latitude));
183 1
        $newVerticalHeight = $this->verticalPoint->getHeight()->add($verticalOffset)->add($latitudeTerm)->add($longitudeTerm);
184
185 1
        $newVerticalPoint = VerticalPoint::create($newVerticalHeight, $to->getVertical());
186
187 1
        return static::create($this->horizontalPoint, $newVerticalPoint, $to);
188
    }
189
}
190