From 2634d1aef17118c15afc86c8adb7965af12bb4d9 Mon Sep 17 00:00:00 2001 From: Doug Wright Date: Fri, 23 Aug 2024 19:32:18 +0100 Subject: [PATCH] #67 Add a proper API for checking if a point is within the bounding area of it's CRS --- CHANGELOG.md | 8 ++++- src/CoordinateOperation/AutoConversion.php | 10 ++++++ tests/Geometry/BoundingAreaTest.php | 37 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28247ab46..2b4a2d919 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +## [5.10.0] - 2024-08-23 +### Added +- Added a new method `isWithinCRSBoundingArea()` on most `Point` objects to check if they lie within the bounds + of their defined CRS + ## [5.9.2] - 2024-08-18 ### Changed - Split declaration of the `Projected::EPSG_*` constants into multiple files internally to aid with static analysis @@ -340,8 +345,9 @@ Initial release of this fork (based off of v2.3 of original) - Eastings and northings are rounded to 1m, and lat/long to 5dp (approx 1m) to avoid any misconceptions that precision is the same thing as accuracy. - When calculating surface distances, a more accurate mean radius is now used rather than that derived from historical definitions of a nautical mile -[Unreleased]: https://github.com/dvdoug/PHPCoord/compare/v5.9.2..master +[Unreleased]: https://github.com/dvdoug/PHPCoord/compare/v5.10.0..master +[5.10.0]: https://github.com/dvdoug/PHPCoord/compare/v5.9.2..v5.10.0 [5.9.2]: https://github.com/dvdoug/PHPCoord/compare/v5.9.1..v5.9.2 [5.9.1]: https://github.com/dvdoug/PHPCoord/compare/v5.9.0..v5.9.1 [5.9.0]: https://github.com/dvdoug/PHPCoord/compare/v5.8.0..v5.9.0 diff --git a/src/CoordinateOperation/AutoConversion.php b/src/CoordinateOperation/AutoConversion.php index faaf7ae7e..1d8818cf4 100644 --- a/src/CoordinateOperation/AutoConversion.php +++ b/src/CoordinateOperation/AutoConversion.php @@ -74,6 +74,16 @@ public function convert(Compound|Geocentric|Geographic2D|Geographic3D|Projected| return $point; } + /** + * Calculates if the point as constructed actually lies within the bounding box of the CRS. + */ + public function isWithinCRSBoundingArea(): bool + { + $pointAsWGS84 = $this->getPointForBoundaryCheck(); // some obscure CRSs might not be able to convert + + return !$pointAsWGS84 instanceof GeographicValue || $this->crs->getBoundingArea()->containsPoint($pointAsWGS84); + } + /** * @return array */ diff --git a/tests/Geometry/BoundingAreaTest.php b/tests/Geometry/BoundingAreaTest.php index 6bddda408..c4e279635 100644 --- a/tests/Geometry/BoundingAreaTest.php +++ b/tests/Geometry/BoundingAreaTest.php @@ -9,8 +9,13 @@ namespace PHPCoord\Geometry; use PHPCoord\CoordinateOperation\GeographicValue; +use PHPCoord\CoordinateReferenceSystem\Geographic2D; +use PHPCoord\CoordinateReferenceSystem\Projected; use PHPCoord\Datum\Datum; +use PHPCoord\Point\GeographicPoint; +use PHPCoord\Point\ProjectedPoint; use PHPCoord\UnitOfMeasure\Angle\Degree; +use PHPCoord\UnitOfMeasure\Length\Metre; use PHPUnit\Framework\TestCase; class BoundingAreaTest extends TestCase @@ -102,4 +107,36 @@ public function testNetherlandsBufferedCorrectly(): void $polygon = BoundingArea::createFromExtentCodes(['urn:ogc:def:area:EPSG::1275']); self::assertTrue($polygon->containsPoint(new GeographicValue(new Degree(50.965613067768), new Degree(5.8249181759236), null, Datum::fromSRID(Datum::EPSG_WORLD_GEODETIC_SYSTEM_1984_ENSEMBLE)))); } + + public function testBoundaryChecking(): void + { + $newYorkInED50 = GeographicPoint::create( + latitude: new Degree(40.689167), + longitude: new Degree(-74.044444), + crs: Geographic2D::fromSRID(Geographic2D::EPSG_ED50) + ); + + $newYorkInNAD83 = GeographicPoint::create( + latitude: new Degree(40.689167), + longitude: new Degree(-74.044444), + crs: Geographic2D::fromSRID(Geographic2D::EPSG_NAD83_2011) + ); + + $newYorkInCorrectUTM = ProjectedPoint::createFromEastingNorthing( + easting: new Metre(580741), + northing: new Metre(4504692), + crs: Projected::fromSRID(Projected::EPSG_WGS_84_UTM_ZONE_18N) + ); + + $newYorkInOSGB = ProjectedPoint::createFromEastingNorthing( + easting: new Metre(580741), + northing: new Metre(4504692), + crs: Projected::fromSRID(Projected::EPSG_OSGB36_BRITISH_NATIONAL_GRID) + ); + + self::assertFalse($newYorkInED50->isWithinCRSBoundingArea()); + self::assertTrue($newYorkInNAD83->isWithinCRSBoundingArea()); + self::assertTrue($newYorkInCorrectUTM->isWithinCRSBoundingArea()); + self::assertFalse($newYorkInOSGB->isWithinCRSBoundingArea()); + } }