UNPKG

@tak-ps/node-cot

Version:

Lightweight JavaScript library for parsing and manipulating TAK messages

106 lines (88 loc) 3.1 kB
import Err from '@openaddresses/batch-error'; import { v4 as randomUUID } from 'uuid'; import type { Static } from '@sinclair/typebox'; import { coordEach } from "@turf/meta"; import TypeValidator from '../type.js'; import { Feature } from '../types/feature.js'; import PointOnFeature from '@turf/point-on-feature'; import { GeoJSONFeature } from '../types/geojson.js'; /** * Given a generic GeoJSON Feature, convert it to a CoT Featurt * * @param {Object} feature GeoJSON Feature * * @return {CoT} */ export async function normalize_geojson( feature: Static<typeof GeoJSONFeature>, ): Promise<Static<typeof Feature>> { try { feature = await TypeValidator.type(GeoJSONFeature, feature); } catch (err) { throw new Err(400, null, `Validation Error: ${err}`); } if (!feature.id) { feature.id = randomUUID(); } const props = feature.properties; feature.properties = { metadata: props || {} } if (feature.geometry.type === 'Point') { feature.properties.type = 'u-d-p'; } else if (feature.geometry.type === 'LineString') { feature.properties.type = 'u-d-f'; } else if (feature.geometry.type === 'Polygon') { feature.properties.type = 'u-d-f'; } else { throw new Err(400, null, `Unsupported Geometry Type`); } for (const color of ['marker-color', 'stroke', 'fill']) { if ( props[color] && typeof props[color] === 'string' && /^#?[0-9a-fA-F]{6}$/.test(props[color]) ) { feature.properties[color] = props[color].startsWith('#') ? props[color] : `#${props[color]}`; } } for (const number of ['marker-opacity', 'stroke-opacity', 'stroke-width', 'fill-opacity']) { if ( props[number] && typeof props[number] === 'number' ) { feature.properties[number] = props[number]; } } // Callsign Options for (const callsign of ['callsign', 'title', 'name']) { if (props[callsign] && typeof props[callsign] === 'string') { feature.properties.callsign = props[callsign]; break; } } if (!feature.properties.callsign) { feature.properties.callsign = 'New Feature'; } // Remarks Options for (const remarks of ['remarks', 'description']) { if (props[remarks] && typeof props[remarks] === 'string') { feature.properties.remarks = props[remarks]; break; } } if (!feature.properties.remarks) { feature.properties.remarks = ''; } feature.properties.time = new Date().toISOString(); feature.properties.start = new Date().toISOString(); const stale = new Date(); stale.setHours(stale.getHours() + 1); feature.properties.stale = stale; feature.properties.center = PointOnFeature(feature).geometry.coordinates; feature.properties.archived = true; coordEach(feature.geometry, (coord) => { return coord.slice(0, 3); }); return feature as Static<typeof Feature>; }