flatsql 0.4.0 → 0.4.3
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.
- package/README.md +100 -0
- package/package.json +21 -6
- package/sdm/flatsql-spatial.wasm +0 -0
- package/sdm/index.d.ts +88 -0
- package/sdm/index.js +253 -0
- package/sdm/manifest.json +402 -0
- package/wasm/flatsql-wasi.wasm +0 -0
- package/wasm/flatsql.js +16 -2
- package/wasm/flatsql.wasm +0 -0
- package/wasm/index.d.ts +40 -1
- package/wasm/index.js +75 -19
package/README.md
CHANGED
|
@@ -250,6 +250,106 @@ FlatSQL ingests size-prefixed FlatBuffer streams:
|
|
|
250
250
|
|
|
251
251
|
The 4-byte file identifier in each FlatBuffer determines which table receives the record.
|
|
252
252
|
|
|
253
|
+
## Spatial Extensions
|
|
254
|
+
|
|
255
|
+
FlatSQL includes a full spatial computation engine with SpatiaLite-compatible functions, polygon boolean operations, Voronoi/Delaunay tessellation, and coordinate transforms.
|
|
256
|
+
|
|
257
|
+
### Spatial SQL Functions
|
|
258
|
+
|
|
259
|
+
| Category | Functions |
|
|
260
|
+
|----------|-----------|
|
|
261
|
+
| **Point ops** | `geo_distance`, `geo_bearing`, `geo_destination`, `geo_midpoint`, `geo_area_bbox`, `geo_within_radius`, `geo_bbox_contains` |
|
|
262
|
+
| **Geohash** | `geo_geohash_encode`, `geo_geohash_decode_lat`, `geo_geohash_decode_lon` |
|
|
263
|
+
| **Geometry I/O** | `geo_from_text` (WKT→blob), `geo_as_text` (blob→WKT), `geo_from_geojson`, `geo_as_geojson` |
|
|
264
|
+
| **Predicates** | `geo_contains` (point-in-polygon, ray casting with hole support) |
|
|
265
|
+
| **Boolean ops** | `geo_intersection`, `geo_union`, `geo_difference`, `geo_sym_difference`, `geo_buffer` |
|
|
266
|
+
| **Analysis** | `geo_area_geom`, `geo_centroid`, `geo_length_geom`, `geo_envelope`, `geo_convex_hull` |
|
|
267
|
+
| **Voronoi/Delaunay** | `geo_voronoi`, `geo_delaunay` |
|
|
268
|
+
| **Coord transforms** | `geo_to_ecef` (WGS84→ECEF), `geo_from_ecef` (ECEF→WGS84) |
|
|
269
|
+
|
|
270
|
+
### Examples
|
|
271
|
+
|
|
272
|
+
```sql
|
|
273
|
+
-- Distance between NYC and DC (~328 km)
|
|
274
|
+
SELECT geo_distance(40.7128, -74.0060, 38.9072, -77.0369);
|
|
275
|
+
|
|
276
|
+
-- Bearing from NYC to LA
|
|
277
|
+
SELECT geo_bearing(40.7128, -74.0060, 34.0522, -118.2437);
|
|
278
|
+
|
|
279
|
+
-- Geohash encode/decode
|
|
280
|
+
SELECT geo_geohash_encode(42.6, -5.6, 5); -- 'ezs42'
|
|
281
|
+
|
|
282
|
+
-- Point-in-polygon
|
|
283
|
+
SELECT geo_contains('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', 5, 5); -- 1
|
|
284
|
+
|
|
285
|
+
-- Polygon intersection (accepts WKT or blob)
|
|
286
|
+
SELECT geo_as_text(geo_intersection(
|
|
287
|
+
'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))',
|
|
288
|
+
'POLYGON((5 5, 15 5, 15 15, 5 15, 5 5))'
|
|
289
|
+
));
|
|
290
|
+
|
|
291
|
+
-- WGS84 to ECEF coordinate transform
|
|
292
|
+
SELECT geo_to_ecef(48.8566, 2.3522, 35); -- '4200952.xxx,172458.xxx,4780111.xxx'
|
|
293
|
+
|
|
294
|
+
-- Voronoi diagram
|
|
295
|
+
SELECT geo_as_text(geo_voronoi(
|
|
296
|
+
'MULTIPOINT((0 0), (10 0), (10 10), (0 10))',
|
|
297
|
+
'POLYGON((-5 -5, 15 -5, 15 15, -5 15, -5 -5))'
|
|
298
|
+
));
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### R-Tree Spatial Indexing
|
|
302
|
+
|
|
303
|
+
FlatSQL automatically creates R-Tree shadow tables for spatial columns during ingest. Spatial columns are detected by:
|
|
304
|
+
- **Convention**: columns named `latitude`/`lat` + `longitude`/`lon`/`lng`
|
|
305
|
+
- **Schema attribute**: fields marked with `(spatial)` in FlatBuffers IDL
|
|
306
|
+
|
|
307
|
+
```sql
|
|
308
|
+
-- R-Tree pre-filter + precise radius check (72x faster than full scan)
|
|
309
|
+
SELECT p.* FROM points p
|
|
310
|
+
INNER JOIN _rtree_points r ON p.rowid = r.id
|
|
311
|
+
WHERE r.minLat >= 36.2 AND r.maxLat <= 45.2
|
|
312
|
+
AND r.minLon >= -80 AND r.maxLon <= -68
|
|
313
|
+
AND geo_within_radius(40.7, -74.0, p.lat, p.lon, 500) = 1;
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Spatial Performance
|
|
317
|
+
|
|
318
|
+
| Operation | Throughput | Latency |
|
|
319
|
+
|-----------|-----------|---------|
|
|
320
|
+
| Point operations (distance, bearing) | 733K–1.07M ops/sec | ~1 µs |
|
|
321
|
+
| Geohash encode/decode | 631K–746K ops/sec | ~1.4 µs |
|
|
322
|
+
| Point-in-polygon | 127K–255K ops/sec | ~4 µs |
|
|
323
|
+
| Polygon intersection | 81K ops/sec | ~12 µs |
|
|
324
|
+
| Voronoi (4 sites) | 34K ops/sec | ~29 µs |
|
|
325
|
+
| Coordinate transforms | 556K–609K ops/sec | ~1.7 µs |
|
|
326
|
+
| R-Tree bbox query (10K records) | 77K ops/sec | ~13 µs |
|
|
327
|
+
| R-Tree vs full scan speedup | **58–72x** | |
|
|
328
|
+
|
|
329
|
+
### Space Data Module (SDM)
|
|
330
|
+
|
|
331
|
+
FlatSQL Spatial is also available as a standalone WASM module compliant with the [Space Data Module SDK](https://github.com/DigitalArsenal/space-data-module-sdk):
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
import { initSpatialSDM } from 'flatsql/sdm';
|
|
335
|
+
|
|
336
|
+
const sdm = await initSpatialSDM();
|
|
337
|
+
|
|
338
|
+
// Read the embedded manifest
|
|
339
|
+
console.log(sdm.getManifest().pluginId);
|
|
340
|
+
// → 'com.digitalarsenal.flatsql.spatial'
|
|
341
|
+
|
|
342
|
+
// Compute distance
|
|
343
|
+
const km = sdm.computeDistance(40.7128, -74.006, 38.9072, -77.0369);
|
|
344
|
+
|
|
345
|
+
// Point-in-polygon
|
|
346
|
+
const inside = sdm.pointInPolygon('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', 5, 5);
|
|
347
|
+
|
|
348
|
+
// Coordinate transform
|
|
349
|
+
const ecef = sdm.toECEF(48.8566, 2.3522, 35);
|
|
350
|
+
const back = sdm.fromECEF(ecef.x, ecef.y, ecef.z);
|
|
351
|
+
```
|
|
352
|
+
|
|
253
353
|
## SQL Support
|
|
254
354
|
|
|
255
355
|
### Supported
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flatsql",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "SQL queries over raw FlatBuffer storage - zero conversion, real-time indexing, pure streaming",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,13 +18,22 @@
|
|
|
18
18
|
"types": "./wasm/wasi.d.ts",
|
|
19
19
|
"import": "./wasm/wasi.js"
|
|
20
20
|
},
|
|
21
|
-
"./wasi.wasm": "./wasm/flatsql-wasi.wasm"
|
|
21
|
+
"./wasi.wasm": "./wasm/flatsql-wasi.wasm",
|
|
22
|
+
"./sdm": {
|
|
23
|
+
"types": "./sdm/index.d.ts",
|
|
24
|
+
"import": "./sdm/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./sdm.wasm": "./sdm/flatsql-spatial.wasm"
|
|
22
27
|
},
|
|
23
28
|
"files": [
|
|
24
29
|
"dist",
|
|
25
30
|
"wasm/*.js",
|
|
26
31
|
"wasm/*.wasm",
|
|
27
32
|
"wasm/*.d.ts",
|
|
33
|
+
"sdm/*.js",
|
|
34
|
+
"sdm/*.wasm",
|
|
35
|
+
"sdm/*.d.ts",
|
|
36
|
+
"sdm/*.json",
|
|
28
37
|
"README.md",
|
|
29
38
|
"LICENSE"
|
|
30
39
|
],
|
|
@@ -64,20 +73,26 @@
|
|
|
64
73
|
"wasm",
|
|
65
74
|
"webassembly",
|
|
66
75
|
"query",
|
|
67
|
-
"virtual-table"
|
|
76
|
+
"virtual-table",
|
|
77
|
+
"spatial",
|
|
78
|
+
"geospatial",
|
|
79
|
+
"voronoi",
|
|
80
|
+
"delaunay",
|
|
81
|
+
"rtree",
|
|
82
|
+
"space-data-module"
|
|
68
83
|
],
|
|
69
84
|
"author": "Digital Arsenal <tj@digitalarsenal.io>",
|
|
70
85
|
"license": "Apache-2.0",
|
|
71
86
|
"dependencies": {
|
|
72
|
-
"flatc-wasm": "^26.1.
|
|
87
|
+
"flatc-wasm": "^26.1.32",
|
|
73
88
|
"sql.js": "^1.10.0"
|
|
74
89
|
},
|
|
75
90
|
"devDependencies": {
|
|
91
|
+
"@types/jest": "^29.5.0",
|
|
76
92
|
"@types/node": "^20.0.0",
|
|
77
|
-
"typescript": "^5.3.0",
|
|
78
93
|
"jest": "^29.7.0",
|
|
79
|
-
"@types/jest": "^29.5.0",
|
|
80
94
|
"ts-jest": "^29.1.0",
|
|
95
|
+
"typescript": "^5.3.0",
|
|
81
96
|
"vite": "^5.0.0"
|
|
82
97
|
},
|
|
83
98
|
"engines": {
|
|
Binary file
|
package/sdm/index.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlatSQL Spatial Engine — Space Data Module (SDM)
|
|
3
|
+
* TypeScript type definitions
|
|
4
|
+
*
|
|
5
|
+
* @see https://github.com/DigitalArsenal/space-data-module-sdk
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ECEFPoint {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
z: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface GeodeticPoint {
|
|
15
|
+
lat: number;
|
|
16
|
+
lon: number;
|
|
17
|
+
alt: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MethodResult {
|
|
21
|
+
status: number;
|
|
22
|
+
output: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PluginManifest {
|
|
26
|
+
pluginId: string;
|
|
27
|
+
name: string;
|
|
28
|
+
version: string;
|
|
29
|
+
pluginFamily: string;
|
|
30
|
+
description: string;
|
|
31
|
+
capabilities: string[];
|
|
32
|
+
externalInterfaces: string[];
|
|
33
|
+
methods: Array<{
|
|
34
|
+
methodId: string;
|
|
35
|
+
description: string;
|
|
36
|
+
inputPorts: Array<{
|
|
37
|
+
portId: string;
|
|
38
|
+
schemaNames: string[];
|
|
39
|
+
maxItems: number;
|
|
40
|
+
}>;
|
|
41
|
+
outputPorts: Array<{
|
|
42
|
+
portId: string;
|
|
43
|
+
schemaNames: string[];
|
|
44
|
+
maxItems: number;
|
|
45
|
+
}>;
|
|
46
|
+
maxBatch: number;
|
|
47
|
+
drainPolicy: string;
|
|
48
|
+
}>;
|
|
49
|
+
runtimeTargets: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface FlatSQLSpatialSDM {
|
|
53
|
+
/** Get the embedded plugin manifest */
|
|
54
|
+
getManifest(): PluginManifest;
|
|
55
|
+
|
|
56
|
+
/** Compute haversine distance between two WGS84 points (km) */
|
|
57
|
+
computeDistance(lat1: number, lon1: number, lat2: number, lon2: number): number;
|
|
58
|
+
|
|
59
|
+
/** Compute forward azimuth between two WGS84 points (degrees 0-360) */
|
|
60
|
+
computeBearing(lat1: number, lon1: number, lat2: number, lon2: number): number;
|
|
61
|
+
|
|
62
|
+
/** Test if a WGS84 point is inside a WKT polygon */
|
|
63
|
+
pointInPolygon(wkt: string, lat: number, lon: number): boolean;
|
|
64
|
+
|
|
65
|
+
/** Compute intersection of two WKT polygons */
|
|
66
|
+
polygonIntersection(wkt1: string, wkt2: string): string;
|
|
67
|
+
|
|
68
|
+
/** Compute union of two WKT polygons */
|
|
69
|
+
polygonUnion(wkt1: string, wkt2: string): string;
|
|
70
|
+
|
|
71
|
+
/** Compute Voronoi diagram from multipoint WKT within bounds */
|
|
72
|
+
computeVoronoi(multipointWkt: string, boundsWkt: string): string;
|
|
73
|
+
|
|
74
|
+
/** Compute Delaunay triangulation from multipoint WKT */
|
|
75
|
+
computeDelaunay(multipointWkt: string): string;
|
|
76
|
+
|
|
77
|
+
/** Transform WGS84 geodetic to ECEF */
|
|
78
|
+
toECEF(lat: number, lon: number, alt: number): ECEFPoint;
|
|
79
|
+
|
|
80
|
+
/** Transform ECEF to WGS84 geodetic */
|
|
81
|
+
fromECEF(x: number, y: number, z: number): GeodeticPoint;
|
|
82
|
+
|
|
83
|
+
/** Low-level method call */
|
|
84
|
+
callMethod(methodName: string, input: string): MethodResult;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Initialize the FlatSQL Spatial SDM module */
|
|
88
|
+
export function initSpatialSDM(): Promise<FlatSQLSpatialSDM>;
|
package/sdm/index.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlatSQL Spatial Engine — Space Data Module (SDM)
|
|
3
|
+
*
|
|
4
|
+
* Standalone WASM module compliant with space-data-module-sdk.
|
|
5
|
+
* Provides spatial computation functions without requiring full FlatSQL.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/DigitalArsenal/space-data-module-sdk
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the FlatSQL Spatial SDM module.
|
|
18
|
+
* @returns {Promise<FlatSQLSpatialSDM>}
|
|
19
|
+
*/
|
|
20
|
+
export async function initSpatialSDM() {
|
|
21
|
+
const wasmPath = join(__dirname, "flatsql-spatial.wasm");
|
|
22
|
+
const wasmBytes = await readFile(wasmPath);
|
|
23
|
+
let exports;
|
|
24
|
+
const invoke = () => (fnPtr, ...args) => {
|
|
25
|
+
const table = exports?.__indirect_function_table;
|
|
26
|
+
const fn = table?.get(fnPtr);
|
|
27
|
+
if (typeof fn !== "function") {
|
|
28
|
+
throw new Error(`Missing indirect WASM function: ${fnPtr}`);
|
|
29
|
+
}
|
|
30
|
+
return fn(...args);
|
|
31
|
+
};
|
|
32
|
+
const { instance } = await WebAssembly.instantiate(wasmBytes, {
|
|
33
|
+
env: {
|
|
34
|
+
invoke_v: invoke("v"),
|
|
35
|
+
invoke_i: invoke("i"),
|
|
36
|
+
invoke_ii: invoke("ii"),
|
|
37
|
+
invoke_iii: invoke("iii"),
|
|
38
|
+
invoke_iiii: invoke("iiii"),
|
|
39
|
+
invoke_iiiii: invoke("iiiii"),
|
|
40
|
+
invoke_iiiiii: invoke("iiiiii"),
|
|
41
|
+
invoke_iiiiiii: invoke("iiiiiii"),
|
|
42
|
+
invoke_iiiiiiii: invoke("iiiiiiii"),
|
|
43
|
+
invoke_iiiiiiiiiiii: invoke("iiiiiiiiiiii"),
|
|
44
|
+
invoke_iiiiid: invoke("iiiiid"),
|
|
45
|
+
invoke_di: invoke("di"),
|
|
46
|
+
invoke_dii: invoke("dii"),
|
|
47
|
+
invoke_diii: invoke("diii"),
|
|
48
|
+
invoke_fiii: invoke("fiii"),
|
|
49
|
+
invoke_iid: invoke("iid"),
|
|
50
|
+
invoke_jiiii: invoke("jiiii"),
|
|
51
|
+
invoke_vi: invoke("vi"),
|
|
52
|
+
invoke_vid: invoke("vid"),
|
|
53
|
+
invoke_vii: invoke("vii"),
|
|
54
|
+
invoke_viii: invoke("viii"),
|
|
55
|
+
invoke_viiii: invoke("viiii"),
|
|
56
|
+
invoke_viiiii: invoke("viiiii"),
|
|
57
|
+
invoke_viiiiiii: invoke("viiiiiii"),
|
|
58
|
+
invoke_viiiiiiiiii: invoke("viiiiiiiiii"),
|
|
59
|
+
invoke_viiiiiiiiiiiiiii: invoke("viiiiiiiiiiiiiii"),
|
|
60
|
+
__cxa_begin_catch: (ptr) => ptr,
|
|
61
|
+
__cxa_end_catch: () => {},
|
|
62
|
+
__cxa_find_matching_catch_2: () => 0,
|
|
63
|
+
__cxa_find_matching_catch_3: () => 0,
|
|
64
|
+
__cxa_rethrow: () => {},
|
|
65
|
+
__cxa_throw: () => {},
|
|
66
|
+
__cxa_uncaught_exceptions: () => 0,
|
|
67
|
+
__resumeException: (ptr) => {
|
|
68
|
+
throw new Error(`Unhandled WASM exception: ${ptr}`);
|
|
69
|
+
},
|
|
70
|
+
emscripten_notify_memory_growth: () => {},
|
|
71
|
+
},
|
|
72
|
+
wasi_snapshot_preview1: {
|
|
73
|
+
environ_get: () => 0,
|
|
74
|
+
environ_sizes_get: (environCount, environBufSize) => {
|
|
75
|
+
const memory = exports?.memory;
|
|
76
|
+
if (memory) {
|
|
77
|
+
const view = new DataView(memory.buffer);
|
|
78
|
+
view.setUint32(environCount, 0, true);
|
|
79
|
+
view.setUint32(environBufSize, 0, true);
|
|
80
|
+
}
|
|
81
|
+
return 0;
|
|
82
|
+
},
|
|
83
|
+
proc_exit: () => {},
|
|
84
|
+
fd_write: () => 0,
|
|
85
|
+
fd_seek: () => 0,
|
|
86
|
+
fd_close: () => 0,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
exports = instance.exports;
|
|
90
|
+
const memory = /** @type {WebAssembly.Memory} */ (exports.memory);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Write a string to the input buffer.
|
|
94
|
+
* @param {string} str
|
|
95
|
+
*/
|
|
96
|
+
function writeInput(str) {
|
|
97
|
+
const inputPtr = /** @type {Function} */ (exports.sdm_get_input_buffer)();
|
|
98
|
+
const encoder = new TextEncoder();
|
|
99
|
+
const bytes = encoder.encode(str);
|
|
100
|
+
const view = new Uint8Array(memory.buffer, inputPtr, bytes.length);
|
|
101
|
+
view.set(bytes);
|
|
102
|
+
/** @type {Function} */ (exports.sdm_set_input_length)(bytes.length);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Read the output buffer as a string.
|
|
107
|
+
* @returns {string}
|
|
108
|
+
*/
|
|
109
|
+
function readOutput() {
|
|
110
|
+
const outputLen = /** @type {Function} */ (exports.sdm_get_output_length)();
|
|
111
|
+
const outputPtr = /** @type {Function} */ (exports.sdm_get_output_buffer)();
|
|
112
|
+
const view = new Uint8Array(memory.buffer, outputPtr, outputLen);
|
|
113
|
+
return new TextDecoder().decode(view);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Call a method with string input, return string output.
|
|
118
|
+
* @param {string} methodName
|
|
119
|
+
* @param {string} input
|
|
120
|
+
* @returns {{ status: number, output: string }}
|
|
121
|
+
*/
|
|
122
|
+
function callMethod(methodName, input) {
|
|
123
|
+
writeInput(input);
|
|
124
|
+
const fn = exports[methodName];
|
|
125
|
+
if (!fn) throw new Error(`Unknown method: ${methodName}`);
|
|
126
|
+
const status = /** @type {Function} */ (fn)();
|
|
127
|
+
return { status, output: readOutput() };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get the embedded plugin manifest.
|
|
132
|
+
* @returns {object}
|
|
133
|
+
*/
|
|
134
|
+
function getManifest() {
|
|
135
|
+
const ptr = /** @type {Function} */ (exports.plugin_get_manifest)();
|
|
136
|
+
const size = /** @type {Function} */ (exports.plugin_get_manifest_size)();
|
|
137
|
+
const view = new Uint8Array(memory.buffer, ptr, size);
|
|
138
|
+
const text = new TextDecoder().decode(view);
|
|
139
|
+
return JSON.parse(text);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
/** Get the plugin manifest */
|
|
144
|
+
getManifest,
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Compute haversine distance between two points.
|
|
148
|
+
* @param {number} lat1 @param {number} lon1
|
|
149
|
+
* @param {number} lat2 @param {number} lon2
|
|
150
|
+
* @returns {number} distance in km
|
|
151
|
+
*/
|
|
152
|
+
computeDistance(lat1, lon1, lat2, lon2) {
|
|
153
|
+
const { status, output } = callMethod("compute_distance", `${lat1},${lon1},${lat2},${lon2}`);
|
|
154
|
+
if (status !== 0) throw new Error(output);
|
|
155
|
+
return parseFloat(output);
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Compute bearing from point 1 to point 2.
|
|
160
|
+
* @param {number} lat1 @param {number} lon1
|
|
161
|
+
* @param {number} lat2 @param {number} lon2
|
|
162
|
+
* @returns {number} bearing in degrees (0-360)
|
|
163
|
+
*/
|
|
164
|
+
computeBearing(lat1, lon1, lat2, lon2) {
|
|
165
|
+
const { status, output } = callMethod("compute_bearing", `${lat1},${lon1},${lat2},${lon2}`);
|
|
166
|
+
if (status !== 0) throw new Error(output);
|
|
167
|
+
return parseFloat(output);
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Test if a point is inside a polygon.
|
|
172
|
+
* @param {string} wkt - WKT polygon
|
|
173
|
+
* @param {number} lat @param {number} lon
|
|
174
|
+
* @returns {boolean}
|
|
175
|
+
*/
|
|
176
|
+
pointInPolygon(wkt, lat, lon) {
|
|
177
|
+
const { status, output } = callMethod("point_in_polygon", `${wkt}\n${lat},${lon}`);
|
|
178
|
+
if (status !== 0) throw new Error(output);
|
|
179
|
+
return output === "1";
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Compute polygon intersection.
|
|
184
|
+
* @param {string} wkt1 @param {string} wkt2
|
|
185
|
+
* @returns {string} WKT of intersection
|
|
186
|
+
*/
|
|
187
|
+
polygonIntersection(wkt1, wkt2) {
|
|
188
|
+
const { status, output } = callMethod("polygon_intersection", `${wkt1}\n${wkt2}`);
|
|
189
|
+
if (status !== 0) throw new Error(output);
|
|
190
|
+
return output;
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Compute polygon union.
|
|
195
|
+
* @param {string} wkt1 @param {string} wkt2
|
|
196
|
+
* @returns {string} WKT of union
|
|
197
|
+
*/
|
|
198
|
+
polygonUnion(wkt1, wkt2) {
|
|
199
|
+
const { status, output } = callMethod("polygon_union", `${wkt1}\n${wkt2}`);
|
|
200
|
+
if (status !== 0) throw new Error(output);
|
|
201
|
+
return output;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Compute Voronoi diagram.
|
|
206
|
+
* @param {string} multipointWkt @param {string} boundsWkt
|
|
207
|
+
* @returns {string} MULTIPOLYGON WKT
|
|
208
|
+
*/
|
|
209
|
+
computeVoronoi(multipointWkt, boundsWkt) {
|
|
210
|
+
const { status, output } = callMethod("compute_voronoi", `${multipointWkt}\n${boundsWkt}`);
|
|
211
|
+
if (status !== 0) throw new Error(output);
|
|
212
|
+
return output;
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Compute Delaunay triangulation.
|
|
217
|
+
* @param {string} multipointWkt
|
|
218
|
+
* @returns {string} MULTIPOLYGON WKT
|
|
219
|
+
*/
|
|
220
|
+
computeDelaunay(multipointWkt) {
|
|
221
|
+
const { status, output } = callMethod("compute_delaunay", multipointWkt);
|
|
222
|
+
if (status !== 0) throw new Error(output);
|
|
223
|
+
return output;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Transform WGS84 to ECEF.
|
|
228
|
+
* @param {number} lat @param {number} lon @param {number} alt
|
|
229
|
+
* @returns {{ x: number, y: number, z: number }}
|
|
230
|
+
*/
|
|
231
|
+
toECEF(lat, lon, alt) {
|
|
232
|
+
const { status, output } = callMethod("transform_to_ecef", `${lat},${lon},${alt}`);
|
|
233
|
+
if (status !== 0) throw new Error(output);
|
|
234
|
+
const [x, y, z] = output.split(",").map(Number);
|
|
235
|
+
return { x, y, z };
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Transform ECEF to WGS84.
|
|
240
|
+
* @param {number} x @param {number} y @param {number} z
|
|
241
|
+
* @returns {{ lat: number, lon: number, alt: number }}
|
|
242
|
+
*/
|
|
243
|
+
fromECEF(x, y, z) {
|
|
244
|
+
const { status, output } = callMethod("transform_from_ecef", `${x},${y},${z}`);
|
|
245
|
+
if (status !== 0) throw new Error(output);
|
|
246
|
+
const [lat, lon, alt] = output.split(",").map(Number);
|
|
247
|
+
return { lat, lon, alt };
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/** Low-level method call */
|
|
251
|
+
callMethod,
|
|
252
|
+
};
|
|
253
|
+
}
|