geoplegma-js 0.0.0-beta

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 ADDED
@@ -0,0 +1,74 @@
1
+ # Introduction
2
+
3
+ JavaScript package for GeoPlegma. At this point, it runs only DGGRID.
4
+
5
+ ## Get Started
6
+
7
+ Install the library.
8
+
9
+ ```bash
10
+ npm install GeoPlegma-js
11
+ ```
12
+
13
+ or
14
+
15
+ ```bash
16
+ yarn add GeoPlegma-js
17
+ ```
18
+
19
+ or
20
+
21
+ ```bash
22
+ pnpm install GeoPlegma-js
23
+ ```
24
+
25
+ Example:
26
+
27
+ ```js
28
+ import { Dggrs } from "geoplegma-js";
29
+ const g = new Dggrs("isea3h");
30
+ const rl = 3;
31
+ const bbox = [
32
+ [-10.0, -10.0],
33
+ [10.0, 10.0],
34
+ ];
35
+ const a = g.zonesFromBbox(rl, bbox);
36
+
37
+ console.log("from bbox: " + a.map((v) => v.id));
38
+ // from bbox: 307fffffffffffff,30bfffffffffffff,31bfffffffffffff,323fffffffffffff,327fffffffffffff,32bfffffffffffff,3a7fffffffffffff
39
+ ```
40
+
41
+ ## Development
42
+
43
+ - Install dependencies:
44
+
45
+ ```bash
46
+ npm install
47
+ ```
48
+
49
+ - Get the native binding files:
50
+
51
+ ```bash
52
+ npm run build-native
53
+ ```
54
+
55
+ This will:
56
+ Build the .node files from GeoPlegma/gp-bindings/js.
57
+ Copy them into GeoPlegma-js/native/.
58
+ Let your JS code require('./native/something.node') without committing them.
59
+
60
+ - Run the unit tests:
61
+
62
+ ```bash
63
+ npm run test
64
+ ```
65
+
66
+ - Build the library:
67
+
68
+ ```bash
69
+ npm run build
70
+ ```
71
+
72
+ The `build` script will build a new folder `dist` with the bundled files inside, and copy the index.node and index.d.ts files into that same folder. This folder will be used in the npm library as the source code files.
73
+
74
+ NOTE: Eventually a github job will be added for this statement workflow.
package/dist/index.cjs ADDED
@@ -0,0 +1,110 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ const module$1 = __toESM(require("module"));
25
+ const url = __toESM(require("url"));
26
+ const path = __toESM(require("path"));
27
+
28
+ //#region src/utils.ts
29
+ function decodeZones(zones) {
30
+ const decodedZones = [];
31
+ const bufferIds = Buffer.from(zones.utf8Ids);
32
+ const bufferCoords = new Float64Array(zones.regionCoords);
33
+ for (let i = 0; i < zones.idOffsets.length; i++) {
34
+ const start = zones.idOffsets[i];
35
+ const end = i + 1 < zones.idOffsets.length ? zones.idOffsets[i + 1] : bufferIds.length;
36
+ const id = new TextDecoder("utf-8").decode(bufferIds.subarray(start, end));
37
+ const vertexCount = zones.vertexCount[i];
38
+ const regionStart = zones.regionOffsets[i];
39
+ const bufferRegion = bufferCoords.subarray(regionStart, regionStart + vertexCount * 2);
40
+ const region = [];
41
+ for (let j = 0; j < bufferRegion.length; j += 2) region.push([bufferRegion[j], bufferRegion[j + 1]]);
42
+ const children = decodeChildren(zones, i);
43
+ const neighbors = decodeNeighbors(zones, i);
44
+ decodedZones.push({
45
+ id,
46
+ center: [zones.centerX[i], zones.centerY[i]],
47
+ vertexCount,
48
+ region,
49
+ children,
50
+ neighbors
51
+ });
52
+ }
53
+ return decodedZones;
54
+ }
55
+ function decodeChildren(jsZones, zoneIndex) {
56
+ const children = [];
57
+ const start = jsZones.childrenOffsets[zoneIndex];
58
+ const end = zoneIndex + 1 < jsZones.childrenOffsets.length ? jsZones.childrenOffsets[zoneIndex + 1] : jsZones.childrenIdOffsets.length;
59
+ const buffer = new Float64Array(jsZones.childrenUtf8Ids);
60
+ for (let i = start; i < end; i++) {
61
+ const childStart = jsZones.childrenIdOffsets[i];
62
+ const childEnd = i + 1 < jsZones.childrenIdOffsets.length ? jsZones.childrenIdOffsets[i + 1] : jsZones.childrenUtf8Ids.length;
63
+ children.push(new TextDecoder("utf-8").decode(buffer.subarray(childStart, childEnd)));
64
+ }
65
+ return children;
66
+ }
67
+ function decodeNeighbors(jsZones, zoneIndex) {
68
+ const neighbors = [];
69
+ const start = jsZones.neighborsOffsets[zoneIndex];
70
+ const end = zoneIndex + 1 < jsZones.neighborsOffsets.length ? jsZones.neighborsOffsets[zoneIndex + 1] : jsZones.neighborsIdOffsets.length;
71
+ const buffer = new Float64Array(jsZones.neighborsUtf8Ids);
72
+ for (let i = start; i < end; i++) {
73
+ const nStart = jsZones.neighborsIdOffsets[i];
74
+ const nEnd = i + 1 < jsZones.neighborsIdOffsets.length ? jsZones.neighborsIdOffsets[i + 1] : jsZones.neighborsUtf8Ids.length;
75
+ neighbors.push(new TextDecoder("utf-8").decode(buffer.subarray(nStart, nEnd)));
76
+ }
77
+ return neighbors;
78
+ }
79
+
80
+ //#endregion
81
+ //#region src/native-loader.ts
82
+ const __dirname$1 = path.default.dirname((0, url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
83
+ const require$1 = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
84
+ const bindings = require$1(path.default.join(__dirname$1, "native/napi.node"));
85
+ var native_loader_default = bindings;
86
+
87
+ //#endregion
88
+ //#region src/extend.ts
89
+ const { Dggrs: Aux } = native_loader_default;
90
+ var Dggrs = class extends Aux {
91
+ constructor(name) {
92
+ super(name);
93
+ }
94
+ zonesFromBbox(refinement_level, bbox, config) {
95
+ return decodeZones(super.zonesFromBbox(refinement_level, bbox, config));
96
+ }
97
+ zoneFromPoint(refinement_level, point, config) {
98
+ return decodeZones(super.zoneFromPoint(refinement_level, point, config));
99
+ }
100
+ zonesFromParent(relative_depth, parentZoneId, config) {
101
+ return decodeZones(super.zonesFromParent(relative_depth, parentZoneId, config));
102
+ }
103
+ zoneFromId(zoneId, config) {
104
+ return decodeZones(super.zoneFromId(zoneId, config));
105
+ }
106
+ };
107
+
108
+ //#endregion
109
+ exports.Dggrs = Dggrs;
110
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["zones: any","decodedZones: any","jsZones: any","zoneIndex: any","__dirname","require","bindings","name: string","refinement_level: number","bbox?: number[][]","config?: Config","point?: number[]","relative_depth: number","parentZoneId: string","zoneId: string"],"sources":["../src/utils.ts","../src/native-loader.ts","../src/extend.ts"],"sourcesContent":["// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\n// for now the type is `any`, I will add other types in other PRs\nexport function decodeZones(zones: any) {\n const decodedZones: any = [];\n const bufferIds = Buffer.from(zones.utf8Ids);\n const bufferCoords = new Float64Array(zones.regionCoords);\n\n for (let i = 0; i < zones.idOffsets.length; i++) {\n const start = zones.idOffsets[i];\n const end =\n i + 1 < zones.idOffsets.length\n ? zones.idOffsets[i + 1]\n : bufferIds.length;\n const id = new TextDecoder(\"utf-8\").decode(bufferIds.subarray(start, end));\n\n // region coords\n const vertexCount = zones.vertexCount[i];\n const regionStart = zones.regionOffsets[i];\n const bufferRegion = bufferCoords.subarray(\n regionStart,\n regionStart + vertexCount * 2\n );\n const region = [];\n for (let j = 0; j < bufferRegion.length; j += 2) {\n region.push([bufferRegion[j], bufferRegion[j + 1]]);\n }\n\n // children\n const children = decodeChildren(zones, i);\n\n // neighbors\n const neighbors = decodeNeighbors(zones, i);\n\n decodedZones.push({\n id,\n center: [zones.centerX[i], zones.centerY[i]],\n vertexCount,\n region,\n children,\n neighbors,\n });\n }\n\n return decodedZones;\n}\n\nexport function decodeChildren(jsZones: any, zoneIndex: any) {\n const children = [];\n const start = jsZones.childrenOffsets[zoneIndex];\n const end =\n zoneIndex + 1 < jsZones.childrenOffsets.length\n ? jsZones.childrenOffsets[zoneIndex + 1]\n : jsZones.childrenIdOffsets.length;\n const buffer = new Float64Array(jsZones.childrenUtf8Ids);\n\n // childrenOffsets -> [0, 6, 12,...]\n // childrenIdOffsets -> [0, 18, 36,...]\n for (let i = start; i < end; i++) {\n const childStart = jsZones.childrenIdOffsets[i];\n const childEnd =\n i + 1 < jsZones.childrenIdOffsets.length\n ? jsZones.childrenIdOffsets[i + 1]\n : jsZones.childrenUtf8Ids.length;\n children.push(\n new TextDecoder(\"utf-8\").decode(buffer.subarray(childStart, childEnd))\n );\n }\n\n return children;\n}\n\nexport function decodeNeighbors(jsZones: any, zoneIndex: any) {\n const neighbors = [];\n const start = jsZones.neighborsOffsets[zoneIndex];\n const end =\n zoneIndex + 1 < jsZones.neighborsOffsets.length\n ? jsZones.neighborsOffsets[zoneIndex + 1]\n : jsZones.neighborsIdOffsets.length;\n\n const buffer = new Float64Array(jsZones.neighborsUtf8Ids);\n for (let i = start; i < end; i++) {\n const nStart = jsZones.neighborsIdOffsets[i];\n const nEnd =\n i + 1 < jsZones.neighborsIdOffsets.length\n ? jsZones.neighborsIdOffsets[i + 1]\n : jsZones.neighborsUtf8Ids.length;\n neighbors.push(\n new TextDecoder(\"utf-8\").decode(buffer.subarray(nStart, nEnd))\n );\n }\n return neighbors;\n}\n","// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\nimport { createRequire } from \"module\";\nimport { fileURLToPath } from \"url\";\nimport path from \"path\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst require = createRequire(import.meta.url);\n\nconst bindings = require(path.join(__dirname, \"native/napi.node\"));\n\nexport default bindings;\n","// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\nimport { decodeZones } from \"./utils\";\n\nimport bindings from \"./native-loader\";\n\nconst { Dggrs: Aux } = bindings;\n\ninterface Config {\n region: boolean;\n center: boolean;\n vertexCount: boolean;\n children: boolean;\n neighbors: boolean;\n areaSqm: boolean;\n densify: boolean;\n}\n\nexport class Dggrs extends Aux {\n constructor(name: string) {\n super(name);\n }\n zonesFromBbox(refinement_level: number, bbox?: number[][], config?: Config) {\n return decodeZones(super.zonesFromBbox(refinement_level, bbox, config));\n }\n zoneFromPoint(refinement_level: number, point?: number[], config?: Config) {\n return decodeZones(super.zoneFromPoint(refinement_level, point, config));\n }\n zonesFromParent(\n relative_depth: number,\n parentZoneId: string,\n config?: Config\n ): any {\n return decodeZones(\n super.zonesFromParent(relative_depth, parentZoneId, config)\n );\n }\n zoneFromId(zoneId: string, config?: Config): any {\n return decodeZones(super.zoneFromId(zoneId, config));\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ //#region src/extend.d.ts
2
+ declare const Aux: any;
3
+ interface Config {
4
+ region: boolean;
5
+ center: boolean;
6
+ vertexCount: boolean;
7
+ children: boolean;
8
+ neighbors: boolean;
9
+ areaSqm: boolean;
10
+ densify: boolean;
11
+ }
12
+ declare class Dggrs extends Aux {
13
+ constructor(name: string);
14
+ zonesFromBbox(refinement_level: number, bbox?: number[][], config?: Config): any;
15
+ zoneFromPoint(refinement_level: number, point?: number[], config?: Config): any;
16
+ zonesFromParent(relative_depth: number, parentZoneId: string, config?: Config): any;
17
+ zoneFromId(zoneId: string, config?: Config): any;
18
+ }
19
+ //#endregion
20
+ export { Dggrs };
21
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,21 @@
1
+ //#region src/extend.d.ts
2
+ declare const Aux: any;
3
+ interface Config {
4
+ region: boolean;
5
+ center: boolean;
6
+ vertexCount: boolean;
7
+ children: boolean;
8
+ neighbors: boolean;
9
+ areaSqm: boolean;
10
+ densify: boolean;
11
+ }
12
+ declare class Dggrs extends Aux {
13
+ constructor(name: string);
14
+ zonesFromBbox(refinement_level: number, bbox?: number[][], config?: Config): any;
15
+ zoneFromPoint(refinement_level: number, point?: number[], config?: Config): any;
16
+ zonesFromParent(relative_depth: number, parentZoneId: string, config?: Config): any;
17
+ zoneFromId(zoneId: string, config?: Config): any;
18
+ }
19
+ //#endregion
20
+ export { Dggrs };
21
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,87 @@
1
+ import { createRequire } from "module";
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+
5
+ //#region src/utils.ts
6
+ function decodeZones(zones) {
7
+ const decodedZones = [];
8
+ const bufferIds = Buffer.from(zones.utf8Ids);
9
+ const bufferCoords = new Float64Array(zones.regionCoords);
10
+ for (let i = 0; i < zones.idOffsets.length; i++) {
11
+ const start = zones.idOffsets[i];
12
+ const end = i + 1 < zones.idOffsets.length ? zones.idOffsets[i + 1] : bufferIds.length;
13
+ const id = new TextDecoder("utf-8").decode(bufferIds.subarray(start, end));
14
+ const vertexCount = zones.vertexCount[i];
15
+ const regionStart = zones.regionOffsets[i];
16
+ const bufferRegion = bufferCoords.subarray(regionStart, regionStart + vertexCount * 2);
17
+ const region = [];
18
+ for (let j = 0; j < bufferRegion.length; j += 2) region.push([bufferRegion[j], bufferRegion[j + 1]]);
19
+ const children = decodeChildren(zones, i);
20
+ const neighbors = decodeNeighbors(zones, i);
21
+ decodedZones.push({
22
+ id,
23
+ center: [zones.centerX[i], zones.centerY[i]],
24
+ vertexCount,
25
+ region,
26
+ children,
27
+ neighbors
28
+ });
29
+ }
30
+ return decodedZones;
31
+ }
32
+ function decodeChildren(jsZones, zoneIndex) {
33
+ const children = [];
34
+ const start = jsZones.childrenOffsets[zoneIndex];
35
+ const end = zoneIndex + 1 < jsZones.childrenOffsets.length ? jsZones.childrenOffsets[zoneIndex + 1] : jsZones.childrenIdOffsets.length;
36
+ const buffer = new Float64Array(jsZones.childrenUtf8Ids);
37
+ for (let i = start; i < end; i++) {
38
+ const childStart = jsZones.childrenIdOffsets[i];
39
+ const childEnd = i + 1 < jsZones.childrenIdOffsets.length ? jsZones.childrenIdOffsets[i + 1] : jsZones.childrenUtf8Ids.length;
40
+ children.push(new TextDecoder("utf-8").decode(buffer.subarray(childStart, childEnd)));
41
+ }
42
+ return children;
43
+ }
44
+ function decodeNeighbors(jsZones, zoneIndex) {
45
+ const neighbors = [];
46
+ const start = jsZones.neighborsOffsets[zoneIndex];
47
+ const end = zoneIndex + 1 < jsZones.neighborsOffsets.length ? jsZones.neighborsOffsets[zoneIndex + 1] : jsZones.neighborsIdOffsets.length;
48
+ const buffer = new Float64Array(jsZones.neighborsUtf8Ids);
49
+ for (let i = start; i < end; i++) {
50
+ const nStart = jsZones.neighborsIdOffsets[i];
51
+ const nEnd = i + 1 < jsZones.neighborsIdOffsets.length ? jsZones.neighborsIdOffsets[i + 1] : jsZones.neighborsUtf8Ids.length;
52
+ neighbors.push(new TextDecoder("utf-8").decode(buffer.subarray(nStart, nEnd)));
53
+ }
54
+ return neighbors;
55
+ }
56
+
57
+ //#endregion
58
+ //#region src/native-loader.ts
59
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
60
+ const require = createRequire(import.meta.url);
61
+ const bindings = require(path.join(__dirname, "native/napi.node"));
62
+ var native_loader_default = bindings;
63
+
64
+ //#endregion
65
+ //#region src/extend.ts
66
+ const { Dggrs: Aux } = native_loader_default;
67
+ var Dggrs = class extends Aux {
68
+ constructor(name) {
69
+ super(name);
70
+ }
71
+ zonesFromBbox(refinement_level, bbox, config) {
72
+ return decodeZones(super.zonesFromBbox(refinement_level, bbox, config));
73
+ }
74
+ zoneFromPoint(refinement_level, point, config) {
75
+ return decodeZones(super.zoneFromPoint(refinement_level, point, config));
76
+ }
77
+ zonesFromParent(relative_depth, parentZoneId, config) {
78
+ return decodeZones(super.zonesFromParent(relative_depth, parentZoneId, config));
79
+ }
80
+ zoneFromId(zoneId, config) {
81
+ return decodeZones(super.zoneFromId(zoneId, config));
82
+ }
83
+ };
84
+
85
+ //#endregion
86
+ export { Dggrs };
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["zones: any","decodedZones: any","jsZones: any","zoneIndex: any","bindings","name: string","refinement_level: number","bbox?: number[][]","config?: Config","point?: number[]","relative_depth: number","parentZoneId: string","zoneId: string"],"sources":["../src/utils.ts","../src/native-loader.ts","../src/extend.ts"],"sourcesContent":["// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\n// for now the type is `any`, I will add other types in other PRs\nexport function decodeZones(zones: any) {\n const decodedZones: any = [];\n const bufferIds = Buffer.from(zones.utf8Ids);\n const bufferCoords = new Float64Array(zones.regionCoords);\n\n for (let i = 0; i < zones.idOffsets.length; i++) {\n const start = zones.idOffsets[i];\n const end =\n i + 1 < zones.idOffsets.length\n ? zones.idOffsets[i + 1]\n : bufferIds.length;\n const id = new TextDecoder(\"utf-8\").decode(bufferIds.subarray(start, end));\n\n // region coords\n const vertexCount = zones.vertexCount[i];\n const regionStart = zones.regionOffsets[i];\n const bufferRegion = bufferCoords.subarray(\n regionStart,\n regionStart + vertexCount * 2\n );\n const region = [];\n for (let j = 0; j < bufferRegion.length; j += 2) {\n region.push([bufferRegion[j], bufferRegion[j + 1]]);\n }\n\n // children\n const children = decodeChildren(zones, i);\n\n // neighbors\n const neighbors = decodeNeighbors(zones, i);\n\n decodedZones.push({\n id,\n center: [zones.centerX[i], zones.centerY[i]],\n vertexCount,\n region,\n children,\n neighbors,\n });\n }\n\n return decodedZones;\n}\n\nexport function decodeChildren(jsZones: any, zoneIndex: any) {\n const children = [];\n const start = jsZones.childrenOffsets[zoneIndex];\n const end =\n zoneIndex + 1 < jsZones.childrenOffsets.length\n ? jsZones.childrenOffsets[zoneIndex + 1]\n : jsZones.childrenIdOffsets.length;\n const buffer = new Float64Array(jsZones.childrenUtf8Ids);\n\n // childrenOffsets -> [0, 6, 12,...]\n // childrenIdOffsets -> [0, 18, 36,...]\n for (let i = start; i < end; i++) {\n const childStart = jsZones.childrenIdOffsets[i];\n const childEnd =\n i + 1 < jsZones.childrenIdOffsets.length\n ? jsZones.childrenIdOffsets[i + 1]\n : jsZones.childrenUtf8Ids.length;\n children.push(\n new TextDecoder(\"utf-8\").decode(buffer.subarray(childStart, childEnd))\n );\n }\n\n return children;\n}\n\nexport function decodeNeighbors(jsZones: any, zoneIndex: any) {\n const neighbors = [];\n const start = jsZones.neighborsOffsets[zoneIndex];\n const end =\n zoneIndex + 1 < jsZones.neighborsOffsets.length\n ? jsZones.neighborsOffsets[zoneIndex + 1]\n : jsZones.neighborsIdOffsets.length;\n\n const buffer = new Float64Array(jsZones.neighborsUtf8Ids);\n for (let i = start; i < end; i++) {\n const nStart = jsZones.neighborsIdOffsets[i];\n const nEnd =\n i + 1 < jsZones.neighborsIdOffsets.length\n ? jsZones.neighborsIdOffsets[i + 1]\n : jsZones.neighborsUtf8Ids.length;\n neighbors.push(\n new TextDecoder(\"utf-8\").decode(buffer.subarray(nStart, nEnd))\n );\n }\n return neighbors;\n}\n","// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\nimport { createRequire } from \"module\";\nimport { fileURLToPath } from \"url\";\nimport path from \"path\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst require = createRequire(import.meta.url);\n\nconst bindings = require(path.join(__dirname, \"native/napi.node\"));\n\nexport default bindings;\n","// Copyright 2025 contributors to the GeoPlegma project.\n// Originally authored by João Manuel (GeoInsight GmbH, joao.manuel@geoinsight.ai)\n//\n// Licenced under the Apache Licence, Version 2.0 <LICENCE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n// <LICENCE-MIT or http://opensource.org/licenses/MIT>, at your\n// discretion. This file may not be copied, modified, or distributed\n// except according to those terms.\n\nimport { decodeZones } from \"./utils\";\n\nimport bindings from \"./native-loader\";\n\nconst { Dggrs: Aux } = bindings;\n\ninterface Config {\n region: boolean;\n center: boolean;\n vertexCount: boolean;\n children: boolean;\n neighbors: boolean;\n areaSqm: boolean;\n densify: boolean;\n}\n\nexport class Dggrs extends Aux {\n constructor(name: string) {\n super(name);\n }\n zonesFromBbox(refinement_level: number, bbox?: number[][], config?: Config) {\n return decodeZones(super.zonesFromBbox(refinement_level, bbox, config));\n }\n zoneFromPoint(refinement_level: number, point?: number[], config?: Config) {\n return decodeZones(super.zoneFromPoint(refinement_level, point, config));\n }\n zonesFromParent(\n relative_depth: number,\n parentZoneId: string,\n config?: Config\n ): any {\n return decodeZones(\n super.zonesFromParent(relative_depth, parentZoneId, config)\n );\n }\n zoneFromId(zoneId: string, config?: Config): any {\n return decodeZones(super.zoneFromId(zoneId, config));\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /* auto-generated by NAPI-RS */
2
+ /* eslint-disable */
3
+ export declare class Dggrs {
4
+ constructor(dggrs: string)
5
+ zonesFromBbox(refinementLevel: number, bbox?: Array<Array<number>> | undefined | null, config?: Config | undefined | null): FlatZones
6
+ zoneFromPoint(refinementLevel: number, point?: Array<number> | undefined | null, config?: Config | undefined | null): FlatZones
7
+ zonesFromParent(relativeDepth: number, parentZoneId: string, config?: Config | undefined | null): FlatZones
8
+ zoneFromId(zoneId: string, config?: Config | undefined | null): FlatZones
9
+ }
10
+
11
+ export interface Config {
12
+ region: boolean
13
+ center: boolean
14
+ vertexCount: boolean
15
+ children: boolean
16
+ neighbors: boolean
17
+ areaSqm: boolean
18
+ densify: boolean
19
+ }
20
+
21
+ export declare function defaultConfig(): Config
22
+
23
+ /**
24
+ * The Zone struct has nested heap allocations (String, Vec<(f64,f64)>, Vec<String>), which means:
25
+ * - Each String is 24 bytes (ptr, len, capacity) + heap data.
26
+ * - Each (f64, f64) is fine in Rust, but Vec<(f64,f64)> is not a flat Vec<f64> in wasm/napi-rs.
27
+ * - wasm/napi-rs will have to walk and serialize everything, which is slow for thousands of zones.
28
+ * No napi-rs overhead per zone — you pass one pointer + length per field instead of millions of small objects.
29
+ * Zero-copy — JS reads directly from WebAssembly memory.
30
+ * Keeps geometry-heavy Zone struct in Rust for efficient calculations.
31
+ * Scales to millions of zones without crashing the browser or blowing up memory usage.
32
+ * Tradeoff
33
+ * Pro: Hugely faster for large datasets
34
+ * Con: JS side reconstruction is manual — you need to decode UTF-8 strings from byte arrays using TextDecoder and use offset tables.
35
+ */
36
+ export interface FlatZones {
37
+ idOffsets: Array<number>
38
+ utf8Ids: Array<number>
39
+ centerX: Array<number>
40
+ centerY: Array<number>
41
+ vertexCount: Array<number>
42
+ regionOffsets: Array<number>
43
+ regionCoords: Array<number>
44
+ childrenOffsets: Array<number>
45
+ childrenIdOffsets: Array<number>
46
+ childrenUtf8Ids: Array<number>
47
+ neighborsOffsets: Array<number>
48
+ neighborsIdOffsets: Array<number>
49
+ neighborsUtf8Ids: Array<number>
50
+ }
51
+
52
+ export declare const enum Id {
53
+ String = 'String',
54
+ U64 = 'U64'
55
+ }
56
+
57
+ export interface Zone {
58
+ id: Id
59
+ region: Array<Array<number>>
60
+ center: Array<number>
61
+ vertexCount: number
62
+ children?: Array<Id>
63
+ neighbors?: Array<Id>
64
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "geoplegma-js",
3
+ "version": "0.0.0-beta",
4
+ "description": "A JavaScript library for GeoPlegma.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/GeoPlegma/GeoPlegma-js#readme",
8
+ "bugs": {
9
+ "url": "https://github.com/GeoPlegma/GeoPlegma-js/issues"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/GeoPlegma/GeoPlegma-js.git"
14
+ },
15
+ "author": "João Manuel <joaocsmanuel@gmail.com>",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": "./dist/index.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsdown",
31
+ "dev": "tsdown --watch",
32
+ "build-native": "scripts/dev.sh",
33
+ "test": "vitest",
34
+ "typecheck": "tsc --noEmit",
35
+ "release": "bumpp && npm publish"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.15.17",
39
+ "bumpp": "^10.1.0",
40
+ "tsdown": "^0.11.9",
41
+ "typescript": "^5.8.3",
42
+ "vitest": "^3.1.3"
43
+ },
44
+ "dependencies": {
45
+ "bindings": "^1.5.0"
46
+ }
47
+ }