2021-05-23 14:20:53 +00:00
|
|
|
import { getDistance } from "geolib"
|
2021-05-22 02:08:39 +00:00
|
|
|
import osmZoomLevels from "../utils/osmZoomLevels"
|
2021-05-24 03:02:07 +00:00
|
|
|
import Coordinates from "./Coordinates"
|
|
|
|
import { SerializationError } from "./Errors"
|
2021-05-22 01:50:04 +00:00
|
|
|
|
|
|
|
|
2021-05-22 01:36:42 +00:00
|
|
|
/**
|
2021-05-22 01:50:04 +00:00
|
|
|
* An area on a map, defined by a `center` and a `radius` in meters.
|
2021-05-22 01:36:42 +00:00
|
|
|
*/
|
|
|
|
export default class MapArea {
|
2021-05-22 01:50:04 +00:00
|
|
|
radius
|
|
|
|
center
|
|
|
|
|
2021-05-22 01:36:42 +00:00
|
|
|
/**
|
2021-05-22 01:50:04 +00:00
|
|
|
* @param radius - The radius of the area in meters.
|
|
|
|
* @param center - The center of the area.
|
2021-05-22 01:36:42 +00:00
|
|
|
*/
|
2021-05-22 01:50:04 +00:00
|
|
|
constructor(radius, center) {
|
|
|
|
this.radius = radius
|
|
|
|
this.center = center
|
2021-05-22 01:36:42 +00:00
|
|
|
}
|
|
|
|
|
2021-05-22 02:08:39 +00:00
|
|
|
/**
|
|
|
|
* Create a new {@link MapArea} from the [zoom level of OpenStreetMaps][1], assuming the window is
|
|
|
|
* ~400 pixels large.
|
|
|
|
*
|
|
|
|
* [1]: https://wiki.openstreetmap.org/wiki/Zoom_levels
|
|
|
|
*
|
|
|
|
* @param zoom
|
|
|
|
* @param center
|
|
|
|
* @returns {MapArea}
|
|
|
|
*/
|
|
|
|
static fromZoomLevel(zoom, center) {
|
|
|
|
return new MapArea(osmZoomLevels[zoom], center)
|
|
|
|
}
|
|
|
|
|
2021-05-24 03:02:07 +00:00
|
|
|
static rawRegex = /^< (?<radius>[0-9.]+) (?<lat>[0-9.]+) (?<lng>[0-9.]+)$/
|
|
|
|
|
|
|
|
static fromRaw(data) {
|
|
|
|
const match = this.rawRegex.exec(data)
|
|
|
|
|
|
|
|
if(!match) throw new SerializationError(data)
|
|
|
|
|
|
|
|
const radius = Number(match.groups.radius)
|
|
|
|
const lat = Number(match.groups.lat)
|
|
|
|
const lng = Number(match.groups.lng)
|
|
|
|
const center = new Coordinates(lat, lng)
|
|
|
|
|
|
|
|
return new MapArea(radius, center)
|
|
|
|
}
|
|
|
|
|
2021-05-22 01:36:42 +00:00
|
|
|
/**
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
toString() {
|
2021-05-22 02:32:47 +00:00
|
|
|
return `< ${this.radius} ${this.center.toString()}`
|
2021-05-22 01:36:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-05-22 02:08:39 +00:00
|
|
|
* Render the {@link MapArea} as an human-readable string.
|
2021-05-22 01:36:42 +00:00
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
toHumanString() {
|
2021-05-22 01:50:04 +00:00
|
|
|
if(this.radius >= 2000) {
|
|
|
|
const kmRadius = Math.round(this.radius / 1000)
|
2021-05-22 02:32:47 +00:00
|
|
|
return `< ${kmRadius}km ${this.center.toHumanString()}`
|
2021-05-22 01:36:42 +00:00
|
|
|
}
|
2021-05-22 02:32:47 +00:00
|
|
|
return `< ${this.radius}m ${this.center.toHumanString()}`
|
2021-05-22 01:50:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a pair of coordinates is included in the area.
|
|
|
|
*
|
|
|
|
* @param coords - The coordinates to check.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
includes(coords) {
|
|
|
|
return getDistance(this.center.toGeolib(), coords.toGeolib()) <= this.radius
|
2021-05-22 01:36:42 +00:00
|
|
|
}
|
|
|
|
}
|