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 +74 -0
- package/dist/index.cjs +110 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/native/index.d.ts +64 -0
- package/dist/native/napi.node +0 -0
- package/package.json +47 -0
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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"}
|
package/dist/index.d.cts
ADDED
|
@@ -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
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|