ofs-object 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4887 @@
1
+ import { Feature } from 'geojson';
2
+ import { FeatureCollection } from 'geojson';
3
+ import { Geometry } from 'geojson';
4
+ import { LineString } from 'geojson';
5
+ import { MultiLineString } from 'geojson';
6
+ import { MultiPolygon } from 'geojson';
7
+ import { Point } from 'geojson';
8
+ import { Polygon } from 'geojson';
9
+ import { Position } from 'geojson';
10
+ import * as turf from '@turf/turf';
11
+
12
+ export declare interface AddedLayer {
13
+ layerId: string;
14
+ name: string;
15
+ featureCount: number;
16
+ sourceCrs: string;
17
+ }
18
+
19
+ /**
20
+ * Add imported layers to a data source. Feature ids from the file are kept when unique within the layer;
21
+ * duplicates get new ids (reported).
22
+ */
23
+ export declare function addImportedLayers(ds: OFSDataSource, imported: ImportedLayer[], issues?: ImportIssue[]): AddedLayer[];
24
+
25
+ export declare interface AiExecutionFeedback {
26
+ success: boolean;
27
+ tool: string;
28
+ summary: string;
29
+ data?: any;
30
+ error?: string;
31
+ /** What the command expects, sent back when a call was refused so the model can retry */
32
+ help?: string[];
33
+ mapSnapshot?: {
34
+ activeLayerId: string | null;
35
+ totalLayers: number;
36
+ layerFeatureCounts: Record<string, number>;
37
+ };
38
+ }
39
+
40
+ export declare interface AiToolDeclaration {
41
+ type: 'function';
42
+ function: {
43
+ name: string;
44
+ description: string;
45
+ parameters: {
46
+ type: 'object';
47
+ properties: Record<string, any>;
48
+ required?: string[];
49
+ };
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Signed distance field for recolorable (SDF) map icons, using the Felzenszwalb-Huttenlocher
55
+ * Euclidean distance transform (the same approach as mapbox/tiny-sdf).
56
+ *
57
+ * GL renders an SDF icon edge where the alpha value is 0.75 (191/255); halos grow outward from it.
58
+ */
59
+ /**
60
+ * Convert coverage alpha (0-255, row-major) into SDF alpha values.
61
+ * @param radius Distance in pixels mapped across the full alpha range
62
+ * @param cutoff Share of the range inside the shape (0.25 puts the edge at 191)
63
+ */
64
+ export declare function alphaToSdf(alpha: ArrayLike<number>, width: number, height: number, radius?: number, cutoff?: number): Uint8ClampedArray;
65
+
66
+ export declare type AngleConvention = 'bearing' | 'cad';
67
+
68
+ export declare interface AngleMeasure {
69
+ /** Angle at the middle point, 0–180° */
70
+ degrees: number;
71
+ /** Direction from the middle point to the first / third point, in the given convention */
72
+ firstAngleDeg: number;
73
+ secondAngleDeg: number;
74
+ firstMeters: number;
75
+ secondMeters: number;
76
+ }
77
+
78
+ declare type AnyFeature = Feature<Geometry, any>;
79
+
80
+ /** Apply a class color / size / override on top of the base symbol */
81
+ export declare function applyClassSymbol(base: SymbolStyle, classColor: string | undefined, classSize: number | undefined, override?: ClassSymbolOverride): SymbolStyle;
82
+
83
+ /** 1 rai = 4 ngan = 400 square wa = 1600 m² */
84
+ export declare const AREA_UNITS: Record<string, number>;
85
+
86
+ export declare interface AreaMeasure {
87
+ /** Area in m² (holes subtracted) */
88
+ area: number;
89
+ /** Perimeter in m (all rings) */
90
+ perimeter: number;
91
+ /** Mean width 2A/P in m (0 when the perimeter is 0) */
92
+ width: number;
93
+ }
94
+
95
+ export declare class ArgumentError extends OFSError {
96
+ readonly command: string;
97
+ readonly issues: string[];
98
+ constructor(command: string, issues: string[], usage?: string);
99
+ }
100
+
101
+ /**
102
+ * Ask for a map point or free text. Falls back to text-only input on consoles without point picking.
103
+ */
104
+ export declare function askPointOrText(consoleService: IOFSConsole, prompt: string, basePoint?: Coordinate | null): Promise<{
105
+ point: Coordinate;
106
+ } | {
107
+ text: string;
108
+ }>;
109
+
110
+ /**
111
+ * Ask for a required point; throws when the user answers with an empty input.
112
+ */
113
+ export declare function askRequiredPoint(consoleService: IOFSConsole, prompt: string, basePoint?: Coordinate | null): Promise<Coordinate>;
114
+
115
+ export declare function assertValidPolygon(geometry: Polygon | MultiPolygon, what: string): void;
116
+
117
+ export declare interface AttributeRow {
118
+ featureId: string | number;
119
+ selected: boolean;
120
+ values: Record<string, unknown>;
121
+ }
122
+
123
+ export declare interface AttributeTableOptions {
124
+ /** Called when a row is opened (double click): zoom the map to the feature */
125
+ onZoom?: (layerId: string, featureId: string | number) => void;
126
+ onClose?: () => void;
127
+ /** Ask before deleting a field (default: window.confirm) */
128
+ confirmDelete?: (field: FieldSchema, layerName: string) => boolean;
129
+ }
130
+
131
+ export declare abstract class BaseGLAdapter implements IMapAdapter {
132
+ abstract readonly engineName: 'maplibre' | 'mapbox';
133
+ protected map: any;
134
+ protected _isReady: boolean;
135
+ /**
136
+ * False when the map came from `attach()`: the host application created it and destroy()
137
+ * must leave it running, removing only what this adapter added.
138
+ */
139
+ protected ownsMap: boolean;
140
+ protected dataSource: OFSDataSource | null;
141
+ protected thematicEngine: OFSThematicEngine | null;
142
+ protected unsubscribers: (() => void)[];
143
+ protected clickHandlers: Set<(e: MapClickEvent) => void>;
144
+ protected dblClickHandlers: Set<(e: MapClickEvent) => void>;
145
+ protected contextMenuHandlers: Set<(e: MapClickEvent) => void>;
146
+ protected moveHandlers: Set<(e: MapClickEvent) => void>;
147
+ protected mouseDownHandlers: Set<(e: MapClickEvent) => void>;
148
+ protected mouseUpHandlers: Set<(e: MapClickEvent) => void>;
149
+ protected activeFeatureStateIds: Map<string, Set<string | number>>;
150
+ /** Feature object references last sent to each map source, used to compute incremental diffs */
151
+ protected renderedFeatures: Map<string, Map<string | number, Feature<Geometry, any>>>;
152
+ /** Compiled label expressions per layer (labels that are not a plain field) */
153
+ protected labelSources: Map<string, LabelSource>;
154
+ protected pendingSourceUpdates: Set<string>;
155
+ protected flushScheduled: boolean;
156
+ /** GL layers created for each data layer, with the property values last sent to the map */
157
+ protected glLayers: Map<string, GLLayerRecord[]>;
158
+ protected glLayerOwner: Map<string, string>;
159
+ protected glLayerZIndex: Map<string, number>;
160
+ private orderScheduled;
161
+ protected symbolImages: SymbolImageManager;
162
+ private unsubscribeIcons;
163
+ get isReady(): boolean;
164
+ abstract init(container: HTMLElement | string, options?: Record<string, any>): Promise<void>;
165
+ /**
166
+ * Use a map the host application created (Angular, React, Vue, or a plain page) instead of
167
+ * creating one. The map keeps belonging to the host: `destroy()` removes the layers, sources and
168
+ * listeners this adapter added and leaves the map itself alive.
169
+ *
170
+ * Resolves once the style is parsed, whether that happened before or after this call.
171
+ */
172
+ attach(map: any): Promise<void>;
173
+ /**
174
+ * Wait until the style is usable. `isStyleLoaded()` is checked first because `load` has often
175
+ * already fired by the time a host hands over its map, and `loaded()` is not used because it goes
176
+ * back to false whenever tiles are in flight.
177
+ */
178
+ protected whenStyleLoaded(map: any): Promise<void>;
179
+ bindDataSource(dataSource: OFSDataSource, thematicEngine?: OFSThematicEngine): void;
180
+ protected syncAllLayers(): void;
181
+ syncLayer(layer: OFSLayerData): void;
182
+ /** Reordering several layers emits one update per layer; restack once */
183
+ private scheduleLayerOrder;
184
+ /** GL layer ids that render a data layer, bottom to top */
185
+ getGLLayerIds(layerId: string): string[];
186
+ /** Data layer that owns a GL layer id */
187
+ protected dataLayerIdFor(glLayerId: string): string;
188
+ protected isLayerRendered(layer: OFSLayerData): boolean;
189
+ private serialize;
190
+ /** Set changed properties and reset properties that are no longer specified */
191
+ private applyProperties;
192
+ private safely;
193
+ /** Draw tool layers stay above data layers */
194
+ private drawLayerAnchor;
195
+ private removeGLLayer;
196
+ /** Stack all GL layers by data layer zIndex (each data layer's GL layers stay together, in order) */
197
+ protected applyLayerOrder(): void;
198
+ removeLayer(layerId: string): void;
199
+ /**
200
+ * Queue a source refresh for a layer. Multiple edits in the same animation frame
201
+ * (e.g. dragging a grip) are sent to the map once.
202
+ */
203
+ protected scheduleSourceUpdate(layerId: string): void;
204
+ /**
205
+ * Immediately send all queued source updates to the map.
206
+ */
207
+ flushPendingSourceUpdates(): void;
208
+ /**
209
+ * Build the full render collection for a layer and remember what was sent.
210
+ */
211
+ protected buildRenderCollection(layer: OFSLayerData): FeatureCollection<Geometry, any>;
212
+ /**
213
+ * Keep the label text generator of a layer up to date. Returns true when it changed, which means the
214
+ * whole source has to be resent (every feature's label text changes at once).
215
+ */
216
+ protected syncLabelSource(layer: OFSLayerData): boolean;
217
+ /**
218
+ * Send changes of a layer to its map source. Uses GeoJSONSource.updateData (MapLibre) with only
219
+ * the added / changed / removed features when possible, otherwise falls back to setData.
220
+ * Changed features are detected by object identity: OFSLayerData replaces the stored object on
221
+ * every add or update.
222
+ */
223
+ protected updateSourceData(layer: OFSLayerData): void;
224
+ protected updateSelectionState(layerId: string, featureIds: (string | number)[]): void;
225
+ setFeatureState(layerId: string, featureId: string | number, state: Record<string, any>): void;
226
+ getFeatureState(layerId: string, featureId: string | number): Record<string, any>;
227
+ setLayerVisibility(layerId: string, visible: boolean): void;
228
+ /** Layer opacity multiplies every symbol opacity, so it is applied by recompiling the style */
229
+ setLayerOpacity(layerId: string, opacity: number): void;
230
+ setLayerZIndex(_layerId: string, _zIndex: number): void;
231
+ fitBounds(bbox: BoundingBox, padding?: number): void;
232
+ flyTo(options: MapViewportOptions): void;
233
+ getCenter(): Coordinate;
234
+ setCenter(coord: Coordinate): void;
235
+ getZoom(): number;
236
+ setZoom(zoom: number): void;
237
+ getBounds(): BoundingBox;
238
+ onMapClick(handler: (e: MapClickEvent) => void): () => void;
239
+ onMapDblClick(handler: (e: MapClickEvent) => void): () => void;
240
+ onContextMenu(handler: (e: MapClickEvent) => void): () => void;
241
+ onMouseMove(handler: (e: MapClickEvent) => void): () => void;
242
+ onMouseDown(handler: (e: MapClickEvent) => void): () => void;
243
+ onMouseUp(handler: (e: MapClickEvent) => void): () => void;
244
+ setDoubleClickZoom(enabled: boolean): void;
245
+ /**
246
+ * Register a map listener and remember how to remove it, so a map owned by the host
247
+ * is left without our handlers after destroy().
248
+ */
249
+ protected listen(event: string, handler: (e: any) => void): void;
250
+ protected setupMapEventListeners(): void;
251
+ getRawMap<T = any>(): T;
252
+ /**
253
+ * Take every source and layer this adapter added off a map it does not own, so the host is
254
+ * handed back the map it created. Layers of the data source first, then anything named `_ofs_*`
255
+ * (the temporary drawing layers).
256
+ */
257
+ protected removeOwnLayers(): void;
258
+ destroy(): void;
259
+ }
260
+
261
+ export declare type BoundingBox = [number, number, number, number];
262
+
263
+ /** Build contiguous breaks from ascending upper bounds, with colors, labels and counts */
264
+ export declare function buildBreaks(sortedValues: number[], lower: number, uppers: number[], palette: Palette, reverse?: boolean): ClassBreak[];
265
+
266
+ /**
267
+ * Expression evaluating to the class index of a feature, or -1. Null for single-symbol themes.
268
+ */
269
+ export declare function buildClassIndexExpression(theme: ThematicDefinition): any[] | null;
270
+
271
+ export declare function buildNetwork(points: Coordinate[], source: Coordinate, options?: NetworkOptions): NetworkResult;
272
+
273
+ export declare const BUILTIN_MARKER_SHAPES: MarkerShape[];
274
+
275
+ /** Points along a bulge segment (excluding the start point, including the end point) */
276
+ export declare function bulgePoints(p1: Position, p2: Position, bulge: number, maxStepDeg: number): Position[];
277
+
278
+ export declare class CADOperations {
279
+ /**
280
+ * Split a Polygon using a LineString.
281
+ * Creates a hairline buffer "blade" to perform difference, then flattens into pieces.
282
+ */
283
+ /**
284
+ * Extend a ray from startPt through endPt until safely outside the polygon's bounding box.
285
+ * Uses Cartesian unit vector in coordinate space to avoid spherical bearing drift.
286
+ */
287
+ private static extendRayOutside;
288
+ /**
289
+ * Prepare cutting line: ensures head and tail pierce outside the polygon if they stop inside.
290
+ * The cutting line is ALWAYS kept as a single continuous LineString (never decomposed into separate rays).
291
+ */
292
+ private static prepareCuttingLine;
293
+ /**
294
+ * Split a single Polygon by a single LineString using planar graph noded polygonization.
295
+ */
296
+ private static splitSinglePolygonByLine;
297
+ /**
298
+ * Split a Polygon using a LineString.
299
+ * Ensures cutting lines pierce completely through boundaries without leaving unsevered edges or dead-end slits.
300
+ */
301
+ static splitPolygonByLine(polygon: Feature<Polygon | MultiPolygon>, cuttingLine: Feature<LineString>): Feature<Polygon>[] | null;
302
+ /**
303
+ * Connect multiple LineStrings that share endpoints or are within tolerance
304
+ */
305
+ static connectLines(lines: Feature<LineString>[], toleranceMeters?: number, preserveFirstLineDirection?: boolean): Feature<LineString> | null;
306
+ /**
307
+ * Smooth a LineString using Bezier curve interpolation
308
+ */
309
+ static smoothLineBezier(line: Feature<LineString>, resolution?: number): Feature<LineString>;
310
+ /**
311
+ * Helper: extend a LineString forward and backward
312
+ */
313
+ private static extendLine;
314
+ /**
315
+ * Offset a LineString or Polygon (AutoCAD OFFSET), computed in planar meters.
316
+ * - LineString: parallel line with mitered joins (positive = right of direction, negative = left)
317
+ * - Polygon: sharp-cornered offset (positive = outward, negative = inward). An inward offset that
318
+ * splits the shape returns a MultiPolygon; one that collapses it returns null.
319
+ * @param feature LineString or Polygon to offset
320
+ * @param distanceMeters Distance in meters
321
+ */
322
+ static offset(feature: Feature<LineString | Polygon>, distanceMeters: number): Feature<LineString | Polygon | MultiPolygon> | null;
323
+ /**
324
+ * Rotate a feature by angleDegrees around a pivot point (AutoCAD ROTATE), rigid in planar meters.
325
+ * @param feature Geometry feature to rotate
326
+ * @param angleDegrees Angle in degrees (clockwise)
327
+ * @param pivot Optional pivot point (defaults to feature centroid)
328
+ */
329
+ static rotate<T extends Geometry>(feature: Feature<T>, angleDegrees: number, pivot?: Coordinate): Feature<T>;
330
+ /**
331
+ * Scale a feature by scaleFactor around an origin point (AutoCAD SCALE), uniform in planar meters.
332
+ * @param feature Geometry feature to scale
333
+ * @param scaleFactor Scale multiplier (e.g. 1.5 = 150%, 0.8 = 80%)
334
+ * @param origin Optional origin point (defaults to feature centroid)
335
+ */
336
+ static scale<T extends Geometry>(feature: Feature<T>, scaleFactor: number, origin?: Coordinate): Feature<T>;
337
+ /**
338
+ * Explode a Polygon or MultiPolygon into individual LineString segments (AutoCAD EXPLODE)
339
+ */
340
+ static explode(feature: Feature<Polygon | MultiPolygon>): Feature<LineString>[];
341
+ /**
342
+ * Fillet (round corner) at a vertex with a true circular arc of radiusMeters (AutoCAD FILLET).
343
+ * Vertices other than the filleted corner keep their exact original coordinates.
344
+ * Returns null when the vertex cannot be filleted (endpoint of a line, straight corner,
345
+ * or radius too large for the adjacent segments). Use `maxFilletRadius` to find the limit.
346
+ */
347
+ static fillet(feature: Feature<Polygon | LineString>, vertexIndex: number, radiusMeters?: number): Feature<Polygon | LineString> | null;
348
+ /**
349
+ * Largest fillet radius (meters) that fits at the given vertex, or 0 if it cannot be filleted.
350
+ */
351
+ static maxFilletRadius(feature: Feature<Polygon | LineString>, vertexIndex: number): number;
352
+ private static getFilletCorner;
353
+ /**
354
+ * Translate / Move a feature by distance and bearing (AutoCAD MOVE), rigid in planar meters.
355
+ * @param feature Feature to translate
356
+ * @param distanceMeters Distance in meters
357
+ * @param bearingDegrees Direction in degrees (0 = North, 90 = East, 180 = South, 270 = West)
358
+ */
359
+ static translate<T extends Geometry>(feature: Feature<T>, distanceMeters: number, bearingDegrees: number): Feature<T>;
360
+ /**
361
+ * Translate a feature by planar offsets in meters (AutoCAD relative move @dx,dy)
362
+ * @param dxMeters Easting offset in meters (positive = East)
363
+ * @param dyMeters Northing offset in meters (positive = North)
364
+ */
365
+ static translateByMeters<T extends Geometry>(feature: Feature<T>, dxMeters: number, dyMeters: number): Feature<T>;
366
+ /**
367
+ * Move a feature by the displacement from `from` to `to` (AutoCAD MOVE base point -> second point).
368
+ * The base point lands exactly on the second point. The shape is measured on a ground-true plane at
369
+ * `from` and rebuilt on a plane at `to`, so edge lengths and true bearings are preserved even for
370
+ * long moves (a single plane would slowly rotate shapes moved kilometers away).
371
+ */
372
+ static translateByVector<T extends Geometry>(feature: Feature<T>, from: Coordinate, to: Coordinate): Feature<T>;
373
+ /**
374
+ * AutoCAD ALIGN: move source point 1 onto destination point 1, then (optionally) rotate so the
375
+ * direction source1->source2 matches destination1->destination2, and optionally scale so the
376
+ * lengths match. All steps are rigid / uniform on the ground plane.
377
+ */
378
+ static align<T extends Geometry>(feature: Feature<T>, source1: Coordinate, destination1: Coordinate, source2?: Coordinate | null, destination2?: Coordinate | null, scaleToFit?: boolean): Feature<T>;
379
+ /**
380
+ * Mirror a feature across the line through p1 and p2 (AutoCAD MIRROR).
381
+ * Polygon rings are reversed afterwards so their winding order is preserved.
382
+ */
383
+ static mirror<T extends Geometry>(feature: Feature<T>, p1: Coordinate, p2: Coordinate): Feature<T>;
384
+ /**
385
+ * Translate a feature by delta longitude and latitude
386
+ */
387
+ static translateByOffset<T extends Geometry>(feature: Feature<T>, dxLng: number, dyLat: number): Feature<T>;
388
+ /**
389
+ * Subtract a cutter feature from a target feature (AutoCAD SUBTRACT / Difference)
390
+ */
391
+ static difference(target: Feature<Polygon | MultiPolygon>, cutter: Feature<Polygon | MultiPolygon>): Feature<Polygon | MultiPolygon> | null;
392
+ /**
393
+ * Calculate intersection between two geometries (AutoCAD INTERSECT)
394
+ */
395
+ static intersect(featureA: Feature<Polygon | MultiPolygon>, featureB: Feature<Polygon | MultiPolygon>): Feature<Polygon | MultiPolygon> | null;
396
+ /**
397
+ * Simplify geometry using Douglas-Peucker algorithm
398
+ * @param feature Feature to simplify
399
+ * @param tolerance Tolerance in degrees (~0.0001 is ~10m)
400
+ */
401
+ static simplify<T extends Geometry>(feature: Feature<T>, tolerance?: number): Feature<T>;
402
+ /**
403
+ * Reverse coordinate direction of a LineString or Polygon ring
404
+ */
405
+ static reverse<T extends LineString | Polygon>(feature: Feature<T>): Feature<T>;
406
+ /**
407
+ * Clone feature with an optional new ID (AutoCAD COPY)
408
+ */
409
+ static cloneFeature<T extends Geometry>(feature: Feature<T>, newId?: string | number): Feature<T>;
410
+ /**
411
+ * Snap vertices of different features together when they are within toleranceMeters.
412
+ * Each vertex is moved onto the nearest vertex of an earlier feature in the list, so shared
413
+ * boundaries become exactly identical. Vertices within the same feature are never merged.
414
+ * Returns new features; inputs are not modified.
415
+ */
416
+ static snapVertices<T extends Geometry>(features: Feature<T>[], toleranceMeters?: number): Feature<T>[];
417
+ /**
418
+ * Remove redundant vertices that lie on a straight edge between their neighbors.
419
+ * A vertex is removed only if its perpendicular distance to the line through its neighbors is
420
+ * within toleranceMeters AND it lies between them, so real corners (even very shallow ones on
421
+ * long edges) are never removed. Remaining vertices keep their exact original coordinates.
422
+ * @param feature Polygon or MultiPolygon feature
423
+ * @param toleranceMeters Maximum perpendicular deviation in meters (default: 1 mm)
424
+ */
425
+ static cleanCollinearVertices<T extends Polygon | MultiPolygon>(feature: Feature<T>, toleranceMeters?: number): Feature<T>;
426
+ /**
427
+ * Split two overlapping polygons into mutually exclusive pieces:
428
+ * (A \ B, A ∩ B, B \ A)
429
+ */
430
+ static splitOverlappingPolygons(polyA: Feature<Polygon | MultiPolygon>, polyB: Feature<Polygon | MultiPolygon>): {
431
+ pieceA: Feature<Polygon>[];
432
+ overlap: Feature<Polygon>[];
433
+ pieceB: Feature<Polygon>[];
434
+ } | null;
435
+ /**
436
+ * Split a LineString by a Point, Coordinate, or another intersecting LineString (AutoCAD BREAK / SPLIT)
437
+ */
438
+ static splitLine(line: Feature<LineString>, splitter: Feature<Point | LineString> | Coordinate): Feature<LineString>[] | null;
439
+ }
440
+
441
+ /**
442
+ * Calculate bounding box from a list of coordinates.
443
+ */
444
+ export declare function calculateBBox(coordinates: Coordinate[]): BoundingBox;
445
+
446
+ export declare interface CalculateOptions {
447
+ onlySelected?: boolean;
448
+ /** Create the field when it does not exist yet (type defaults to the first result's type) */
449
+ createField?: FieldSchema | boolean;
450
+ /** Keep going when a feature fails instead of refusing the whole calculation (default: refuse) */
451
+ skipErrors?: boolean;
452
+ }
453
+
454
+ export declare interface CalculateResult {
455
+ field: string;
456
+ updated: number;
457
+ skipped: number;
458
+ errors: {
459
+ featureId: string | number;
460
+ message: string;
461
+ }[];
462
+ }
463
+
464
+ export declare interface CategoricalFieldStats {
465
+ distinctValues: string[];
466
+ frequencies: Record<string, number>;
467
+ }
468
+
469
+ export declare interface CategoricalThemeOptions {
470
+ reverse?: boolean;
471
+ baseSymbol?: SymbolStyleInput;
472
+ }
473
+
474
+ /**
475
+ * Index of the category whose value strictly equals `value` (type-sensitive: 1 and "1" differ, as in
476
+ * GL expressions), or -1.
477
+ */
478
+ export declare function categoryIndexForValue(categories: CategoryItem[], value: unknown): number;
479
+
480
+ export declare interface CategoryItem {
481
+ value: string | number | boolean;
482
+ color: string;
483
+ label: string;
484
+ count?: number;
485
+ visible?: boolean;
486
+ symbol?: ClassSymbolOverride;
487
+ }
488
+
489
+ /**
490
+ * Check one layer's features in one go. Features are not modified.
491
+ * On a large layer this can take a minute; `checkTopologyAsync` reports progress and can be stopped.
492
+ */
493
+ export declare function checkTopology(features: AnyFeature[], layer: {
494
+ id: string;
495
+ name?: string;
496
+ }, options?: TopologyOptions): TopologyReport;
497
+
498
+ /**
499
+ * The same checks, handing control back between chunks so the page keeps responding.
500
+ * `onProgress` is called as the work moves on, and an aborted `signal` stops it with `TopologyCancelled`.
501
+ */
502
+ export declare function checkTopologyAsync(features: AnyFeature[], layer: {
503
+ id: string;
504
+ name?: string;
505
+ }, options?: TopologyOptions, control?: {
506
+ onProgress?: (progress: TopologyProgress) => void;
507
+ signal?: AbortSignal;
508
+ sliceMs?: number;
509
+ }): Promise<TopologyReport>;
510
+
511
+ export declare function childNamed(el: XmlElement, name: string): XmlElement | undefined;
512
+
513
+ export declare function childrenNamed(el: XmlElement, name: string): XmlElement[];
514
+
515
+ /**
516
+ * Graduated class. A value v belongs to the class when min < v <= max (the first class also includes
517
+ * v == min), the same rule QGIS uses. Rendering and counts both follow this rule.
518
+ */
519
+ export declare interface ClassBreak {
520
+ min: number;
521
+ max: number;
522
+ color: string;
523
+ label: string;
524
+ count?: number;
525
+ /** Hidden classes are not drawn (default true) */
526
+ visible?: boolean;
527
+ /** Marker diameter / line width for graduated size mode */
528
+ size?: number;
529
+ symbol?: ClassSymbolOverride;
530
+ }
531
+
532
+ export declare type ClassificationMethod = 'equal_interval' | 'quantile' | 'natural_breaks' | 'pretty_breaks' | 'manual';
533
+
534
+ export declare function classifyByMethod(method: ClassificationMethod, values: number[], numClasses: number, palette?: Palette, reverse?: boolean): ClassBreak[];
535
+
536
+ /**
537
+ * Equal Interval Classification
538
+ */
539
+ export declare function classifyEqualInterval(values: number[], numClasses: number, palette?: Palette, reverse?: boolean): ClassBreak[];
540
+
541
+ /** Manual breaks from ascending upper bounds (the first class starts at the data minimum, or `lower`) */
542
+ export declare function classifyManual(values: number[], uppers: number[], palette?: Palette, lower?: number, reverse?: boolean): ClassBreak[];
543
+
544
+ /**
545
+ * Jenks Natural Breaks Classification (Fisher-Jenks: minimizes the sum of squared deviations from
546
+ * the class means).
547
+ */
548
+ export declare function classifyNaturalBreaks(values: number[], numClasses: number, palette?: Palette, reverse?: boolean): ClassBreak[];
549
+
550
+ /**
551
+ * Pretty Breaks: round boundaries (multiples of 1, 2 or 5 × 10^n) close to the requested class count.
552
+ * The first class starts at the data minimum and the last ends at the maximum.
553
+ */
554
+ export declare function classifyPrettyBreaks(values: number[], numClasses: number, palette?: Palette, reverse?: boolean): ClassBreak[];
555
+
556
+ /**
557
+ * Quantile Classification (equal count per class). Tied values cannot be split, so classes may hold
558
+ * unequal counts and duplicate boundaries collapse into fewer classes.
559
+ */
560
+ export declare function classifyQuantile(values: number[], numClasses: number, palette?: Palette, reverse?: boolean): ClassBreak[];
561
+
562
+ /**
563
+ * Categorical / Unique Values Classification. Values are compared by type (1 and "1" are different
564
+ * categories, matching how the map evaluates them) and sorted.
565
+ */
566
+ export declare function classifyUniqueValues(values: (string | number | boolean)[], palette?: Palette, reverse?: boolean): CategoryItem[];
567
+
568
+ /** Index of the class containing `value`, or -1 (non-numeric or outside all classes) */
569
+ export declare function classIndexForValue(breaks: ClassBreak[], value: unknown): number;
570
+
571
+ /** Number of decimals that keeps class boundaries readable and distinct */
572
+ export declare function classLabelPrecision(breaks: {
573
+ min: number;
574
+ max: number;
575
+ }[]): number;
576
+
577
+ export declare interface ClassPatch {
578
+ color?: string;
579
+ label?: string;
580
+ min?: number;
581
+ max?: number;
582
+ size?: number;
583
+ visible?: boolean;
584
+ /** Merged into the existing override; pass null to clear all overrides */
585
+ symbol?: ClassSymbolOverride | null;
586
+ }
587
+
588
+ /** Per-class overrides of the data-driven symbol properties */
589
+ export declare interface ClassSymbolOverride {
590
+ color?: string;
591
+ opacity?: number;
592
+ strokeColor?: string;
593
+ /** Polygon outline width or marker stroke width */
594
+ strokeWidth?: number;
595
+ /** Line width (line layers) or marker diameter (point layers) */
596
+ size?: number;
597
+ /** Hatch pattern for polygon classes; null forces no pattern */
598
+ pattern?: HatchPattern | null;
599
+ shape?: MarkerShape;
600
+ icon?: string;
601
+ rotationDeg?: number;
602
+ }
603
+
604
+ /**
605
+ * Check and convert one value for a field. Text is converted to the field type only when the meaning is
606
+ * unambiguous ("12" for a number field, "true"/"1" for a boolean); anything else is refused.
607
+ */
608
+ export declare function coerceFieldValue(field: FieldSchema, raw: unknown): CoerceResult;
609
+
610
+ export declare type CoerceResult = {
611
+ ok: true;
612
+ value: string | number | boolean | null;
613
+ } | {
614
+ ok: false;
615
+ error: string;
616
+ };
617
+
618
+ /** Convert one raw value (string from the command line, or JSON value) to the schema's type */
619
+ export declare function coerceValue(value: unknown, property: string, schema: any, issues: string[]): unknown;
620
+
621
+ /** Vertices this close to a result edge are the same line (floating-point noise only) */
622
+ export declare const COLLINEAR_RESTORE_METERS = 0.000001;
623
+
624
+ export declare interface ColorRampDefinition {
625
+ name: string;
626
+ type: ColorRampType;
627
+ source: 'colorbrewer' | 'carto' | 'matplotlib' | 'ofs';
628
+ colors: string[];
629
+ }
630
+
631
+ /** CSS linear-gradient preview of a ramp (for pickers) */
632
+ export declare function colorRampGradientCss(name: string, reverse?: boolean): string;
633
+
634
+ /**
635
+ * Cartographic Color Ramps & Color Utilities
636
+ *
637
+ * Named ramps from ColorBrewer (Cynthia Brewer, Penn State), CARTOColors (CARTO) and matplotlib
638
+ * (viridis family). Names are case-insensitive ("YlGn", "ylgn").
639
+ *
640
+ * - Sequential / diverging ramps are interpolated in Lab space to any class count.
641
+ * - Qualitative ramps are never interpolated (blending two category colors gives a misleading third
642
+ * color); their colors are used in order, and extra colors are generated deterministically.
643
+ */
644
+ export declare type ColorRampType = 'sequential' | 'diverging' | 'qualitative';
645
+
646
+ export declare interface CommandArgSpec {
647
+ /** Schema properties filled from the words before any --option, in order */
648
+ positional?: string[];
649
+ /**
650
+ * Property that collects every remaining word. A text property keeps the words exactly as they were
651
+ * typed (quotes and spacing included, e.g. an expression); an array property gets one entry per word.
652
+ */
653
+ rest?: string;
654
+ /** Extra option spellings: option name (without --) → property name */
655
+ aliases?: Record<string, string>;
656
+ /** Properties usable as `--flag` without a value (booleans are flags automatically) */
657
+ flags?: string[];
658
+ /** Options that stand for one fixed value, e.g. `--add` → mode "add", `--xy` → csvGeometry "xy" */
659
+ switches?: Record<string, {
660
+ property: string;
661
+ value: unknown;
662
+ }>;
663
+ /**
664
+ * Where a word goes when it does not fit a positional property that lists its values, e.g.
665
+ * `{ action: 'layerId' }`: "fields add …" is the action, "fields plots" is the layer.
666
+ */
667
+ fallback?: Record<string, string>;
668
+ }
669
+
670
+ export declare class CommandCancelledError extends OFSError {
671
+ constructor(message?: string);
672
+ }
673
+
674
+ export declare interface CommandEngineEvents {
675
+ 'workflow:start': {
676
+ context: OFSWorkflowContext;
677
+ };
678
+ 'workflow:step': {
679
+ context: OFSWorkflowContext;
680
+ commandName: string;
681
+ };
682
+ 'workflow:waiting': {
683
+ context: OFSWorkflowContext;
684
+ prompt: string;
685
+ };
686
+ 'workflow:completed': {
687
+ context: OFSWorkflowContext;
688
+ };
689
+ 'workflow:failed': {
690
+ context: OFSWorkflowContext;
691
+ error: Error;
692
+ };
693
+ 'workflow:cancelled': {
694
+ context: OFSWorkflowContext;
695
+ };
696
+ }
697
+
698
+ export declare interface CommandHistoryItem {
699
+ command: string;
700
+ status: 'success' | 'error';
701
+ durationMs: number;
702
+ errorMsg?: string;
703
+ resultSummary?: string;
704
+ }
705
+
706
+ /** Sort category values: numbers ascending, then booleans, then strings (natural, locale-aware) */
707
+ export declare function compareCategoryValues(a: string | number | boolean, b: string | number | boolean): number;
708
+
709
+ export declare interface CompiledExpression {
710
+ source: string;
711
+ /** Field names the expression reads */
712
+ fields: string[];
713
+ evaluate(feature: Feature<Geometry, any>, row?: number): ExpressionValue;
714
+ /** Evaluate as a filter: NULL and false are "no" */
715
+ test(feature: Feature<Geometry, any>, row?: number): boolean;
716
+ }
717
+
718
+ export declare interface CompiledGLLayer {
719
+ id: string;
720
+ role: GLLayerRole;
721
+ type: 'fill' | 'line' | 'circle' | 'symbol';
722
+ filter: any[];
723
+ paint: Record<string, any>;
724
+ layout: Record<string, any>;
725
+ /** Zoom range of the GL layer (labels only, so far) */
726
+ minzoom?: number;
727
+ maxzoom?: number;
728
+ }
729
+
730
+ export declare interface CompiledLayerStyle {
731
+ /** Paint of the main GL layer (kept for existing callers) */
732
+ paint: Record<string, any>;
733
+ layout?: Record<string, any>;
734
+ /** GL layers, bottom to top */
735
+ layers: CompiledGLLayer[];
736
+ /** Map images the layers reference (patterns, marker icons) */
737
+ images: SymbolImageRequest[];
738
+ }
739
+
740
+ /**
741
+ * Parse an expression once and reuse it for every feature.
742
+ * @param knownFields when given, unknown field names are an error instead of NULL
743
+ */
744
+ export declare function compileExpression(source: string, knownFields?: Iterable<string>): CompiledExpression;
745
+
746
+ /**
747
+ * Compile the label settings into a GL symbol layer. Expression labels read the text from the
748
+ * `_ofs_label` property the adapter fills in; field labels read the field directly.
749
+ */
750
+ export declare function compileLabelLayer(label: LabelSettings | undefined, layerId: string, kind: 'polygon' | 'line' | 'point', layerOpacity?: number): CompiledGLLayer | null;
751
+
752
+ /** Feature count per class (index -1 = matches no class), using the same rules the map renders with */
753
+ export declare function computeClassCounts(theme: ThematicDefinition, layer: OFSLayerData): Map<number, number>;
754
+
755
+ /**
756
+ * Everything a host application needs to render the transcript itself.
757
+ * The widget works without `mount()`: drive it with `submit()` and draw these events.
758
+ */
759
+ export declare interface ConsoleEventMap {
760
+ 'console:line': ConsoleLine;
761
+ 'console:cleared': void;
762
+ /** A command started or finished waiting for input; `promptText` is null when nothing is pending */
763
+ 'console:prompt': {
764
+ promptText: string | null;
765
+ };
766
+ }
767
+
768
+ /** Handles command-line text while no command is waiting for input (e.g. typed points while drawing) */
769
+ export declare type ConsoleInputInterceptor = (text: string) => {
770
+ handled: boolean;
771
+ message?: string;
772
+ error?: string;
773
+ };
774
+
775
+ export declare interface ConsoleInputRequest {
776
+ promptText: string;
777
+ type?: 'text' | 'coordinate' | 'number' | 'confirmation';
778
+ }
779
+
780
+ export declare interface ConsoleLine {
781
+ kind: ConsoleLineKind;
782
+ text: string;
783
+ time: number;
784
+ }
785
+
786
+ export declare type ConsoleLineKind = 'system' | 'input' | 'output' | 'prompt' | 'error' | 'success';
787
+
788
+ /**
789
+ * Source of map-picked points and cursor position for point prompts (implemented by OFSDrawTools)
790
+ */
791
+ export declare interface ConsolePointProvider {
792
+ beginPointPick(options: {
793
+ basePoint?: Coordinate | null;
794
+ }, onPick: (coord: Coordinate) => void): () => void;
795
+ getCursorCoordinate(): Coordinate | null;
796
+ readonly inputFrame: InputFrame;
797
+ }
798
+
799
+ export declare interface ConstrainedPoint {
800
+ coordinate: Coordinate;
801
+ /** Locked direction in the frame's convention, when a constraint applied */
802
+ lockedAngle: number | null;
803
+ mode: 'ortho' | 'polar' | null;
804
+ }
805
+
806
+ /**
807
+ * Apply ORTHO (always lock to UCS axes) or POLAR tracking (lock when near an increment) to a cursor
808
+ * position relative to `anchor`. The cursor is projected onto the locked direction.
809
+ */
810
+ export declare function constrainToAngle(anchor: Coordinate, cursor: Coordinate, options: {
811
+ ortho: boolean;
812
+ polar: PolarTrackingSettings;
813
+ frame: InputFrame;
814
+ }): ConstrainedPoint;
815
+
816
+ /**
817
+ * OFSObject Core Types
818
+ */
819
+ export declare type Coordinate = [number, number];
820
+
821
+ export declare type Coordinate3D = [number, number, number];
822
+
823
+ export declare interface CoordinateInputContext {
824
+ /** Last placed point / base point that relative input is measured from */
825
+ basePoint?: Coordinate | null;
826
+ /** Current cursor position, used for direct distance entry */
827
+ cursor?: Coordinate | null;
828
+ frame?: InputFrame;
829
+ }
830
+
831
+ export declare type CoordinateInputResult = {
832
+ kind: 'point';
833
+ coordinate: Coordinate;
834
+ description: string;
835
+ } | {
836
+ kind: 'error';
837
+ message: string;
838
+ };
839
+
840
+ /** Why a text is not a coordinate, naming the right order when the numbers were simply swapped */
841
+ export declare function coordinateProblem(raw: string): string;
842
+
843
+ export declare function createCadCommands(drawTools: OFSDrawTools, dataSource: OFSDataSource): OFSCommandProcess[];
844
+
845
+ export declare function createDrawCommands(drawTools: OFSDrawTools, dataSource: OFSDataSource): OFSCommandProcess[];
846
+
847
+ export declare function createIoCommands(dataSource: OFSDataSource, io: OFSFileIO, onImported?: (layerIds: string[]) => void): OFSCommandProcess[];
848
+
849
+ export declare function createMapCommands(mapAdapter: IMapAdapter, dataSource: OFSDataSource, legendTools: OFSLegendTools, registry: OFSCommandRegistry): OFSCommandProcess[];
850
+
851
+ export declare function createSpatialCommands(dataSource: OFSDataSource, drawTools: OFSDrawTools): OFSCommandProcess[];
852
+
853
+ export declare function createSymbologyCommands(dataSource: OFSDataSource, legendTools: OFSLegendTools): OFSCommandProcess[];
854
+
855
+ /**
856
+ * OGC WKT 1 with an explicit TOWGS84, for formats that store a CRS definition (GeoPackage). Only for the
857
+ * built-in Indian 1975 CRSs, whose EPSG codes alone make GDAL / QGIS choose their own datum transformation.
858
+ */
859
+ export declare function crsToOgcWkt(crs: ResolvedCrs): string;
860
+
861
+ /** WKT for .prj export (ESRI flavour for common CRSs) */
862
+ export declare function crsToPrj(crs: ResolvedCrs): string;
863
+
864
+ export declare interface DbfTable {
865
+ fields: (FieldDefinition & {
866
+ dbfType: string;
867
+ length: number;
868
+ decimals: number;
869
+ })[];
870
+ records: Record<string, any>[];
871
+ deleted: boolean[];
872
+ encoding: string;
873
+ }
874
+
875
+ export declare interface DbfWriteResult {
876
+ dbf: Uint8Array;
877
+ cpg: string;
878
+ fieldNames: Map<string, string>;
879
+ }
880
+
881
+ export declare function decodeEntities(text: string): string;
882
+
883
+ export declare function decodeRecord(payload: Uint8Array): SqlValue[];
884
+
885
+ /** Default tolerance for treating a vertex as lying on a straight edge (1 mm) */
886
+ export declare const DEFAULT_COLLINEAR_TOLERANCE_METERS = 0.001;
887
+
888
+ export declare const DEFAULT_DRAW_GUIDES: DrawGuideSettings;
889
+
890
+ export declare const DEFAULT_HATCH: HatchPattern;
891
+
892
+ export declare const DEFAULT_INPUT_FRAME: InputFrame;
893
+
894
+ export declare const DEFAULT_MAX_GRID_POINTS = 50000;
895
+
896
+ export declare const DEFAULT_MAX_NETWORK_POINTS = 5000;
897
+
898
+ export declare const DEFAULT_POLAR_TRACKING: PolarTrackingSettings;
899
+
900
+ export declare const DEFAULT_SYMBOL_COLOR = "#3b82f6";
901
+
902
+ export declare const DEFAULT_TOPOLOGY_OPTIONS: ResolvedTopologyOptions;
903
+
904
+ export declare function defaultSymbolStyle(color?: string): SymbolStyle;
905
+
906
+ /** All descendants with a local name (depth-first, document order) */
907
+ export declare function descendantsNamed(el: XmlElement, name: string, out?: XmlElement[]): XmlElement[];
908
+
909
+ /** Help lines for one command, built from its schema */
910
+ export declare function describeCommand(command: OFSCommandProcess): string[];
911
+
912
+ export declare function describeTheme(theme: ThematicDefinition, layer: OFSLayerData): string[];
913
+
914
+ /** Detect the encoding of character field bytes; returns null for pure ASCII */
915
+ export declare function detectTextEncoding(samples: Uint8Array[]): {
916
+ encoding: string;
917
+ confidence: 'ascii' | 'valid-utf8' | 'thai-bytes' | 'guess';
918
+ };
919
+
920
+ /** Fields found in the features, in the order they first appear (internal properties are left out) */
921
+ export declare function discoverFields(features: Feature<Geometry, any>[]): FieldSchema[];
922
+
923
+ export declare interface DistanceMeasure {
924
+ segments: SegmentMeasure[];
925
+ totalMeters: number;
926
+ /** Straight line from the first to the last point */
927
+ closingMeters: number;
928
+ }
929
+
930
+ /** Save an exported image in the browser */
931
+ export declare function downloadMapImage(image: MapImage): void;
932
+
933
+ export declare interface DrawEvents {
934
+ 'draw:mode-change': {
935
+ mode: DrawMode;
936
+ };
937
+ 'draw:start': {
938
+ mode: DrawMode;
939
+ coordinate: Coordinate;
940
+ };
941
+ 'draw:vertex-added': {
942
+ mode: DrawMode;
943
+ coordinate: Coordinate;
944
+ coordinates: Coordinate[];
945
+ };
946
+ 'draw:move': {
947
+ coordinate: Coordinate;
948
+ isSnapped: boolean;
949
+ snapResult?: SnapResult;
950
+ };
951
+ 'draw:complete': {
952
+ mode: DrawMode;
953
+ feature: Feature<Geometry, any>;
954
+ layerId: string;
955
+ };
956
+ 'draw:cancel': {
957
+ mode: DrawMode;
958
+ };
959
+ 'draw:ortho-change': {
960
+ enabled: boolean;
961
+ };
962
+ 'draw:measure': {
963
+ distanceMeters: number;
964
+ bearingDegrees: number;
965
+ /** Direction in the configured angle convention, relative to the UCS */
966
+ angle: number;
967
+ /** Active angle constraint, if any */
968
+ constraint: 'ortho' | 'polar' | 'tracking' | null;
969
+ coordinate: Coordinate;
970
+ };
971
+ 'draw:polar-change': {
972
+ enabled: boolean;
973
+ incrementDeg: number;
974
+ };
975
+ 'draw:ucs-change': {
976
+ ucsRotationDeg: number;
977
+ convention: AngleConvention;
978
+ };
979
+ 'draw:vertex-removed': {
980
+ mode: DrawMode;
981
+ coordinates: Coordinate[];
982
+ };
983
+ 'draw:tracking-points': {
984
+ points: Coordinate[];
985
+ };
986
+ 'draw:otrack-change': {
987
+ enabled: boolean;
988
+ };
989
+ 'selection:draw-complete': {
990
+ mode: 'select-box' | 'select-polygon';
991
+ selectionPolygon: Feature<Polygon>;
992
+ selectedFeatures: Feature<Geometry, any>[];
993
+ count: number;
994
+ };
995
+ 'selection:drag-progress': {
996
+ widthMeters: number;
997
+ heightMeters: number;
998
+ count: number;
999
+ coordinate: Coordinate;
1000
+ };
1001
+ }
1002
+
1003
+ /**
1004
+ * Transient drawing guides: the crosshair across the map and the measurements written on it.
1005
+ * These are never saved — for dimensions that stay with a feature see `3D-3` in ROADMAP.md.
1006
+ */
1007
+ export declare interface DrawGuideSettings {
1008
+ /** Dashed lines across the whole viewport through the anchor */
1009
+ crosshair: boolean;
1010
+ /** Length of the segment being dragged, written on the map */
1011
+ dimensions: boolean;
1012
+ /** Also measure the segments already drawn, not just the one under the cursor */
1013
+ segmentLabels: boolean;
1014
+ /** Area (and perimeter) of the polygon being drawn */
1015
+ areaLabel: boolean;
1016
+ /** What the crosshair follows: the cursor, like a CAD crosshair, or the last point clicked */
1017
+ anchor: 'cursor' | 'vertex';
1018
+ crosshairColor: string;
1019
+ crosshairWidth: number;
1020
+ /** Arc and degrees at each corner, always the angle of 180 degrees or less */
1021
+ angles: boolean;
1022
+ /** How far off the segment the dimension line sits, in screen pixels */
1023
+ dimensionOffsetPixels: number;
1024
+ /** Glyph names for the labels; the map style must provide them */
1025
+ font: string[];
1026
+ }
1027
+
1028
+ /** Minimal 2D context surface used by the drawing helpers (so they can be tested without a DOM) */
1029
+ export declare interface DrawingContext {
1030
+ save(): void;
1031
+ restore(): void;
1032
+ beginPath(): void;
1033
+ moveTo(x: number, y: number): void;
1034
+ lineTo(x: number, y: number): void;
1035
+ closePath(): void;
1036
+ fill(): void;
1037
+ stroke(): void;
1038
+ fillRect(x: number, y: number, w: number, h: number): void;
1039
+ strokeRect(x: number, y: number, w: number, h: number): void;
1040
+ fillText(text: string, x: number, y: number): void;
1041
+ translate(x: number, y: number): void;
1042
+ rotate(angle: number): void;
1043
+ fillStyle: string;
1044
+ strokeStyle: string;
1045
+ lineWidth: number;
1046
+ font: string;
1047
+ textAlign: string;
1048
+ textBaseline: string;
1049
+ }
1050
+
1051
+ export declare interface DrawInputResult {
1052
+ /** True if the text was consumed as drawing input */
1053
+ handled: boolean;
1054
+ message?: string;
1055
+ error?: string;
1056
+ }
1057
+
1058
+ export declare type DrawMode = 'point' | 'line' | 'polygon' | 'circle' | 'rectangle' | 'select' | 'select-box' | 'select-polygon' | 'modify' | null;
1059
+
1060
+ /**
1061
+ * Draw a north arrow centred at (x, y). `bearingDeg` is the map rotation (the map's bearing), so the
1062
+ * arrow turns the opposite way and keeps pointing at true north.
1063
+ */
1064
+ export declare function drawNorthArrow(ctx: DrawingContext, x: number, y: number, size?: number, bearingDeg?: number): void;
1065
+
1066
+ /** Draw a scale bar with its left end at (x, y) (y is the bottom of the bar) */
1067
+ export declare function drawScaleBar(ctx: DrawingContext, plan: ScaleBarPlan, x: number, y: number, style?: ScaleBarStyle): void;
1068
+
1069
+ export declare class DuplicateFeatureIdError extends OFSError {
1070
+ constructor(featureId: string | number, layerId?: string);
1071
+ }
1072
+
1073
+ export declare interface DxfLayerInput {
1074
+ name: string;
1075
+ features: Feature<Geometry, Record<string, any>>[];
1076
+ }
1077
+
1078
+ export declare interface DynamicInputState {
1079
+ distanceMeters?: number | null;
1080
+ angle?: number | null;
1081
+ convention?: 'bearing' | 'cad';
1082
+ constraint?: 'ortho' | 'polar' | 'tracking' | null;
1083
+ snapType?: SnapType | null;
1084
+ }
1085
+
1086
+ export declare function encodeRecord(values: SqlValue[]): Uint8Array;
1087
+
1088
+ /** TIS-620 encoder (Thai U+0E01..U+0E5B <-> 0xA1..0xFB); unsupported characters become '?' */
1089
+ export declare function encodeTis620(text: string): {
1090
+ bytes: Uint8Array;
1091
+ lossy: boolean;
1092
+ };
1093
+
1094
+ export declare function encodeVarint(input: number | bigint): number[];
1095
+
1096
+ /** Escape text for use in HTML content or attribute values */
1097
+ export declare function escapeHtml(value: unknown): string;
1098
+
1099
+ export declare function escapeXml(text: string): string;
1100
+
1101
+ /**
1102
+ * Euclidean distance in 2D coordinate space.
1103
+ */
1104
+ export declare function euclideanDistance(p1: [number, number], p2: [number, number]): number;
1105
+
1106
+ /** Evaluate an expression for one feature (parses every time; use compileExpression for many features) */
1107
+ export declare function evaluateExpression(source: string, feature: Feature<Geometry, any>, knownFields?: Iterable<string>): ExpressionValue;
1108
+
1109
+ /**
1110
+ * Framework-agnostic Typed Event Emitter
1111
+ */
1112
+ export declare type EventHandler<T = any> = (data: T) => void;
1113
+
1114
+ /** Expand a lng/lat bbox by a distance in meters */
1115
+ export declare function expandBBox(bbox: [number, number, number, number], meters: number): [number, number, number, number];
1116
+
1117
+ export declare const EXPORT_FORMATS: ExportFormat[];
1118
+
1119
+ export declare function exportCsv(features: Feature<Geometry, Record<string, any>>[], options?: ExportOptions, issues?: ImportIssue[]): ExportedFile;
1120
+
1121
+ export declare function exportDxf(layers: DxfLayerInput[], options?: ExportOptions, issues?: ImportIssue[]): ExportedFile & {
1122
+ crs: ResolvedCrs;
1123
+ };
1124
+
1125
+ export declare interface ExportedFile {
1126
+ filename: string;
1127
+ mimeType: string;
1128
+ data: Uint8Array | string;
1129
+ }
1130
+
1131
+ export declare type ExportFormat = 'geojson' | 'shapefile' | 'gpkg' | 'kml' | 'kmz' | 'csv' | 'dxf';
1132
+
1133
+ export declare function exportGeoJSON(features: Feature<Geometry, any>[], options?: ExportOptions): ExportedFile;
1134
+
1135
+ export declare function exportGeoPackage(layers: GeoPackageLayerInput[], options?: ExportOptions, issues?: ImportIssue[]): ExportedFile;
1136
+
1137
+ export declare function exportKml(features: Feature<Geometry, Record<string, any>>[], options?: ExportOptions): ExportedFile;
1138
+
1139
+ export declare function exportKmlText(features: Feature<Geometry, Record<string, any>>[], options?: ExportOptions): string;
1140
+
1141
+ export declare function exportKmz(features: Feature<Geometry, Record<string, any>>[], options?: ExportOptions): ExportedFile;
1142
+
1143
+ /**
1144
+ * Render the current map view into an image. Browser only (needs a canvas).
1145
+ */
1146
+ export declare function exportMapImage(adapter: IMapAdapter, options?: MapExportOptions): MapImage;
1147
+
1148
+ export declare interface ExportOptions {
1149
+ /** Target CRS (default EPSG:4326; DXF defaults to the WGS 84 UTM zone of the data) */
1150
+ crs?: string;
1151
+ /** DBF / CSV text encoding: 'utf-8' (default) or 'tis-620' */
1152
+ encoding?: string;
1153
+ /** Decimal places for coordinates (default 8 for degrees, 3 for meters) */
1154
+ precision?: number;
1155
+ /** File name without extension */
1156
+ name?: string;
1157
+ /** CSV: 'wkt' column (default) or 'xy' columns (points only) */
1158
+ csvGeometry?: 'wkt' | 'xy';
1159
+ }
1160
+
1161
+ /** Zipped shapefile(s): one shapefile per geometry kind present */
1162
+ export declare function exportShapefileZip(features: Feature<Geometry, Record<string, any>>[], fields: FieldDefinition[], options?: ExportOptions, issues?: ImportIssue[]): ExportedFile;
1163
+
1164
+ export declare const EXPRESSION_FUNCTIONS: Record<string, FunctionSpec>;
1165
+
1166
+ export declare interface ExpressionContext {
1167
+ feature: Feature<Geometry, any>;
1168
+ /** 0-based position in the current result set (for $row) */
1169
+ row?: number;
1170
+ }
1171
+
1172
+ export declare class ExpressionError extends Error {
1173
+ readonly position?: number | undefined;
1174
+ constructor(message: string, position?: number | undefined);
1175
+ }
1176
+
1177
+ export declare type ExpressionValue = string | number | boolean | null;
1178
+
1179
+ export declare class FeatureNotFoundError extends OFSError {
1180
+ constructor(featureId: string | number, layerId?: string);
1181
+ }
1182
+
1183
+ declare type FeatureSource = OFSLayerData | Feature<Geometry, any>[];
1184
+
1185
+ export declare type FeatureState = {
1186
+ hover?: boolean;
1187
+ selected?: boolean;
1188
+ active?: boolean;
1189
+ disabled?: boolean;
1190
+ [key: string]: unknown;
1191
+ };
1192
+
1193
+ export declare interface FieldDefinition {
1194
+ name: string;
1195
+ type: 'string' | 'number' | 'boolean' | 'date';
1196
+ /** Original name when it had to be changed (e.g. DBF 10-character limit) */
1197
+ sourceName?: string;
1198
+ }
1199
+
1200
+ export declare interface FieldSchema {
1201
+ name: string;
1202
+ type: FieldType;
1203
+ /** Original name in the source file when it had to be changed (DBF 10-character limit) */
1204
+ sourceName?: string;
1205
+ /** Label shown instead of the name */
1206
+ alias?: string;
1207
+ /** Value used for new features and for a new field */
1208
+ defaultValue?: string | number | boolean | null;
1209
+ /** Only these values are accepted (pick list) */
1210
+ allowedValues?: (string | number | boolean)[];
1211
+ /** NULL / empty is refused */
1212
+ required?: boolean;
1213
+ /** Decimals shown in the table (display only, values keep their precision) */
1214
+ precision?: number;
1215
+ /** Maximum text length */
1216
+ length?: number;
1217
+ min?: number;
1218
+ max?: number;
1219
+ /** The table refuses to edit this field */
1220
+ readOnly?: boolean;
1221
+ }
1222
+
1223
+ export declare interface FieldStatistics {
1224
+ field: string;
1225
+ type: FieldSchema['type'];
1226
+ count: number;
1227
+ nullCount: number;
1228
+ min?: number | string;
1229
+ max?: number | string;
1230
+ sum?: number;
1231
+ mean?: number;
1232
+ median?: number;
1233
+ stdDev?: number;
1234
+ distinct?: number;
1235
+ topValues?: {
1236
+ value: string;
1237
+ count: number;
1238
+ }[];
1239
+ }
1240
+
1241
+ export declare type FieldType = 'string' | 'number' | 'boolean' | 'date';
1242
+
1243
+ /** Merge a gap polygon into a neighbouring polygon */
1244
+ export declare function fillGap(receiver: Polygon | MultiPolygon, gap: Polygon, neighbours?: Geometry[]): Polygon | MultiPolygon;
1245
+
1246
+ export declare interface FillSymbol {
1247
+ color: string;
1248
+ opacity: number;
1249
+ /** 'solid' fills with color, 'pattern' draws the hatch (over color when patternBackground), 'none' = outline only */
1250
+ style: 'solid' | 'pattern' | 'none';
1251
+ pattern?: HatchPattern;
1252
+ /** With style 'pattern', also paint `color` behind the hatch */
1253
+ patternBackground?: boolean;
1254
+ outlineColor: string;
1255
+ outlineWidth: number;
1256
+ outlineOpacity: number;
1257
+ /** Outline dash pattern in pixels (layer-wide) */
1258
+ outlineDash?: number[];
1259
+ /** Screen offset [x, y] in pixels (layer-wide) */
1260
+ offset?: [number, number];
1261
+ }
1262
+
1263
+ export declare function findField(fields: FieldSchema[], name: string): FieldSchema | undefined;
1264
+
1265
+ /**
1266
+ * Find the first feature (in any layer) that intersects `target`, uses the layer R-tree index
1267
+ * to test only features whose bounding boxes overlap the target.
1268
+ */
1269
+ export declare function findIntersectingFeature(dataSource: OFSDataSource, target: Feature<Geometry>, accept: (feature: Feature<Geometry, any>) => boolean): {
1270
+ layerId: string;
1271
+ feature: Feature<Geometry, any>;
1272
+ } | null;
1273
+
1274
+ export declare function forEachPosition(geometry: Geometry, fn: (c: Position) => void): void;
1275
+
1276
+ /** Degrees as "45°30'20"" (bearing) or "45.5056°" */
1277
+ export declare function formatAngle(degrees: number, convention?: AngleConvention | 'decimal'): string;
1278
+
1279
+ /** "4,000.00 m² · 2.50 rai · 2-2-0.0 (rai-ngan-wa)" */
1280
+ export declare function formatArea(areaSqm: number, decimals?: number): string;
1281
+
1282
+ export declare function formatClassLabel(min: number, max: number, precision: number): string;
1283
+
1284
+ /**
1285
+ * Build the command line text for an argument object, so an AI tool call runs through exactly the same
1286
+ * path as typed input. Commands without an `args` spec get their arguments as JSON.
1287
+ */
1288
+ export declare function formatCommandArgs(command: OFSCommandProcess, args: Record<string, unknown>): string;
1289
+
1290
+ /**
1291
+ * Format a coordinate for display, in the same lng,lat order the library reads,
1292
+ * so a coordinate shown on screen can be typed straight back into a command.
1293
+ */
1294
+ export declare function formatCoordinate(coord: Coordinate, precision?: number): string;
1295
+
1296
+ /** Text shown in the HUD for a measurement state (pure, for reuse and testing) */
1297
+ export declare function formatDynamicInputLabel(state: DynamicInputState): string;
1298
+
1299
+ /** Value as shown in the attribute table (precision applies to display only) */
1300
+ export declare function formatFieldValue(field: FieldSchema | undefined, value: unknown): string;
1301
+
1302
+ /** "123.456 m" / "1.235 km" */
1303
+ export declare function formatLength(meters: number, decimals?: number): string;
1304
+
1305
+ /** Thai land measure: "rai-ngan-wa" (1 rai = 4 ngan = 400 square wa) */
1306
+ export declare function formatRaiNganWa(areaSqm: number, decimals?: number): string;
1307
+
1308
+ declare interface FunctionSpec {
1309
+ minArgs: number;
1310
+ maxArgs: number;
1311
+ /** Short description for help output / UI */
1312
+ help: string;
1313
+ call: (args: ExpressionValue[], ctx: ExpressionContext) => ExpressionValue;
1314
+ }
1315
+
1316
+ export declare function generateAiToolDeclarations(registry: OFSCommandRegistry): AiToolDeclaration[];
1317
+
1318
+ /**
1319
+ * Generate smooth Bezier curve through given control points.
1320
+ */
1321
+ export declare function generateBezierCurve(points: Coordinate[], segments?: number): Coordinate[];
1322
+
1323
+ /**
1324
+ * Generate `count` colors from a ramp name or explicit color list.
1325
+ * @param reverse Reverse the ramp direction (e.g. dark-to-light)
1326
+ */
1327
+ export declare function generateColors(palette: PaletteName | string | string[], count: number, reverse?: boolean): string[];
1328
+
1329
+ /** Generate a feature ID that is unique across the session */
1330
+ export declare function generateFeatureId(): string;
1331
+
1332
+ export declare function geometryBBox(geometry: Geometry): [number, number, number, number];
1333
+
1334
+ /** Convert a geometry from WGS84 lng/lat to `crs` */
1335
+ export declare function geometryFromWgs84<G extends Geometry>(geometry: G, crs: ResolvedCrs): G;
1336
+
1337
+ export declare function geometryKind(type: string): ImportGeometryKind | null;
1338
+
1339
+ /** Convert a geometry from `crs` to WGS84 lng/lat */
1340
+ export declare function geometryToWgs84<G extends Geometry>(geometry: G, crs: ResolvedCrs): G;
1341
+
1342
+ export declare type GeometryType = 'Point' | 'MultiPoint' | 'LineString' | 'MultiLineString' | 'Polygon' | 'MultiPolygon' | 'GeometryCollection';
1343
+
1344
+ export declare interface GeoPackageLayerInput {
1345
+ name: string;
1346
+ features: Feature<Geometry, Record<string, any>>[];
1347
+ fields?: FieldDefinition[];
1348
+ }
1349
+
1350
+ /** Look up a ramp by name (case-insensitive) */
1351
+ export declare function getColorRamp(name: string): ColorRampDefinition | undefined;
1352
+
1353
+ /**
1354
+ * Complete schema of a layer: the stored schema first, then fields that only exist in the data.
1355
+ */
1356
+ export declare function getLayerSchema(layer: LayerLike): FieldSchema[];
1357
+
1358
+ export declare function getMarkerIcon(name: string): MarkerIconDefinition | undefined;
1359
+
1360
+ declare interface GLLayerRecord {
1361
+ id: string;
1362
+ type: string;
1363
+ filter: string;
1364
+ paint: Record<string, string>;
1365
+ layout: Record<string, string>;
1366
+ minzoom?: number;
1367
+ maxzoom?: number;
1368
+ }
1369
+
1370
+ export declare type GLLayerRole = 'fill' | 'pattern' | 'stroke' | 'line' | 'circle' | 'marker' | 'label';
1371
+
1372
+ export declare type GraduatedMode = 'color' | 'size';
1373
+
1374
+ export declare interface GraduatedThemeOptions {
1375
+ reverse?: boolean;
1376
+ mode?: GraduatedMode;
1377
+ sizeRange?: [number, number];
1378
+ baseSymbol?: SymbolStyleInput;
1379
+ }
1380
+
1381
+ export declare interface GridOptions {
1382
+ /** Distance between neighbouring points in meters */
1383
+ spacingMeters: number;
1384
+ /** Row spacing when it differs from the column spacing (square pattern only) */
1385
+ rowSpacingMeters?: number;
1386
+ pattern?: GridPattern;
1387
+ /** Turn the grid this many degrees counter-clockwise from east */
1388
+ rotateDegrees?: number;
1389
+ /** Keep points at least this far inside the boundary */
1390
+ insetMeters?: number;
1391
+ /** Refuse rather than build a layout this large (default 50,000) */
1392
+ maxPoints?: number;
1393
+ }
1394
+
1395
+ export declare type GridPattern = 'square' | 'triangular';
1396
+
1397
+ /**
1398
+ * Fill `boundary` with points `spacingMeters` apart.
1399
+ *
1400
+ * @param boundary One or more polygons in lng/lat; a point is kept when it falls inside any of them
1401
+ */
1402
+ export declare function gridPoints(boundary: (Polygon | MultiPolygon)[], options: GridOptions): GridResult;
1403
+
1404
+ export declare interface GridResult {
1405
+ points: Coordinate[];
1406
+ /** Points the pattern produced before the boundary was applied */
1407
+ candidates: number;
1408
+ pattern: GridPattern;
1409
+ spacingMeters: number;
1410
+ rowSpacingMeters: number;
1411
+ }
1412
+
1413
+ export declare class GridTooLargeError extends OFSError {
1414
+ constructor(count: number, max: number, spacingMeters: number);
1415
+ }
1416
+
1417
+ export declare interface GripHandle {
1418
+ id: string;
1419
+ coordinate: Coordinate;
1420
+ type: 'vertex' | 'midpoint' | 'center';
1421
+ index: number;
1422
+ ringIndex: number;
1423
+ partIndex?: number;
1424
+ }
1425
+
1426
+ export declare interface GripsEditorEvents {
1427
+ 'grip:select': {
1428
+ handle: GripHandle;
1429
+ };
1430
+ 'grip:move': {
1431
+ handle: GripHandle;
1432
+ coordinate: Coordinate;
1433
+ };
1434
+ 'grip:commit': {
1435
+ featureId: string | number;
1436
+ layerId: string;
1437
+ };
1438
+ 'grip:delete-vertex': {
1439
+ featureId: string | number;
1440
+ index: number;
1441
+ };
1442
+ 'grip:clear': void;
1443
+ }
1444
+
1445
+ /** Stable short hash for image ids */
1446
+ export declare function hashString(text: string): string;
1447
+
1448
+ /** True for CRSs whose datum shift is project-specific (EPSG code alone is ambiguous in other software) */
1449
+ export declare function hasProjectDatumShift(crs: ResolvedCrs): boolean;
1450
+
1451
+ export declare function hatchImageId(pattern: HatchPattern): string;
1452
+
1453
+ /** Hatch fill pattern, rasterized into a seamless map image */
1454
+ export declare interface HatchPattern {
1455
+ kind: 'lines' | 'cross' | 'dots';
1456
+ color: string;
1457
+ /** Distance between lines / dots in pixels */
1458
+ spacing: number;
1459
+ /** Line angle in degrees counter-clockwise from horizontal (0 = "—", 45 = "/", 90 = "|"), as in QGIS */
1460
+ angleDeg: number;
1461
+ /** Line width, or dot diameter, in pixels */
1462
+ lineWidth: number;
1463
+ /** Optional dash pattern along the hatch lines, in pixels */
1464
+ dash?: number[];
1465
+ }
1466
+
1467
+ export declare interface HatchTilePlan {
1468
+ /** Tile side in device pixels */
1469
+ size: number;
1470
+ pixelRatio: number;
1471
+ color: string;
1472
+ /** Line width / dot diameter in device pixels */
1473
+ lineWidth: number;
1474
+ /** Segments [x1, y1, x2, y2] in device pixels (may extend past the tile; clip when drawing) */
1475
+ segments: [number, number, number, number][];
1476
+ /** Dot centers in device pixels (including wrapped copies near the edges) */
1477
+ dots: [number, number][];
1478
+ /** Dash pattern in device pixels; each segment starts at a dash period boundary */
1479
+ dash: number[] | null;
1480
+ effectiveAngleDeg: number;
1481
+ effectiveSpacing: number;
1482
+ }
1483
+
1484
+ /**
1485
+ * Calculate distance between two coordinates in meters (Haversine formula).
1486
+ */
1487
+ export declare function haversineDistance(c1: Coordinate, c2: Coordinate): number;
1488
+
1489
+ export declare interface IMapAdapter {
1490
+ readonly engineName: 'maplibre' | 'mapbox';
1491
+ readonly isReady: boolean;
1492
+ /** Create the map engine in a DOM container */
1493
+ init(container: HTMLElement | string, options?: Record<string, any>): Promise<void>;
1494
+ /**
1495
+ * Use a map the host application created and still owns. Resolves once its style is ready;
1496
+ * `destroy()` then removes only what OFSObject added and leaves the map running.
1497
+ */
1498
+ attach(map: unknown): Promise<void>;
1499
+ /** Bind to central data source and thematic engine */
1500
+ bindDataSource(dataSource: OFSDataSource, thematicEngine?: OFSThematicEngine): void;
1501
+ /** Viewport methods */
1502
+ fitBounds(bbox: BoundingBox, padding?: number): void;
1503
+ flyTo(options: MapViewportOptions): void;
1504
+ getCenter(): Coordinate;
1505
+ setCenter(coord: Coordinate): void;
1506
+ getZoom(): number;
1507
+ setZoom(zoom: number): void;
1508
+ getBounds(): BoundingBox;
1509
+ /** Source & Layer syncing */
1510
+ syncLayer(layer: OFSLayerData): void;
1511
+ removeLayer(layerId: string): void;
1512
+ setLayerVisibility(layerId: string, visible: boolean): void;
1513
+ setLayerOpacity(layerId: string, opacity: number): void;
1514
+ setLayerZIndex(layerId: string, zIndex: number): void;
1515
+ /** Feature state (hover / selected) */
1516
+ setFeatureState(layerId: string, featureId: string | number, state: Record<string, any>): void;
1517
+ getFeatureState(layerId: string, featureId: string | number): Record<string, any>;
1518
+ /** Event listeners */
1519
+ onMapClick(handler: (e: MapClickEvent) => void): () => void;
1520
+ onMapDblClick(handler: (e: MapClickEvent) => void): () => void;
1521
+ onContextMenu(handler: (e: MapClickEvent) => void): () => void;
1522
+ onMouseMove(handler: (e: MapClickEvent) => void): () => void;
1523
+ onMouseDown(handler: (e: MapClickEvent) => void): () => void;
1524
+ onMouseUp(handler: (e: MapClickEvent) => void): () => void;
1525
+ setDoubleClickZoom(enabled: boolean): void;
1526
+ /** Raw map engine access */
1527
+ getRawMap<T = any>(): T;
1528
+ /** Cleanup */
1529
+ destroy(): void;
1530
+ }
1531
+
1532
+ export declare const IMPORT_EXTENSIONS: string[];
1533
+
1534
+ export declare function importCsv(file: InputFile, options?: ImportOptions): ImportResult;
1535
+
1536
+ export declare function importDxf(file: InputFile, options?: ImportOptions): ImportResult;
1537
+
1538
+ export declare interface ImportedLayer {
1539
+ name: string;
1540
+ kind: ImportGeometryKind;
1541
+ /** Features in WGS84 lng/lat */
1542
+ features: Feature<Geometry, Record<string, any>>[];
1543
+ fields: FieldDefinition[];
1544
+ /** CRS the source coordinates were in */
1545
+ sourceCrs: string;
1546
+ sourceFile?: string;
1547
+ }
1548
+
1549
+ /** Parse files into layers (no data source changes) */
1550
+ export declare function importFiles(files: InputFile[], options?: ImportOptions): ImportResult;
1551
+
1552
+ export declare function importGeoJSON(file: InputFile, options?: ImportOptions): ImportResult;
1553
+
1554
+ export declare type ImportGeometryKind = 'point' | 'line' | 'polygon';
1555
+
1556
+ export declare function importGeoPackage(file: InputFile, options?: ImportOptions & {
1557
+ wal?: InputFile['data'];
1558
+ }): ImportResult;
1559
+
1560
+ export declare interface ImportIssue {
1561
+ severity: 'error' | 'warning';
1562
+ code: string;
1563
+ message: string;
1564
+ /** Source file name */
1565
+ file?: string;
1566
+ /** Index of the feature / record in the source file */
1567
+ featureIndex?: number;
1568
+ }
1569
+
1570
+ export declare function importKml(file: InputFile, options?: ImportOptions): ImportResult;
1571
+
1572
+ export declare function importKmlText(text: string, fileName: string, options?: ImportOptions): ImportResult;
1573
+
1574
+ export declare function importKmz(file: InputFile, options?: ImportOptions): ImportResult;
1575
+
1576
+ export declare interface ImportOptions {
1577
+ /** Source CRS when the file has none (CSV, DXF, GeoJSON without crs, shapefile without .prj) */
1578
+ sourceCrs?: string;
1579
+ /** Text encoding for DBF / CSV when it cannot be detected ('utf-8', 'windows-874' / 'tis-620', 'windows-1252') */
1580
+ encoding?: string;
1581
+ /** Close polygon rings that are not closed (reported as warnings). Default false: such features are rejected. */
1582
+ closeRings?: boolean;
1583
+ /** Curves (DXF arcs, bulges, circles): maximum angle per generated segment in degrees. Default 5. */
1584
+ arcSegmentDegrees?: number;
1585
+ /** CSV: column names holding coordinates or WKT (auto-detected when omitted) */
1586
+ csv?: {
1587
+ x?: string;
1588
+ y?: string;
1589
+ wkt?: string;
1590
+ delimiter?: string;
1591
+ };
1592
+ /** DXF: import closed polylines as polygons (default true) */
1593
+ dxfClosedAsPolygons?: boolean;
1594
+ }
1595
+
1596
+ export declare interface ImportResult {
1597
+ layers: ImportedLayer[];
1598
+ issues: ImportIssue[];
1599
+ }
1600
+
1601
+ export declare function importShapefileParts(parts: ShapefileParts, options?: ImportOptions): ImportResult;
1602
+
1603
+ /** Import one or more shapefiles from a .zip, or from loose .shp/.dbf/.prj/.cpg files */
1604
+ export declare function importShapefiles(files: InputFile[], options?: ImportOptions): ImportResult;
1605
+
1606
+ export declare interface ImportToDataSourceResult {
1607
+ layers: AddedLayer[];
1608
+ issues: ImportIssue[];
1609
+ }
1610
+
1611
+ /**
1612
+ * Indian 1975 -> WGS 84 three-parameter shift used by the project (Thailand):
1613
+ * WGS 84 -> Indian 1975 is ΔX = -204.4798, ΔY = -837.8940, ΔZ = -294.7765 m, so the proj4 +towgs84
1614
+ * (source datum -> WGS 84) values are the same numbers with the opposite sign. EPSG:1812 (204.64, 834.74,
1615
+ * 293.8) differs by about 0.5 m. Override with setDatumShift('indian_1975', ...) if another survey uses other values.
1616
+ */
1617
+ export declare const INDIAN_1975_TOWGS84 = "204.4798,837.894,294.7765,0,0,0,0";
1618
+
1619
+ /** Field type that fits every value (text wins over everything, number over date/boolean mixes) */
1620
+ export declare function inferFieldType(values: unknown[]): FieldType;
1621
+
1622
+ /** A file given to the importer: name + content */
1623
+ export declare interface InputFile {
1624
+ name: string;
1625
+ data: ArrayBuffer | Uint8Array | string;
1626
+ }
1627
+
1628
+ export declare interface InputFrame {
1629
+ convention: AngleConvention;
1630
+ /** Counter-clockwise rotation of the UCS X axis from true East, in degrees */
1631
+ ucsRotationDeg: number;
1632
+ }
1633
+
1634
+ /** Point strictly usable as a label / zoom target inside a polygon (falls back to the first vertex) */
1635
+ export declare function interiorPoint(geometry: Polygon | MultiPolygon): Coordinate;
1636
+
1637
+ /** Properties starting with this prefix belong to the library, not to the user's data */
1638
+ export declare const INTERNAL_PROPERTY_PREFIX = "_ofs_";
1639
+
1640
+ export declare class InvalidCoordinateError extends OFSError {
1641
+ constructor(raw: string);
1642
+ }
1643
+
1644
+ export declare class InvalidGeometryError extends OFSError {
1645
+ constructor(message?: string);
1646
+ }
1647
+
1648
+ export declare type IOFormat = 'geojson' | 'shapefile' | 'gpkg' | 'kml' | 'kmz' | 'csv' | 'dxf';
1649
+
1650
+ export declare interface IOFSConsole {
1651
+ print(text: string, kind?: 'system' | 'input' | 'output' | 'prompt' | 'error' | 'success'): void;
1652
+ clear(): void;
1653
+ requestInput(promptText: string): Promise<string>;
1654
+ /**
1655
+ * Ask for a point: typed lng,lat / @dx,dy / @distance<angle / distance, or a map click when the
1656
+ * console is connected to a point provider. `basePoint` enables relative input and a preview line.
1657
+ * Resolves null when the user presses Enter without input.
1658
+ */
1659
+ requestPoint(promptText: string, options?: {
1660
+ basePoint?: Coordinate | null;
1661
+ }): Promise<Coordinate | null>;
1662
+ /**
1663
+ * Ask for either a map-picked point or free text (e.g. "angle or [Reference]").
1664
+ * Optional: when missing, commands fall back to requestInput (text only).
1665
+ */
1666
+ requestPointOrText?(promptText: string, options?: {
1667
+ basePoint?: Coordinate | null;
1668
+ }): Promise<{
1669
+ point: Coordinate;
1670
+ } | {
1671
+ text: string;
1672
+ }>;
1673
+ cancel(): void;
1674
+ isWaitingInput(): boolean;
1675
+ }
1676
+
1677
+ export declare function isDateText(value: string): boolean;
1678
+
1679
+ /** True when `source` is inline SVG markup rather than a URL */
1680
+ export declare function isInlineSvg(source: string): boolean;
1681
+
1682
+ export declare function isInternalProperty(name: string): boolean;
1683
+
1684
+ export declare function isTruthy(value: ExpressionValue): boolean;
1685
+
1686
+ /**
1687
+ * Validates longitude and latitude ranges.
1688
+ */
1689
+ export declare function isValidLngLat(lng: number, lat: number): boolean;
1690
+
1691
+ /** Property that carries a pre-computed label text (expression labels) into the map source */
1692
+ export declare const LABEL_PROPERTY = "_ofs_label";
1693
+
1694
+ export declare function labelIsActive(label: LabelSettings | undefined): boolean;
1695
+
1696
+ /** True when the labels need text computed in the library (expression) instead of a plain field */
1697
+ export declare function labelNeedsComputedText(label: LabelSettings | undefined): boolean;
1698
+
1699
+ /**
1700
+ * Labels drawn from a field or an attribute expression (QGIS "Labels" tab).
1701
+ * Text is placed by the map engine, which hides labels that would overlap unless `allowOverlap` is set.
1702
+ */
1703
+ export declare interface LabelSettings {
1704
+ /** Draw the labels (default true when a field or expression is given) */
1705
+ enabled?: boolean;
1706
+ /** Field whose value is the label */
1707
+ field?: string;
1708
+ /**
1709
+ * Attribute expression (`lib/attributes/expression.ts`), e.g. `concat(owner, ' ', rai_ngan_wa())`.
1710
+ * The text is computed per feature before it reaches the map, so geometry values ($area, $length) work.
1711
+ */
1712
+ expression?: string;
1713
+ /** Decimals for a numeric field (display only) */
1714
+ decimals?: number;
1715
+ /** Font stack of the basemap style, e.g. ['Noto Sans Regular']; omitted = the style's default font */
1716
+ font?: string[];
1717
+ /** Text size in pixels (default 12) */
1718
+ size?: number;
1719
+ color?: string;
1720
+ haloColor?: string;
1721
+ haloWidth?: number;
1722
+ opacity?: number;
1723
+ /** Offset in ems (text size), [right, down] */
1724
+ offset?: [number, number];
1725
+ anchor?: MarkerAnchor;
1726
+ /** Point placement (default) or along the line */
1727
+ placement?: 'point' | 'line';
1728
+ /** Draw even when labels overlap (default false: the engine drops colliding labels) */
1729
+ allowOverlap?: boolean;
1730
+ /** Line break width in ems (default 10) */
1731
+ maxWidth?: number;
1732
+ /** Rotation in degrees, clockwise */
1733
+ rotationDeg?: number;
1734
+ transform?: 'none' | 'uppercase' | 'lowercase';
1735
+ /** Zoom range in which labels are drawn */
1736
+ minZoom?: number;
1737
+ maxZoom?: number;
1738
+ /** Features with a higher priority keep their label when labels collide */
1739
+ priorityField?: string;
1740
+ }
1741
+
1742
+ /** Expression labels: the text is computed here and sent as a feature property */
1743
+ declare interface LabelSource {
1744
+ source: string;
1745
+ compiled: CompiledExpression | null;
1746
+ }
1747
+
1748
+ export declare interface LandAreaMeasure {
1749
+ areaSqm: number;
1750
+ perimeterMeters: number;
1751
+ rai: number;
1752
+ ngan: number;
1753
+ squareWa: number;
1754
+ /** "3-2-45.5" (rai-ngan-square wa) */
1755
+ raiNganWa: string;
1756
+ }
1757
+
1758
+ export declare type LayerGeometryType = 'point' | 'line' | 'polygon' | 'circle' | 'symbol';
1759
+
1760
+ /** Legend group of layers; groups can be nested */
1761
+ export declare interface LayerGroup {
1762
+ id: string;
1763
+ name: string;
1764
+ parentId: string | null;
1765
+ visible: boolean;
1766
+ expanded: boolean;
1767
+ }
1768
+
1769
+ declare interface LayerLike {
1770
+ fields?: FieldSchema[];
1771
+ getFeatures(): Feature<Geometry, any>[];
1772
+ }
1773
+
1774
+ export declare interface LayerMetadata {
1775
+ id: string;
1776
+ name: string;
1777
+ type: LayerGeometryType;
1778
+ zIndex?: number;
1779
+ visible?: boolean;
1780
+ opacity?: number;
1781
+ pinned?: boolean;
1782
+ tag?: string;
1783
+ /** Layer group (see OFSDataSource.addLayerGroup) */
1784
+ groupId?: string;
1785
+ /** CRS of the file the layer was imported from (data is always stored as WGS84) */
1786
+ sourceCrs?: string;
1787
+ sourceFile?: string;
1788
+ /** Attribute schema in source order (kept for export; edited through OFSAttributeTools) */
1789
+ fields?: FieldSchema[];
1790
+ [key: string]: unknown;
1791
+ }
1792
+
1793
+ export declare class LayerNotFoundError extends OFSError {
1794
+ constructor(layerId: string);
1795
+ }
1796
+
1797
+ export declare interface LegendEvents {
1798
+ 'legend:updated': {
1799
+ snapshot: LegendSnapshot;
1800
+ };
1801
+ }
1802
+
1803
+ export declare interface LegendGroupViewModel {
1804
+ id: string;
1805
+ name: string;
1806
+ parentId: string | null;
1807
+ visible: boolean;
1808
+ rendered: boolean;
1809
+ expanded: boolean;
1810
+ }
1811
+
1812
+ export declare interface LegendLayerViewModel {
1813
+ id: string;
1814
+ name: string;
1815
+ type: LayerGeometryType;
1816
+ visible: boolean;
1817
+ /** Visible and all parent groups visible */
1818
+ rendered: boolean;
1819
+ opacity: number;
1820
+ zIndex: number;
1821
+ pinned: boolean;
1822
+ groupId: string | null;
1823
+ featureCount: number;
1824
+ thematicType: ThematicType;
1825
+ fieldName?: string;
1826
+ classificationMethod?: ClassificationMethod;
1827
+ graduatedMode?: GraduatedMode;
1828
+ paletteName?: string;
1829
+ items: LegendSwatchItem[];
1830
+ }
1831
+
1832
+ export declare interface LegendSnapshot {
1833
+ /** All layers, top-most first */
1834
+ layers: LegendLayerViewModel[];
1835
+ /** Layers and groups as a tree, top-most first */
1836
+ tree: LegendTreeNode[];
1837
+ groups: LegendGroupViewModel[];
1838
+ activeLayerId: string | null;
1839
+ totalLayers: number;
1840
+ }
1841
+
1842
+ export declare interface LegendSwatchItem {
1843
+ label: string;
1844
+ color: string;
1845
+ /** Features currently in this class (same rule the map renders with) */
1846
+ count?: number;
1847
+ min?: number;
1848
+ max?: number;
1849
+ value?: string | number | boolean;
1850
+ /** Class index for setClassVisible / updateClass; -1 = "all other values" */
1851
+ index: number;
1852
+ visible: boolean;
1853
+ /** Complete symbol of the class, for drawing the swatch */
1854
+ symbol: SymbolStyle;
1855
+ }
1856
+
1857
+ export declare type LegendTreeNode = {
1858
+ kind: 'group';
1859
+ group: LegendGroupViewModel;
1860
+ children: LegendTreeNode[];
1861
+ } | {
1862
+ kind: 'layer';
1863
+ layer: LegendLayerViewModel;
1864
+ };
1865
+
1866
+ export declare class LegendWidget {
1867
+ private legendTools;
1868
+ private container;
1869
+ private unsubscriber;
1870
+ private options;
1871
+ constructor(legendTools: OFSLegendTools, options?: LegendWidgetOptions);
1872
+ mount(target: HTMLElement | string): void;
1873
+ unmount(): void;
1874
+ private render;
1875
+ private renderNode;
1876
+ private renderLayer;
1877
+ private handleClick;
1878
+ private handleChange;
1879
+ private handleDoubleClick;
1880
+ private handleInput;
1881
+ }
1882
+
1883
+ export declare interface LegendWidgetOptions {
1884
+ /** Called when the layer "symbology" button is clicked (e.g. open OFSSymbologyPanel) */
1885
+ onEditSymbology?: (layerId: string) => void;
1886
+ /** Shows an "Import" button in the header (e.g. open a file picker / ofs.consoleWidget.submit('import')) */
1887
+ onImport?: () => void;
1888
+ /** Shows an export button per layer */
1889
+ onExportLayer?: (layerId: string) => void;
1890
+ }
1891
+
1892
+ export declare const LENGTH_UNITS: Record<string, number>;
1893
+
1894
+ /** Ground length of a line part in m */
1895
+ export declare function lineLength(line: Position[], projection?: PlanarProjection): number;
1896
+
1897
+ /** Line parts of a LineString / MultiLineString */
1898
+ export declare function linesOf(geometry: Geometry): Position[][];
1899
+
1900
+ export declare interface LineSymbol {
1901
+ color: string;
1902
+ width: number;
1903
+ opacity: number;
1904
+ /** Dash pattern in pixels, e.g. [6, 3] (layer-wide) */
1905
+ dash?: number[];
1906
+ cap?: 'butt' | 'round' | 'square';
1907
+ join?: 'bevel' | 'round' | 'miter';
1908
+ /** Perpendicular offset in pixels, positive = right of the line direction */
1909
+ offset?: number;
1910
+ }
1911
+
1912
+ /** All registered ramps, optionally of one type */
1913
+ export declare function listColorRamps(type?: ColorRampType): ColorRampDefinition[];
1914
+
1915
+ export declare function listCrs(): {
1916
+ code: string;
1917
+ name: string;
1918
+ }[];
1919
+
1920
+ declare type Listener = (report: TopologyReport | null, layerId: string) => void;
1921
+
1922
+ export declare function listExpressionFunctions(): {
1923
+ name: string;
1924
+ help: string;
1925
+ }[];
1926
+
1927
+ export declare function listExpressionVariables(): string[];
1928
+
1929
+ export declare function listMarkerIcons(): string[];
1930
+
1931
+ export declare function localName(name: string): string;
1932
+
1933
+ export declare type LocationPredicate = 'intersects' | 'within' | 'contains' | 'disjoint' | 'touches' | 'crosses' | 'within-distance';
1934
+
1935
+ /** True when every coordinate is a plausible lng/lat */
1936
+ export declare function looksGeographic(bounds: [number, number, number, number]): boolean;
1937
+
1938
+ export declare class MapboxAdapter extends BaseGLAdapter {
1939
+ readonly engineName: "mapbox";
1940
+ init(container: HTMLElement | string, options?: Record<string, any>): Promise<void>;
1941
+ }
1942
+
1943
+ export declare interface MapClickEvent {
1944
+ coordinate: Coordinate;
1945
+ point: {
1946
+ x: number;
1947
+ y: number;
1948
+ };
1949
+ features: Array<{
1950
+ id?: string | number;
1951
+ layerId: string;
1952
+ properties: Record<string, any>;
1953
+ geometry: any;
1954
+ }>;
1955
+ originalEvent: MouseEvent;
1956
+ }
1957
+
1958
+ export declare class MapEngineNotInitializedError extends OFSError {
1959
+ constructor(message?: string);
1960
+ }
1961
+
1962
+ export declare interface MapExportOptions {
1963
+ /** Output width in pixels (default: the map's current width) */
1964
+ width?: number;
1965
+ height?: number;
1966
+ title?: string;
1967
+ /** Draw the scale bar (default true) */
1968
+ scaleBar?: boolean;
1969
+ /** Draw the north arrow (default true) */
1970
+ northArrow?: boolean;
1971
+ /** Text in the bottom right (basemap attribution) */
1972
+ attribution?: string;
1973
+ /** File name without extension */
1974
+ name?: string;
1975
+ /** image/png (default) or image/jpeg */
1976
+ mimeType?: 'image/png' | 'image/jpeg';
1977
+ }
1978
+
1979
+ export declare interface MapImage {
1980
+ dataUrl: string;
1981
+ width: number;
1982
+ height: number;
1983
+ filename: string;
1984
+ scaleBar?: ScaleBarPlan;
1985
+ }
1986
+
1987
+ export declare class MapLibreAdapter extends BaseGLAdapter {
1988
+ readonly engineName: "maplibre";
1989
+ init(container: HTMLElement | string, options?: Record<string, any>): Promise<void>;
1990
+ }
1991
+
1992
+ export declare interface MapViewportOptions {
1993
+ center?: Coordinate;
1994
+ zoom?: number;
1995
+ pitch?: number;
1996
+ bearing?: number;
1997
+ duration?: number;
1998
+ }
1999
+
2000
+ export declare const MARKER_ICON_BUFFER_CSS = 8;
2001
+
2002
+ export declare const MARKER_ICON_PIXEL_RATIO = 2;
2003
+
2004
+ /** Marker icon images: shape diameter and transparent buffer in CSS pixels, rendered at 2x */
2005
+ export declare const MARKER_ICON_SHAPE_CSS = 24;
2006
+
2007
+ export declare type MarkerAnchor = 'center' | 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
2008
+
2009
+ export declare interface MarkerIconDefinition {
2010
+ /** Image URL or inline SVG markup */
2011
+ source: string;
2012
+ /**
2013
+ * Recolorable (SDF) icon: the icon's alpha shape is drawn with the symbol color and stroke.
2014
+ * Use false for multi-color images, which are drawn as-is.
2015
+ */
2016
+ sdf: boolean;
2017
+ }
2018
+
2019
+ export declare function markerImageId(shape: MarkerShape, icon?: string): string;
2020
+
2021
+ /** Built-in marker shapes (rendered as SDF icons, except a plain 'circle' layer) */
2022
+ export declare type MarkerShape = 'circle' | 'square' | 'diamond' | 'triangle' | 'star' | 'pentagon' | 'hexagon' | 'cross' | 'x' | 'icon';
2023
+
2024
+ /** Unit polygon of a shape, or null for 'circle' / 'icon' */
2025
+ export declare function markerShapePolygon(shape: MarkerShape): UnitPoint[] | null;
2026
+
2027
+ /** SVG path data of a shape scaled to `radius` around (cx, cy) */
2028
+ export declare function markerSvgPath(shape: MarkerShape, cx: number, cy: number, radius: number): string;
2029
+
2030
+ export declare interface MarkerSymbol {
2031
+ shape: MarkerShape;
2032
+ /** Registered icon name when shape is 'icon' (see registerMarkerIcon) */
2033
+ icon?: string;
2034
+ /** Marker diameter in pixels */
2035
+ size: number;
2036
+ color: string;
2037
+ opacity: number;
2038
+ strokeColor: string;
2039
+ strokeWidth: number;
2040
+ /** Clockwise rotation in degrees */
2041
+ rotationDeg?: number;
2042
+ anchor?: MarkerAnchor;
2043
+ /** Screen offset [x, y] in pixels (layer-wide) */
2044
+ offset?: [number, number];
2045
+ /** Draw markers even when they collide (layer-wide, icon markers only) */
2046
+ allowOverlap?: boolean;
2047
+ }
2048
+
2049
+ /** Distance (m) and user angle from `from` to `to` */
2050
+ export declare function measure(from: Coordinate, to: Coordinate, frame?: InputFrame): {
2051
+ distance: number;
2052
+ angle: number;
2053
+ };
2054
+
2055
+ /** Angle at `vertex` between the two other points (0–180°), plus the direction and length of both legs */
2056
+ export declare function measureAngle(first: Coordinate, vertex: Coordinate, second: Coordinate, frame?: InputFrame): AngleMeasure;
2057
+
2058
+ /** Area and perimeter of a ring (the ring is closed for the measurement only; the input is not changed) */
2059
+ export declare function measureArea(ring: Coordinate[]): LandAreaMeasure;
2060
+
2061
+ /** Distance of each segment and the total length of a path */
2062
+ export declare function measureDistance(coords: Coordinate[], frame?: InputFrame): DistanceMeasure;
2063
+
2064
+ /** Measure an existing feature: polygons give area + perimeter, lines give length, points give nothing */
2065
+ export declare function measureFeature(feature: Feature<Geometry, any>, frame?: InputFrame): {
2066
+ area?: LandAreaMeasure;
2067
+ length?: DistanceMeasure;
2068
+ };
2069
+
2070
+ /** Ground area and perimeter of a Polygon / MultiPolygon on a local TM plane */
2071
+ export declare function measurePolygon(geometry: Polygon | MultiPolygon, projection?: PlanarProjection): AreaMeasure;
2072
+
2073
+ /** Merge a partial symbol into a complete one (returns a new object) */
2074
+ export declare function mergeSymbolStyle(base: SymbolStyle, input?: SymbolStyleInput): SymbolStyle;
2075
+
2076
+ /** Meters per degree of longitude and latitude at a latitude (WGS84 ellipsoid) */
2077
+ export declare function metersPerDegree(lat: number): [number, number];
2078
+
2079
+ /** Web Mercator ground resolution at a latitude and zoom (meters per CSS pixel) */
2080
+ export declare function metersPerPixel(latitude: number, zoom: number, tileSize?: number): number;
2081
+
2082
+ /**
2083
+ * Get midpoint between two coordinates.
2084
+ */
2085
+ export declare function midpoint(c1: Coordinate, c2: Coordinate): Coordinate;
2086
+
2087
+ /** Shortest distance in meters between two features (0 when they intersect) */
2088
+ export declare function minDistanceMeters(a: Feature<Geometry, any>, b: Feature<Geometry, any>): number;
2089
+
2090
+ /** Jenks optimisation is O(k·n²); larger inputs are classified on an evenly spaced sample of sorted values */
2091
+ export declare const NATURAL_BREAKS_MAX_SAMPLE = 3000;
2092
+
2093
+ export declare interface NetworkLine {
2094
+ /** `branch` is a run through points, `trunk` connects runs (or points) back towards the source */
2095
+ role: 'branch' | 'trunk';
2096
+ coordinates: Coordinate[];
2097
+ lengthMeters: number;
2098
+ }
2099
+
2100
+ export declare type NetworkMode = 'tree' | 'rows';
2101
+
2102
+ export declare interface NetworkOptions {
2103
+ mode?: NetworkMode;
2104
+ /** rows: how far off a line a point may sit and still belong to it (default 1/4 of the row spacing found) */
2105
+ toleranceMeters?: number;
2106
+ /** rows: direction of the runs in degrees counter-clockwise from east; found from the points when absent */
2107
+ angleDegrees?: number;
2108
+ /** Refuse rather than connect more points than this (the tree is O(n²)) — default 5,000 */
2109
+ maxPoints?: number;
2110
+ }
2111
+
2112
+ export declare interface NetworkResult {
2113
+ lines: NetworkLine[];
2114
+ totalLengthMeters: number;
2115
+ branchLengthMeters: number;
2116
+ trunkLengthMeters: number;
2117
+ /** rows: how many runs the points fell into */
2118
+ runCount: number;
2119
+ mode: NetworkMode;
2120
+ angleDegrees: number | null;
2121
+ }
2122
+
2123
+ export declare class NetworkTooLargeError extends OFSError {
2124
+ constructor(count: number, max: number);
2125
+ }
2126
+
2127
+ /**
2128
+ * Notify the user if the target feature belongs to a layer different from the active layer.
2129
+ */
2130
+ export declare function notifyTargetLayer(consoleService: IOFSConsole, targetLayerId: string, activeLayerId: string | null): void;
2131
+
2132
+ export declare interface NumericFieldStats {
2133
+ min: number;
2134
+ max: number;
2135
+ mean: number;
2136
+ sum: number;
2137
+ count: number;
2138
+ }
2139
+
2140
+ /** Numeric values of a field (finite numbers only) */
2141
+ export declare function numericFieldValues(layer: OFSLayerData, fieldName: string): number[];
2142
+
2143
+ declare interface ObjectTrackingSettings {
2144
+ enabled: boolean;
2145
+ /** Hover time on a snap point before it is acquired (or released) */
2146
+ acquireDelayMs: number;
2147
+ /** Cursor distance to a tracking line that activates it */
2148
+ tolerancePixels: number;
2149
+ /** Oldest acquired points are dropped beyond this count */
2150
+ maxPoints: number;
2151
+ }
2152
+
2153
+ /** Coordinate at `distance` meters from `base` in world math direction `rad` */
2154
+ export declare function offsetByPolar(base: Coordinate, distance: number, rad: number): Coordinate;
2155
+
2156
+ export declare class OFSAiBridge {
2157
+ private engine;
2158
+ private dataSource;
2159
+ private instructions;
2160
+ constructor(engine: OFSCommandEngine, dataSource: OFSDataSource);
2161
+ /**
2162
+ * Add the host application's own instructions to the system prompt — what this particular project
2163
+ * is for, its rules of thumb, the layers it expects. The library stays domain-free; the knowledge
2164
+ * of what is being designed lives in the application.
2165
+ *
2166
+ * Pass null to remove them.
2167
+ */
2168
+ setInstructions(instructions: string | null): void;
2169
+ getInstructions(): string | null;
2170
+ /**
2171
+ * Get function declarations (JSON schema) for AI tools
2172
+ */
2173
+ getToolDeclarations(): AiToolDeclaration[];
2174
+ /**
2175
+ * Get system prompt describing the map context
2176
+ */
2177
+ getSystemContextPrompt(): string;
2178
+ private snapshot;
2179
+ /**
2180
+ * Execute an AI tool call with arguments and return structured feedback
2181
+ */
2182
+ executeToolCall(toolName: string, args?: Record<string, any>): Promise<AiExecutionFeedback>;
2183
+ }
2184
+
2185
+ export declare class OFSAttributeTable {
2186
+ private readonly dataSource;
2187
+ private readonly attributes;
2188
+ private readonly options;
2189
+ private container;
2190
+ private unsubscribers;
2191
+ private layerId;
2192
+ private filter;
2193
+ private onlySelected;
2194
+ private sortBy;
2195
+ private sortDescending;
2196
+ private page;
2197
+ private editing;
2198
+ private message;
2199
+ private dialog;
2200
+ constructor(dataSource: OFSDataSource, attributes: OFSAttributeTools, options?: AttributeTableOptions);
2201
+ mount(target: HTMLElement | string): void;
2202
+ unmount(): void;
2203
+ /** Show a layer's table */
2204
+ open(layerId: string): void;
2205
+ getLayerId(): string | null;
2206
+ private dataLayers;
2207
+ private currentLayerId;
2208
+ private render;
2209
+ private renderHeader;
2210
+ private renderRow;
2211
+ private renderDialog;
2212
+ private value;
2213
+ private checked;
2214
+ private run;
2215
+ private handleChange;
2216
+ private handleKeyDown;
2217
+ private handleDoubleClick;
2218
+ private handleClick;
2219
+ }
2220
+
2221
+ export declare class OFSAttributeTools {
2222
+ private readonly dataSource;
2223
+ constructor(dataSource: OFSDataSource);
2224
+ private layerOrThrow;
2225
+ /** Stored schema plus fields that only exist in the data */
2226
+ getSchema(layerId: string): FieldSchema[];
2227
+ /** Replace the stored schema (undoable together with the values written in the same transaction) */
2228
+ setSchema(layerId: string, fields: FieldSchema[]): void;
2229
+ /** Change one field's settings (alias, default, allowed values, limits, read-only …) */
2230
+ updateField(layerId: string, name: string, patch: Partial<Omit<FieldSchema, 'name'>> & {
2231
+ name?: string;
2232
+ }): FieldSchema;
2233
+ /**
2234
+ * Add a field to the schema and write its value to every feature (default value, or an expression).
2235
+ */
2236
+ addField(layerId: string, field: FieldSchema, options?: {
2237
+ expression?: string;
2238
+ }): CalculateResult;
2239
+ deleteField(layerId: string, name: string): number;
2240
+ renameField(layerId: string, from: string, to: string): number;
2241
+ /** Properties for a new feature: the schema's default values */
2242
+ defaultProperties(layerId: string): Record<string, unknown>;
2243
+ query(layerId: string, query?: TableQuery): TableResult;
2244
+ /** Write one value (checked against the field schema) */
2245
+ setValue(layerId: string, featureId: string | number, field: string, value: unknown): ExpressionValue;
2246
+ /** Write several values as one undo step; nothing is written when any value is refused */
2247
+ setValues(layerId: string, edits: {
2248
+ featureId: string | number;
2249
+ field: string;
2250
+ value: unknown;
2251
+ }[]): ExpressionValue[];
2252
+ private compile;
2253
+ /** Parse an expression against a layer's fields without running it (for input validation) */
2254
+ validateExpression(layerId: string, expression: string): {
2255
+ ok: true;
2256
+ fields: string[];
2257
+ } | {
2258
+ ok: false;
2259
+ error: string;
2260
+ };
2261
+ /** Try an expression on one feature (preview in the UI) */
2262
+ previewExpression(layerId: string, expression: string, featureId?: string | number): ExpressionValue;
2263
+ /**
2264
+ * Field calculator: write the expression's value into a field for every feature (or only the selected ones).
2265
+ * By default nothing is written when a feature's value does not fit the field.
2266
+ */
2267
+ calculateField(layerId: string, fieldName: string, expression: string, options?: CalculateOptions): CalculateResult;
2268
+ private applySelection;
2269
+ /** Select features whose expression is true */
2270
+ selectByExpression(layerId: string, expression: string, mode?: SelectionMode_2): (string | number)[];
2271
+ /**
2272
+ * Select features by their spatial relation to another layer (or to the selected features of that layer).
2273
+ */
2274
+ selectByLocation(layerId: string, predicate: LocationPredicate, referenceLayerId: string, options?: {
2275
+ referenceFeatureIds?: (string | number)[];
2276
+ onlySelectedReference?: boolean;
2277
+ distanceMeters?: number;
2278
+ mode?: SelectionMode_2;
2279
+ }): (string | number)[];
2280
+ private matchesPredicate;
2281
+ /** Bounding box of the current selection (for zooming) */
2282
+ selectionBBox(layerId: string): BoundingBox | null;
2283
+ statistics(layerId: string, fieldName: string, options?: {
2284
+ onlySelected?: boolean;
2285
+ }): FieldStatistics;
2286
+ /** Field names that exist in the data but not in the schema */
2287
+ undeclaredFields(layerId: string): string[];
2288
+ }
2289
+
2290
+ export declare class OFSCommandEngine extends TypedEventEmitter<CommandEngineEvents> {
2291
+ readonly registry: OFSCommandRegistry;
2292
+ private consoleService;
2293
+ private currentAbortController;
2294
+ private currentContext;
2295
+ constructor(consoleService: IOFSConsole);
2296
+ getContext(): OFSWorkflowContext | null;
2297
+ /**
2298
+ * Run a pipeline of commands in sequence
2299
+ * @param commands Array of command strings e.g. ["draw_polygon", "buffer 5m"]
2300
+ * @param initialData Optional input payload passed into context
2301
+ */
2302
+ run(commands: string[], initialData?: any): Promise<OFSWorkflowContext>;
2303
+ /**
2304
+ * Run more commands inside the workflow that is already running (used by macros): the current
2305
+ * workflow is neither cancelled nor replaced, and the commands share its context.
2306
+ */
2307
+ runNested(commands: string[], context: OFSWorkflowContext): Promise<OFSWorkflowContext>;
2308
+ /** The command loop shared by `run` and `runNested` */
2309
+ private executeCommands;
2310
+ /**
2311
+ * Cancel currently running workflow
2312
+ */
2313
+ cancel(): void;
2314
+ /**
2315
+ * Parse command line string e.g. "buffer 10 meters" -> { cmdName: "buffer", args: "10 meters" }
2316
+ */
2317
+ parseCommandString(raw: string): {
2318
+ cmdName: string;
2319
+ args: string;
2320
+ };
2321
+ }
2322
+
2323
+ export declare interface OFSCommandProcess {
2324
+ name: string;
2325
+ aliases: string[];
2326
+ description: string;
2327
+ usage?: string;
2328
+ isInteractive?: boolean;
2329
+ schema?: {
2330
+ type: 'object';
2331
+ properties: Record<string, any>;
2332
+ required?: string[];
2333
+ };
2334
+ /**
2335
+ * How the schema's parameters appear on the command line. With this, the engine parses and checks the
2336
+ * arguments once and the command reads them from `context.intermediate.get('_args')`.
2337
+ */
2338
+ args?: CommandArgSpec;
2339
+ execute(context: OFSWorkflowContext, consoleService: IOFSConsole): Promise<OFSWorkflowContext>;
2340
+ }
2341
+
2342
+ export declare class OFSCommandRegistry {
2343
+ private commands;
2344
+ private aliasMap;
2345
+ register(cmd: OFSCommandProcess): void;
2346
+ get(nameOrAlias: string): OFSCommandProcess | undefined;
2347
+ getAll(): OFSCommandProcess[];
2348
+ has(nameOrAlias: string): boolean;
2349
+ /** Every command name (aliases included when `withAliases`) */
2350
+ getNames(withAliases?: boolean): string[];
2351
+ /** Command names and aliases starting with a prefix, for autocomplete */
2352
+ suggest(prefix: string): string[];
2353
+ }
2354
+
2355
+ export declare class OFSDataSource extends TypedEventEmitter<OFSDataSourceEvents> {
2356
+ private layers;
2357
+ private groups;
2358
+ private activeLayerId;
2359
+ private selectionStore;
2360
+ readonly transactions: TransactionManager;
2361
+ private pendingChangedLayers;
2362
+ constructor();
2363
+ /**
2364
+ * Emit an event. While a transaction is running, 'features:changed' is coalesced
2365
+ * and emitted once per layer when the outermost transaction finishes.
2366
+ */
2367
+ emit<K extends keyof OFSDataSourceEvents>(event: K, data: OFSDataSourceEvents[K]): void;
2368
+ /**
2369
+ * Run several edits as one atomic, undoable operation.
2370
+ * - All undo steps recorded inside `fn` become a single undo/redo step named `description`.
2371
+ * - If `fn` throws, every recorded change is reverted and the error is rethrown.
2372
+ * - Map refresh events ('features:changed') are emitted once per layer at the end.
2373
+ */
2374
+ runTransaction<T>(description: string, fn: () => T): T;
2375
+ private withCoalescedEvents;
2376
+ /**
2377
+ * Add a new layer with optional initial GeoJSON features
2378
+ */
2379
+ addLayer(metadata: LayerMetadata, initialFeatures?: Feature<Geometry, any>[]): OFSLayerData;
2380
+ /**
2381
+ * Remove a layer by ID
2382
+ */
2383
+ removeLayer(layerId: string): boolean;
2384
+ /**
2385
+ * Get layer by ID
2386
+ */
2387
+ getLayer(layerId: string): OFSLayerData | undefined;
2388
+ /**
2389
+ * Check if layer exists
2390
+ */
2391
+ hasLayer(layerId: string): boolean;
2392
+ /**
2393
+ * Get all layers sorted by zIndex ascending (higher zIndex renders on top)
2394
+ */
2395
+ getAllLayers(): OFSLayerData[];
2396
+ /**
2397
+ * Set layer visibility
2398
+ */
2399
+ setLayerVisibility(layerId: string, visible: boolean): void;
2400
+ /**
2401
+ * Set layer opacity (0.0 to 1.0)
2402
+ */
2403
+ setLayerOpacity(layerId: string, opacity: number): void;
2404
+ /**
2405
+ * Set layer z-index
2406
+ */
2407
+ setLayerZIndex(layerId: string, zIndex: number): void;
2408
+ /**
2409
+ * Reorder layers by ID order
2410
+ */
2411
+ reorderLayers(orderedLayerIds: string[]): void;
2412
+ /**
2413
+ * Pin / unpin a layer (pinned layers cannot be removed)
2414
+ */
2415
+ setLayerPinned(layerId: string, pinned: boolean): void;
2416
+ addLayerGroup(group: {
2417
+ id: string;
2418
+ name?: string;
2419
+ parentId?: string | null;
2420
+ visible?: boolean;
2421
+ expanded?: boolean;
2422
+ }): LayerGroup;
2423
+ getLayerGroup(groupId: string): LayerGroup | undefined;
2424
+ getLayerGroups(): LayerGroup[];
2425
+ /**
2426
+ * Remove a group. Its layers and sub-groups move to the group's parent (nothing is deleted).
2427
+ */
2428
+ removeLayerGroup(groupId: string): void;
2429
+ updateLayerGroup(groupId: string, patch: {
2430
+ name?: string;
2431
+ visible?: boolean;
2432
+ expanded?: boolean;
2433
+ parentId?: string | null;
2434
+ }): void;
2435
+ setLayerGroupVisibility(groupId: string, visible: boolean): void;
2436
+ /** Move a layer into a group (null = top level) */
2437
+ moveLayerToGroup(layerId: string, groupId: string | null): void;
2438
+ /** True when the layer is inside the group, directly or through sub-groups */
2439
+ isLayerInGroup(layerId: string, groupId: string): boolean;
2440
+ /** A layer is drawn when it and all of its parent groups are visible */
2441
+ isLayerRendered(layerId: string): boolean;
2442
+ setActiveLayer(layerId: string | null): void;
2443
+ getActiveLayerId(): string | null;
2444
+ getActiveLayer(): OFSLayerData | null;
2445
+ selectFeature(layerId: string, featureId: string | number, multi?: boolean): void;
2446
+ deselectFeature(layerId: string, featureId: string | number): void;
2447
+ /**
2448
+ * Toggle selection state of a feature (if selected -> deselect, if not selected -> select)
2449
+ * Returns true if feature is now selected, false if deselected.
2450
+ */
2451
+ toggleFeatureSelection(layerId: string, featureId: string | number): boolean;
2452
+ /**
2453
+ * Select multiple features in a layer at once
2454
+ */
2455
+ selectFeatures(layerId: string, featureIds: (string | number)[], multi?: boolean): void;
2456
+ /**
2457
+ * Get total count of currently selected features across all layers
2458
+ */
2459
+ getSelectedCount(): number;
2460
+ clearSelection(layerId?: string): void;
2461
+ deselectAll(layerId?: string): void;
2462
+ getSelectedFeatureIds(layerId: string): (string | number)[];
2463
+ getSelectedFeatures(layerId: string): Feature<Geometry, any>[];
2464
+ /**
2465
+ * Get any selected feature across layers, prioritizing the active layer.
2466
+ */
2467
+ getAnySelectedFeature(): {
2468
+ layerId: string;
2469
+ featureId: string | number;
2470
+ } | null;
2471
+ /**
2472
+ * Get any selected features across layers, prioritizing the active layer.
2473
+ */
2474
+ getAnySelectedFeatures(): {
2475
+ layerId: string;
2476
+ featureIds: (string | number)[];
2477
+ } | null;
2478
+ addFeature(layerId: string, feature: Feature<Geometry, any>, recordUndo?: boolean): Feature<Geometry, any>;
2479
+ addFeatures(layerId: string, features: Feature<Geometry, any>[], recordUndo?: boolean): Feature<Geometry, any>[];
2480
+ updateFeature(layerId: string, feature: Feature<Geometry, any>, recordUndo?: boolean): boolean;
2481
+ /**
2482
+ * Change only the properties of a feature (a property given as `undefined` is removed).
2483
+ *
2484
+ * Unlike `updateFeature`, nothing copies the geometry: undo keeps just the previous values of the
2485
+ * properties that changed. Editing one attribute of 98,000 parcels costs a few MB this way instead of
2486
+ * a full copy of the layer (about 240 MB), which is what the field calculator and the attribute table use.
2487
+ */
2488
+ updateFeatureProperties(layerId: string, featureId: string | number, patch: Record<string, unknown>, recordUndo?: boolean): boolean;
2489
+ /**
2490
+ * Change the properties of many features as one undo step.
2491
+ *
2492
+ * The step keeps one list of the previous values, not one entry per feature, so a field calculated over
2493
+ * a whole large layer stays cheap to undo.
2494
+ * @returns how many features changed
2495
+ */
2496
+ updateFeaturePropertiesBatch(layerId: string, edits: {
2497
+ featureId: string | number;
2498
+ patch: Record<string, unknown>;
2499
+ }[], recordUndo?: boolean, description?: string): number;
2500
+ /** The values a patch is about to replace, or null when nothing would change */
2501
+ private propertiesBefore;
2502
+ removeFeature(layerId: string, featureId: string | number, recordUndo?: boolean): boolean;
2503
+ /**
2504
+ * Return `preferredId` if unused in the layer, otherwise a suffixed variant; without a preferred
2505
+ * ID a random unique ID is generated.
2506
+ */
2507
+ getAvailableFeatureId(layerId: string, preferredId?: string | number): string | number;
2508
+ getFeature(layerId: string, featureId: string | number): Feature<Geometry, any> | undefined;
2509
+ /**
2510
+ * Create buffer around feature and add as new feature or replace
2511
+ */
2512
+ buffer(layerId: string, featureId: string | number, distance: number, units?: turf.Units, targetLayerId?: string): Feature<Polygon | MultiPolygon>;
2513
+ /**
2514
+ * Calculate polygon area in square meters or hectares
2515
+ */
2516
+ calculateArea(layerId: string, featureId: string | number, unit?: 'sqm' | 'hectares' | 'rai'): number;
2517
+ /**
2518
+ * Calculate line length in meters or kilometers
2519
+ */
2520
+ calculateLength(layerId: string, featureId: string | number, units?: turf.Units): number;
2521
+ /**
2522
+ * Union multiple polygons in a layer into a single feature.
2523
+ * Vertices of different polygons closer than `snapToleranceMeters` (default 1 mm) are first
2524
+ * snapped together so shared boundaries dissolve cleanly. No buffering or simplification is
2525
+ * applied: if the polygons are genuinely disjoint the result is a MultiPolygon.
2526
+ */
2527
+ union(layerId: string, featureIds: (string | number)[], options?: {
2528
+ snapToleranceMeters?: number;
2529
+ }): Feature<Polygon | MultiPolygon>;
2530
+ /**
2531
+ * Split two overlapping polygons into non-overlapping pieces:
2532
+ * (A \ B, A ∩ B, B \ A)
2533
+ */
2534
+ splitOverlapping(layerId: string, featureIdA: string | number, featureIdB: string | number): {
2535
+ pieceA: Feature<Polygon>[];
2536
+ overlap: Feature<Polygon>[];
2537
+ pieceB: Feature<Polygon>[];
2538
+ } | null;
2539
+ /**
2540
+ * Subtract (difference) one polygon from another
2541
+ */
2542
+ difference(layerId: string, baseFeatureId: string | number, cutFeatureId: string | number): Feature<Polygon | MultiPolygon> | null;
2543
+ /**
2544
+ * Get BoundingBox across a layer or the entire data source
2545
+ */
2546
+ getBoundingBox(layerId?: string): BoundingBox;
2547
+ undo(): string | null;
2548
+ redo(): string | null;
2549
+ canUndo(): boolean;
2550
+ canRedo(): boolean;
2551
+ private getLayerOrThrow;
2552
+ private getFeatureOrThrow;
2553
+ }
2554
+
2555
+ export declare interface OFSDataSourceEvents {
2556
+ 'layer:added': {
2557
+ layer: OFSLayerData;
2558
+ };
2559
+ 'layer:removed': {
2560
+ layerId: string;
2561
+ };
2562
+ 'layer:updated': {
2563
+ layer: OFSLayerData;
2564
+ };
2565
+ 'feature:added': {
2566
+ layerId: string;
2567
+ feature: Feature<Geometry, any>;
2568
+ };
2569
+ 'feature:updated': {
2570
+ layerId: string;
2571
+ feature: Feature<Geometry, any>;
2572
+ };
2573
+ 'feature:removed': {
2574
+ layerId: string;
2575
+ featureId: string | number;
2576
+ };
2577
+ 'features:changed': {
2578
+ layerId: string;
2579
+ };
2580
+ 'selection:changed': {
2581
+ layerId: string;
2582
+ featureIds: (string | number)[];
2583
+ };
2584
+ 'active-layer:changed': {
2585
+ layerId: string | null;
2586
+ };
2587
+ 'group:added': {
2588
+ group: LayerGroup;
2589
+ };
2590
+ 'group:removed': {
2591
+ groupId: string;
2592
+ };
2593
+ 'group:updated': {
2594
+ group: LayerGroup;
2595
+ };
2596
+ 'transaction:undo': {
2597
+ description: string;
2598
+ };
2599
+ 'transaction:redo': {
2600
+ description: string;
2601
+ };
2602
+ }
2603
+
2604
+ /**
2605
+ * Internal diagnostics - a single channel for errors the library recovers from.
2606
+ *
2607
+ * Map style operations (moving layers, setting paint properties, feature state) can fail in
2608
+ * normal situations, e.g. before a style has loaded. The library keeps working in those cases,
2609
+ * but the error is reported here instead of being swallowed silently.
2610
+ */
2611
+ export declare type OFSDiagnosticHandler = (scope: string, error: unknown) => void;
2612
+
2613
+ export declare class OFSDrawTools extends TypedEventEmitter<DrawEvents> {
2614
+ private dataSource;
2615
+ private mapAdapter;
2616
+ readonly snapping: SnappingEngine;
2617
+ readonly grips: OFSGripsEditor;
2618
+ readonly selectionOverlay: OFSSelectionOverlay;
2619
+ orthoEnabled: boolean;
2620
+ polarTracking: PolarTrackingSettings;
2621
+ /** Angle convention and UCS used for typed angles, relative coordinates, ortho and polar tracking */
2622
+ inputFrame: InputFrame;
2623
+ private lastCursorCoord;
2624
+ private lastConstraint;
2625
+ /** Object snap tracking (AutoCAD OTRACK, F11) */
2626
+ objectTracking: ObjectTrackingSettings;
2627
+ private trackingPoints;
2628
+ private trackingHover;
2629
+ /** Clock used for tracking acquisition (replaceable in tests) */
2630
+ now: () => number;
2631
+ private pointPick;
2632
+ private currentMode;
2633
+ private activeCoordinates;
2634
+ private targetLayerId;
2635
+ private tempSourceId;
2636
+ private unsubClick;
2637
+ private unsubDblClick;
2638
+ private unsubContextMenu;
2639
+ private unsubMove;
2640
+ private unsubMouseDown;
2641
+ private unsubMouseUp;
2642
+ private isDrawing;
2643
+ private guides;
2644
+ private dragSelectStart;
2645
+ private isDragSelecting;
2646
+ private justFinishedDrag;
2647
+ private handleKeyDown;
2648
+ constructor(dataSource: OFSDataSource, mapAdapter: IMapAdapter);
2649
+ setOrtho(enabled: boolean): void;
2650
+ toggleOrtho(): boolean;
2651
+ /**
2652
+ * Enable/disable polar tracking and optionally change its angle increment (AutoCAD F10)
2653
+ */
2654
+ setPolarTracking(settings: Partial<PolarTrackingSettings>): void;
2655
+ togglePolarTracking(): boolean;
2656
+ /**
2657
+ * Rotate the drawing axes (UCS). `rotationDeg` is the counter-clockwise angle of the X axis
2658
+ * from true East, e.g. align with a field edge so ORTHO and @dx,dy follow the field.
2659
+ */
2660
+ setUcsRotation(rotationDeg: number): void;
2661
+ /**
2662
+ * Choose how typed angles are interpreted: 'bearing' (0° = North, clockwise) or 'cad' (0° = East, counter-clockwise)
2663
+ */
2664
+ setAngleConvention(convention: AngleConvention): void;
2665
+ /** Map adapter used by these tools */
2666
+ getMapAdapter(): IMapAdapter;
2667
+ /** Last known cursor position after snapping / tracking */
2668
+ getCursorCoordinate(): Coordinate | null;
2669
+ private isDrawModeActive;
2670
+ /** Point that relative input and tracking are currently measured from */
2671
+ getReferencePoint(): Coordinate | null;
2672
+ /**
2673
+ * Resolve a raw cursor position: object snaps win over ORTHO / polar tracking (AutoCAD behavior).
2674
+ */
2675
+ private resolveCursor;
2676
+ /** Ground meters per screen pixel at a coordinate (1 m when the map cannot project) */
2677
+ private metersPerPixel;
2678
+ /** Enable/disable object snap tracking or change its settings (AutoCAD F11) */
2679
+ setObjectTracking(settings: Partial<ObjectTrackingSettings>): void;
2680
+ /** Points currently acquired for object snap tracking */
2681
+ getTrackingPoints(): Coordinate[];
2682
+ clearTrackingPoints(): void;
2683
+ /**
2684
+ * Acquire (or release) a snap point after hovering on it for `acquireDelayMs`.
2685
+ */
2686
+ private updateTrackingAcquisition;
2687
+ /** In-progress vertices that the cursor may snap to (polygon start, previous line vertices) */
2688
+ private getInProgressSnapCoords;
2689
+ /**
2690
+ * Feed command-line text to the active drawing (AutoCAD dynamic input).
2691
+ * Supports @dx,dy / @distance<angle / distance (toward cursor) / lng,lat,
2692
+ * empty text (finish), "u" (undo last vertex) and "c" (close polygon / line).
2693
+ * Returns handled=false when no drawing is active or the text is not drawing input.
2694
+ */
2695
+ submitInput(text: string): DrawInputResult;
2696
+ /**
2697
+ * Remove the most recently placed vertex of the drawing in progress (AutoCAD "U" inside LINE).
2698
+ */
2699
+ undoLastVertex(): boolean;
2700
+ /**
2701
+ * Let the next map click provide a point (used by commands asking "Specify base point").
2702
+ * Clicks are snapped and tracked relative to `basePoint`, and do not change the selection.
2703
+ * Returns a function that cancels the pick.
2704
+ */
2705
+ beginPointPick(options: PointPickOptions, onPick: (coord: Coordinate) => void): () => void;
2706
+ isPickingPoint(): boolean;
2707
+ setupTempDrawingLayer(): void;
2708
+ /**
2709
+ * Dashed ORTHO / POLAR tracking ray layer (and keep it out of the regular rubber-band line layer)
2710
+ */
2711
+ private ensureTrackingLayer;
2712
+ /**
2713
+ * Dashed rays for the active ORTHO / POLAR / tracking lines, plus markers for acquired tracking points.
2714
+ */
2715
+ private trackingFeatures;
2716
+ /**
2717
+ * Ensure temporary drawing and snap guide layers stay top-most above all data layers
2718
+ */
2719
+ bringTempLayersToFront(): void;
2720
+ private bindMapEvents;
2721
+ /**
2722
+ * Get the required geometry type for a given draw mode
2723
+ */
2724
+ getRequiredGeometryType(mode: DrawMode): LayerGeometryType;
2725
+ /**
2726
+ * Resolve or auto-detect a compatible target layer for the given mode
2727
+ */
2728
+ resolveTargetLayerId(mode: DrawMode, preferredLayerId?: string): string;
2729
+ /**
2730
+ * Current target layer id
2731
+ */
2732
+ getTargetLayerId(): string | null;
2733
+ /**
2734
+ * Set the active draw mode
2735
+ */
2736
+ setMode(mode: DrawMode, targetLayerId?: string): void;
2737
+ getMode(): DrawMode;
2738
+ /**
2739
+ * Whether drawing is currently in progress
2740
+ */
2741
+ getIsDrawing(): boolean;
2742
+ /**
2743
+ * Current active vertices
2744
+ */
2745
+ getActiveCoordinates(): Coordinate[];
2746
+ /**
2747
+ * Handle mouse down on map (drag selection start)
2748
+ */
2749
+ private handleMouseDown;
2750
+ /**
2751
+ * Handle mouse up on map (drag selection complete)
2752
+ */
2753
+ private handleMouseUp;
2754
+ /**
2755
+ * Handle map click
2756
+ */
2757
+ private handleMapClick;
2758
+ /**
2759
+ * Place a vertex of the drawing in progress (from a click or typed input).
2760
+ */
2761
+ private commitDrawPoint;
2762
+ /**
2763
+ * Handle double click on map (finishes LineString or Polygon)
2764
+ */
2765
+ private handleMapDblClick;
2766
+ /**
2767
+ * Handle right-click / context menu on map (finishes if valid, else cancels)
2768
+ */
2769
+ private handleContextMenu;
2770
+ /**
2771
+ * Handle mouse move (rubberband preview)
2772
+ */
2773
+ private handleMouseMove;
2774
+ private emitMeasure;
2775
+ /** Rubber-band preview from the pick base point to the cursor */
2776
+ private updatePickPreview;
2777
+ /**
2778
+ * Complete current drawing or geometry editing session
2779
+ */
2780
+ finishDrawing(): Feature<Geometry, any> | null;
2781
+ /**
2782
+ * Reset internal coordinate state and temporary rubberband
2783
+ */
2784
+ private resetDrawingState;
2785
+ /**
2786
+ * Cancel drawing or geometry editing session
2787
+ */
2788
+ cancel(): void;
2789
+ drawPointByCoords(coord: Coordinate, targetLayerId?: string, props?: Record<string, any>): Feature<Point>;
2790
+ drawLineByCoords(coords: Coordinate[], targetLayerId?: string, props?: Record<string, any>): Feature<LineString>;
2791
+ drawPolygonByCoords(coords: Coordinate[], targetLayerId?: string, props?: Record<string, any>): Feature<Polygon>;
2792
+ splitPolygon(layerId: string, polygonFeatureId: string | number, cuttingLineFeatureId?: string | number): Feature<Polygon>[] | null;
2793
+ /**
2794
+ * Split two overlapping polygons into non-overlapping pieces:
2795
+ * (A \ B, A ∩ B, B \ A)
2796
+ */
2797
+ splitOverlappingPolygons(layerId: string, featureIdA: string | number, featureIdB: string | number): {
2798
+ pieceA: Feature<Polygon>[];
2799
+ overlap: Feature<Polygon>[];
2800
+ pieceB: Feature<Polygon>[];
2801
+ } | null;
2802
+ /**
2803
+ * Split a LineString by a point coordinate or cutter line (AutoCAD BREAK / SPLIT)
2804
+ */
2805
+ splitLine(layerId: string, lineFeatureId: string | number, splitter: Feature<Point | LineString> | Coordinate | string | number): Feature<LineString>[] | null;
2806
+ /**
2807
+ * Connect / Join two lines, strictly preserving the direction of the first line
2808
+ */
2809
+ joinLines(layerId: string, lineId1: string | number, lineId2: string | number, toleranceMeters?: number): Feature<LineString> | null;
2810
+ offsetFeature(layerId: string, featureId: string | number, distanceMeters: number, copy?: boolean): Feature<LineString | Polygon | MultiPolygon> | null;
2811
+ rotateFeature(layerId: string, featureId: string | number, angleDegrees: number, pivot?: Coordinate): Feature<Geometry> | null;
2812
+ scaleFeature(layerId: string, featureId: string | number, factor: number, origin?: Coordinate): Feature<Geometry> | null;
2813
+ explodeFeature(layerId: string, featureId: string | number): Feature<LineString>[] | null;
2814
+ filletFeature(layerId: string, featureId: string | number, vertexIndex: number, radiusMeters?: number): Feature<Polygon | LineString> | null;
2815
+ /**
2816
+ * Start interactive Grips editing on a feature
2817
+ */
2818
+ startEdit(layerId: string, featureId: string | number): boolean;
2819
+ /**
2820
+ * Stop interactive Grips editing
2821
+ */
2822
+ stopEdit(): void;
2823
+ /**
2824
+ * Check if geometry editing is currently active
2825
+ */
2826
+ isEditing(): boolean;
2827
+ /**
2828
+ * Get the active feature currently being edited
2829
+ */
2830
+ getActiveEditingFeature(): Feature<Geometry, any> | null;
2831
+ /**
2832
+ * Get the layer ID of the feature currently being edited
2833
+ */
2834
+ getActiveEditingLayerId(): string | null;
2835
+ /**
2836
+ * Get the feature ID of the feature currently being edited
2837
+ */
2838
+ getActiveEditingFeatureId(): string | number | null;
2839
+ /**
2840
+ * Replace or update the entire geometry of a feature
2841
+ */
2842
+ updateGeometry(layerId: string, featureId: string | number, geometry: Geometry): boolean;
2843
+ /**
2844
+ * Move / Translate a feature by distance and bearing (AutoCAD MOVE)
2845
+ */
2846
+ moveFeature(layerId: string, featureId: string | number, distanceMeters: number, bearingDegrees: number): Feature<Geometry> | null;
2847
+ /**
2848
+ * Move / Translate a feature by delta coordinates (dx, dy)
2849
+ */
2850
+ moveFeatureByOffset(layerId: string, featureId: string | number, dxLng: number, dyLat: number): Feature<Geometry> | null;
2851
+ /**
2852
+ * Copy a feature to an offset position (AutoCAD COPY)
2853
+ */
2854
+ copyFeature(layerId: string, featureId: string | number, dxLng: number, dyLat: number): Feature<Geometry> | null;
2855
+ /**
2856
+ * Copy a feature by a distance in meters along a bearing (AutoCAD COPY with polar offset)
2857
+ */
2858
+ copyFeatureByDistance(layerId: string, featureId: string | number, distanceMeters: number, bearingDegrees: number): Feature<Geometry> | null;
2859
+ /**
2860
+ * Apply a geometry transform to several features as one undoable step.
2861
+ * With `copy`, transformed copies are added and the originals stay unchanged.
2862
+ * Returns the resulting features (updated originals or new copies).
2863
+ */
2864
+ transformFeatures(targets: {
2865
+ layerId: string;
2866
+ featureId: string | number;
2867
+ }[], description: string, transform: (feature: Feature<Geometry, any>) => Feature<Geometry, any>, copy?: boolean): Feature<Geometry, any>[];
2868
+ /**
2869
+ * Find the LineString nearest to a map point within `tolerancePixels` (or 2 m without a map projection).
2870
+ */
2871
+ findLineAt(coord: Coordinate, tolerancePixels?: number): {
2872
+ layerId: string;
2873
+ feature: Feature<LineString, any>;
2874
+ distance: number;
2875
+ } | null;
2876
+ /**
2877
+ * Find the line or polygon under a map point. Lines and polygon edges within `tolerancePixels`
2878
+ * win; otherwise a polygon containing the point is returned.
2879
+ */
2880
+ findFeatureAt(coord: Coordinate, options?: {
2881
+ tolerancePixels?: number;
2882
+ types?: ('LineString' | 'Polygon')[];
2883
+ }): {
2884
+ layerId: string;
2885
+ feature: Feature<LineString | Polygon, any>;
2886
+ distance: number;
2887
+ } | null;
2888
+ /**
2889
+ * AutoCAD BREAK: remove the part of the picked line between two points (same point = split there).
2890
+ */
2891
+ breakLineAt(pick1: Coordinate, pick2: Coordinate): {
2892
+ layerId: string;
2893
+ featureId: string | number;
2894
+ pieces: Feature<LineString>[];
2895
+ } | null;
2896
+ /**
2897
+ * AutoCAD LENGTHEN: change the end of the picked line nearest `pick`.
2898
+ * mode 'delta' adds meters (negative shortens), 'total' sets the total length, 'percent' scales the length.
2899
+ * @throws Error with a user-facing message when the result is invalid
2900
+ */
2901
+ lengthenLineAt(pick: Coordinate, mode: 'delta' | 'total' | 'percent', value: number): Feature<LineString> | null;
2902
+ /**
2903
+ * AutoCAD OFFSET by picking: create a parallel copy of the picked line / polygon on the side of `sidePoint`.
2904
+ * With distance 'through', the copy passes through `sidePoint`.
2905
+ * @throws Error with a user-facing message when the offset is not possible
2906
+ */
2907
+ offsetAt(pick: Coordinate, sidePoint: Coordinate, distance: number | 'through'): {
2908
+ layerId: string;
2909
+ source: Feature<Geometry>;
2910
+ result: Feature<Geometry>;
2911
+ };
2912
+ private replaceLineWithPieces;
2913
+ private safeRawMap;
2914
+ /** Segments of all visible features except `exclude` (used as cutting edges / boundaries) */
2915
+ private boundarySegments;
2916
+ /**
2917
+ * AutoCAD TRIM (quick mode): remove the part of the line under `pick` between the nearest
2918
+ * intersections with any other visible feature. Returns the remaining pieces, or null when no
2919
+ * line is under the pick point or nothing intersects it.
2920
+ */
2921
+ trimLineAt(pick: Coordinate): {
2922
+ layerId: string;
2923
+ featureId: string | number;
2924
+ pieces: Feature<LineString>[];
2925
+ } | null;
2926
+ /**
2927
+ * AutoCAD EXTEND: extend the end of the line nearest `pick` to the nearest visible boundary.
2928
+ */
2929
+ extendLineAt(pick: Coordinate): {
2930
+ layerId: string;
2931
+ feature: Feature<LineString>;
2932
+ } | null;
2933
+ /**
2934
+ * AutoCAD FILLET between two picked lines (radius 0 = sharp corner). Both lines are trimmed or
2935
+ * extended; for radius > 0 an arc line is added to the first line's layer.
2936
+ * @throws Error with a user-facing message when the fillet is not possible
2937
+ */
2938
+ filletLinesAt(pick1: Coordinate, pick2: Coordinate, radiusMeters: number): {
2939
+ lines: Feature<LineString>[];
2940
+ arc: Feature<LineString> | null;
2941
+ };
2942
+ /**
2943
+ * AutoCAD STRETCH: move vertices inside the window (two opposite corners) by base -> second point.
2944
+ * Applies to the given targets, or to every visible feature crossing the window when omitted.
2945
+ * Returns the changed features and the number of moved vertices.
2946
+ */
2947
+ stretch(corner1: Coordinate, corner2: Coordinate, from: Coordinate, to: Coordinate, targets?: {
2948
+ layerId: string;
2949
+ featureId: string | number;
2950
+ }[]): {
2951
+ features: Feature<Geometry, any>[];
2952
+ movedVertices: number;
2953
+ };
2954
+ /**
2955
+ * Delete a feature from a layer
2956
+ */
2957
+ deleteFeature(layerId: string, featureId: string | number): boolean;
2958
+ /**
2959
+ * Update a specific vertex in a feature's geometry
2960
+ */
2961
+ updateVertex(layerId: string, featureId: string | number, index: number, coordinate: Coordinate, ringIndex?: number): boolean;
2962
+ /**
2963
+ * Insert a vertex into a feature's geometry
2964
+ */
2965
+ insertVertex(layerId: string, featureId: string | number, coordinate: Coordinate, index?: number, ringIndex?: number): boolean;
2966
+ /**
2967
+ * Delete a vertex from a feature's geometry
2968
+ */
2969
+ deleteVertex(layerId: string, featureId: string | number, vertexIndex: number, ringIndex?: number): boolean;
2970
+ /**
2971
+ * Simplify geometry using Douglas-Peucker algorithm
2972
+ */
2973
+ simplifyFeature(layerId: string, featureId: string | number, tolerance?: number): Feature<Geometry> | null;
2974
+ /**
2975
+ * Smooth a LineString feature with Bezier curve
2976
+ */
2977
+ smoothFeature(layerId: string, featureId: string | number, resolution?: number): Feature<Geometry> | null;
2978
+ /**
2979
+ * Reverse coordinate direction of a LineString feature
2980
+ */
2981
+ reverseLine(layerId: string, featureId: string | number): Feature<Geometry> | null;
2982
+ /**
2983
+ * Subtract a cutting feature from a target feature
2984
+ */
2985
+ differenceFeature(layerId: string, targetId: string | number, cutterId: string | number): Feature<Polygon | MultiPolygon> | null;
2986
+ /**
2987
+ * Calculate intersection between two polygons
2988
+ */
2989
+ intersectFeatures(layerId: string, idA: string | number, idB: string | number): Feature<Polygon | MultiPolygon> | null;
2990
+ /**
2991
+ * Pointer shape for what is happening now: answering a point prompt always wins (it can be asked for
2992
+ * in any mode), then the active drawing mode, and nothing at all when no tool is running.
2993
+ */
2994
+ private applyCursor;
2995
+ /** Current guide settings (a copy: change them through `setGuides`) */
2996
+ getGuides(): DrawGuideSettings;
2997
+ /**
2998
+ * Turn drawing guides on or off. Only the keys given change, and the preview redraws at once so a
2999
+ * toggle is visible without moving the mouse.
3000
+ */
3001
+ setGuides(settings: Partial<DrawGuideSettings>): DrawGuideSettings;
3002
+ /** Dashed lines across the whole viewport through `anchor` */
3003
+ private crosshairFeatures;
3004
+ private formatLength;
3005
+ /**
3006
+ * Measurements written on the drawing: one label per segment at its midpoint, and the area of a
3007
+ * polygon at its centre. Overlapping labels are dropped by the map's own text collision handling,
3008
+ * so a dense outline thins out instead of turning into a smear.
3009
+ */
3010
+ /** Screen-space helper: the map, when it can convert between pixels and coordinates */
3011
+ private projector;
3012
+ /**
3013
+ * A drawn dimension for one segment: two extension lines out from the ends and a dimension line
3014
+ * between them, offset to the side, carrying the length. No arrowheads.
3015
+ *
3016
+ * The offset is measured in pixels, so the dimension keeps the same distance from the segment at
3017
+ * every zoom. Without a projection (headless, or an adapter that cannot project) it falls back to
3018
+ * a plain label at the midpoint.
3019
+ */
3020
+ private dimensionFeatures;
3021
+ /**
3022
+ * Arc and degrees at one corner. The turn from one leg to the other is normalised to (-180°, 180°],
3023
+ * so the angle shown is always the one of 180 degrees or less and the arc is drawn on that side.
3024
+ */
3025
+ private angleFeatures;
3026
+ private measurementFeatures;
3027
+ private updateTempFeatures;
3028
+ /**
3029
+ * Render real-time preview of drag box marquee selection
3030
+ */
3031
+ private updateDragBoxPreview;
3032
+ /**
3033
+ * Query all features within or intersecting the given geometry across visible layers
3034
+ */
3035
+ queryFeaturesInGeometry(geom: Feature<Polygon>): Array<{
3036
+ layerId: string;
3037
+ feature: Feature<Geometry, any>;
3038
+ }>;
3039
+ /**
3040
+ * Execute selection for draw-selection modes (box or polygon)
3041
+ */
3042
+ executeDrawSelection(mode: 'select-box' | 'select-polygon', selectionPolygon: Feature<Polygon>, multi?: boolean): void;
3043
+ /**
3044
+ * Visual flash highlight for features to confirm CAD operation execution
3045
+ */
3046
+ flashFeatures(features: Feature<Geometry, any> | Feature<Geometry, any>[], durationMs?: number): void;
3047
+ private clearTempFeatures;
3048
+ destroy(): void;
3049
+ }
3050
+
3051
+ export declare class OFSDynamicInputWidget {
3052
+ private drawTools;
3053
+ private consoleWidget;
3054
+ private container;
3055
+ private root;
3056
+ private promptEl;
3057
+ private labelEl;
3058
+ private inputEl;
3059
+ private unsubscribers;
3060
+ private keyHandler;
3061
+ private state;
3062
+ private lastCoordinate;
3063
+ /** Pixel offset of the HUD from the cursor */
3064
+ offset: {
3065
+ x: number;
3066
+ y: number;
3067
+ };
3068
+ constructor(drawTools: OFSDrawTools, consoleWidget: OFSWebConsoleWidget);
3069
+ /**
3070
+ * Attach the HUD to the map container (the element that holds the map canvas).
3071
+ */
3072
+ mount(target: HTMLElement | string): void;
3073
+ unmount(): void;
3074
+ private isActive;
3075
+ private bindEvents;
3076
+ private hideInput;
3077
+ private render;
3078
+ }
3079
+
3080
+ /**
3081
+ * OFSObject Core Errors
3082
+ */
3083
+ export declare class OFSError extends Error {
3084
+ constructor(message: string);
3085
+ }
3086
+
3087
+ export declare interface OFSFeatureMetadata {
3088
+ createdAt?: number;
3089
+ updatedAt?: number;
3090
+ sourceLayer?: string;
3091
+ [key: string]: unknown;
3092
+ }
3093
+
3094
+ export declare class OFSFileIO {
3095
+ private dataSource;
3096
+ constructor(dataSource: OFSDataSource);
3097
+ /** Parse and add files as new layers */
3098
+ import(files: InputFile[], options?: ImportOptions): ImportToDataSourceResult;
3099
+ /** Browser File objects (from <input type="file"> or drag & drop) */
3100
+ importFileList(fileList: FileList | File[], options?: ImportOptions): Promise<ImportToDataSourceResult>;
3101
+ /** Export one or more layers. Shapefile / KML / GeoJSON / CSV merge the layers; DXF keeps them as CAD layers. */
3102
+ export(layerIds: string[], format: ExportFormat, options?: ExportOptions): {
3103
+ file: ExportedFile;
3104
+ issues: ImportIssue[];
3105
+ };
3106
+ /** Save an exported file in the browser */
3107
+ static download(file: ExportedFile): void;
3108
+ }
3109
+
3110
+ export declare class OFSGripsEditor extends TypedEventEmitter<GripsEditorEvents> {
3111
+ private dataSource;
3112
+ private mapAdapter;
3113
+ private snapping;
3114
+ private currentSnapResult;
3115
+ private sourceId;
3116
+ private activeFeatureId;
3117
+ private activeLayerId;
3118
+ private activeGrip;
3119
+ private isDragging;
3120
+ private dragHasMoved;
3121
+ private isEnabled;
3122
+ private activationTimestamp;
3123
+ private initialFeatureSnapshot;
3124
+ private unsubClick;
3125
+ private unsubMouseDown;
3126
+ private unsubMouseUp;
3127
+ private unsubMove;
3128
+ private unsubContextMenu;
3129
+ private handleKeyDown;
3130
+ constructor(dataSource: OFSDataSource, mapAdapter: IMapAdapter, snapping?: SnappingEngine);
3131
+ setSnappingEngine(snapping: SnappingEngine | null): void;
3132
+ getSnappingEngine(): SnappingEngine | null;
3133
+ /**
3134
+ * Start editing a feature's geometry with grips
3135
+ */
3136
+ editFeature(layerId: string, featureId: string | number): void;
3137
+ /**
3138
+ * Stop editing and clear grips
3139
+ */
3140
+ clear(): void;
3141
+ getActiveFeature(): Feature<Geometry, any> | null;
3142
+ getActiveLayerId(): string | null;
3143
+ getActiveFeatureId(): string | number | null;
3144
+ getIsEditing(): boolean;
3145
+ hasHandleAt(coord: Coordinate, tolerancePx?: number): boolean;
3146
+ /**
3147
+ * Generate grip handles for the active feature
3148
+ */
3149
+ getHandles(): GripHandle[];
3150
+ private setupLayers;
3151
+ private renderGrips;
3152
+ private clearSource;
3153
+ private bindEvents;
3154
+ private findNearestHandle;
3155
+ private handleMouseDown;
3156
+ private handleMouseUp;
3157
+ private handleClick;
3158
+ private handleContextMenu;
3159
+ private handleMove;
3160
+ private applyCoordinateChange;
3161
+ private insertVertexAtMidpoint;
3162
+ /**
3163
+ * Delete selected vertex
3164
+ */
3165
+ deleteVertex(gripIndex: number, ringIndex?: number, partIndex?: number): boolean;
3166
+ destroy(): void;
3167
+ }
3168
+
3169
+ export declare class OFSLayerData {
3170
+ readonly id: string;
3171
+ name: string;
3172
+ type: LayerGeometryType;
3173
+ zIndex: number;
3174
+ visible: boolean;
3175
+ opacity: number;
3176
+ pinned: boolean;
3177
+ tag?: string;
3178
+ groupId?: string;
3179
+ sourceCrs?: string;
3180
+ sourceFile?: string;
3181
+ fields?: LayerMetadata['fields'];
3182
+ private featuresMap;
3183
+ private spatialIndex;
3184
+ private indexItems;
3185
+ private cachedFieldStats;
3186
+ constructor(metadata: LayerMetadata, initialFeatures?: Feature<Geometry, any>[]);
3187
+ /**
3188
+ * Get all features as array
3189
+ */
3190
+ getFeatures(): Feature<Geometry, any>[];
3191
+ /**
3192
+ * Get feature count
3193
+ */
3194
+ get count(): number;
3195
+ /**
3196
+ * Resolve the stored map key for an ID. Accepts the exact ID or its numeric/string twin
3197
+ * (e.g. 5 and "5"), which map engines and CLI input may produce. Never falls back to
3198
+ * array position or attribute values, so a lookup can only ever return the intended feature.
3199
+ */
3200
+ private resolveKey;
3201
+ /**
3202
+ * Get single feature by ID
3203
+ */
3204
+ getFeature(id: string | number): Feature<Geometry, any> | undefined;
3205
+ /**
3206
+ * Check whether a feature ID (or its numeric/string twin) exists in this layer
3207
+ */
3208
+ hasFeature(id: string | number): boolean;
3209
+ /**
3210
+ * Return `preferredId` if it is free, otherwise the first free `${preferredId}_2`, `_3`, ...
3211
+ * Without a preferred ID a random unique ID is generated.
3212
+ */
3213
+ getAvailableId(preferredId?: string | number): string | number;
3214
+ /**
3215
+ * Add a single feature (generates unique ID if missing).
3216
+ * @throws DuplicateFeatureIdError if a feature with the same ID already exists
3217
+ */
3218
+ addFeature(feature: Feature<Geometry, any>): Feature<Geometry, any>;
3219
+ /**
3220
+ * Add multiple features
3221
+ */
3222
+ addFeatures(features: Feature<Geometry, any>[]): Feature<Geometry, any>[];
3223
+ /**
3224
+ * Update an existing feature
3225
+ */
3226
+ updateFeature(feature: Feature<Geometry, any>): boolean;
3227
+ /**
3228
+ * Change only the properties of a feature. The geometry object is kept as it is - no copy, no
3229
+ * re-indexing - which is what makes editing an attribute of every feature in a large layer affordable.
3230
+ * A property given as `undefined` is removed.
3231
+ * @returns the stored feature, or null when there is no such feature
3232
+ */
3233
+ updateProperties(id: string | number, patch: Record<string, unknown>): Feature<Geometry, any> | null;
3234
+ /**
3235
+ * Remove a feature by ID
3236
+ */
3237
+ removeFeature(id: string | number): boolean;
3238
+ /**
3239
+ * Replace all features.
3240
+ * Features sharing an ID are kept by giving later duplicates a suffixed ID (with a warning).
3241
+ */
3242
+ setFeatures(features: Feature<Geometry, any>[]): void;
3243
+ /**
3244
+ * Clear all features
3245
+ */
3246
+ clear(): void;
3247
+ /**
3248
+ * Export as GeoJSON FeatureCollection
3249
+ */
3250
+ toGeoJSON(): FeatureCollection<Geometry, any>;
3251
+ /**
3252
+ * Compute bounding box [minLng, minLat, maxLng, maxLat] from the spatial index (O(1))
3253
+ */
3254
+ getBoundingBox(): BoundingBox;
3255
+ /**
3256
+ * Features whose bounding boxes intersect the given bbox. This is a fast candidate filter;
3257
+ * callers needing exact geometry tests should refine the result.
3258
+ */
3259
+ queryBBox(bbox: BoundingBox): Feature<Geometry, any>[];
3260
+ /**
3261
+ * Features whose bounding boxes lie within `radiusDegrees` of a coordinate (candidate filter).
3262
+ */
3263
+ queryNear(coord: Coordinate, radiusDegrees: number): Feature<Geometry, any>[];
3264
+ private indexFeature;
3265
+ private unindexFeature;
3266
+ /**
3267
+ * Get all property/attribute names across all features
3268
+ */
3269
+ getPropertyFields(): {
3270
+ name: string;
3271
+ type: 'number' | 'string' | 'boolean';
3272
+ }[];
3273
+ /**
3274
+ * Get statistics for a numeric field (cached)
3275
+ */
3276
+ getNumericFieldStats(fieldName: string): NumericFieldStats | null;
3277
+ /**
3278
+ * Get statistics for a categorical field (cached)
3279
+ */
3280
+ getCategoricalFieldStats(fieldName: string): CategoricalFieldStats | null;
3281
+ private invalidateCache;
3282
+ }
3283
+
3284
+ export declare class OFSLegendTools extends TypedEventEmitter<LegendEvents> {
3285
+ private dataSource;
3286
+ private thematicEngine;
3287
+ private unsubscribers;
3288
+ private groupCounter;
3289
+ constructor(dataSource: OFSDataSource, thematicEngine?: OFSThematicEngine);
3290
+ private bindDataSourceEvents;
3291
+ /**
3292
+ * Get the current complete Legend Snapshot
3293
+ */
3294
+ getSnapshot(): LegendSnapshot;
3295
+ private isGroupRendered;
3296
+ private buildTree;
3297
+ /**
3298
+ * Notify subscribers of a state change
3299
+ */
3300
+ notifyUpdate(): void;
3301
+ toggleLayerVisibility(layerId: string): void;
3302
+ setLayerOpacity(layerId: string, opacity: number): void;
3303
+ setActiveLayer(layerId: string): void;
3304
+ toggleLayerPinned(layerId: string): void;
3305
+ /** Move a layer one place up among its siblings in the legend tree (above a sibling group as a whole) */
3306
+ moveLayerUp(layerId: string): void;
3307
+ moveLayerDown(layerId: string): void;
3308
+ moveGroupUp(groupId: string): void;
3309
+ moveGroupDown(groupId: string): void;
3310
+ private nodeLayers;
3311
+ private findSiblings;
3312
+ /** direction -1 = up (towards the top of the legend), 1 = down */
3313
+ private moveNode;
3314
+ addGroup(name: string, parentId?: string | null, id?: string): string;
3315
+ removeGroup(groupId: string): void;
3316
+ renameGroup(groupId: string, name: string): void;
3317
+ toggleGroupVisibility(groupId: string): void;
3318
+ toggleGroupExpanded(groupId: string): void;
3319
+ /** Put a layer into a group (null = top level); it is placed on top of that group's layers */
3320
+ moveLayerToGroup(layerId: string, groupId: string | null): void;
3321
+ setThematicSimple(layerId: string, color: string): void;
3322
+ setThematicCategorical(layerId: string, fieldName: string, palette?: PaletteName | string, options?: CategoricalThemeOptions): void;
3323
+ setThematicGraduated(layerId: string, fieldName: string, method?: ClassificationMethod, classes?: number, palette?: PaletteName | string, options?: GraduatedThemeOptions): void;
3324
+ /** Recompute classes from current data, keeping hidden classes and overrides */
3325
+ reclassify(layerId: string): void;
3326
+ updateBaseSymbol(layerId: string, patch: SymbolStyleInput): void;
3327
+ /** Labels from a field or an attribute expression (null removes them) */
3328
+ setLabel(layerId: string, settings: LabelSettings | null): void;
3329
+ getLabel(layerId: string): LabelSettings | undefined;
3330
+ /** Show / hide one class (index -1 = "all other values") */
3331
+ setClassVisible(layerId: string, classIndex: number, visible: boolean): void;
3332
+ toggleClassVisible(layerId: string, classIndex: number): void;
3333
+ setAllClassesVisible(layerId: string, visible: boolean): void;
3334
+ updateClass(layerId: string, classIndex: number, patch: ClassPatch): void;
3335
+ getThematicEngine(): OFSThematicEngine;
3336
+ getDataSource(): OFSDataSource;
3337
+ destroy(): void;
3338
+ }
3339
+
3340
+ export declare interface OFSMacro {
3341
+ name: string;
3342
+ commands: string[];
3343
+ createdAt: number;
3344
+ description?: string;
3345
+ }
3346
+
3347
+ export declare class OFSMacroStore {
3348
+ private readonly engine;
3349
+ private macros;
3350
+ private recording;
3351
+ private unsubscribe;
3352
+ constructor(engine: OFSCommandEngine);
3353
+ private load;
3354
+ private persist;
3355
+ isRecording(): boolean;
3356
+ recordingName(): string | null;
3357
+ recordedCount(): number;
3358
+ /** Start recording into `name` (an existing macro with that name is replaced when recording stops) */
3359
+ startRecording(name: string): void;
3360
+ /** Stop recording and keep the macro (empty recordings are discarded) */
3361
+ stopRecording(): OFSMacro | null;
3362
+ cancelRecording(): void;
3363
+ list(): OFSMacro[];
3364
+ get(name: string): OFSMacro | undefined;
3365
+ save(macro: OFSMacro): OFSMacro;
3366
+ remove(name: string): boolean;
3367
+ export(): OFSMacro[];
3368
+ import(macros: OFSMacro[], replace?: boolean): number;
3369
+ }
3370
+
3371
+ /**
3372
+ * OFSObject - Unified GIS Orchestrator
3373
+ */
3374
+ export declare class OFSObject {
3375
+ readonly dataSource: OFSDataSource;
3376
+ readonly thematicEngine: OFSThematicEngine;
3377
+ readonly mapAdapter: IMapAdapter;
3378
+ readonly drawTools: OFSDrawTools;
3379
+ readonly legendTools: OFSLegendTools;
3380
+ /** The built-in console widget, or null when the host passed its own `config.console` */
3381
+ readonly consoleWidget: OFSWebConsoleWidget | null;
3382
+ /** Where commands print and ask for input: the built-in widget unless one was passed in */
3383
+ readonly console: IOFSConsole;
3384
+ readonly commandEngine: OFSCommandEngine;
3385
+ readonly aiBridge: OFSAiBridge;
3386
+ /** File import / export (GeoJSON, Shapefile, KML/KMZ, CSV, DXF) */
3387
+ readonly io: OFSFileIO;
3388
+ /** Topology checks (invalid geometry, overlaps, gaps, slivers, near-miss vertices) and fixes */
3389
+ readonly topology: OFSTopologyTools;
3390
+ /** Attribute schema, table, field calculator, select by attribute / location */
3391
+ readonly attributes: OFSAttributeTools;
3392
+ /** Recorded command macros (kept in localStorage in the browser) */
3393
+ readonly macros: OFSMacroStore;
3394
+ private dynamicInput;
3395
+ /** Map handed over by the host application (config.map), attached on init() */
3396
+ private readonly hostMap;
3397
+ constructor(config?: OFSObjectConfig);
3398
+ /**
3399
+ * Initialize map adapter and bind data source.
3400
+ *
3401
+ * With `config.map` the host's map is attached instead and no container is needed; passing no
3402
+ * container and no map binds the data source to an adapter the caller has already started.
3403
+ */
3404
+ init(container?: HTMLElement | string, options?: Record<string, any>): Promise<void>;
3405
+ /**
3406
+ * Show the AutoCAD-style dynamic input HUD next to the cursor (distance, angle, snap, prompt).
3407
+ * While enabled, typing during drawing or point prompts goes to the HUD instead of the console.
3408
+ * @param container Map container element; defaults to the map engine's container
3409
+ */
3410
+ enableDynamicInput(container?: HTMLElement | string): OFSDynamicInputWidget;
3411
+ /** Remove the dynamic input HUD and send typing back to the command line */
3412
+ disableDynamicInput(): void;
3413
+ isDynamicInputEnabled(): boolean;
3414
+ private registerDefaultCommands;
3415
+ /**
3416
+ * Clean up all resources
3417
+ */
3418
+ destroy(): void;
3419
+ }
3420
+
3421
+ export declare interface OFSObjectConfig {
3422
+ mapAdapter?: IMapAdapter;
3423
+ container?: HTMLElement | string;
3424
+ mapOptions?: Record<string, any>;
3425
+ /**
3426
+ * A MapLibre / Mapbox map the host application created and keeps owning (Angular, React, Vue).
3427
+ * `init()` then attaches to it instead of creating one, and `destroy()` leaves it running.
3428
+ * With a Mapbox map, pass `mapAdapter: new MapboxAdapter()` as well.
3429
+ */
3430
+ map?: unknown;
3431
+ /**
3432
+ * Replace the built-in command console with the host application's own (Angular, React, Vue).
3433
+ * Commands and `aiBridge` then print and ask for input through it, and `consoleWidget` is null.
3434
+ *
3435
+ * Most applications do not need this: the built-in widget also works without `mount()` — drive it
3436
+ * with `consoleWidget.submit(text)` and render the `console:line` / `console:prompt` events.
3437
+ */
3438
+ console?: IOFSConsole;
3439
+ }
3440
+
3441
+ declare class OFSSelectionOverlay {
3442
+ private dataSource;
3443
+ private mapAdapter;
3444
+ private selectionSourceId;
3445
+ private hoverSourceId;
3446
+ private flashSourceId;
3447
+ private unsubSelection;
3448
+ private currentHoveredFeatureId;
3449
+ private flashTimer;
3450
+ constructor(dataSource: OFSDataSource, mapAdapter: IMapAdapter);
3451
+ /**
3452
+ * Setup GeoJSON sources and MapLibre/Mapbox styling layers for selection and hover feedback
3453
+ */
3454
+ setupLayers(): void;
3455
+ /**
3456
+ * Keep selection and hover overlay layers top-most
3457
+ */
3458
+ bringToFront(): void;
3459
+ /**
3460
+ * Synchronize selection highlights from data source
3461
+ */
3462
+ syncSelectionOverlay(): void;
3463
+ /**
3464
+ * Preview selection highlights in real-time (e.g. while dragging marquee box)
3465
+ */
3466
+ previewSelection(features: Feature<Geometry, any>[]): void;
3467
+ /**
3468
+ * Set currently hovered feature highlight
3469
+ */
3470
+ setHoverFeature(feature: Feature<Geometry, any> | null): void;
3471
+ /**
3472
+ * Flash animation effect on features to confirm CAD operation success
3473
+ */
3474
+ flashFeatures(features: Feature<Geometry, any> | Feature<Geometry, any>[], durationMs?: number): void;
3475
+ /**
3476
+ * Cleanup
3477
+ */
3478
+ destroy(): void;
3479
+ }
3480
+
3481
+ export declare class OFSSymbologyPanel {
3482
+ private legendTools;
3483
+ private container;
3484
+ private layerId;
3485
+ private unsubscribers;
3486
+ private options;
3487
+ /** Renderer settings chosen in the form but not yet applied with "Classify" */
3488
+ private draft;
3489
+ constructor(legendTools: OFSLegendTools, options?: SymbologyPanelOptions);
3490
+ mount(target: HTMLElement | string): void;
3491
+ unmount(): void;
3492
+ /** Edit a layer's symbology */
3493
+ open(layerId: string): void;
3494
+ getLayerId(): string | null;
3495
+ private get layer();
3496
+ private get theme();
3497
+ private render;
3498
+ /** Labels tab: field or expression, size, colour, halo and zoom range */
3499
+ private renderLabels;
3500
+ private renderClassification;
3501
+ private renderClassTable;
3502
+ private dashSelect;
3503
+ private renderSymbolEditor;
3504
+ private classify;
3505
+ private handleClick;
3506
+ private handleChange;
3507
+ }
3508
+
3509
+ export declare class OFSThematicEngine extends TypedEventEmitter<ThematicEvents> {
3510
+ private themes;
3511
+ constructor();
3512
+ /**
3513
+ * Get current theme definition for a layer
3514
+ */
3515
+ getTheme(layerId: string): ThematicDefinition | undefined;
3516
+ /**
3517
+ * Set explicit theme definition for a layer
3518
+ */
3519
+ setTheme(theme: ThematicDefinition): void;
3520
+ removeTheme(layerId: string): void;
3521
+ /** All themes as JSON-safe copies (for saving a project) */
3522
+ exportThemes(): ThematicDefinition[];
3523
+ /** Restore themes saved with exportThemes */
3524
+ importThemes(themes: ThematicDefinition[]): void;
3525
+ private carriedSymbol;
3526
+ /**
3527
+ * Create a simple uniform color theme
3528
+ */
3529
+ createSimpleTheme(layerId: string, style?: SimpleStyle, defaultColor?: string): ThematicDefinition;
3530
+ /**
3531
+ * Create a categorical / unique values theme based on an attribute field
3532
+ */
3533
+ createCategoricalTheme(layer: OFSLayerData, fieldName: string, palette?: PaletteName | string, defaultColor?: string, options?: CategoricalThemeOptions): ThematicDefinition;
3534
+ /**
3535
+ * Create a graduated / choropleth theme based on a numeric attribute field
3536
+ */
3537
+ createGraduatedTheme(layer: OFSLayerData, fieldName: string, method?: ClassificationMethod, numClasses?: number, palette?: PaletteName | string, defaultColor?: string, options?: GraduatedThemeOptions): ThematicDefinition;
3538
+ /**
3539
+ * Graduated theme with manual class upper bounds (the first class starts at `lower`, or the data minimum)
3540
+ */
3541
+ setManualBreaks(layer: OFSLayerData, uppers: number[], lower?: number): ThematicDefinition;
3542
+ /**
3543
+ * Recompute classes from the current data with the theme's own settings. Hidden classes and class
3544
+ * symbol overrides are kept where the same category value / class position still exists.
3545
+ */
3546
+ reclassify(layer: OFSLayerData): ThematicDefinition | undefined;
3547
+ private createCategoricalThemeData;
3548
+ /**
3549
+ * Merge changes into the base symbol (creates a simple theme when the layer has none)
3550
+ */
3551
+ updateBaseSymbol(layerId: string, patch: SymbolStyleInput): ThematicDefinition;
3552
+ /**
3553
+ * Set or change the labels of a layer (pass null to remove them). Creates a simple theme when the
3554
+ * layer has none, so labels can be turned on without styling the layer first.
3555
+ */
3556
+ setLabel(layerId: string, settings: LabelSettings | null): ThematicDefinition;
3557
+ getLabel(layerId: string): LabelSettings | undefined;
3558
+ /**
3559
+ * Show or hide one class (index -1 = "all other values")
3560
+ */
3561
+ setClassVisible(layerId: string, classIndex: number, visible: boolean): void;
3562
+ setAllClassesVisible(layerId: string, visible: boolean): void;
3563
+ /**
3564
+ * Edit one class. Changing a graduated boundary also moves the touching boundary of the neighbour
3565
+ * class so classes stay contiguous (as in QGIS), and regenerates labels unless one is given.
3566
+ */
3567
+ updateClass(layerId: string, classIndex: number, patch: ClassPatch): void;
3568
+ private classList;
3569
+ private requireTheme;
3570
+ private defaultTheme;
3571
+ /**
3572
+ * Theme of a layer, creating the default simple theme silently (no event) when it has none
3573
+ */
3574
+ getEffectiveTheme(layerId: string): ThematicDefinition;
3575
+ /**
3576
+ * Compile layer's theme into GL style
3577
+ */
3578
+ compile(layer: OFSLayerData): CompiledLayerStyle;
3579
+ }
3580
+
3581
+ export declare class OFSTopologyPanel {
3582
+ private readonly dataSource;
3583
+ private readonly topology;
3584
+ private readonly panelOptions;
3585
+ private container;
3586
+ private unsubscribers;
3587
+ private layerId;
3588
+ private options;
3589
+ private disabledChecks;
3590
+ private busy;
3591
+ /** Set while a check runs, so it can be stopped from the panel */
3592
+ private running;
3593
+ private progress;
3594
+ private message;
3595
+ private stale;
3596
+ constructor(dataSource: OFSDataSource, topology: OFSTopologyTools, panelOptions?: TopologyPanelOptions);
3597
+ mount(target: HTMLElement | string): void;
3598
+ unmount(): void;
3599
+ /** Select the layer shown in the panel */
3600
+ open(layerId: string): void;
3601
+ private dataLayers;
3602
+ private currentLayerId;
3603
+ private currentReport;
3604
+ private render;
3605
+ private renderReport;
3606
+ private handleChange;
3607
+ private handleClick;
3608
+ private runCheck;
3609
+ /** Fix one issue (number) or every fixable issue of one code (string) */
3610
+ private runFix;
3611
+ private ask;
3612
+ }
3613
+
3614
+ export declare class OFSTopologyTools {
3615
+ private readonly dataSource;
3616
+ private readonly thematicEngine?;
3617
+ private readonly reports;
3618
+ private readonly listeners;
3619
+ private issueLayersFor;
3620
+ constructor(dataSource: OFSDataSource, thematicEngine?: OFSThematicEngine | undefined);
3621
+ /** Called with the new report after every check / fix (null when a report is cleared) */
3622
+ onChange(listener: Listener): () => void;
3623
+ private emit;
3624
+ /** Check a layer. Options are remembered and reused when the layer is re-checked after a fix. */
3625
+ check(layerId: string, options?: TopologyOptions): TopologyReport;
3626
+ /**
3627
+ * The same check, but it lets the page breathe: `onProgress` follows the work and an aborted `signal`
3628
+ * stops it. On a layer of 98,000 parcels the overlap and gap checks each take about a minute.
3629
+ */
3630
+ checkAsync(layerId: string, options?: TopologyOptions, control?: {
3631
+ onProgress?: (progress: TopologyProgress) => void;
3632
+ signal?: AbortSignal;
3633
+ }): Promise<TopologyReport>;
3634
+ private checkTarget;
3635
+ private storeReport;
3636
+ /** Re-run the last check of a layer with the same options */
3637
+ recheck(layerId: string): TopologyReport;
3638
+ /** Last report of a layer, or the most recent report of any layer */
3639
+ getReport(layerId?: string): TopologyReport | undefined;
3640
+ getIssue(issueId: number, layerId?: string): TopologyIssue | undefined;
3641
+ clear(layerId?: string): void;
3642
+ /** Bounding box to zoom to an issue (padded so points and tiny areas are visible) */
3643
+ issueBBox(issue: TopologyIssue, paddingMeters?: number): BoundingBox;
3644
+ /** Show the issues of a layer's last report as two layers (areas + locations) in a "Topology errors" group */
3645
+ showIssues(layerId?: string): void;
3646
+ hideIssues(): void;
3647
+ isShowingIssues(): boolean;
3648
+ /** Apply the automatic fix of one issue (one undo step), then re-check the layer */
3649
+ fixIssue(issueId: number, options?: TopologyFixOptions, layerId?: string): TopologyFixResult;
3650
+ /**
3651
+ * Fix several issues in one undo step. Fixes use the current geometry, so later issues see earlier fixes;
3652
+ * issues an earlier fix already resolved, and gaps whose neighbours changed, are `skipped` (re-check and run
3653
+ * again). An issue whose fix is refused is reported in `failed`.
3654
+ */
3655
+ fixIssues(issueIds: number[], options?: TopologyFixOptions, layerId?: string): TopologyBatchResult;
3656
+ private storedFor;
3657
+ private resolveIssue;
3658
+ /** Features must be as they were at check time, or as an earlier fix of the same batch left them */
3659
+ private assertCurrent;
3660
+ private applyFix;
3661
+ }
3662
+
3663
+ export declare class OFSWebConsoleWidget extends TypedEventEmitter<ConsoleEventMap> implements IOFSConsole {
3664
+ private container;
3665
+ private lines;
3666
+ private history;
3667
+ private historyIndex;
3668
+ private engine;
3669
+ private pointProvider;
3670
+ private inputInterceptor;
3671
+ private typeToFocusHandler;
3672
+ private typeToFocusCondition;
3673
+ private waitingInput;
3674
+ private currentPromptText;
3675
+ private pendingResolve;
3676
+ private pendingReject;
3677
+ private outputEl;
3678
+ private promptLabelEl;
3679
+ private inputEl;
3680
+ constructor();
3681
+ /** The transcript so far, for a host UI that mounts after commands have already run */
3682
+ getLines(): readonly ConsoleLine[];
3683
+ setEngine(engine: OFSCommandEngine): void;
3684
+ /** Allow point prompts to be answered by clicking the map */
3685
+ setPointProvider(provider: ConsolePointProvider | null): void;
3686
+ /** Route command-line text to another handler first (e.g. coordinate input while drawing) */
3687
+ setInputInterceptor(interceptor: ConsoleInputInterceptor | null): void;
3688
+ /**
3689
+ * While `shouldCapture()` is true, typing anywhere on the page (outside other inputs) goes to the
3690
+ * command line, like AutoCAD dynamic input.
3691
+ */
3692
+ enableTypeToFocus(shouldCapture: () => boolean): void;
3693
+ private attachTypeToFocus;
3694
+ disableTypeToFocus(): void;
3695
+ private detachTypeToFocus;
3696
+ mount(target: HTMLElement | string): void;
3697
+ unmount(): void;
3698
+ focus(): void;
3699
+ setInput(text: string): void;
3700
+ print(text: string, kind?: ConsoleLineKind): void;
3701
+ clear(): void;
3702
+ requestInput(promptText: string): Promise<string>;
3703
+ requestPointOrText(promptText: string, options?: {
3704
+ basePoint?: Coordinate | null;
3705
+ }): Promise<{
3706
+ point: Coordinate;
3707
+ } | {
3708
+ text: string;
3709
+ }>;
3710
+ requestPoint(promptText: string, options?: {
3711
+ basePoint?: Coordinate | null;
3712
+ }): Promise<Coordinate | null>;
3713
+ cancel(): void;
3714
+ /** Prompt text of the pending request, or null when no command is waiting for input */
3715
+ getPromptText(): string | null;
3716
+ isWaitingInput(): boolean;
3717
+ /**
3718
+ * Fulfill current pending request with string
3719
+ */
3720
+ fulfill(text: string): boolean;
3721
+ private cancelPending;
3722
+ private clearPending;
3723
+ /**
3724
+ * Submit command-line text exactly as if typed and Enter was pressed:
3725
+ * answers a waiting prompt, else goes to the input interceptor (drawing input), else runs a command.
3726
+ * Use from buttons or other input surfaces (e.g. the dynamic input HUD).
3727
+ */
3728
+ submit(text: string): void;
3729
+ /** Cancel the running command (same as Escape in the command line) */
3730
+ cancelCommand(): void;
3731
+ private setupListeners;
3732
+ /**
3733
+ * Tab completion: command names on the first word, then the command's options (from its schema).
3734
+ * A single match is filled in; several matches fill in their common prefix and are listed.
3735
+ */
3736
+ private handleTabAutocomplete;
3737
+ /** Fill in a single match, or the common prefix of several, and list them */
3738
+ private completeInto;
3739
+ private renderLines;
3740
+ private escapeHtml;
3741
+ }
3742
+
3743
+ export declare interface OFSWorkflowContext {
3744
+ jobId: string;
3745
+ status: WorkflowStatus;
3746
+ commands: string[];
3747
+ currentIndex: number;
3748
+ currentCommandName: string | null;
3749
+ currentPrompt: string | null;
3750
+ initialData: any;
3751
+ payload: any;
3752
+ intermediate: Map<string, any>;
3753
+ history: CommandHistoryItem[];
3754
+ abortSignal?: AbortSignal;
3755
+ }
3756
+
3757
+ /** Notified when an icon is registered or replaced (map adapters refresh their images) */
3758
+ export declare function onMarkerIconRegistered(listener: (name: string) => void): () => void;
3759
+
3760
+ declare type OptionMap = Map<string, OptionValue>;
3761
+
3762
+ /** camelCase → kebab-case, the spelling used for command line options */
3763
+ export declare function optionName(property: string): string;
3764
+
3765
+ /** Every option spelling a command accepts: its schema properties, its aliases and its switches */
3766
+ export declare function optionSpellings(command: OFSCommandProcess): string[];
3767
+
3768
+ /** Style options as they appear on the command line; the values keep the type the schema gives them */
3769
+ declare type OptionValue = string | number | boolean | number[] | true;
3770
+
3771
+ export declare class OrthoEngine {
3772
+ /**
3773
+ * Calculate orthogonal coordinate from anchor point to current cursor
3774
+ */
3775
+ static calculateOrtho(anchor: Coordinate, cursor: Coordinate, frame?: InputFrame): OrthoResult;
3776
+ }
3777
+
3778
+ export declare interface OrthoResult {
3779
+ coordinate: Coordinate;
3780
+ distanceMeters: number;
3781
+ bearingDegrees: number;
3782
+ axis: 'horizontal' | 'vertical';
3783
+ }
3784
+
3785
+ export declare interface OSnapModes {
3786
+ /** Endpoint / vertex */
3787
+ vertex: boolean;
3788
+ /** Crossing point of two segments (different features or the same feature) */
3789
+ intersection: boolean;
3790
+ midpoint: boolean;
3791
+ /** Center of circle features (drawn with the circle tool) */
3792
+ center: boolean;
3793
+ /** Foot of the perpendicular from the previous point onto a segment */
3794
+ perpendicular: boolean;
3795
+ /** Nearest point on an edge */
3796
+ edge: boolean;
3797
+ }
3798
+
3799
+ declare type Palette = PaletteName | string | string[];
3800
+
3801
+ export declare type PaletteName = keyof typeof PALETTES;
3802
+
3803
+ /** Legacy short palettes (kept for existing callers) */
3804
+ export declare const PALETTES: {
3805
+ readonly viridis: readonly ["#440154", "#3b528b", "#21918c", "#5ec962", "#fde725"];
3806
+ readonly magma: readonly ["#000004", "#51127c", "#b73779", "#fb8861", "#fcfdbf"];
3807
+ readonly blues: readonly ["#eff3ff", "#bdd7e7", "#6baed6", "#3182bd", "#08519c"];
3808
+ readonly greens: readonly ["#edf8e9", "#bae4b3", "#74c476", "#31a354", "#006d2c"];
3809
+ readonly oranges: readonly ["#feedde", "#fdbe85", "#fd8d3c", "#e6550d", "#a63603"];
3810
+ readonly purples: readonly ["#f2f0f7", "#cbc9e2", "#9e9ac8", "#756bb1", "#54278f"];
3811
+ readonly ylgnbu: readonly ["#ffffd9", "#c7e9b4", "#41b6c4", "#225ea8", "#081d58"];
3812
+ readonly ylorrd: readonly ["#ffffb2", "#fecc5c", "#fd8d3c", "#f03b20", "#bd0026"];
3813
+ readonly spectral: readonly ["#d7191c", "#fdae61", "#ffffbf", "#abdda4", "#2b83ba"];
3814
+ readonly rdylgn: readonly ["#d73027", "#fc8d59", "#fee08b", "#d9ef8b", "#91cf60", "#1a9850"];
3815
+ readonly rdbu: readonly ["#ca0020", "#f4a582", "#f7f7f7", "#92c5de", "#0571b0"];
3816
+ readonly category10: readonly ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"];
3817
+ readonly set1: readonly ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf"];
3818
+ readonly set2: readonly ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"];
3819
+ readonly pastel: readonly ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec"];
3820
+ };
3821
+
3822
+ /**
3823
+ * Parse the raw argument text (or a JSON object) of a command into typed arguments.
3824
+ * @throws ArgumentError when a value does not fit the schema
3825
+ */
3826
+ export declare function parseCommandArgs(command: OFSCommandProcess, raw: string, options?: {
3827
+ enforceRequired?: boolean;
3828
+ }): Record<string, unknown>;
3829
+
3830
+ /**
3831
+ * Parses JSON coordinate array string e.g. "[[100.5, 13.7], [100.6, 13.8]]"
3832
+ */
3833
+ export declare function parseCoordinateArray(raw: string): Coordinate[] | null;
3834
+
3835
+ /**
3836
+ * Parse AutoCAD-style coordinate input.
3837
+ * - `@dx,dy` relative offset in meters along the UCS axes (X = UCS east, Y = UCS north)
3838
+ * - `@dist<angle` relative polar: distance in meters at an angle in the frame's convention
3839
+ * - `dist` direct distance entry: distance in meters toward the cursor
3840
+ * - `lng,lat` / `[lng,lat]` absolute geographic coordinate (longitude first, as in GeoJSON)
3841
+ * Returns null when the text is not coordinate syntax (so it can be treated as a command).
3842
+ */
3843
+ export declare function parseCoordinateInput(text: string, context?: CoordinateInputContext): CoordinateInputResult | null;
3844
+
3845
+ /** Column definitions of a CREATE TABLE statement */
3846
+ export declare function parseCreateTable(sql: string): {
3847
+ columns: SqliteColumn[];
3848
+ withoutRowid: boolean;
3849
+ };
3850
+
3851
+ export declare function parseCsv(text: string, delimiter?: string): string[][];
3852
+
3853
+ /** GeoPackage binary geometry: header (magic, flags, srs id, envelope) + WKB */
3854
+ export declare function parseGpkgGeometry(blob: Uint8Array): Geometry | null;
3855
+
3856
+ /**
3857
+ * Parse a coordinate text as [lng, lat] — longitude first, the order GeoJSON uses.
3858
+ * This is the only order the library reads: "13.7563, 100.5018" is not accepted as lat,lng, because
3859
+ * guessing the order would silently move points whenever both numbers are below 90.
3860
+ * Use `coordinateProblem()` for the message when this returns null.
3861
+ */
3862
+ export declare function parseLngLat(raw: string): Coordinate | null;
3863
+
3864
+ /** Parse a number, or null when the text is not a finite number */
3865
+ export declare function parseNumber(text: string): number | null;
3866
+
3867
+ export declare function parseWkb(bytes: Uint8Array, offset?: number): {
3868
+ geometry: Geometry;
3869
+ end: number;
3870
+ };
3871
+
3872
+ export declare function parseWkt(text: string): Geometry | null;
3873
+
3874
+ export declare function parseXml(source: string): XmlElement;
3875
+
3876
+ /** Boundary paths: polygon rings or line parts */
3877
+ export declare function pathsOf(geometry: Geometry): Position[][];
3878
+
3879
+ export declare type PlanarPoint = [number, number];
3880
+
3881
+ export declare class PlanarProjection {
3882
+ /** proj4 definition of the planar CRS */
3883
+ readonly definition: string;
3884
+ private readonly converter;
3885
+ private constructor();
3886
+ /** UTM zone number (1-60) for a longitude */
3887
+ static utmZoneFor(lng: number): number;
3888
+ /**
3889
+ * WGS84 / UTM plane (grid coordinates, scale factor 0.9996). Use for survey coordinates
3890
+ * (e.g. EPSG:32647 / 32648 in Thailand), not for ground distances.
3891
+ */
3892
+ static utm(zone: number, south?: boolean): PlanarProjection;
3893
+ /** Local ground-true plane centered near the given coordinate */
3894
+ static forCoordinate(coord: Coordinate | number[]): PlanarProjection;
3895
+ /** Local ground-true plane centered on a bounding box */
3896
+ static forBBox(bbox: BoundingBox): PlanarProjection;
3897
+ /** Local ground-true plane centered on the combined extent of one or more geometries */
3898
+ static forGeometries(geometries: Geometry[]): PlanarProjection;
3899
+ toPlanar(coord: Coordinate | number[]): PlanarPoint;
3900
+ toGeographic(point: PlanarPoint | number[]): Coordinate;
3901
+ projectGeometry<G extends Geometry>(geometry: G): G;
3902
+ unprojectGeometry<G extends Geometry>(geometry: G): G;
3903
+ /** Planar distance in meters between two lng/lat coordinates */
3904
+ distance(a: Coordinate, b: Coordinate): number;
3905
+ }
3906
+
3907
+ export declare function planHatchTile(pattern: HatchPattern, pixelRatio?: number): HatchTilePlan;
3908
+
3909
+ /** Longest 1 / 2 / 5 × 10ⁿ distance that fits in `maxWidthPx` */
3910
+ export declare function planScaleBar(metersPerPx: number, maxWidthPx: number): ScaleBarPlan;
3911
+
3912
+ /** Distance in meters between two nearby lng/lat points */
3913
+ export declare function pointDistance(a: Position, b: Position): number;
3914
+
3915
+ export declare interface PointPickOptions {
3916
+ /** Base point for relative input, tracking and the rubber-band preview */
3917
+ basePoint?: Coordinate | null;
3918
+ }
3919
+
3920
+ /** Distance in meters from a point to a lng/lat segment, with the closest point */
3921
+ export declare function pointSegmentDistance(p: Position, a: Position, b: Position, scale?: [number, number]): SegmentHit;
3922
+
3923
+ export declare interface PolarTrackingSettings {
3924
+ enabled: boolean;
3925
+ /** Angle increment to track, e.g. 15, 30, 45, 90 */
3926
+ incrementDeg: number;
3927
+ /** Cursor must be within this many degrees of a tracking angle to lock on */
3928
+ toleranceDeg: number;
3929
+ }
3930
+
3931
+ /** Polygons of a Polygon / MultiPolygon as ring lists */
3932
+ export declare function polygonsOf(geometry: Geometry): Position[][][];
3933
+
3934
+ export declare function printImportResult(consoleService: IOFSConsole, result: ImportToDataSourceResult): void;
3935
+
3936
+ /** Print an import / export report: summary lines, then issues grouped by code */
3937
+ export declare function printIssues(consoleService: IOFSConsole, issues: ImportIssue[], limit?: number): void;
3938
+
3939
+ export declare class PromptBuilder {
3940
+ /**
3941
+ * Summarize current map state for LLM prompt context.
3942
+ * @param extraInstructions Instructions from the host application, appended after the library's own
3943
+ */
3944
+ static buildMapContext(dataSource: OFSDataSource, extraInstructions?: string): string;
3945
+ }
3946
+
3947
+ declare interface RasterImage {
3948
+ width: number;
3949
+ height: number;
3950
+ data: Uint8ClampedArray;
3951
+ pixelRatio: number;
3952
+ sdf: boolean;
3953
+ }
3954
+
3955
+ export declare function rasterizeHatch(request: Extract<SymbolImageRequest, {
3956
+ kind: 'hatch';
3957
+ }>, pixelRatio?: number): RasterImage | null;
3958
+
3959
+ export declare function rasterizeIcon(name: string): Promise<RasterImage | null>;
3960
+
3961
+ export declare function rasterizeMarker(request: Extract<SymbolImageRequest, {
3962
+ kind: 'marker';
3963
+ }>): RasterImage | null;
3964
+
3965
+ /**
3966
+ * One coordinate from an argument, in the library's only order: [lng, lat].
3967
+ * A value that is not a coordinate is refused with the right order spelled out — never turned around
3968
+ * silently, because "13.7, 100.5" and "100.5, 13.7" are both plausible and one of them is a wrong place.
3969
+ */
3970
+ export declare function readCoordinate(value: unknown): Coordinate;
3971
+
3972
+ export declare function readDbf(buffer: Uint8Array, options?: {
3973
+ encoding?: string;
3974
+ cpg?: string;
3975
+ file?: string;
3976
+ }, issues?: ImportIssue[]): DbfTable;
3977
+
3978
+ export declare function readShp(buffer: Uint8Array, issues?: ImportIssue[], file?: string): {
3979
+ shapeType: number;
3980
+ records: ShpRecord[];
3981
+ };
3982
+
3983
+ /** Register (or replace) a custom named ramp */
3984
+ export declare function registerColorRamp(definition: ColorRampDefinition): void;
3985
+
3986
+ /** Register or replace a CRS (e.g. a project-specific datum shift) */
3987
+ export declare function registerCrs(code: string, definition: string, name?: string, aliases?: string[]): void;
3988
+
3989
+ /** Register a custom marker icon usable as `{ shape: 'icon', icon: name }` */
3990
+ export declare function registerMarkerIcon(name: string, source: string, options?: {
3991
+ sdf?: boolean;
3992
+ }): void;
3993
+
3994
+ /** Remove consecutive vertices closer than `toleranceMeters` (keeps the first of each run and ring closure) */
3995
+ export declare function removeDuplicateVertices<G extends Geometry>(geometry: G, toleranceMeters: number): {
3996
+ geometry: G;
3997
+ removed: number;
3998
+ };
3999
+
4000
+ /** Remove the area of `other` from `target` (target gives up the overlap) */
4001
+ export declare function removeOverlap(target: Polygon | MultiPolygon, other: Polygon | MultiPolygon): Polygon | MultiPolygon;
4002
+
4003
+ /**
4004
+ * SVG markup of a symbol swatch.
4005
+ * @param size Swatch width and height in pixels
4006
+ */
4007
+ export declare function renderSymbolSwatchSvg(symbol: SymbolStyle, geomType: LayerGeometryType, size?: number): string;
4008
+
4009
+ /** Report an error that was caught and recovered from */
4010
+ export declare function reportInternalError(scope: string, error: unknown): void;
4011
+
4012
+ /**
4013
+ * Resolves all selected features across all layers in the dataset,
4014
+ * prioritizing active layer features first, followed by other layers,
4015
+ * and falling back to any currently active feature in the grips editor.
4016
+ */
4017
+ export declare function resolveAllSelectedFeatures(dataSource: OFSDataSource, drawTools?: OFSDrawTools): SelectedFeatureRef[];
4018
+
4019
+ /** Complete base symbol of a theme (defaults <- legacy simpleStyle <- baseSymbol) */
4020
+ export declare function resolveBaseSymbol(theme: ThematicDefinition): SymbolStyle;
4021
+
4022
+ /**
4023
+ * Resolve a CRS from an EPSG code ("EPSG:32647", "32647"), a URN, a registered name or a proj4 string.
4024
+ */
4025
+ export declare function resolveCrs(input: string | number): ResolvedCrs;
4026
+
4027
+ export declare interface ResolvedClass {
4028
+ /** Class index, or -1 for "all other values" */
4029
+ index: number;
4030
+ label: string;
4031
+ visible: boolean;
4032
+ symbol: SymbolStyle;
4033
+ min?: number;
4034
+ max?: number;
4035
+ value?: string | number | boolean;
4036
+ count?: number;
4037
+ }
4038
+
4039
+ export declare interface ResolvedCrs {
4040
+ /** Canonical code, e.g. "EPSG:32647", or "CUSTOM" */
4041
+ code: string;
4042
+ name: string;
4043
+ /** proj4 definition used for conversion */
4044
+ definition: string;
4045
+ isGeographic: boolean;
4046
+ /** Warnings produced while resolving (e.g. default datum shift applied) */
4047
+ warnings: string[];
4048
+ }
4049
+
4050
+ export declare interface ResolvedMultiTargets {
4051
+ layerId: string;
4052
+ featureIds: (string | number)[];
4053
+ }
4054
+
4055
+ export declare interface ResolvedTarget {
4056
+ layerId: string;
4057
+ featureId: string | number;
4058
+ }
4059
+
4060
+ export declare type ResolvedTopologyOptions = Required<Omit<TopologyOptions, 'gapMaxAreaSqm' | 'minAreaSqm'>> & Pick<TopologyOptions, 'gapMaxAreaSqm' | 'minAreaSqm'>;
4061
+
4062
+ /**
4063
+ * Resolve the CRS of a .prj file (WKT). Known names map to registered CRSs; other WKT is converted by
4064
+ * proj4. A non-WGS84 datum without TOWGS84 gets the registered shift for that datum, with a warning, or
4065
+ * is rejected when no shift is known (coordinates would otherwise be off by hundreds of meters).
4066
+ */
4067
+ export declare function resolvePrj(wkt: string): ResolvedCrs;
4068
+
4069
+ /**
4070
+ * Resolves the primary target feature for CAD / Spatial operations.
4071
+ * Priority order:
4072
+ * 1. Feature currently active in Grips Editor (drawTools.isEditing())
4073
+ * 2. Feature selected in dataSource's activeLayerId
4074
+ * 3. Feature selected in ANY layer across dataSource (activeLayerId remains unchanged)
4075
+ */
4076
+ export declare function resolveTargetFeature(dataSource: OFSDataSource, drawTools?: OFSDrawTools): ResolvedTarget | null;
4077
+
4078
+ /**
4079
+ * Resolves multiple target features (e.g. for union, difference, intersect).
4080
+ */
4081
+ export declare function resolveTargetFeatures(dataSource: OFSDataSource, drawTools?: OFSDrawTools): ResolvedMultiTargets | null;
4082
+
4083
+ /**
4084
+ * All classes of a theme with complete symbols, in legend order, plus the "other values" entry
4085
+ * (index -1) when the theme draws unmatched features.
4086
+ */
4087
+ export declare function resolveThemeClasses(theme: ThematicDefinition, geomType: LayerGeometryType): ResolvedClass[];
4088
+
4089
+ export declare function resolveTopologyOptions(options?: TopologyOptions): ResolvedTopologyOptions;
4090
+
4091
+ /**
4092
+ * All selected features (across layers) as transform targets.
4093
+ */
4094
+ export declare function resolveTransformTargets(dataSource: OFSDataSource, drawTools?: OFSDrawTools): {
4095
+ layerId: string;
4096
+ featureId: string | number;
4097
+ feature: Feature<Geometry>;
4098
+ }[];
4099
+
4100
+ /**
4101
+ * Re-insert original vertices that an overlay dropped because they were collinear (e.g. T-junctions with a
4102
+ * neighbour). Only vertices within `COLLINEAR_RESTORE_METERS` of a result edge are inserted, so the shape is unchanged.
4103
+ */
4104
+ export declare function restoreCollinearVertices<G extends Polygon | MultiPolygon>(geometry: G, originals: Geometry[]): {
4105
+ geometry: G;
4106
+ restored: number;
4107
+ };
4108
+
4109
+ /** Planar area of one ring in m² (absolute) */
4110
+ export declare function ringArea(ring: Position[], projection: PlanarProjection): number;
4111
+
4112
+ /**
4113
+ * A ring has no area when every vertex lies within `toleranceMeters` of the line through its two farthest-apart
4114
+ * vertices (all on one line or at one point). The signed area is not used: a figure-eight ring has zero net area.
4115
+ */
4116
+ export declare function ringIsCollapsed(ring: Position[], projection: PlanarProjection, toleranceMeters: number): boolean;
4117
+
4118
+ /** Group shapefile rings into GeoJSON polygons */
4119
+ export declare function ringsToPolygons(rings: Position[][], index: number, issues: ImportIssue[], file?: string): Geometry | null;
4120
+
4121
+ /**
4122
+ * Run the checks step by step. Features are not modified.
4123
+ *
4124
+ * The work is handed back between chunks so a caller can show progress and stop: on a layer of 98,000
4125
+ * parcels the overlap and gap checks take about a minute each, which must not freeze the page.
4126
+ */
4127
+ export declare function runTopologyChecks(features: AnyFeature[], layer: {
4128
+ id: string;
4129
+ name?: string;
4130
+ }, options?: TopologyOptions): Generator<TopologyProgress, TopologyReport, void>;
4131
+
4132
+ export declare interface ScaleBarPlan {
4133
+ /** Ground distance the bar represents, in meters */
4134
+ meters: number;
4135
+ /** Bar length in pixels */
4136
+ pixels: number;
4137
+ /** "500 m" / "2 km" */
4138
+ label: string;
4139
+ }
4140
+
4141
+ export declare interface ScaleBarStyle {
4142
+ color?: string;
4143
+ background?: string;
4144
+ fontSize?: number;
4145
+ height?: number;
4146
+ }
4147
+
4148
+ declare type Schema = NonNullable<OFSCommandProcess['schema']>;
4149
+
4150
+ /** Property names of a schema, including none when the command has no schema */
4151
+ export declare function schemaProperties(schema: Schema | undefined): string[];
4152
+
4153
+ export declare interface SegmentHit {
4154
+ distance: number;
4155
+ /** Parameter along the segment, 0..1 */
4156
+ t: number;
4157
+ /** Closest point, on the lng/lat segment */
4158
+ point: Coordinate;
4159
+ }
4160
+
4161
+ export declare interface SegmentMeasure {
4162
+ from: Coordinate;
4163
+ to: Coordinate;
4164
+ meters: number;
4165
+ /** Direction in the given convention (bearing: 0° = north, clockwise) */
4166
+ angleDeg: number;
4167
+ }
4168
+
4169
+ export declare interface SelectedFeatureRef {
4170
+ layerId: string;
4171
+ feature: Feature<Geometry>;
4172
+ }
4173
+
4174
+ declare type SelectionMode_2 = 'new' | 'add' | 'remove' | 'intersect';
4175
+ export { SelectionMode_2 as SelectionMode }
4176
+
4177
+ /** Override the default shift used for a datum (proj4 datum code, e.g. "indian_1975") */
4178
+ export declare function setDatumShift(datumCode: string, towgs84: string): void;
4179
+
4180
+ /**
4181
+ * Replace the diagnostic handler (e.g. to forward to an app logger or to fail tests).
4182
+ * Pass null to restore the default console handler.
4183
+ */
4184
+ export declare function setDiagnosticHandler(handler: OFSDiagnosticHandler | null): void;
4185
+
4186
+ export declare interface ShapefileParts {
4187
+ name: string;
4188
+ shp: Uint8Array;
4189
+ dbf?: Uint8Array;
4190
+ prj?: string;
4191
+ cpg?: string;
4192
+ }
4193
+
4194
+ /** Length in meters of the part of `path` that runs along `boundary` (both segment ends within tolerance) */
4195
+ export declare function sharedBoundaryLength(path: Position[], boundary: Geometry, toleranceMeters: number): number;
4196
+
4197
+ declare interface ShpRecord {
4198
+ geometry: Geometry | null;
4199
+ /** Shape type number for reporting */
4200
+ type: number;
4201
+ }
4202
+
4203
+ /** @deprecated Use `baseSymbol`. Kept for existing callers; mapped onto the base symbol. */
4204
+ export declare interface SimpleStyle {
4205
+ fillColor?: string;
4206
+ fillOpacity?: number;
4207
+ strokeColor?: string;
4208
+ strokeWidth?: number;
4209
+ strokeOpacity?: number;
4210
+ circleRadius?: number;
4211
+ circleColor?: string;
4212
+ }
4213
+
4214
+ /** Nearest integer direction (a, b) to a line angle (degrees CCW from horizontal) */
4215
+ export declare function snapHatchDirection(angleDeg: number, maxTileCssPx: number, spacing: number): {
4216
+ a: number;
4217
+ b: number;
4218
+ };
4219
+
4220
+ export declare class SnappingEngine {
4221
+ private dataSource;
4222
+ private mapAdapter;
4223
+ enabled: boolean;
4224
+ tolerancePixels: number;
4225
+ modes: OSnapModes;
4226
+ constructor(dataSource: OFSDataSource, mapAdapter: IMapAdapter);
4227
+ /**
4228
+ * Set which OSnap modes are active
4229
+ */
4230
+ setModes(modes: Partial<OSnapModes>): void;
4231
+ /**
4232
+ * Toggle a specific snap mode
4233
+ */
4234
+ toggleMode(mode: keyof OSnapModes): boolean;
4235
+ /**
4236
+ * Find snap point for mouse coordinate
4237
+ * @param cursorCoord Current cursor coordinate
4238
+ * @param additionalCoords Optional extra coordinates to snap to (e.g. start vertex of in-progress polygon)
4239
+ * @param options.excludeFeatureId Feature to ignore (e.g. the feature being edited)
4240
+ * @param options.fromPoint Previous point, enables perpendicular snapping
4241
+ */
4242
+ getSnap(cursorCoord: Coordinate, additionalCoords?: Coordinate[], options?: {
4243
+ excludeFeatureId?: string | number | null;
4244
+ fromPoint?: Coordinate | null;
4245
+ }): SnapResult | null;
4246
+ /**
4247
+ * Proper crossing point of two segments (shared endpoints are vertices, not intersections)
4248
+ */
4249
+ private static segmentIntersection;
4250
+ /**
4251
+ * Foot of the perpendicular from `from` onto segment a-b, measured with true angles
4252
+ * (longitude scaled by cos(latitude)). Null if the foot falls outside the segment.
4253
+ */
4254
+ private static perpendicularFoot;
4255
+ /**
4256
+ * Geographic bbox covering the snap tolerance circle around the cursor.
4257
+ * Uses all four screen corners so rotated / pitched maps are covered.
4258
+ * Returns null if the map cannot unproject (then every feature is checked).
4259
+ */
4260
+ private getSearchBBox;
4261
+ }
4262
+
4263
+ export declare interface SnapResult {
4264
+ coordinate: Coordinate;
4265
+ type: SnapType;
4266
+ distanceMeters: number;
4267
+ /** The segment the point was found on (perpendicular and edge snaps), for drawing the guide */
4268
+ segment?: {
4269
+ a: Coordinate;
4270
+ b: Coordinate;
4271
+ };
4272
+ }
4273
+
4274
+ /**
4275
+ * Snap a geometry onto a reference boundary (JTS GeometrySnapper approach):
4276
+ * 1. vertices within `toleranceMeters` move to the nearest reference vertex, else onto the nearest reference edge;
4277
+ * 2. reference vertices within tolerance of a segment are inserted into it, so the two boundaries follow the
4278
+ * same vertices where they run together.
4279
+ * Vertices farther than the tolerance keep their exact coordinates.
4280
+ */
4281
+ export declare function snapToReference<G extends Polygon | MultiPolygon | LineString | MultiLineString>(geometry: G, reference: Geometry, toleranceMeters: number, options?: {
4282
+ insertVertices?: boolean;
4283
+ endpointsOnly?: boolean;
4284
+ }): SnapToReferenceResult<G>;
4285
+
4286
+ export declare interface SnapToReferenceResult<G extends Geometry> {
4287
+ geometry: G;
4288
+ movedVertices: number;
4289
+ insertedVertices: number;
4290
+ maxMoveMeters: number;
4291
+ }
4292
+
4293
+ export declare type SnapType = 'vertex' | 'intersection' | 'midpoint' | 'center' | 'perpendicular' | 'edge';
4294
+
4295
+ export declare class SpatialIndexHelper {
4296
+ /**
4297
+ * Features that intersect the query bbox
4298
+ */
4299
+ static queryBBox(source: FeatureSource, bbox: BoundingBox): Feature<Geometry, any>[];
4300
+ /**
4301
+ * Features that intersect an arbitrary polygon (R-tree prefilter, exact refinement)
4302
+ */
4303
+ static queryGeometry(source: FeatureSource, geometry: Feature<Polygon | MultiPolygon>): Feature<Geometry, any>[];
4304
+ /**
4305
+ * Find features that contain a given coordinate point
4306
+ */
4307
+ static queryPoint(source: FeatureSource, pointCoord: Coordinate): Feature<Geometry, any>[];
4308
+ /**
4309
+ * Find nearest feature to a point
4310
+ */
4311
+ static findNearest(source: FeatureSource, pointCoord: Coordinate): {
4312
+ feature: Feature<Geometry, any>;
4313
+ distanceMeters: number;
4314
+ } | null;
4315
+ /**
4316
+ * turf.booleanIntersects throws on some degenerate geometries; treat those as a bbox hit so a
4317
+ * malformed feature is still selectable (and therefore fixable) instead of disappearing.
4318
+ */
4319
+ private static intersectsSafely;
4320
+ }
4321
+
4322
+ export declare interface SqliteColumn {
4323
+ name: string;
4324
+ declaredType: string;
4325
+ /** INTEGER PRIMARY KEY column: its value is the rowid */
4326
+ isRowidAlias: boolean;
4327
+ }
4328
+
4329
+ export declare class SqliteReader {
4330
+ private readonly pages;
4331
+ readonly pageSize: number;
4332
+ private readonly usable;
4333
+ private readonly walPages;
4334
+ readonly header: {
4335
+ applicationId: number;
4336
+ userVersion: number;
4337
+ walMode: boolean;
4338
+ textEncoding: number;
4339
+ };
4340
+ readonly warnings: string[];
4341
+ constructor(file: Uint8Array, wal?: Uint8Array);
4342
+ /** Apply frames of committed transactions from a -wal file */
4343
+ private loadWal;
4344
+ private page;
4345
+ /** Visit every row of a table B-tree in rowid order */
4346
+ scanTable(rootPage: number): Generator<{
4347
+ rowid: number | bigint;
4348
+ values: SqlValue[];
4349
+ }>;
4350
+ private payload;
4351
+ tables(): SqliteTable[];
4352
+ /** All rows of a table as objects (rowid alias columns filled in) */
4353
+ rows(table: SqliteTable): Generator<Record<string, SqlValue>>;
4354
+ }
4355
+
4356
+ export declare interface SqliteTable {
4357
+ name: string;
4358
+ rootPage: number;
4359
+ sql: string;
4360
+ columns: SqliteColumn[];
4361
+ }
4362
+
4363
+ export declare class SqliteWriter {
4364
+ readonly pageSize = 4096;
4365
+ private pages;
4366
+ private allocate;
4367
+ private get usable();
4368
+ /** Cell bytes for a table leaf, spilling to overflow pages when needed */
4369
+ private tableLeafCell;
4370
+ private indexLeafCell;
4371
+ private localSize;
4372
+ private cellWithOverflow;
4373
+ private writePage;
4374
+ private capacity;
4375
+ /** Build a table B-tree into `rootPage` (already allocated) */
4376
+ private buildTable;
4377
+ private buildIndex;
4378
+ /**
4379
+ * Build a complete database file. `header` sets the application id and user version.
4380
+ */
4381
+ build(tables: WriterTable[], header: {
4382
+ applicationId: number;
4383
+ userVersion: number;
4384
+ }): Uint8Array;
4385
+ }
4386
+
4387
+ /**
4388
+ * Minimal SQLite database file reader and writer (no SQL engine, no WASM).
4389
+ *
4390
+ * Reader: the file header, table B-trees (interior + leaf pages, overflow pages), record decoding, the
4391
+ * schema table, rowid-alias columns, and committed frames of a -wal file. Index B-trees are not needed
4392
+ * for full table scans and are skipped. WITHOUT ROWID tables are not supported.
4393
+ *
4394
+ * Writer: a new database with rowid tables and single-page indexes (enough for GeoPackage metadata
4395
+ * constraints), in the documented file format (https://www.sqlite.org/fileformat2.html). Files are checked
4396
+ * in the tests with SQLite itself (PRAGMA integrity_check) and GDAL.
4397
+ */
4398
+ export declare type SqlValue = null | number | bigint | string | Uint8Array;
4399
+
4400
+ export declare const SQM_PER_NGAN = 400;
4401
+
4402
+ export declare const SQM_PER_RAI = 1600;
4403
+
4404
+ export declare const SQM_PER_SQUARE_WA = 4;
4405
+
4406
+ export declare interface StyleCompileOptions {
4407
+ /** Data layer id used for GL layer ids (defaults to theme.layerId) */
4408
+ layerId?: string;
4409
+ /** Layer opacity multiplied into every opacity property */
4410
+ opacity?: number;
4411
+ }
4412
+
4413
+ export declare class StyleCompiler {
4414
+ /**
4415
+ * Compiles a ThematicDefinition into Mapbox/MapLibre GL layers
4416
+ */
4417
+ static compile(theme: ThematicDefinition, geomType: LayerGeometryType, options?: StyleCompileOptions): CompiledLayerStyle;
4418
+ }
4419
+
4420
+ /** Closest candidate within a small edit distance, for "did you mean" messages */
4421
+ export declare function suggestName(input: string, candidates: string[]): string | null;
4422
+
4423
+ /** The same numbers the other way round, when those would be a valid coordinate */
4424
+ export declare function swappedLngLat(raw: string): Coordinate | null;
4425
+
4426
+ export declare class SymbolImageManager {
4427
+ private readonly getMap;
4428
+ /** Image ids used by each data layer */
4429
+ private usage;
4430
+ /** Every image request seen, for re-creation on 'styleimagemissing' */
4431
+ private requests;
4432
+ private loadingIcons;
4433
+ private boundMap;
4434
+ private missingHandler;
4435
+ constructor(getMap: () => any);
4436
+ private bind;
4437
+ /** Make sure the images of a layer exist, and drop images no layer uses any more */
4438
+ ensure(layerId: string, requests: SymbolImageRequest[]): void;
4439
+ release(layerId: string): void;
4440
+ /** Re-create an icon image after its registration changed */
4441
+ refreshIcon(name: string): void;
4442
+ private isUsed;
4443
+ private removeUnused;
4444
+ private put;
4445
+ private addImage;
4446
+ destroy(): void;
4447
+ }
4448
+
4449
+ export declare type SymbolImageRequest = {
4450
+ id: string;
4451
+ kind: 'hatch';
4452
+ pattern: HatchPattern;
4453
+ } | {
4454
+ id: string;
4455
+ kind: 'marker';
4456
+ shape: MarkerShape;
4457
+ } | {
4458
+ id: string;
4459
+ kind: 'icon';
4460
+ icon: string;
4461
+ };
4462
+
4463
+ export declare interface SymbologyPanelOptions {
4464
+ /** Called when the close button is pressed */
4465
+ onClose?: () => void;
4466
+ }
4467
+
4468
+ /** The single geometry-specific part of a symbol */
4469
+ export declare function symbolPart(style: SymbolStyle, geomType: LayerGeometryType): FillSymbol | LineSymbol | MarkerSymbol;
4470
+
4471
+ /** Build a base-symbol patch from symbol options (unknown options are rejected) */
4472
+ export declare function symbolPatchFromOptions(options: OptionMap, current: FillSymbol): SymbolStyleInput;
4473
+
4474
+ export declare interface SymbolStyle {
4475
+ fill: FillSymbol;
4476
+ line: LineSymbol;
4477
+ marker: MarkerSymbol;
4478
+ }
4479
+
4480
+ /** Deep-partial symbol used for editing and for base symbol input */
4481
+ export declare interface SymbolStyleInput {
4482
+ fill?: Partial<FillSymbol>;
4483
+ line?: Partial<LineSymbol>;
4484
+ marker?: Partial<MarkerSymbol>;
4485
+ }
4486
+
4487
+ export declare interface TableQuery {
4488
+ /** Expression filter, e.g. `area > 1600 AND crop = 'ข้าว'` */
4489
+ filter?: string;
4490
+ onlySelected?: boolean;
4491
+ sortBy?: string;
4492
+ sortDescending?: boolean;
4493
+ offset?: number;
4494
+ limit?: number;
4495
+ }
4496
+
4497
+ export declare interface TableResult {
4498
+ layerId: string;
4499
+ fields: FieldSchema[];
4500
+ rows: AttributeRow[];
4501
+ /** Features in the layer */
4502
+ total: number;
4503
+ /** Features left after filter / selection */
4504
+ filtered: number;
4505
+ }
4506
+
4507
+ /** Text content including descendants */
4508
+ export declare function textContent(el: XmlElement | undefined): string;
4509
+
4510
+ export declare interface ThematicDefinition {
4511
+ type: ThematicType;
4512
+ layerId: string;
4513
+ fieldName?: string;
4514
+ classificationMethod?: ClassificationMethod;
4515
+ classCount?: number;
4516
+ paletteName?: string;
4517
+ /** Color for features that match no class ("all other values") */
4518
+ defaultColor: string;
4519
+ breaks?: ClassBreak[];
4520
+ categories?: CategoryItem[];
4521
+ /** Base symbol; missing parts use the defaults for the layer geometry */
4522
+ baseSymbol?: SymbolStyleInput;
4523
+ /** @deprecated Use baseSymbol */
4524
+ simpleStyle?: SimpleStyle;
4525
+ /** Graduated: vary color (default) or size (line width / marker diameter) */
4526
+ graduatedMode?: GraduatedMode;
4527
+ /** Graduated size mode: [smallest, largest] size in pixels */
4528
+ sizeRange?: [number, number];
4529
+ /** Draw features that match no class with defaultColor (default true) */
4530
+ showOther?: boolean;
4531
+ /** Label of the "other values" legend row */
4532
+ otherLabel?: string;
4533
+ highlightColor?: string;
4534
+ enableSelectionHighlight?: boolean;
4535
+ /** Labels drawn for this layer */
4536
+ label?: LabelSettings;
4537
+ }
4538
+
4539
+ export declare interface ThematicEvents {
4540
+ 'theme:changed': {
4541
+ layerId: string;
4542
+ theme: ThematicDefinition;
4543
+ };
4544
+ }
4545
+
4546
+ /**
4547
+ * Thematic Symbology Types
4548
+ *
4549
+ * A theme is plain JSON (serializable, AI-editable) modelled on QGIS renderers:
4550
+ * - 'simple' = Single Symbol
4551
+ * - 'categorical' = Categorized (unique values)
4552
+ * - 'graduated' = Graduated (class breaks), by color or by size
4553
+ *
4554
+ * Every theme has a base symbol (fill / line / marker). Classes may override the data-driven parts of
4555
+ * it (color, opacity, stroke, size, pattern, icon, rotation) and can be hidden individually.
4556
+ * Units: sizes, widths, offsets and spacings are screen pixels; opacity is 0-1. Angles follow QGIS:
4557
+ * hatch line angle counter-clockwise from horizontal (45 = "/"), marker rotation clockwise.
4558
+ */
4559
+ export declare type ThematicType = 'simple' | 'categorical' | 'graduated';
4560
+
4561
+ /** Split on whitespace, keeping "quoted text" together */
4562
+ export declare function tokenizeArgs(raw: string): string[];
4563
+
4564
+ export declare const TOPOLOGY_AREA_LAYER_ID = "topology-errors-area";
4565
+
4566
+ export declare const TOPOLOGY_GROUP_ID = "topology-errors";
4567
+
4568
+ export declare const TOPOLOGY_POINT_LAYER_ID = "topology-errors-point";
4569
+
4570
+ export declare interface TopologyBatchResult {
4571
+ results: TopologyFixResult[];
4572
+ /** Issues not fixed because an earlier fix in the batch already resolved them or changed a gap's neighbours */
4573
+ skipped: {
4574
+ issueId: number;
4575
+ reason: string;
4576
+ }[];
4577
+ failed: {
4578
+ issueId: number;
4579
+ message: string;
4580
+ }[];
4581
+ }
4582
+
4583
+ /** Thrown by `checkTopologyAsync` when the caller aborts the check */
4584
+ export declare class TopologyCancelled extends OFSError {
4585
+ constructor();
4586
+ }
4587
+
4588
+ export declare type TopologyCheck =
4589
+ /** OGC validity (self-intersection, holes outside shells, …), zero area / length, duplicate vertices */
4590
+ 'validity'
4591
+ /** Polygons of the layer overlapping each other (area above tolerance) */
4592
+ | 'overlap'
4593
+ /** Enclosed empty areas between polygons (holes of the layer union bounded by 2+ features) */
4594
+ | 'gap'
4595
+ /** Polygons thinner than `sliverWidthMeters` or smaller than `minAreaSqm` */
4596
+ | 'sliver'
4597
+ /** Vertices close to another feature's boundary without touching it; line ends that stop short (undershoot) */
4598
+ | 'near-vertex'
4599
+ /** Point features at the same location */
4600
+ | 'duplicate-point';
4601
+
4602
+ export declare type TopologyFixKind = 'remove-duplicate-vertices' | 'snap-vertices' | 'remove-overlap' | 'fill-gap' | 'snap-line-end';
4603
+
4604
+ export declare interface TopologyFixOptions {
4605
+ /** remove-overlap: feature that gives up the overlapping area (id), or 'smaller' / 'larger' */
4606
+ removeFrom?: string | number | 'smaller' | 'larger';
4607
+ /** fill-gap: feature that receives the gap (id), or 'longest-boundary' (default) / 'largest' */
4608
+ mergeInto?: string | number | 'longest-boundary' | 'largest';
4609
+ /** snap-vertices: feature whose vertices move (default: the first feature of the issue) */
4610
+ moveFeatureId?: string | number;
4611
+ }
4612
+
4613
+ export declare interface TopologyFixResult {
4614
+ issueId: number;
4615
+ code: TopologyIssueCode;
4616
+ changedFeatureIds: (string | number)[];
4617
+ message: string;
4618
+ movedVertices?: number;
4619
+ maxMoveMeters?: number;
4620
+ }
4621
+
4622
+ export declare interface TopologyIssue {
4623
+ /** Sequential number within the report (1-based) */
4624
+ id: number;
4625
+ check: TopologyCheck;
4626
+ code: TopologyIssueCode;
4627
+ severity: 'error' | 'warning';
4628
+ layerId: string;
4629
+ /** Features involved (first = the feature the issue is about, e.g. whose vertices are near) */
4630
+ featureIds: (string | number)[];
4631
+ message: string;
4632
+ /** A representative location to zoom to (inside the problem area when it is an area) */
4633
+ location: Coordinate;
4634
+ /** Problem area / points: overlap or gap polygon, vertex or crossing points */
4635
+ geometry?: Geometry;
4636
+ areaSqm?: number;
4637
+ /** Mean width of an area (2 × area / perimeter) */
4638
+ widthMeters?: number;
4639
+ distanceMeters?: number;
4640
+ /** Number of vertices involved (near-vertex, duplicate-vertex) */
4641
+ vertexCount?: number;
4642
+ /** Automatic fix available (always applied on request only) */
4643
+ fix?: TopologyFixKind;
4644
+ }
4645
+
4646
+ export declare type TopologyIssueCode = 'self-intersection' | 'ring-self-intersection' | 'hole-outside-shell' | 'nested-holes' | 'disconnected-interior' | 'nested-shells' | 'duplicate-rings' | 'too-few-points' | 'invalid-coordinate' | 'ring-not-closed' | 'invalid-geometry' | 'zero-area' | 'zero-length' | 'duplicate-vertex' | 'line-self-intersection' | 'overlap' | 'duplicate-geometry' | 'gap' | 'sliver' | 'small-area' | 'near-vertex' | 'undershoot' | 'duplicate-point';
4647
+
4648
+ export declare interface TopologyOptions {
4649
+ /** Checks to run (default: all that apply to the layer geometry type) */
4650
+ checks?: TopologyCheck[];
4651
+ /**
4652
+ * Points closer than this are the same point; vertices this close to a boundary touch it.
4653
+ * Default 0.001 m (1 mm, the same as `union`).
4654
+ */
4655
+ vertexToleranceMeters?: number;
4656
+ /** Overlaps and gaps with a smaller area are not reported (counted in `ignored`). Default 0.01 m² */
4657
+ areaToleranceSqm?: number;
4658
+ /** Gaps larger than this are treated as intentional open space (counted in `ignored`). Default: no limit */
4659
+ gapMaxAreaSqm?: number;
4660
+ /** Polygons whose mean width (2A/P) is below this are slivers. Default 0.2 m */
4661
+ sliverWidthMeters?: number;
4662
+ /** Polygons smaller than this are reported as `small-area`. Default: off */
4663
+ minAreaSqm?: number;
4664
+ /** Vertices / line ends within this distance of another feature (but not touching) are reported. Default 0.1 m */
4665
+ nearToleranceMeters?: number;
4666
+ /**
4667
+ * How many polygons the gap check unions at once. The area is split into grid cells of about this many
4668
+ * features, because one union of everything is far slower (2,000 parcels ≈ 0.7 s, 98,000 ≈ 10 minutes)
4669
+ * and a failure would cost the whole check instead of one cell. Default 2000.
4670
+ */
4671
+ unionCellSize?: number;
4672
+ }
4673
+
4674
+ export declare interface TopologyPanelOptions {
4675
+ /** Called when an issue row is clicked: zoom the map and highlight the features */
4676
+ onZoom?: (issue: TopologyIssue, report: TopologyReport) => void;
4677
+ /** Called when the close button is pressed */
4678
+ onClose?: () => void;
4679
+ /** Ask the user to confirm a batch fix (default: window.confirm) */
4680
+ confirmFix?: (issueCount: number, report: TopologyReport) => boolean;
4681
+ }
4682
+
4683
+ /** Where a running check has got to, so a caller can show progress */
4684
+ export declare interface TopologyProgress {
4685
+ stage: TopologyCheck;
4686
+ done: number;
4687
+ total: number;
4688
+ }
4689
+
4690
+ export declare interface TopologyReport {
4691
+ layerId: string;
4692
+ layerName: string;
4693
+ checkedAt: number;
4694
+ durationMs: number;
4695
+ options: ResolvedTopologyOptions;
4696
+ featureCount: number;
4697
+ issues: TopologyIssue[];
4698
+ /** Issue count per code */
4699
+ summary: Partial<Record<TopologyIssueCode, number>>;
4700
+ /** Findings below / above the reporting thresholds, so nothing disappears silently */
4701
+ ignored: {
4702
+ overlapsBelowTolerance: number;
4703
+ gapsBelowTolerance: number;
4704
+ gapsAboveMaxArea: number;
4705
+ /** Holes of the union bounded by a single feature (its own interior ring) */
4706
+ ownHoles: number;
4707
+ };
4708
+ /** Features excluded from overlay checks (overlap / gap) because their geometry is invalid */
4709
+ skippedFeatureIds: (string | number)[];
4710
+ /** Checks that could not complete */
4711
+ failures: {
4712
+ check: TopologyCheck;
4713
+ message: string;
4714
+ }[];
4715
+ }
4716
+
4717
+ /** Rai / ngan / square wa of an area in m² */
4718
+ export declare function toThaiUnits(areaSqm: number): {
4719
+ rai: number;
4720
+ ngan: number;
4721
+ squareWa: number;
4722
+ raiNganWa: string;
4723
+ };
4724
+
4725
+ export declare function toWkt(g: Geometry, precision?: number): string;
4726
+
4727
+ export declare class TransactionManager {
4728
+ private undoStack;
4729
+ private redoStack;
4730
+ private maxHistory;
4731
+ private groupStack;
4732
+ constructor(maxHistory?: number);
4733
+ record(step: TransactionStep): void;
4734
+ /**
4735
+ * Start grouping recorded steps into a single undoable step.
4736
+ * Groups may be nested; nested groups merge into the outermost one.
4737
+ */
4738
+ beginGroup(description: string): void;
4739
+ /**
4740
+ * Close the current group and record it as one compound step (if it recorded anything).
4741
+ */
4742
+ commitGroup(): void;
4743
+ /**
4744
+ * Close the current group, reverting every step it recorded. Nothing is added to history.
4745
+ */
4746
+ rollbackGroup(): void;
4747
+ isGrouping(): boolean;
4748
+ canUndo(): boolean;
4749
+ canRedo(): boolean;
4750
+ undo(): string | null;
4751
+ redo(): string | null;
4752
+ clear(): void;
4753
+ getUndoDescriptions(): string[];
4754
+ getRedoDescriptions(): string[];
4755
+ }
4756
+
4757
+ /**
4758
+ * Undo / Redo Transaction Stack for OFSDataSource
4759
+ */
4760
+ export declare interface TransactionStep {
4761
+ description: string;
4762
+ undo: () => void;
4763
+ redo: () => void;
4764
+ }
4765
+
4766
+ /** Arguments the engine parsed from the command's `args` spec (empty when the command has none) */
4767
+ export declare function typedArgs(ctx: {
4768
+ intermediate: Map<string, any>;
4769
+ }): Record<string, any>;
4770
+
4771
+ /** Coordinates given as a typed `coordinates` argument, e.g. [[lng, lat], …] (null when none were given) */
4772
+ export declare function typedCoordinates(ctx: {
4773
+ intermediate: Map<string, any>;
4774
+ }): Coordinate[] | null;
4775
+
4776
+ export declare class TypedEventEmitter<EventMap extends Record<string, any>> {
4777
+ private listeners;
4778
+ /**
4779
+ * Subscribe to an event. Returns an unsubscribe function.
4780
+ */
4781
+ on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): () => void;
4782
+ /**
4783
+ * Subscribe to an event once.
4784
+ */
4785
+ once<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): () => void;
4786
+ /**
4787
+ * Remove an event listener.
4788
+ */
4789
+ off<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): void;
4790
+ /**
4791
+ * Emit an event with data.
4792
+ */
4793
+ emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void;
4794
+ /**
4795
+ * Remove all listeners for an event or all events.
4796
+ */
4797
+ removeAllListeners(event?: keyof EventMap): void;
4798
+ /**
4799
+ * Return number of active listeners for an event.
4800
+ */
4801
+ listenerCount(event: keyof EventMap): number;
4802
+ }
4803
+
4804
+ declare type UnitPoint = [number, number];
4805
+
4806
+ /** Convert a user angle (in the frame's convention, relative to the UCS) to a world math angle (radians, CCW from East) */
4807
+ export declare function userAngleToWorldRad(angleDeg: number, frame: InputFrame): number;
4808
+
4809
+ /**
4810
+ * Signed user rotation (degrees) to a world math rotation (radians, CCW positive).
4811
+ * Bearing convention treats positive rotation as clockwise, CAD as counter-clockwise.
4812
+ */
4813
+ export declare function userRotationToWorldRad(rotationDeg: number, frame: InputFrame): number;
4814
+
4815
+ /** UTM zone CRS (WGS 84) that contains a longitude, northern hemisphere codes for lat >= 0 */
4816
+ export declare function utmCrsFor(lng: number, lat: number): ResolvedCrs;
4817
+
4818
+ /** Check an argument object against a schema; returns the coerced values or the problems found */
4819
+ export declare function validateArgs(schema: Schema | undefined, args: Record<string, unknown>, options?: {
4820
+ enforceRequired?: boolean;
4821
+ }): {
4822
+ ok: true;
4823
+ value: Record<string, unknown>;
4824
+ } | {
4825
+ ok: false;
4826
+ issues: string[];
4827
+ };
4828
+
4829
+ /** Field names that a new field must not collide with */
4830
+ export declare function validateFieldName(name: string, existing: FieldSchema[]): string | null;
4831
+
4832
+ /**
4833
+ * Validate one feature. Returns the (possibly ring-closed) geometry, or null when it must be rejected.
4834
+ */
4835
+ export declare function validateGeometry(geometry: Geometry | null | undefined, index: number, issues: ImportIssue[], ctx?: ValidationContext): Geometry | null;
4836
+
4837
+ export declare interface ValidationContext {
4838
+ file?: string;
4839
+ closeRings?: boolean;
4840
+ /** Check lng/lat ranges (only after conversion to WGS84) */
4841
+ geographic?: boolean;
4842
+ }
4843
+
4844
+ export declare type WorkflowStatus = 'idle' | 'running' | 'waiting_input' | 'completed' | 'failed' | 'cancelled';
4845
+
4846
+ /** Convert a world math angle (radians, CCW from East) to a user angle in the frame's convention [0, 360) */
4847
+ export declare function worldRadToUserAngle(rad: number, frame: InputFrame): number;
4848
+
4849
+ export declare function writeDbf(records: Record<string, any>[], fields: FieldDefinition[], encoding?: string, issues?: ImportIssue[]): DbfWriteResult;
4850
+
4851
+ export declare function writeGpkgGeometry(geometry: Geometry, srsId: number): Uint8Array;
4852
+
4853
+ export declare interface WriterTable {
4854
+ name: string;
4855
+ sql: string;
4856
+ /** Rows as column value arrays in declared column order; the rowid alias column must be null */
4857
+ rows: {
4858
+ rowid: number;
4859
+ values: SqlValue[];
4860
+ }[];
4861
+ /** Automatic indexes for PRIMARY KEY / UNIQUE constraints, in declaration order: column positions */
4862
+ autoIndexes?: number[][];
4863
+ }
4864
+
4865
+ export declare function writeShapefile(features: Feature<Geometry, Record<string, any>>[], kind: 'point' | 'line' | 'polygon', fields: FieldDefinition[], options?: ExportOptions, issues?: ImportIssue[]): {
4866
+ shp: Uint8Array;
4867
+ shx: Uint8Array;
4868
+ dbf: Uint8Array;
4869
+ prj: string;
4870
+ cpg: string;
4871
+ };
4872
+
4873
+ export declare function writeWkb(geometry: Geometry): Uint8Array;
4874
+
4875
+ /**
4876
+ * Minimal XML reader/writer for KML (no DOM required, so it also runs in Node and workers).
4877
+ * Supports elements, attributes, text, CDATA, comments, processing instructions and the standard +
4878
+ * numeric character entities. Namespace prefixes are kept in names; use localName() to ignore them.
4879
+ */
4880
+ export declare interface XmlElement {
4881
+ name: string;
4882
+ attributes: Record<string, string>;
4883
+ children: XmlElement[];
4884
+ text: string;
4885
+ }
4886
+
4887
+ export { }