Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 0 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"@bimdata/viewer": "2.17.0-beta.4",
"@paddle/paddle-js": "^1.6.2",
"async": "^3.2.6",
"dms-conversion": "^3.1.4",
"lodash": "^4.17.23",
"maplibre-gl": "^5.20.1",
"oidc-client-ts": "^3.5.0",
Expand Down
66 changes: 59 additions & 7 deletions src/utils/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,68 @@
* DD is negative if South or West
*/

import DmsCoordinates, { parseDms } from "dms-conversion";

// ---

/**
* The DMS_REGEX and parseDMS/parseDD utils function are extracted from "dms-conversion" package (https://github.com/WSDOT-GIS/dms-js).
* We had to do this because vite 8 doesn't seem to handle `import DmsCoordinates, { parseDms } from "dms-conversion"` properly...
*/

// Matches DMS DmsCoordinates
const DMS_REGEX = /^(-?\d+(?:\.\d+)?)[°:d]?\s?(?:(\d+(?:\.\d+)?)['′ʹ:]?\s?(?:(\d+(?:\.\d+)?)["″ʺ]?)?)?\s?([NSEW])?/i;

const truncate = n => n > 0 ? Math.floor(n) : Math.ceil(n);

/**
* Parses a Degrees Minutes Seconds string into a Decimal Degrees number.
*
* @param {string} dmsStr A string containing a coordinate in either DMS or DD format.
* @return {Number} If dmsStr is a valid coordinate string, the value in decimal degrees will be returned. Otherwise NaN will be returned.
*/
function parseDMS(dmsStr) {
let output = NaN;
const dmsMatch = DMS_REGEX.exec(dmsStr);
if (dmsMatch) {
const degrees = Number(dmsMatch[1]);
const minutes = typeof (dmsMatch[2]) !== "undefined" ? Number(dmsMatch[2]) / 60 : 0;
const seconds = typeof (dmsMatch[3]) !== "undefined" ? Number(dmsMatch[3]) / 3600 : 0;
const hemisphere = dmsMatch[4] || null;
if (hemisphere !== null && /[SW]/i.test(hemisphere)) {
output = -Math.abs(degrees) - minutes - seconds;
}
else {
output = degrees + minutes + seconds;
}
}
return output;
}

/**
*
* @param {Number} ddValue A number (coordinate) in decimal degrees
* @param {String} type Either "latitude" or "longitude"
* @returns {Array} DMS array
*/
function parseDD(ddValue, type) {
const direction = type === "longitude"
? ddValue < 0 ? "W" : "E"
: ddValue < 0 ? "S" : "N";
const absDD = Math.abs(ddValue);
const degrees = truncate(absDD);
const minutes = truncate((absDD - degrees) * 60);
const seconds = (absDD - degrees - minutes / 60) * Math.pow(60, 2);
return [degrees, minutes, seconds, direction];
}

// ---


/**
* Convert an array of DMS coordinate values into DD system equivalent.
*
* @param {Array} param DMS coordinate
* @param {String} param either latitude or longitude
* @param {String} type either "latitude" or "longitude"
* @returns {Number} DD coordinate
*/
function DMS2DD([degrees, minutes, seconds, secondsFraction = 0], type) {
Expand All @@ -44,7 +98,7 @@ function DMS2DD([degrees, minutes, seconds, secondsFraction = 0], type) {
}
seconds += secondsFraction/1000000;
const dmsString = `${degrees}°${minutes}′${seconds}″ ${direction}`;
return parseDms(dmsString);
return parseDMS(dmsString);
}

/**
Expand All @@ -55,16 +109,14 @@ function DMS2DD([degrees, minutes, seconds, secondsFraction = 0], type) {
* @returns {[Array, Array]} latitude and longitude DMS coordinate
*/
function DD2DMS(lat, long) {
const dmsCoords = new DmsCoordinates(lat, long);
const { longitude, latitude } = dmsCoords.dmsArrays;
let [latD, latM, latS, latDir] = latitude;
let [latD, latM, latS, latDir] = parseDD(lat, "latitude");
if (latDir == "S") {
latD *= -1;
latM *= -1;
latS *= -1;
}

let [longD, longM, longS, longDir] = longitude;
let [longD, longM, longS, longDir] = parseDD(long, "longitude");
if (longDir == "W") {
longD *= -1;
longM *= -1;
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/utils/location.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ describe("DMS2DD location convert", () => {
it("Should work with valid negative values", () => {
expect(DMS2DD([-33, -52, -11.438039999997507])).toBeCloseTo(-33.8698439);
});

it("Should work with valid positive values", () => {
expect(DMS2DD([55, 45, 1.948320000002468])).toBeCloseTo(55.7505412);
});

it("Should work with string", () => { // We have strings in some old IFCs
it("Should work with string", () => { // We have strings in some old IFCs
expect(DMS2DD(["55", "45", "1.948320000002468"])).toBeCloseTo(55.7505412);
});
});


describe("DD2DMS location convert", () => {
it("Should work with legacy errors values", () => {
expect(DD2DMS(-33.8698439, 151.2082848 )).toStrictEqual([[-33, -52, -11.438039999997507], [151, 12, 29.82528000000453]]);
});

it("Should work with valid positive values", () => {
expect(DD2DMS(55.7505412, 37.6174782)).toStrictEqual([[55, 45, 1.948320000002468], [37, 37, 2.9215200000026087]]);
});

});
Loading