1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
//
// Script that generates r-trees for geo data.
// run with `npx ts-node geo-data/prepare-rtree.ts`
//
import * as fs from 'fs';
import * as path from 'path';
import { Topology, GeometryCollection } from 'topojson-specification';
import { GeoJSON } from 'geojson';
import rbush from 'rbush';
interface GeometryTopologyObjects {
[key: string]: any;
geometry: GeometryCollection;
}
function main() {
const GEOMETRY_DATA_FILES = ['geometry', 'states-provinces-lines'];
const POINT_DATA_FILES = ['countries', 'cities'];
const OUTPUT_DIR = path.join(__dirname, 'out');
for (const name of GEOMETRY_DATA_FILES) {
const source = path.join(OUTPUT_DIR, `${name}.json`);
const destination = path.join(OUTPUT_DIR, `${name}.rbush.json`);
try {
processGeometry(source, destination);
} catch (error) {
console.error(`Failed to process ${name}: ${error.message}`);
}
}
for (const name of POINT_DATA_FILES) {
const source = path.join(OUTPUT_DIR, `${name}.json`);
const destination = path.join(OUTPUT_DIR, `${name}.rbush.json`);
try {
processPoints(source, destination);
} catch (error) {
console.error(`Failed to process ${name}: ${error.message}`);
}
}
}
function processGeometry(source: string, destination: string) {
const collection = JSON.parse(fs.readFileSync(source, { encoding: 'utf8' })) as Topology<
GeometryTopologyObjects
>;
const { geometry } = collection.objects;
const treeData = geometry.geometries.map((object, i) => {
if (!object.bbox) {
throw new Error(`Expected a geometry at index ${i} to have a bbox property.`);
}
const [minX, minY, maxX, maxY] = object.bbox;
return {
...object,
minX,
minY,
maxX,
maxY,
};
});
const tree = rbush();
tree.load(treeData);
fs.writeFileSync(destination, JSON.stringify(tree.toJSON()));
console.log(`Saved a rbush to ${destination}`);
}
function processPoints(source: string, destination: string) {
const collection = JSON.parse(fs.readFileSync(source, { encoding: 'utf8' })) as GeoJSON;
if (collection.type !== 'FeatureCollection') {
throw new Error(
`Invalid collection type ${collection.type} in ${source}. Expected FeatureCollection`,
);
}
const treeData = collection.features.map((feat) => {
if (feat.geometry.type !== 'Point') {
throw new Error(`Invalid geometry in ${source}. Expected "Point", got ${feat.geometry.type}`);
}
const { coordinates } = feat.geometry;
return {
...feat,
minX: coordinates[0],
minY: coordinates[1],
maxX: coordinates[0],
maxY: coordinates[1],
};
});
const tree = rbush();
tree.load(treeData);
fs.writeFileSync(destination, JSON.stringify(tree.toJSON()));
console.log(`Saved a rbush to ${destination}`);
}
main();
|