diff --git a/src/CompoundPoint.php b/src/CompoundPoint.php index 8a73b2c21..5d1f4da78 100644 --- a/src/CompoundPoint.php +++ b/src/CompoundPoint.php @@ -146,26 +146,24 @@ public function convert(Compound|Geocentric|Geographic2D|Geographic3D|Projected| } } } - if ($to instanceof Geographic3D) { - // try converting to any/all of the other Compound CRSs that include the same vertical CRS, where the - // horizontal CRS has a 3D equivalent. From there, try converting using the usual mechanisms - $candidateIntermediates = Compound::findFromVertical($this->getVerticalPoint()->getCRS()); - unset($candidateIntermediates[$this->getCRS()->getSRID()]); - - foreach ($candidateIntermediates as $candidateIntermediate) { - try { - if ($candidateIntermediate->getHorizontal() instanceof Geographic2D && $candidateIntermediate->getHorizontal()->getBaseCRS() instanceof Geographic3D) { - $candidateHorizontalPoint = $this->getHorizontalPoint()->convert($candidateIntermediate->getHorizontal()); - $candidateIntermediatePoint = self::create( - $candidateIntermediate, - $candidateHorizontalPoint, - $this->getVerticalPoint() - ); - - return $candidateIntermediatePoint->convert($candidateIntermediate->getHorizontal()->getBaseCRS())->convert($to); - } - } catch (Throwable) { + // try converting to any/all of the other Compound CRSs that include the same vertical CRS, where the + // horizontal CRS has a 3D equivalent. From there, try converting using the usual mechanisms + $candidateIntermediates = Compound::findFromVertical($this->getVerticalPoint()->getCRS()); + unset($candidateIntermediates[$this->getCRS()->getSRID()]); + + foreach ($candidateIntermediates as $candidateIntermediate) { + try { + if ($candidateIntermediate->getHorizontal() instanceof Geographic2D && $candidateIntermediate->getHorizontal()->getBaseCRS() instanceof Geographic3D) { + $candidateHorizontalPoint = $this->getHorizontalPoint()->convert($candidateIntermediate->getHorizontal()); + $candidateIntermediatePoint = self::create( + $candidateIntermediate, + $candidateHorizontalPoint, + $this->getVerticalPoint() + ); + + return $candidateIntermediatePoint->convert($candidateIntermediate->getHorizontal()->getBaseCRS())->convert($to); } + } catch (Throwable) { } } throw $e; diff --git a/src/CoordinateOperation/AutoConversion.php b/src/CoordinateOperation/AutoConversion.php index e4a47c82f..ca4f9896a 100644 --- a/src/CoordinateOperation/AutoConversion.php +++ b/src/CoordinateOperation/AutoConversion.php @@ -98,10 +98,10 @@ protected function validatePath(array $candidatePath, Compound|Geocentric|Geogra // filter out operations that use a 2D CRS as intermediate where this is a 3D point $currentCRS = $this->getCRS(); - if ($currentCRS instanceof Compound || $currentCRS instanceof Geocentric || $currentCRS instanceof Geographic3D || $currentCRS instanceof Vertical) { - if ($target instanceof Compound || $target instanceof Geocentric || $target instanceof Geographic3D || $target instanceof Vertical) { + if ($currentCRS instanceof Compound || count($currentCRS->getCoordinateSystem()->getAxes()) === 3) { + if ($target instanceof Compound || count($target->getCoordinateSystem()->getAxes()) !== 2) { $intermediateTarget = CoordinateReferenceSystem::fromSRID($pathStep['in_reverse'] ? $pathStep['source_crs'] : $pathStep['target_crs']); - if ($intermediateTarget instanceof Geographic2D || $intermediateTarget instanceof Projected) { + if (!$intermediateTarget instanceof Compound && count($intermediateTarget->getCoordinateSystem()->getAxes()) === 2) { return false; } } diff --git a/tests/CoordinateOperation/AutoConversionTest.php b/tests/CoordinateOperation/AutoConversionTest.php index 8f93de6f3..4f41cf9de 100644 --- a/tests/CoordinateOperation/AutoConversionTest.php +++ b/tests/CoordinateOperation/AutoConversionTest.php @@ -396,7 +396,7 @@ public function testRDNAPToETRS89(): void self::assertEqualsWithDelta(301.798133706, $to->getHeight()->asMetres()->getValue(), 0.00001); } - public function testRDNAPToWGS84(): void + public function testRDNAPToWGS84Geographic3D(): void { if (!class_exists(GTXETRS89NAPProvider::class)) { self::markTestSkipped('Requires phpcoord/datapack-europe'); @@ -422,6 +422,32 @@ public function testRDNAPToWGS84(): void self::assertEqualsWithDelta(301.798133706, $to->getHeight()->asMetres()->getValue(), 0.00001); } + public function testRDNAPToWGS84Geocentric(): void + { + if (!class_exists(GTXETRS89NAPProvider::class)) { + self::markTestSkipped('Requires phpcoord/datapack-europe'); + } + + $from = CompoundPoint::create( + Compound::fromSRID(Compound::EPSG_AMERSFOORT_RD_NEW_PLUS_NAP_HEIGHT), + ProjectedPoint::createFromEastingNorthing( + Projected::fromSRID(Projected::EPSG_AMERSFOORT_RD_NEW), + new Metre(108360.8790), + new Metre(415757.2745), + ), + VerticalPoint::create( + Vertical::fromSRID(Vertical::EPSG_NAP_HEIGHT), + new Metre(258.0057) + ) + ); + $toCRS = Geocentric::fromSRID(Geocentric::EPSG_WGS_84); + $to = $from->convert($toCRS); + + self::assertEqualsWithDelta(3945517.9766847, $to->getX()->asMetres()->getValue(), 0.00001); + self::assertEqualsWithDelta(325220.90092962, $to->getY()->asMetres()->getValue(), 0.00001); + self::assertEqualsWithDelta(4984392.7931562, $to->getZ()->asMetres()->getValue(), 0.00001); + } + public function testNAD83NAD27SouthCarolina(): void { if (!class_exists(NADCON5NAD832007NAD832011CONUSLatitudeProvider::class)) {