Skip to content

Commit

Permalink
Fix parsing of 'H' 500km squares (Scottish islands)
Browse files Browse the repository at this point in the history
An erroneous data 'sanity check' rejected all 'H' 500km squares; this does a
more specific format validation instead.
  • Loading branch information
chrisveness committed May 26, 2020
1 parent 4580ee1 commit 5941244
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixed

- Fix parsing of 'H' 500km squares (Scottish islands)

## [2.2.1] - 2020-04-22

### Fixed
Expand Down
21 changes: 9 additions & 12 deletions osgridref.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2019 */
/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2020 */
/* MIT Licence */
/* www.movable-type.co.uk/scripts/latlong-gridref.html */
/* www.movable-type.co.uk/scripts/geodesy-library.html#osgridref */
Expand All @@ -13,7 +13,7 @@ import LatLonEllipsoidal, { Dms } from './latlon-ellipsoidal-datum.js';
* Formulation implemented here due to Thomas, Redfearn, etc is as published by OS, but is inferior
* to Krüger as used by e.g. Karney 2011.
*
* www.ordnancesurvey.co.uk/docs/support/guide-coordinate-systems-great-britain.pdf.
* www.ordnancesurvey.co.uk/documents/resources/guide-coordinate-systems-great-britain.pdf.
*
* Note OSGB grid references cover Great Britain only; Ireland and the Channel Islands have their
* own references.
Expand Down Expand Up @@ -96,14 +96,14 @@ class OsGridRef {
const Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(φ-φ0) * Math.cos(φ+φ0);
const Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(φ-φ0)) * Math.cos(2*(φ+φ0));
const Md = (35/24)*n3 * Math.sin(3*(φ-φ0)) * Math.cos(3*(φ+φ0));
M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc

} while (Math.abs(N-N0-M) >= 0.00001); // ie until < 0.01mm

const cosφ = Math.cos(φ), sinφ = Math.sin(φ);
const ν = a*F0/Math.sqrt(1-e2*sinφ*sinφ); // nu = transverse radius of curvature
const ρ = a*F0*(1-e2)/Math.pow(1-e2*sinφ*sinφ, 1.5); // rho = meridional radius of curvature
const η2 = ν/ρ-1; // eta = ?
const ν = a*F0/Math.sqrt(1-e2*sinφ*sinφ); // nu = transverse radius of curvature
const ρ = a*F0*(1-e2)/Math.pow(1-e2*sinφ*sinφ, 1.5); // rho = meridional radius of curvature
const η2 = ν/ρ-1; // eta = ?

const tanφ = Math.tan(φ);
const tan2φ = tanφ*tanφ, tan4φ = tan2φ*tan2φ, tan6φ = tan4φ*tan2φ;
Expand Down Expand Up @@ -157,19 +157,16 @@ class OsGridRef {
if (match) return new OsGridRef(match[1], match[2]);

// validate format
match = gridref.match(/^[A-Z]{2}\s*[0-9]+\s*[0-9]+$/i);
match = gridref.match(/^[HNST][ABCDEFGHJKLMNOPQRSTUVWXYZ]\s*[0-9]+\s*[0-9]+$/i);
if (!match) throw new Error(`invalid grid reference ‘${gridref}’`);

// get numeric values of letter references, mapping A->0, B->1, C->2, etc:
let l1 = gridref.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
let l2 = gridref.toUpperCase().charCodeAt(1) - 'A'.charCodeAt(0);
let l1 = gridref.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0); // 500km square
let l2 = gridref.toUpperCase().charCodeAt(1) - 'A'.charCodeAt(0); // 100km square
// shuffle down letters after 'I' since 'I' is not used in grid:
if (l1 > 7) l1--;
if (l2 > 7) l2--;

// sanity check
if (l1<8 || l1 > 18) throw new Error(`invalid grid reference ‘${gridref}’`);

// convert grid letters into 100km-square indexes from false origin (grid square SV):
const e100km = ((l1 - 2) % 5) * 5 + (l2 % 5);
const n100km = (19 - Math.floor(l1 / 5) * 5) - Math.floor(l2 / 5);
Expand Down
9 changes: 9 additions & 0 deletions test/os-gridref-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ describe('os-gridref', function() {
});
});

describe('extremities', function() {
test('LE>', () => OsGridRef.parse('SW 34240 25290').toLatLon().toString().should.equal('50.0682°N, 005.7152°W'));
test('LE<', () => new LatLon(50.0682, -5.7152).toOsGrid().toString().should.equal('SW 34240 25290'));
test('NF>', () => OsGridRef.parse('TR 39859 69616').toLatLon().toString().should.equal('51.3749°N, 001.4451°E'));
test('NF<', () => new LatLon(51.3749, 1.4451).toOsGrid().toString().should.equal('TR 39859 69616'));
test('HP>', () => OsGridRef.parse('HY 45153 09450').toLatLon().toString().should.equal('58.9687°N, 002.9555°W'));
test('HP<', () => new LatLon(58.9687, -2.9555).toOsGrid().toString().should.equal('HY 45153 09450'));
});

describe('Extra-UK lat/lon fail', function() {
test('0,0', () => should.Throw(function() { new LatLon(0.00, 0.00).toOsGrid(); }, Error, 'invalid northing ‘-5527598.33’ from (-0.004833,0.000890).toOsGrid()'));
test('Dublin', () => should.Throw(function() { new LatLon(53.35, 6.26).toOsGrid(); }, Error, 'invalid easting ‘949400.51’ from (53.349579,6.262431).toOsGrid()'));
Expand Down

0 comments on commit 5941244

Please sign in to comment.