From 553960bc2437563b9a565f76cc41ba0a7c10842b Mon Sep 17 00:00:00 2001 From: Bouillaguet Quentin Date: Thu, 17 Oct 2024 20:50:52 +0200 Subject: [PATCH] refacto(Crs): cleanup unit handling --- src/Core/Geographic/Crs.ts | 45 ++++++++++++++++++-------------------- test/unit/crs.js | 2 +- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/Core/Geographic/Crs.ts b/src/Core/Geographic/Crs.ts index d1a46f943e..117cbe79d8 100644 --- a/src/Core/Geographic/Crs.ts +++ b/src/Core/Geographic/Crs.ts @@ -1,5 +1,7 @@ import proj4 from 'proj4'; +import type { ProjectionDefinition } from 'proj4'; + proj4.defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs'); /** @@ -50,10 +52,14 @@ function isGeocentric(crs: ProjectionLike) { return !projection ? false : projection.projName == 'geocent'; } -function _unitFromProj4Unit(projunit: string) { - if (projunit === 'degrees') { +function _unitFromProj4Unit(proj: ProjectionDefinition) { + if (proj.units === 'degrees') { return UNIT.DEGREE; - } else if (projunit === 'm') { + } else if (proj.units === 'm') { + return UNIT.METER; + } else if (proj.units === undefined && proj.to_meter === undefined) { + // See https://proj.org/en/9.4/usage/projections.html [17/10/2024] + // > The default unit for projected coordinates is the meter. return UNIT.METER; } else { return undefined; @@ -62,26 +68,11 @@ function _unitFromProj4Unit(projunit: string) { function toUnit(crs: ProjectionLike) { mustBeString(crs); - switch (crs) { - case 'EPSG:4326' : return UNIT.DEGREE; - case 'EPSG:4978' : return UNIT.METER; - default: { - const p = proj4.defs(formatToEPSG(crs)); - if (!p?.units) { - return undefined; - } - return _unitFromProj4Unit(p.units); - } - } -} - -function toUnitWithError(crs: ProjectionLike) { - mustBeString(crs); - const u = toUnit(crs); - if (u === undefined) { - throw new Error(`No unit found for crs: '${crs}'`); + const p = proj4.defs(formatToEPSG(crs)); + if (!p) { + return undefined; } - return u; + return _unitFromProj4Unit(p); } /** @@ -101,7 +92,13 @@ export default { * @throws {@link Error} if the CRS is not valid. */ isValid(crs: ProjectionLike) { - toUnitWithError(crs); + const proj = proj4.defs(crs); + if (!proj) { + throw new Error(`Undefined crs '${crs}'. Add it with proj4.defs('${crs}', string)`); + } + if (!_unitFromProj4Unit(proj)) { + throw new Error(`No valid unit found for crs '${crs}', found ${proj.units}`); + } }, /** @@ -111,7 +108,7 @@ export default { * @throws {@link Error} if the CRS is not valid. */ isGeographic(crs: ProjectionLike) { - return (toUnitWithError(crs) == UNIT.DEGREE); + return (toUnit(crs) == UNIT.DEGREE); }, /** diff --git a/test/unit/crs.js b/test/unit/crs.js index 00c1f3a3b1..bb754de8e3 100644 --- a/test/unit/crs.js +++ b/test/unit/crs.js @@ -3,7 +3,7 @@ import proj4 from 'proj4'; import CRS from 'Core/Geographic/Crs'; proj4.defs('EPSG:7133', '+proj=longlat +ellps=GRS80 +no_defs +units=degrees'); -proj4.defs('EPSG:INVALID', '+no_defs'); +proj4.defs('EPSG:INVALID', '+units=invalid +no_defs'); describe('CRS assertions', function () { it('should assert that the CRS is valid', function () {