@fleetbase/fleetops-engine
Version:
Fleet & Transport Management Extension for Fleetbase
125 lines (99 loc) • 3.91 kB
JavaScript
/* eslint-disable no-unused-vars */
import { MultiPolygon, Polygon, Circle, Feature, FeatureCollection } from '@fleetbase/fleetops-data/utils/geojson';
import { isArray } from '@ember/array';
import wrapCoordinates from './leaflet-wrap-coordinates';
export function toPos(ll) {
// Accept Leaflet LatLng or plain {lat,lng}
return isArray(ll) ? [ll[1], ll[0]] : [ll.lng, ll.lat];
}
/** Ensure we always have an array-of-rings (each ring = LatLng[]) */
function normalizeToRings(latlngs) {
if (!latlngs) return [];
// Simple polygon given as [LatLng,...]
if (isArray(latlngs) && !isArray(latlngs[0])) {
return [latlngs];
}
// Already [ [LatLng,...], ... ]
if (isArray(latlngs) && isArray(latlngs[0]) && !isArray(latlngs[0][0])) {
return latlngs;
}
// Multipolygon case handled elsewhere
return latlngs;
}
export function closeRing(coords) {
if (!coords.length) return coords;
const first = coords[0];
const last = coords[coords.length - 1];
if (first[0] !== last[0] || first[1] !== last[1]) {
return [...coords, first];
}
return coords;
}
export function ringsFromLatLngs(latlngs) {
const rings = normalizeToRings(latlngs);
return rings.map((ring) => closeRing(ring.map(toPos)));
}
/** Normalize Leaflet’s toGeoJSON output to a Feature */
export function getGeoJsonFeature(geojson) {
if (!geojson) return null;
if (geojson.type === 'Feature') return geojson;
if (geojson.type === 'FeatureCollection' && isArray(geojson.features) && geojson.features.length) {
return geojson.features[0];
}
// Geometry -> Feature wrapper (safe fallback)
if (geojson.type && geojson.coordinates) {
return { type: 'Feature', geometry: geojson, properties: {} };
}
return null;
}
/** ---- Polygon ---- */
export function createGeoJsonPolygon(layer, { properties } = {}) {
const latlngs = layer.getLatLngs?.();
if (!latlngs || !latlngs.length) return null;
const coordinates = wrapCoordinates(ringsFromLatLngs(latlngs));
return new Polygon(coordinates);
}
/** ---- MultiPolygon ---- */
export function createGeoJsonMultiPolygon(layer, { properties } = {}) {
// Leaflet MultiPolygon: [ [outer,hole,...], [outer,hole,...], ... ]
const groups = layer.getLatLngs?.();
if (!groups || !groups.length) return null;
const multiCoords = groups.map((g) => ringsFromLatLngs(g));
return new MultiPolygon(wrapCoordinates(multiCoords));
}
/** ---- Circle ---- */
export function createGeoJsonCircle(layer, { properties, steps = 64 } = {}) {
const center = toPos(layer.getLatLng());
const radius = layer.getRadius?.(); // meters
return new Circle(center, radius, steps);
}
/** ---- Catch-all: pick helper by Leaflet layer type ---- */
export function createGeoJsonFromLayer(layer, options = {}) {
const { layerType: type } = options;
if (type === 'circle' || type === 'circlemarker') {
return createGeoJsonCircle(layer, options);
}
// A rectangle is just a single Polygon (one outer ring)
if (type === 'polygon' || type === 'rectangle') {
return createGeoJsonPolygon(layer, options);
}
// Fallback to Leaflet’s own GeoJSON
const feature = getGeoJsonFeature(layer.toGeoJSON?.());
if (!feature) return null;
switch (feature.geometry?.type) {
case 'Polygon':
return new Polygon(feature.geometry.coordinates);
case 'MultiPolygon':
return new MultiPolygon(feature.geometry.coordinates);
default:
return new Feature(feature);
}
}
/** ---- Batching ---- */
export function createFeatureCollectionFromLayers(layers, options) {
const features = []
.concat(layers || [])
.map((l) => createGeoJsonFromLayer(l, options))
.filter(Boolean);
return new FeatureCollection({ features });
}