import type { GeoJsonBbox } from "@trackunit/geo-json-utils"; import type { LabelFootprintDeg } from "./internal/labelFootprint"; import type { MapFocus } from "./mapFocus"; type Position = readonly [number, number, ...Array]; export type BuildLabelPlacementParams = Readonly<{ items: ReadonlyArray; getId: (item: TAsset) => string; getPosition: (item: TAsset) => Position; /** Priority tiers, evaluated high→low; only tier-matching items are label-eligible. */ focus: MapFocus; /** Current camera view box; candidates outside it are skipped. `null` disables clipping. */ bounds: Readonly | null; /** Geo footprint every label is assumed to occupy, for collision testing. */ footprint: LabelFootprintDeg; /** Maximum number of labels to place (DOM-node ceiling). */ ceiling: number; /** Previously-shown ids — kept preferentially within their tier (hysteresis). */ previousIds?: ReadonlySet; }>; /** * Chooses which markers render a label so that no two labels overlap, in priority order. * * Walks `focus.tiers` high→low; only items matching a tier are eligible. Within each tier, * incumbents (in `previousIds`) are considered before newcomers, and each group is visited in * dynamic **farthest-point** order — the candidate whose nearest-neighbour distance to every * already-placed label is largest is tried first — so labels spread across the view box rather * than lumping. Each pick is collision-tested against the placed footprints and skipped if it * would overlap. Placement stops at `ceiling`; the budget is otherwise emergent (what fits). * * All geometry runs in longitudes unwrapped around the view-box centre, so a viewport crossing * the antimeridian is handled correctly. Deterministic: all ties (centroid seed and * farthest-point) break by `getId` ascending, so the result is independent of server return order. */ export declare const buildLabelPlacement: ({ items, getId, getPosition, focus, bounds, footprint, ceiling, previousIds, }: BuildLabelPlacementParams) => ReadonlySet; export {};