@osm-editor-kit/osm-coverage 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +1 -2
- package/dist/coverage-geometry.d.ts +5 -0
- package/dist/index.js +23 -17
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -22,8 +22,7 @@ import { createOsmCoverageApi, OsmDataSource } from '@osm-editor-kit/osm-coverag
|
|
|
22
22
|
const api = createOsmCoverageApi<{ source: OsmDataSource }>({
|
|
23
23
|
getSessionKey: ({ source }) => ['osm', source] as const,
|
|
24
24
|
minZoom: 14,
|
|
25
|
-
getDownloadUrl: (bounds, { source }) =>
|
|
26
|
-
/* build Overpass or Map API URL */ '',
|
|
25
|
+
getDownloadUrl: (bounds, { source }) => /* build Overpass or Map API URL */ '',
|
|
27
26
|
// optional: storage: { load, save, clear }
|
|
28
27
|
})
|
|
29
28
|
|
|
@@ -31,6 +31,11 @@ export declare function isValidBounds(bounds: MapBounds): boolean;
|
|
|
31
31
|
export declare function boundsArea(bounds: MapBounds): number;
|
|
32
32
|
export declare function bufferBoundsInViewport(request: MapBounds, viewport: MapBounds, zoom: number, mapSizePx: MapSizePx): MapBounds;
|
|
33
33
|
export declare function clampBoundsToViewport(request: MapBounds, viewport: MapBounds): MapBounds;
|
|
34
|
+
/** Lon/lat length of the zoom-aware seam overlap (same magnitude as fetch buffer). */
|
|
35
|
+
export declare function overlapDeltaAtZoom(viewport: MapBounds, zoom: number, mapSizePx: MapSizePx): {
|
|
36
|
+
lon: number;
|
|
37
|
+
lat: number;
|
|
38
|
+
};
|
|
34
39
|
export declare function createViewportFetchRequest(viewport: MapBounds, zoom: number, mapSizePx: MapSizePx, kind: CoverageFetchKind): CoverageFetchRequest | null;
|
|
35
40
|
export declare function computeMissingFetchRequests(viewport: MapBounds, coverage: Feature<Polygon | MultiPolygon> | null, zoom: number, mapSizePx: MapSizePx): CoverageFetchRequest[];
|
|
36
41
|
export declare function unionIntoCoverage(coverage: Feature<Polygon | MultiPolygon> | null, requestBounds: MapBounds): Feature<Polygon | MultiPolygon>;
|
package/dist/index.js
CHANGED
|
@@ -48,19 +48,15 @@ function bufferBoundsInViewport(request, viewport, zoom, mapSizePx) {
|
|
|
48
48
|
north: request.north + latBuffer
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function overlapDeltaAtZoom(viewport, zoom, mapSizePx) {
|
|
52
|
+
const px = bufferPxAtZoom(zoom);
|
|
52
53
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
east: Math.min(request.east, viewport.east),
|
|
56
|
-
north: Math.min(request.north, viewport.north)
|
|
54
|
+
lon: px * (viewport.east - viewport.west) / mapSizePx.width,
|
|
55
|
+
lat: px * (viewport.north - viewport.south) / mapSizePx.height
|
|
57
56
|
};
|
|
58
57
|
}
|
|
59
58
|
function prepareFetchBounds(request, viewport, zoom, mapSizePx) {
|
|
60
|
-
const buffered =
|
|
61
|
-
bufferBoundsInViewport(request, viewport, zoom, mapSizePx),
|
|
62
|
-
viewport
|
|
63
|
-
);
|
|
59
|
+
const buffered = bufferBoundsInViewport(request, viewport, zoom, mapSizePx);
|
|
64
60
|
if (!isValidBounds(buffered)) return null;
|
|
65
61
|
const viewportArea = boundsArea(viewport);
|
|
66
62
|
if (boundsArea(buffered) < MIN_MISSING_AREA_RATIO * viewportArea) return null;
|
|
@@ -74,27 +70,28 @@ function missingParts(viewport, coverage) {
|
|
|
74
70
|
(feature) => feature.geometry.type === "Polygon"
|
|
75
71
|
);
|
|
76
72
|
}
|
|
77
|
-
function stripCandidates(viewport, coverage, missingPart) {
|
|
73
|
+
function stripCandidates(viewport, coverage, missingPart, zoom, mapSizePx) {
|
|
78
74
|
const viewportPoly = boundsToPolygon(viewport);
|
|
79
75
|
const covered = intersect(featureCollection([viewportPoly, coverage]));
|
|
80
76
|
if (!covered) return [];
|
|
81
77
|
const coveredBbox = polygonToBounds(covered);
|
|
78
|
+
const { lon, lat } = overlapDeltaAtZoom(viewport, zoom, mapSizePx);
|
|
82
79
|
const candidates = [
|
|
83
80
|
{
|
|
84
81
|
west: viewport.west,
|
|
85
82
|
south: viewport.south,
|
|
86
|
-
east: coveredBbox.west,
|
|
83
|
+
east: Math.min(viewport.east, coveredBbox.west + lon),
|
|
87
84
|
north: viewport.north
|
|
88
85
|
},
|
|
89
86
|
{
|
|
90
|
-
west: coveredBbox.east,
|
|
87
|
+
west: Math.max(viewport.west, coveredBbox.east - lon),
|
|
91
88
|
south: viewport.south,
|
|
92
89
|
east: viewport.east,
|
|
93
90
|
north: viewport.north
|
|
94
91
|
},
|
|
95
92
|
{
|
|
96
93
|
west: viewport.west,
|
|
97
|
-
south: coveredBbox.north,
|
|
94
|
+
south: Math.max(viewport.south, coveredBbox.north - lat),
|
|
98
95
|
east: viewport.east,
|
|
99
96
|
north: viewport.north
|
|
100
97
|
},
|
|
@@ -102,7 +99,7 @@ function stripCandidates(viewport, coverage, missingPart) {
|
|
|
102
99
|
west: viewport.west,
|
|
103
100
|
south: viewport.south,
|
|
104
101
|
east: viewport.east,
|
|
105
|
-
north: coveredBbox.south
|
|
102
|
+
north: Math.min(viewport.north, coveredBbox.south + lat)
|
|
106
103
|
}
|
|
107
104
|
];
|
|
108
105
|
return candidates.filter((strip) => {
|
|
@@ -111,14 +108,14 @@ function stripCandidates(viewport, coverage, missingPart) {
|
|
|
111
108
|
return overlap !== null && area(overlap) > 0;
|
|
112
109
|
});
|
|
113
110
|
}
|
|
114
|
-
function chooseBoundsForMissingPart(viewport, coverage, missingPart) {
|
|
111
|
+
function chooseBoundsForMissingPart(viewport, coverage, missingPart, zoom, mapSizePx) {
|
|
115
112
|
const partArea = area(missingPart);
|
|
116
113
|
const partBbox = polygonToBounds(missingPart);
|
|
117
114
|
const fillRatio = partArea / area(boundsToPolygon(partBbox));
|
|
118
115
|
if (fillRatio >= HIGH_FILL_RATIO) {
|
|
119
116
|
return [partBbox];
|
|
120
117
|
}
|
|
121
|
-
const strips = stripCandidates(viewport, coverage, missingPart);
|
|
118
|
+
const strips = stripCandidates(viewport, coverage, missingPart, zoom, mapSizePx);
|
|
122
119
|
const stripAreas = strips.map((strip) => ({ bounds: strip, area: boundsArea(strip) })).sort((a, b) => b.area - a.area);
|
|
123
120
|
const stripTotalArea = stripAreas.reduce((sum, strip) => sum + strip.area, 0);
|
|
124
121
|
const bboxArea = boundsArea(partBbox);
|
|
@@ -143,7 +140,7 @@ function computeMissingFetchRequests(viewport, coverage, zoom, mapSizePx) {
|
|
|
143
140
|
);
|
|
144
141
|
if (significantParts.length === 0) return [];
|
|
145
142
|
const rawBounds = significantParts.flatMap(
|
|
146
|
-
(part) => chooseBoundsForMissingPart(viewport, coverage, part)
|
|
143
|
+
(part) => chooseBoundsForMissingPart(viewport, coverage, part, zoom, mapSizePx)
|
|
147
144
|
);
|
|
148
145
|
let requests = rawBounds.map((request) => {
|
|
149
146
|
const prepared = prepareFetchBounds(request, viewport, zoom, mapSizePx);
|
|
@@ -160,6 +157,15 @@ function computeMissingFetchRequests(viewport, coverage, zoom, mapSizePx) {
|
|
|
160
157
|
return full ? [full] : [];
|
|
161
158
|
}
|
|
162
159
|
requests = requests.slice(0, MAX_STRIP_REQUESTS);
|
|
160
|
+
let projected = coverage;
|
|
161
|
+
for (const request of requests) {
|
|
162
|
+
projected = unionIntoCoverage(projected, request.bounds);
|
|
163
|
+
}
|
|
164
|
+
const leftover = missingParts(viewport, projected).reduce((sum, part) => sum + area(part), 0);
|
|
165
|
+
if (leftover >= MIN_MISSING_AREA_RATIO * viewportArea) {
|
|
166
|
+
const full = createViewportFetchRequest(viewport, zoom, mapSizePx, "full");
|
|
167
|
+
return full ? [full] : [];
|
|
168
|
+
}
|
|
163
169
|
return requests.map((request) => ({
|
|
164
170
|
bounds: request.bounds,
|
|
165
171
|
kind: request.kind
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osm-editor-kit/osm-coverage",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "Incremental OSM coverage fetching for map viewports with TanStack Query session state.",
|
|
5
|
+
"homepage": "https://github.com/osmberlin/street-space-editor/tree/main/packages/osm-coverage",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"author": "Tobias Jordans",
|
|
7
8
|
"repository": {
|
|
@@ -9,12 +10,11 @@
|
|
|
9
10
|
"url": "git+https://github.com/osmberlin/street-space-editor.git",
|
|
10
11
|
"directory": "packages/osm-coverage"
|
|
11
12
|
},
|
|
12
|
-
"homepage": "https://github.com/osmberlin/street-space-editor/tree/main/packages/osm-coverage",
|
|
13
|
-
"type": "module",
|
|
14
|
-
"sideEffects": false,
|
|
15
13
|
"files": [
|
|
16
14
|
"dist"
|
|
17
15
|
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"postpack": "bun ../../scripts/package-exports-restore.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@osm-editor-kit/osm-data": "
|
|
39
|
+
"@osm-editor-kit/osm-data": "^0.1.0-alpha.1",
|
|
40
40
|
"@tanstack/react-query": "^5.85.5",
|
|
41
41
|
"@turf/area": "^7.3.5",
|
|
42
42
|
"@turf/bbox": "^7.3.5",
|