import _ from 'lodash' ; import axios from 'axios' ; import type { Venue , VenueLocationMap } from '../types/venues' ; const COVID_ZONE_URL = 'https://raw.githubusercontent.com/nusmodifications/nusmods/master/website/src/data/covidZones.json' ; export type CovidZone = { color : string ; positions : [ number , number ] [ ] ; } ; export type CovidZoneId = 'A' | 'B' | 'C' | 'D' | 'E' | 'Unknown' ; export type CovidZones = Record < Exclude < CovidZoneId , 'Unknown' > , CovidZone > ; const getCovidZones = _ . memoize ( async ( ) => { const response = await axios . get < CovidZones > ( COVID_ZONE_URL ) ; return response . data ; } ) ; /**
 * Performs the even-odd-rule Algorithm (a raycasting algorithm) to find out whether a point is in a given polygon.
 * This runs in O(n) where n is the number of edges of the polygon.
 *
 * Source: https://www.algorithms-and-technologies.com/point_in_polygon/javascript
 */ function pointInPolygon ( polygon , point ) { let odd = false ; for ( let i = 0 , j = polygon . length - 1 ; i < polygon . length ; i ++ ) { if ( polygon [ i ] [ 1 ] > point [ 1 ] !== polygon [ j ] [ 1 ] > point [ 1 ] && point [ 0 ] < ( ( polygon [ j ] [ 0 ] - polygon [ i ] [ 0 ] ) * ( point [ 1 ] - polygon [ i ] [ 1 ] ) ) / ( polygon [ j ] [ 1 ] - polygon [ i ] [ 1 ] ) + polygon [ i ] [ 0 ] ) { odd = ! odd ; } j = i ; } return odd ; } const getLocationCovidZone = _ . memoize ( ( zones , location ) : CovidZoneId => { const zoneEntries = Object . entries ( zones ) as [ CovidZoneId , CovidZone ] [ ] ; const zone = zoneEntries . find ( ( [ , { positions } ] ) => pointInPolygon ( positions , [ location . y , location . x ] ) ) ; return zone ?. [ 0 ] ?? 'Unknown' ; } ) ; export function getVenueCovidZone ( venues , zones , venue ) { const venueInfo = venues [ venue ] ; if ( ! venueInfo ?. location ) { return 'Unknown' ; } return getLocationCovidZone ( zones , venueInfo . location ) ; } export default getCovidZones ;