From 5050a296fe002bcf8d0eefec1eb957e841a33477 Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 5 Sep 2023 12:36:09 -0500 Subject: [PATCH] Edge case handling, reduce nesting, general refactor of location funcs --- src/location.ts | 68 +++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/location.ts b/src/location.ts index 815781d..20aa18c 100644 --- a/src/location.ts +++ b/src/location.ts @@ -4,10 +4,11 @@ import * as life360 from 'life360-node-api'; import logger from '@/logger'; import Result, { err, ok } from 'true-myth/result'; -const center = { +const targetCenter = { longitude: env.CENTER_LONGITUDE, latitude: env.CENTER_LATITUDE }; + const MILES_PER_NAUTICAL_MILE = 1.15078; const KILOMETERS_PER_MILE = 1.60934; @@ -16,39 +17,50 @@ export type Position = { latitude: number; }; -// K = Kilometers, N = Nautical Miles, M = Miles (default: M) +/** + * + * Calculate the distance between two points using the Haversine formula + * + * K = Kilometers, N = Nautical Miles, M = Miles (default: M) + * + * @param a + * @param b + * @param unit + */ export function distance( a: Position, b: Position, unit: 'K' | 'N' | 'M' = 'M' ) { + // TODO: Handle floating point precision errors + // Edge case: same point if (a.latitude == b.latitude && a.longitude == b.longitude) { return 0; - } else { - const radlat1 = (Math.PI * a.latitude) / 180; - const radlat2 = (Math.PI * b.latitude) / 180; - const theta = a.longitude - b.longitude; - const radtheta = (Math.PI * theta) / 180; - let dist = - Math.sin(radlat1) * Math.sin(radlat2) + - Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); + } - if (dist > 1) dist = 1; + const radlat1 = (Math.PI * a.latitude) / 180; + const radlat2 = (Math.PI * b.latitude) / 180; + const theta = a.longitude - b.longitude; + const radtheta = (Math.PI * theta) / 180; + let dist = + Math.sin(radlat1) * Math.sin(radlat2) + + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); - dist = Math.acos(dist); - dist = (dist * 180) / Math.PI; - dist = dist * 60 * MILES_PER_NAUTICAL_MILE; // Convert to miles + if (dist > 1) dist = 1; - // Convert to the specified unit - switch (unit) { - case 'K': - return dist * KILOMETERS_PER_MILE; - case 'N': - return dist / MILES_PER_NAUTICAL_MILE; - case 'M': - default: - return dist; - } + dist = Math.acos(dist); + dist = (dist * 180) / Math.PI; + dist = dist * 60 * MILES_PER_NAUTICAL_MILE; // Convert to miles + + // Convert to the specified unit + switch (unit) { + case 'K': + return dist * KILOMETERS_PER_MILE; + case 'N': + return dist / MILES_PER_NAUTICAL_MILE; + case 'M': + default: + return dist; } } @@ -67,6 +79,7 @@ export async function getDistance(): Promise> { })` ); } + logger.debug(`Logged in to Life360 (${env.LIFE360_USERNAME}).`); // Get my current location let me; @@ -88,6 +101,11 @@ export async function getDistance(): Promise> { ); } + if (me == undefined) + return err( + `Failed to find member with ID ${env.LIFE360_MEMBER_ID} in Life360` + ); + // Parse my latitude and longitude into floats const current = { latitude: parseFloat(me.location.latitude), @@ -95,5 +113,5 @@ export async function getDistance(): Promise> { }; // Calculate the distance between my location and the center, multiply x1000 for meters - return ok(distance(current, center, 'K') * 1000); + return ok(distance(current, targetCenter, 'K') * 1000); }