Skip to content

Implemented MGRS in polar regions. #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7d7b9f7
Fixed MGRS zone in South Region
kleinjakob Feb 25, 2025
e8732ca
Added Tests for UPS South
kleinjakob Feb 25, 2025
e646153
Fixed UPS-S Zone Test cases
kleinjakob Feb 25, 2025
ab44d84
Merge branch 'ups-s-tests' into ups-south-fix.
kleinjakob Feb 25, 2025
3721339
Removed error expectaion when parsing
kleinjakob Feb 25, 2025
1b6dbe6
Merge branch 'ups-s-tests' into ups-south-fix
kleinjakob Feb 25, 2025
350c21d
Combined function for LL to MGRS
kleinjakob Feb 25, 2025
14eded3
Simple calculation of easting/northing in polar region.
kleinjakob Feb 25, 2025
e4189ee
Implemented MGRS in polar regions.
kleinjakob Feb 25, 2025
f9d2e80
Merge pull request #1 from kleinjakob/ups-south-fix
kleinjakob Feb 25, 2025
7ffcbde
Merge pull request #2 from kleinjakob/mgrs-in-polar-region
kleinjakob Feb 25, 2025
77306c6
version bump
kleinjakob Feb 25, 2025
6a5bfd2
Create npm-publish-github-packages.yml
kleinjakob Feb 26, 2025
2c2af1b
Create node.js.yml
kleinjakob Feb 26, 2025
269d7aa
removed npm ci
kleinjakob Feb 26, 2025
4b3fee6
Merge pull request #4 from kleinjakob/github-packaging
kleinjakob Feb 26, 2025
9084d52
removed npm ci
kleinjakob Feb 26, 2025
e590f3f
rewrote package to use npx scripts
kleinjakob Feb 26, 2025
44473aa
install before build
kleinjakob Feb 26, 2025
498608b
undo circular definition
kleinjakob Feb 26, 2025
c919353
added install to build script
kleinjakob Feb 26, 2025
60669c2
fixed npm install before build
kleinjakob Feb 26, 2025
ac295e2
Update npm-publish-github-packages.yml
kleinjakob Feb 26, 2025
b86a158
Update npm-publish-github-packages.yml
kleinjakob Feb 26, 2025
c602544
Ran npm audit fix force.
kleinjakob Feb 26, 2025
9cea5f0
yarn added again
kleinjakob Feb 26, 2025
90f87a8
Update npm-publish-github-packages.yml
kleinjakob Feb 26, 2025
7ecd56a
Update package.json
kleinjakob Feb 26, 2025
b9bd6f7
Declare as ESM
kleinjakob Feb 26, 2025
27b1781
Update package.json
kleinjakob Feb 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm install
- run: npm run build --if-present
- run: npm test
35 changes: 35 additions & 0 deletions .github/workflows/npm-publish-github-packages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages

name: Node.js Package

on:
release:
types: [created]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install
- run: npm test

publish-gpr:
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "MIT"
}
],
"homepage": "https://github.com/codice/usng.js",
"homepage": "https://github.com/kleinjakob/usng.js",
"keywords": [
"gps",
"coordinates",
Expand All @@ -22,13 +22,13 @@
],
"repository": {
"type": "git",
"url": "git://github.com/codice/usng.js.git"
"url": "git://github.com/kleinjakob/usng.js.git"
},
"version": "0.4.5",
"version": "0.5.5",
"devDependencies": {
"chai": "^4.1.2",
"chai-match": "^1.1.1",
"mocha": "^5.2.0",
"mocha": "^11.1.0",
"typescript": "^3.0.3",
"typescript-formatter": "^7.2.2",
"underscore": "^1.9.1"
Expand All @@ -46,11 +46,11 @@
},
"scripts": {
"build": "tsc",
"test": "npm run build && mocha tests/tests.js",
"prepare": "npm run build",
"test": "yarn build && mocha tests/tests.js",
"prepare": "yarn build",
"publish:npm": "yarn build && yarn publish --access public && git push --tags",
"format": "tsfmt -r"
},
"author": "codice",
"author": "kleinjakob",
"license": "MIT"
}
48 changes: 34 additions & 14 deletions src/usng.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2009 Larry Moore, [email protected]
// 2014 Mike Adair, Richard Greenwood, Didier Richard, Stephen Irons, Olivier Terral and Calvin Metcalf (proj4js)
// 2014 Codice Foundation
// 2025 Jakob Klein
// Released under the MIT License; see
// http://www.opensource.org/licenses/mit-license.php
// or http://en.wikipedia.org/wiki/MIT_License
Expand Down Expand Up @@ -352,7 +353,7 @@ extend(Converter.prototype, {
const upsZoneLetter = !isUTM
&& utmups.northPole
? (utmups.easting < 2000000 ? 'Y' : 'Z')
: (utmups.northing < 2000000 ? 'A' : 'B')
: (utmups.easting < 2000000 ? 'A' : 'B')
const hemisphere = utmups.northPole ? 'N' : 'S'
const calculatedZone = isUTM ? utmups.zoneNumber + hemisphere : upsZoneLetter
return `${calculatedZone} ${Math.round(utmups.easting)}mE ${Math.round(utmups.northing)}mN`
Expand Down Expand Up @@ -569,7 +570,7 @@ extend(Converter.prototype, {
const upsObject = this.LLtoUPS(lat, lon)
const upsZoneLetter = upsObject.northPole
? (upsObject.easting < 2000000 ? 'Y' : 'Z')
: (upsObject.northing < 2000000 ? 'A' : 'B')
: (upsObject.easting < 2000000 ? 'A' : 'B')

return `${upsZoneLetter} ${Math.round(upsObject.easting)}mE ${Math.round(upsObject.northing)}mN`
},
Expand Down Expand Up @@ -1385,22 +1386,41 @@ extend(Converter.prototype, {
// with no spaces. space delimiters are optional but allowed in USNG, but are not allowed
// in MGRS notation. but the numbers are the same.
LLtoMGRS: function(lat, lon, precision) {
var mgrs_str;
var usng_str = this.LLtoUSNG(lat, lon, precision);
if (this.isInUPSSpace(lat)) {
var ups_obj = this.LLtoUPS(lat, lon);
var mgrs_str = ups_obj.northPole ? (ups_obj.easting < 2e6 ? "Y" : "Z") : (ups_obj.easting < 2e6 ? "A" : "B");
if (precision <= 0) {
return mgrs_str;
}
const UPS_N_east_letters = "RSTUXYZABCFGHJ"; // starting from 1300000mE
const UPS_N_north_letters = "ABCDEFGHJKLMNP"; // starting from 1300000mN
const UPS_S_east_letters = "JKLPQRSTUXYZABCFGHJKLPQR"; // starting from 800000mE
const UPS_S_north_letters = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // starting from 800000mN
if (ups_obj.northPole) {
mgrs_str += UPS_N_east_letters.charAt(Math.floor(ups_obj.easting / 1e5) - 13)
mgrs_str += UPS_N_north_letters.charAt(Math.floor(ups_obj.northing / 1e5) - 13)
}
else {
mgrs_str += UPS_S_east_letters.charAt(Math.floor(ups_obj.easting / 1e5) - 8)
mgrs_str += UPS_S_north_letters.charAt(Math.floor(ups_obj.northing / 1e5) - 8)
}
if (precision <= 1) {
return mgrs_str;
}
const MGRS_easting = String(Math.trunc(ups_obj.easting) % 1e5).padStart(5, "0").slice(0, precision - 1);
const MGRS_northing = String(Math.trunc(ups_obj.northing) % 1e5).padStart(5, "0").slice(0, precision - 1);
mgrs_str += MGRS_easting + MGRS_northing;

// remove space delimiters to conform to mgrs spec
var regexp = / /g;
mgrs_str = usng_str.replace(regexp, "");
} else {
var mgrs_str = "";
var usng_str = this.LLtoUSNG(lat, lon, precision);

return mgrs_str;
},
// remove space delimiters to conform to mgrs spec
var regexp = / /g;
mgrs_str = usng_str.replace(regexp, "");

LLtoMGRSUPS: function(lat, lon, precision) {
if (this.isInUPSSpace(lat)) {
return this.LLtoUPSString(lat, lon)
} else {
return this.LLtoMGRS(lat, lon, precision)
}
return mgrs_str;
},

// wrapper function specific to Google Maps, to make a converstion to lat/lng return a GLatLon instance.
Expand Down
56 changes: 47 additions & 9 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ describe('UPS Conversions', () => {
chai.expect(lat).to.be.closeTo(-85, range)
chai.expect(lon).to.be.closeTo(15, range)
})
describe('test four corners in UPS square', ()=> {
describe('test four corners in UPS square north', ()=> {
it('convert Z 2400000mE 2400000mN', ()=>{
const { lat, lon } = converter.UPStoLL({
northing: 2400000,
Expand Down Expand Up @@ -1456,6 +1456,44 @@ describe('UPS Conversions', () => {
chai.expect(lon).to.be.closeTo(45, range)
})
})
describe('test four corners in UPS square south', ()=> {
it('convert B 2400000mE 2400000mN', ()=>{
const { lat, lon } = converter.UPStoLL({
northing: 2400000,
easting: 2400000,
northPole: false
});
chai.expect(lat).to.be.closeTo(-84.91, range)
chai.expect(lon).to.be.closeTo(45, range)
})
it('convert A 1400000mE 1400000mN', ()=>{
const { lat, lon } = converter.UPStoLL({
northing: 1400000,
easting: 1400000,
northPole: false
});
chai.expect(lat).to.be.closeTo(-82.37, range)
chai.expect(lon).to.be.closeTo(-135, range)
})
it('convert A 1600000mE 2400000mN', ()=>{
const { lat, lon } = converter.UPStoLL({
northing: 2400000,
easting: 1600000,
northPole: false
});
chai.expect(lat).to.be.closeTo(-84.91, range)
chai.expect(lon).to.be.closeTo(-45, range)
})
it('convert B 2400000mE 1600000mN', ()=>{
const { lat, lon } = converter.UPStoLL({
northing: 1600000,
easting: 2400000,
northPole: false
});
chai.expect(lat).to.be.closeTo(-84.91, range)
chai.expect(lon).to.be.closeTo(135, range)
})
})
})
describe('LLtoUTMUPS', () => {
describe('convert to UTM when necessary', () => {
Expand Down Expand Up @@ -1550,9 +1588,9 @@ describe('UPS Conversions', () => {
chai.assert.equal(ups.easting, 2445183);
})
it('zone A', () => {
const ups = converter.deserializeUPS("A 1554816mE 1686771mN")
const ups = converter.deserializeUPS("A 1554816mE 2015504mN")
chai.assert.equal(ups.northPole, false);
chai.assert.equal(ups.northing, 1686771);
chai.assert.equal(ups.northing, 2015504);
chai.assert.equal(ups.easting, 1554816);
})
it('zone Y', () => {
Expand All @@ -1562,9 +1600,9 @@ describe('UPS Conversions', () => {
chai.assert.equal(ups.easting, 1785497);
})
it('zone B', () => {
const ups = converter.deserializeUPS("B 2443997mE 2015504mN")
const ups = converter.deserializeUPS("B 2443997mE 1686771mN")
chai.assert.equal(ups.northPole, false);
chai.assert.equal(ups.northing, 2015504);
chai.assert.equal(ups.northing, 1686771);
chai.assert.equal(ups.easting, 2443997);
})
describe('test invalid strings', () => {
Expand Down Expand Up @@ -1594,10 +1632,10 @@ describe('UPS Conversions', () => {
it('zone A', () => {
const ups = converter.serializeUTMUPS({
northPole: false,
northing: 1686771,
northing: 2486771,
easting: 1554816,
})
chai.expect(ups).to.equal("A 1554816mE 1686771mN")
chai.expect(ups).to.equal("A 1554816mE 2486771mN")
})
it('zone Y', () => {
const ups = converter.serializeUTMUPS({
Expand All @@ -1610,10 +1648,10 @@ describe('UPS Conversions', () => {
it('zone B', () => {
const ups = converter.serializeUTMUPS({
northPole: false,
northing: 2015504,
northing: 1915504,
easting: 2443997,
})
chai.expect(ups).to.equal("B 2443997mE 2015504mN")
chai.expect(ups).to.equal("B 2443997mE 1915504mN")
})
describe('test invalid numbers', () => {
it('invalid easting', () => {
Expand Down
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
"module": "commonjs",
"target": "es5",
"declaration": true,
"outDir": "./dist"
"outDir": "./dist",
"lib": [
"es2017",
"dom"
]
},
"include": [
"src/**/*"
Expand Down
Loading