web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

geojson.ts (2276B)


      1 import type { GeolocationPoint, GeometryPoint, GeometryPolygon } from "./types.js";
      2 
      3 const WGS84_RADIUS_M = 6378137;
      4 const DEFAULT_CIRCLE_STEPS = 64;
      5 const COORD_SCALE = 1_000_000;
      6 
      7 const rad_from_deg = (deg: number): number => (deg * Math.PI) / 180;
      8 const deg_from_rad = (rad: number): number => (rad * 180) / Math.PI;
      9 const wrap_lng = (lng: number): number => ((lng + 540) % 360) - 180;
     10 const round_coord = (value: number): number => Math.round(value * COORD_SCALE) / COORD_SCALE;
     11 
     12 export const geojson_point_from_geopoint = (geol_p: GeolocationPoint): GeometryPoint => ({
     13     type: "Point",
     14     coordinates: [geol_p.lng, geol_p.lat],
     15 });
     16 
     17 export const geojson_polygon_circle_wgs84 = (opts: {
     18     geol_p: GeolocationPoint;
     19     radius_m?: number;
     20     steps?: number;
     21 }): GeometryPolygon => {
     22     const { geol_p } = opts;
     23     const radius_m_raw = opts.radius_m;
     24     const radius_m = typeof radius_m_raw === "number" && Number.isFinite(radius_m_raw) && radius_m_raw > 0
     25         ? radius_m_raw
     26         : 100;
     27     const steps_raw = opts.steps;
     28     const steps_val = typeof steps_raw === "number" && Number.isFinite(steps_raw) && steps_raw > 0
     29         ? Math.round(steps_raw)
     30         : DEFAULT_CIRCLE_STEPS;
     31     const step_count = Math.max(4, steps_val);
     32     const lat_rad = rad_from_deg(geol_p.lat);
     33     const lng_rad = rad_from_deg(geol_p.lng);
     34     const angular_distance = radius_m / WGS84_RADIUS_M;
     35     const sin_lat = Math.sin(lat_rad);
     36     const cos_lat = Math.cos(lat_rad);
     37     const sin_ad = Math.sin(angular_distance);
     38     const cos_ad = Math.cos(angular_distance);
     39     const coords: Array<[number, number]> = [];
     40     for (let i = 0; i <= step_count; i++) {
     41         const bearing = (i * 2 * Math.PI) / step_count;
     42         const lat_rad_next = Math.asin(
     43             sin_lat * cos_ad + cos_lat * sin_ad * Math.cos(bearing),
     44         );
     45         const lng_rad_next = lng_rad + Math.atan2(
     46             Math.sin(bearing) * sin_ad * cos_lat,
     47             cos_ad - sin_lat * Math.sin(lat_rad_next),
     48         );
     49         const lat_next = round_coord(deg_from_rad(lat_rad_next));
     50         const lng_next = round_coord(wrap_lng(deg_from_rad(lng_rad_next)));
     51         coords.push([lng_next, lat_next]);
     52     }
     53     return {
     54         type: "Polygon",
     55         coordinates: [coords],
     56     };
     57 };