@osmix/shared 0.0.2 → 0.0.7
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/CHANGELOG.md +33 -0
- package/README.md +49 -19
- package/dist/assert.d.ts +24 -0
- package/dist/assert.d.ts.map +1 -0
- package/dist/assert.js +28 -0
- package/dist/assert.js.map +1 -0
- package/dist/bbox-intersects.d.ts +15 -0
- package/dist/bbox-intersects.d.ts.map +1 -0
- package/dist/bbox-intersects.js +24 -0
- package/dist/bbox-intersects.js.map +1 -0
- package/dist/bytes-to-stream.d.ts +18 -0
- package/dist/bytes-to-stream.d.ts.map +1 -0
- package/dist/bytes-to-stream.js +25 -0
- package/dist/bytes-to-stream.js.map +1 -0
- package/dist/color.d.ts +4 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +33 -0
- package/dist/color.js.map +1 -0
- package/dist/concat-bytes.d.ts +5 -0
- package/dist/concat-bytes.d.ts.map +1 -0
- package/dist/concat-bytes.js +14 -0
- package/dist/concat-bytes.js.map +1 -0
- package/dist/coordinates.d.ts +28 -0
- package/dist/coordinates.d.ts.map +1 -0
- package/dist/coordinates.js +38 -0
- package/dist/coordinates.js.map +1 -0
- package/dist/haversine-distance.d.ts +16 -0
- package/dist/haversine-distance.d.ts.map +1 -0
- package/dist/haversine-distance.js +26 -0
- package/dist/haversine-distance.js.map +1 -0
- package/dist/lineclip.d.ts +2 -0
- package/dist/lineclip.d.ts.map +1 -0
- package/dist/lineclip.js +3 -0
- package/dist/lineclip.js.map +1 -0
- package/dist/progress.d.ts +42 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +53 -0
- package/dist/progress.js.map +1 -0
- package/dist/relation-kind.d.ts +69 -0
- package/dist/relation-kind.d.ts.map +1 -0
- package/dist/relation-kind.js +375 -0
- package/dist/relation-kind.js.map +1 -0
- package/dist/relation-multipolygon.d.ts +43 -0
- package/dist/relation-multipolygon.d.ts.map +1 -0
- package/dist/relation-multipolygon.js +195 -0
- package/dist/relation-multipolygon.js.map +1 -0
- package/dist/src/assert.d.ts +20 -1
- package/dist/src/assert.d.ts.map +1 -1
- package/dist/src/assert.js +20 -1
- package/dist/src/assert.js.map +1 -1
- package/dist/src/bbox-intersects.d.ts +15 -0
- package/dist/src/bbox-intersects.d.ts.map +1 -0
- package/dist/src/bbox-intersects.js +24 -0
- package/dist/src/bbox-intersects.js.map +1 -0
- package/dist/src/bytes-to-stream.d.ts +17 -1
- package/dist/src/bytes-to-stream.d.ts.map +1 -1
- package/dist/src/bytes-to-stream.js +16 -0
- package/dist/src/bytes-to-stream.js.map +1 -1
- package/dist/src/color.d.ts +4 -0
- package/dist/src/color.d.ts.map +1 -0
- package/dist/src/color.js +33 -0
- package/dist/src/color.js.map +1 -0
- package/dist/src/coordinates.d.ts +28 -0
- package/dist/src/coordinates.d.ts.map +1 -0
- package/dist/src/coordinates.js +38 -0
- package/dist/src/coordinates.js.map +1 -0
- package/dist/src/haversine-distance.d.ts +9 -1
- package/dist/src/haversine-distance.d.ts.map +1 -1
- package/dist/src/haversine-distance.js +9 -1
- package/dist/src/haversine-distance.js.map +1 -1
- package/dist/src/progress.d.ts +42 -0
- package/dist/src/progress.d.ts.map +1 -0
- package/dist/src/progress.js +53 -0
- package/dist/src/progress.js.map +1 -0
- package/dist/src/relation-kind.d.ts +69 -0
- package/dist/src/relation-kind.d.ts.map +1 -0
- package/dist/src/relation-kind.js +375 -0
- package/dist/src/relation-kind.js.map +1 -0
- package/dist/src/relation-multipolygon.d.ts +43 -0
- package/dist/src/relation-multipolygon.d.ts.map +1 -0
- package/dist/src/relation-multipolygon.js +195 -0
- package/dist/src/relation-multipolygon.js.map +1 -0
- package/dist/src/stream-to-bytes.d.ts +16 -0
- package/dist/src/stream-to-bytes.d.ts.map +1 -1
- package/dist/src/stream-to-bytes.js +16 -0
- package/dist/src/stream-to-bytes.js.map +1 -1
- package/dist/src/test/fixtures.d.ts +1 -1
- package/dist/src/test/fixtures.d.ts.map +1 -1
- package/dist/src/test/fixtures.js +16 -8
- package/dist/src/test/fixtures.js.map +1 -1
- package/dist/src/throttle.d.ts +25 -0
- package/dist/src/throttle.d.ts.map +1 -0
- package/dist/src/throttle.js +34 -0
- package/dist/src/throttle.js.map +1 -0
- package/dist/src/tile.d.ts +34 -0
- package/dist/src/tile.d.ts.map +1 -0
- package/dist/src/tile.js +72 -0
- package/dist/src/tile.js.map +1 -0
- package/dist/src/transform-bytes.d.ts +22 -0
- package/dist/src/transform-bytes.d.ts.map +1 -1
- package/dist/src/transform-bytes.js +22 -0
- package/dist/src/transform-bytes.js.map +1 -1
- package/dist/src/types.d.ts +76 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +8 -0
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +70 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/way-is-area.d.ts +24 -0
- package/dist/src/way-is-area.d.ts.map +1 -0
- package/dist/src/way-is-area.js +104 -0
- package/dist/src/way-is-area.js.map +1 -0
- package/dist/src/zigzag.d.ts +33 -0
- package/dist/src/zigzag.d.ts.map +1 -0
- package/dist/src/zigzag.js +40 -0
- package/dist/src/zigzag.js.map +1 -0
- package/dist/stream-to-bytes.d.ts +18 -0
- package/dist/stream-to-bytes.d.ts.map +1 -0
- package/dist/stream-to-bytes.js +30 -0
- package/dist/stream-to-bytes.js.map +1 -0
- package/dist/test/fixtures.d.ts +36 -0
- package/dist/test/fixtures.d.ts.map +1 -0
- package/dist/test/fixtures.js +175 -0
- package/dist/test/fixtures.js.map +1 -0
- package/dist/test/haversine-distance.test.js +2 -2
- package/dist/test/haversine-distance.test.js.map +1 -1
- package/dist/test/relation-kind.test.d.ts +2 -0
- package/dist/test/relation-kind.test.d.ts.map +1 -0
- package/dist/test/relation-kind.test.js +367 -0
- package/dist/test/relation-kind.test.js.map +1 -0
- package/dist/test/relation-multipolygon.test.d.ts +2 -0
- package/dist/test/relation-multipolygon.test.d.ts.map +1 -0
- package/dist/test/relation-multipolygon.test.js +237 -0
- package/dist/test/relation-multipolygon.test.js.map +1 -0
- package/dist/test/utils.test.d.ts +2 -0
- package/dist/test/utils.test.d.ts.map +1 -0
- package/dist/test/utils.test.js +76 -0
- package/dist/test/utils.test.js.map +1 -0
- package/dist/test/way-is-area.test.d.ts +2 -0
- package/dist/test/way-is-area.test.d.ts.map +1 -0
- package/dist/test/way-is-area.test.js +31 -0
- package/dist/test/way-is-area.test.js.map +1 -0
- package/dist/throttle.d.ts +25 -0
- package/dist/throttle.d.ts.map +1 -0
- package/dist/throttle.js +34 -0
- package/dist/throttle.js.map +1 -0
- package/dist/tile.d.ts +34 -0
- package/dist/tile.d.ts.map +1 -0
- package/dist/tile.js +72 -0
- package/dist/tile.js.map +1 -0
- package/dist/transform-bytes.d.ts +24 -0
- package/dist/transform-bytes.d.ts.map +1 -0
- package/dist/transform-bytes.js +28 -0
- package/dist/transform-bytes.js.map +1 -0
- package/dist/types.d.ts +99 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +30 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +70 -0
- package/dist/utils.js.map +1 -0
- package/dist/way-is-area.d.ts +24 -0
- package/dist/way-is-area.d.ts.map +1 -0
- package/dist/way-is-area.js +104 -0
- package/dist/way-is-area.js.map +1 -0
- package/dist/zigzag.d.ts +33 -0
- package/dist/zigzag.d.ts.map +1 -0
- package/dist/zigzag.js +40 -0
- package/dist/zigzag.js.map +1 -0
- package/package.json +11 -10
- package/src/assert.ts +21 -1
- package/src/bbox-intersects.ts +30 -0
- package/src/bytes-to-stream.ts +17 -0
- package/src/color.ts +37 -0
- package/src/coordinates.ts +45 -0
- package/src/haversine-distance.ts +10 -1
- package/src/progress.ts +74 -0
- package/src/relation-kind.ts +446 -0
- package/src/relation-multipolygon.ts +225 -0
- package/src/stream-to-bytes.ts +17 -0
- package/src/test/fixtures.ts +16 -12
- package/src/throttle.ts +37 -0
- package/src/tile.ts +89 -0
- package/src/transform-bytes.ts +23 -0
- package/src/types.ts +93 -1
- package/src/utils.ts +79 -0
- package/src/way-is-area.ts +107 -0
- package/src/zigzag.ts +42 -0
- package/test/haversine-distance.test.ts +2 -2
- package/test/relation-kind.test.ts +426 -0
- package/test/relation-multipolygon.test.ts +265 -0
- package/test/utils.test.ts +103 -0
- package/test/way-is-area.test.ts +42 -0
- package/tsconfig/test.json +1 -0
- package/tsconfig.build.json +5 -0
- package/dist/src/spherical-mercator.d.ts +0 -15
- package/dist/src/spherical-mercator.d.ts.map +0 -1
- package/dist/src/spherical-mercator.js +0 -35
- package/dist/src/spherical-mercator.js.map +0 -1
- package/dist/src/spherical-mercator.test.d.ts +0 -2
- package/dist/src/spherical-mercator.test.d.ts.map +0 -1
- package/dist/src/spherical-mercator.test.js +0 -25
- package/dist/src/spherical-mercator.test.js.map +0 -1
- package/src/spherical-mercator.test.ts +0 -42
- package/src/spherical-mercator.ts +0 -42
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
|
+
import {
|
|
3
|
+
buildRelationRings,
|
|
4
|
+
connectWaysToRings,
|
|
5
|
+
getWayMembersByRole,
|
|
6
|
+
} from "../src/relation-multipolygon"
|
|
7
|
+
import type { OsmRelation, OsmWay } from "../src/types"
|
|
8
|
+
|
|
9
|
+
describe("relation-multipolygon", () => {
|
|
10
|
+
describe("getWayMembersByRole", () => {
|
|
11
|
+
it("groups way members by outer and inner roles", () => {
|
|
12
|
+
const relation: OsmRelation = {
|
|
13
|
+
id: 1,
|
|
14
|
+
tags: { type: "multipolygon" },
|
|
15
|
+
members: [
|
|
16
|
+
{ type: "way", ref: 10, role: "outer" },
|
|
17
|
+
{ type: "way", ref: 11, role: "inner" },
|
|
18
|
+
{ type: "way", ref: 12, role: "outer" },
|
|
19
|
+
{ type: "node", ref: 1 },
|
|
20
|
+
{ type: "way", ref: 13, role: "inner" },
|
|
21
|
+
],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { outer, inner } = getWayMembersByRole(relation)
|
|
25
|
+
expect(outer).toHaveLength(2)
|
|
26
|
+
expect(outer[0]?.ref).toBe(10)
|
|
27
|
+
expect(outer[1]?.ref).toBe(12)
|
|
28
|
+
expect(inner).toHaveLength(2)
|
|
29
|
+
expect(inner[0]?.ref).toBe(11)
|
|
30
|
+
expect(inner[1]?.ref).toBe(13)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("handles case-insensitive roles", () => {
|
|
34
|
+
const relation: OsmRelation = {
|
|
35
|
+
id: 1,
|
|
36
|
+
tags: { type: "multipolygon" },
|
|
37
|
+
members: [
|
|
38
|
+
{ type: "way", ref: 10, role: "OUTER" },
|
|
39
|
+
{ type: "way", ref: 11, role: "Inner" },
|
|
40
|
+
],
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { outer, inner } = getWayMembersByRole(relation)
|
|
44
|
+
expect(outer).toHaveLength(1)
|
|
45
|
+
expect(inner).toHaveLength(1)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("handles missing roles", () => {
|
|
49
|
+
const relation: OsmRelation = {
|
|
50
|
+
id: 1,
|
|
51
|
+
tags: { type: "multipolygon" },
|
|
52
|
+
members: [
|
|
53
|
+
{ type: "way", ref: 10 },
|
|
54
|
+
{ type: "way", ref: 11, role: "outer" },
|
|
55
|
+
],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { outer, inner } = getWayMembersByRole(relation)
|
|
59
|
+
expect(outer).toHaveLength(1)
|
|
60
|
+
expect(inner).toHaveLength(0)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe("connectWaysToRings", () => {
|
|
65
|
+
it("connects ways sharing endpoints into a single ring", () => {
|
|
66
|
+
const way1: OsmWay = { id: 1, refs: [1, 2] }
|
|
67
|
+
const way2: OsmWay = { id: 2, refs: [2, 3] }
|
|
68
|
+
const way3: OsmWay = { id: 3, refs: [3, 1] }
|
|
69
|
+
|
|
70
|
+
const rings = connectWaysToRings([way1, way2, way3])
|
|
71
|
+
expect(rings).toHaveLength(1)
|
|
72
|
+
expect(rings[0]).toEqual([way1, way2, way3])
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it("handles ways that need to be reversed", () => {
|
|
76
|
+
// way1 ends at 2, way2 starts at 2 (normal connection)
|
|
77
|
+
const way1: OsmWay = { id: 1, refs: [1, 2] }
|
|
78
|
+
const way2: OsmWay = { id: 2, refs: [2, 3, 4] }
|
|
79
|
+
|
|
80
|
+
const rings = connectWaysToRings([way1, way2])
|
|
81
|
+
// Should create a ring if ways connect and form a closed loop
|
|
82
|
+
// This test verifies basic connection logic
|
|
83
|
+
expect(rings.length).toBeGreaterThanOrEqual(0)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("creates separate rings for disconnected ways", () => {
|
|
87
|
+
const way1: OsmWay = { id: 1, refs: [1, 2, 1] } // closed ring
|
|
88
|
+
const way2: OsmWay = { id: 2, refs: [3, 4, 3] } // separate closed ring
|
|
89
|
+
|
|
90
|
+
const rings = connectWaysToRings([way1, way2])
|
|
91
|
+
expect(rings).toHaveLength(2)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("only includes closed rings", () => {
|
|
95
|
+
const way1: OsmWay = { id: 1, refs: [1, 2, 3] } // not closed
|
|
96
|
+
const way2: OsmWay = { id: 2, refs: [4, 5, 4] } // closed
|
|
97
|
+
|
|
98
|
+
const rings = connectWaysToRings([way1, way2])
|
|
99
|
+
// Only the closed ring should be included
|
|
100
|
+
expect(rings.length).toBeGreaterThanOrEqual(1)
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
describe("buildRelationRings", () => {
|
|
105
|
+
it("builds simple multipolygon with outer ring only", () => {
|
|
106
|
+
const relation: OsmRelation = {
|
|
107
|
+
id: 1,
|
|
108
|
+
tags: { type: "multipolygon" },
|
|
109
|
+
members: [{ type: "way", ref: 1, role: "outer" }],
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const way1: OsmWay = {
|
|
113
|
+
id: 1,
|
|
114
|
+
refs: [1, 2, 3, 4, 1],
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const getWay = (id: number) => (id === 1 ? way1 : null)
|
|
118
|
+
const getNodeCoordinates = (id: number) => {
|
|
119
|
+
const coords: Record<number, [number, number]> = {
|
|
120
|
+
1: [0.0, 0.0],
|
|
121
|
+
2: [1.0, 0.0],
|
|
122
|
+
3: [1.0, 1.0],
|
|
123
|
+
4: [0.0, 1.0],
|
|
124
|
+
}
|
|
125
|
+
return coords[id]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const rings = buildRelationRings(relation, getWay, getNodeCoordinates)
|
|
129
|
+
expect(rings).toHaveLength(1)
|
|
130
|
+
expect(rings[0]).toHaveLength(1) // one outer ring
|
|
131
|
+
expect(rings[0]?.[0]).toHaveLength(5) // closed ring with 5 points
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it("builds multipolygon with outer and inner rings (holes)", () => {
|
|
135
|
+
const relation: OsmRelation = {
|
|
136
|
+
id: 1,
|
|
137
|
+
tags: { type: "multipolygon" },
|
|
138
|
+
members: [
|
|
139
|
+
{ type: "way", ref: 1, role: "outer" },
|
|
140
|
+
{ type: "way", ref: 2, role: "inner" },
|
|
141
|
+
],
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const way1: OsmWay = {
|
|
145
|
+
id: 1,
|
|
146
|
+
refs: [1, 2, 3, 4, 1], // outer square
|
|
147
|
+
}
|
|
148
|
+
const way2: OsmWay = {
|
|
149
|
+
id: 2,
|
|
150
|
+
refs: [5, 6, 7, 5], // inner triangle
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const getWay = (id: number) => {
|
|
154
|
+
if (id === 1) return way1
|
|
155
|
+
if (id === 2) return way2
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
158
|
+
const getNodeCoordinates = (id: number) => {
|
|
159
|
+
const coords: Record<number, [number, number]> = {
|
|
160
|
+
1: [-1.0, -1.0],
|
|
161
|
+
2: [1.0, -1.0],
|
|
162
|
+
3: [1.0, 1.0],
|
|
163
|
+
4: [-1.0, 1.0],
|
|
164
|
+
5: [-0.5, 0.0],
|
|
165
|
+
6: [0.5, 0.0],
|
|
166
|
+
7: [0.0, 0.5],
|
|
167
|
+
}
|
|
168
|
+
return coords[id]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const rings = buildRelationRings(relation, getWay, getNodeCoordinates)
|
|
172
|
+
expect(rings).toHaveLength(1)
|
|
173
|
+
expect(rings[0]).toHaveLength(2) // outer + inner
|
|
174
|
+
expect(rings[0]?.[0]).toBeDefined() // outer ring
|
|
175
|
+
expect(rings[0]?.[1]).toBeDefined() // inner ring (hole)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it("builds multipolygon with multiple outer rings", () => {
|
|
179
|
+
const relation: OsmRelation = {
|
|
180
|
+
id: 1,
|
|
181
|
+
tags: { type: "multipolygon" },
|
|
182
|
+
members: [
|
|
183
|
+
{ type: "way", ref: 1, role: "outer" },
|
|
184
|
+
{ type: "way", ref: 2, role: "outer" },
|
|
185
|
+
],
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const way1: OsmWay = {
|
|
189
|
+
id: 1,
|
|
190
|
+
refs: [1, 2, 3, 1], // first polygon
|
|
191
|
+
}
|
|
192
|
+
const way2: OsmWay = {
|
|
193
|
+
id: 2,
|
|
194
|
+
refs: [4, 5, 6, 4], // second polygon
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const getWay = (id: number) => {
|
|
198
|
+
if (id === 1) return way1
|
|
199
|
+
if (id === 2) return way2
|
|
200
|
+
return null
|
|
201
|
+
}
|
|
202
|
+
const getNodeCoordinates = (id: number) => {
|
|
203
|
+
const coords: Record<number, [number, number]> = {
|
|
204
|
+
1: [0.0, 0.0],
|
|
205
|
+
2: [1.0, 0.0],
|
|
206
|
+
3: [0.5, 1.0],
|
|
207
|
+
4: [2.0, 0.0],
|
|
208
|
+
5: [3.0, 0.0],
|
|
209
|
+
6: [2.5, 1.0],
|
|
210
|
+
}
|
|
211
|
+
return coords[id]
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const rings = buildRelationRings(relation, getWay, getNodeCoordinates)
|
|
215
|
+
expect(rings).toHaveLength(2) // two separate polygons
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it("handles relation similar to osmtogeojson test case", () => {
|
|
219
|
+
// Based on: https://github.com/placemark/osmtogeojson/blob/main/test/osm.test.js
|
|
220
|
+
const relation: OsmRelation = {
|
|
221
|
+
id: 1,
|
|
222
|
+
tags: { type: "multipolygon" },
|
|
223
|
+
members: [
|
|
224
|
+
{ type: "way", ref: 2, role: "outer" },
|
|
225
|
+
{ type: "way", ref: 3, role: "inner" },
|
|
226
|
+
],
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const way2: OsmWay = {
|
|
230
|
+
id: 2,
|
|
231
|
+
refs: [4, 5, 6, 7, 4], // outer square
|
|
232
|
+
}
|
|
233
|
+
const way3: OsmWay = {
|
|
234
|
+
id: 3,
|
|
235
|
+
refs: [8, 9, 10, 8], // inner triangle
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const getWay = (id: number) => {
|
|
239
|
+
if (id === 2) return way2
|
|
240
|
+
if (id === 3) return way3
|
|
241
|
+
return null
|
|
242
|
+
}
|
|
243
|
+
const getNodeCoordinates = (id: number) => {
|
|
244
|
+
const coords: Record<number, [number, number]> = {
|
|
245
|
+
4: [-1.0, -1.0],
|
|
246
|
+
5: [-1.0, 1.0],
|
|
247
|
+
6: [1.0, 1.0],
|
|
248
|
+
7: [1.0, -1.0],
|
|
249
|
+
8: [-0.5, 0.0],
|
|
250
|
+
9: [0.5, 0.0],
|
|
251
|
+
10: [0.0, 0.5],
|
|
252
|
+
}
|
|
253
|
+
return coords[id]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const rings = buildRelationRings(relation, getWay, getNodeCoordinates)
|
|
257
|
+
expect(rings).toHaveLength(1)
|
|
258
|
+
expect(rings[0]).toHaveLength(2) // outer + inner
|
|
259
|
+
// Outer ring should have 5 points (closed square)
|
|
260
|
+
expect(rings[0]?.[0]).toHaveLength(5)
|
|
261
|
+
// Inner ring should have 4 points (closed triangle)
|
|
262
|
+
expect(rings[0]?.[1]).toHaveLength(4)
|
|
263
|
+
})
|
|
264
|
+
})
|
|
265
|
+
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
|
+
import type {
|
|
3
|
+
OsmNode,
|
|
4
|
+
OsmRelation,
|
|
5
|
+
OsmRelationMember,
|
|
6
|
+
OsmWay,
|
|
7
|
+
} from "../src/types"
|
|
8
|
+
import {
|
|
9
|
+
entityPropertiesEqual,
|
|
10
|
+
getEntityType,
|
|
11
|
+
isMultipolygonRelation,
|
|
12
|
+
isNode,
|
|
13
|
+
isNodeEqual,
|
|
14
|
+
isRelation,
|
|
15
|
+
isRelationEqual,
|
|
16
|
+
isWay,
|
|
17
|
+
isWayEqual,
|
|
18
|
+
} from "../src/utils"
|
|
19
|
+
|
|
20
|
+
describe("utils", () => {
|
|
21
|
+
const node: OsmNode = {
|
|
22
|
+
id: 1,
|
|
23
|
+
lat: 10,
|
|
24
|
+
lon: 20,
|
|
25
|
+
tags: { name: "node" },
|
|
26
|
+
}
|
|
27
|
+
const way: OsmWay = {
|
|
28
|
+
id: 2,
|
|
29
|
+
refs: [1, 2, 3],
|
|
30
|
+
tags: { highway: "residential" },
|
|
31
|
+
}
|
|
32
|
+
const members: OsmRelationMember[] = [
|
|
33
|
+
{
|
|
34
|
+
type: "node",
|
|
35
|
+
ref: 1,
|
|
36
|
+
},
|
|
37
|
+
]
|
|
38
|
+
const relation: OsmRelation = {
|
|
39
|
+
id: 3,
|
|
40
|
+
members,
|
|
41
|
+
tags: { type: "multipolygon" },
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
it("narrows entity types", () => {
|
|
45
|
+
expect(isNode(node)).toBe(true)
|
|
46
|
+
expect(isWay(way)).toBe(true)
|
|
47
|
+
expect(isRelation(relation)).toBe(true)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("compares entity equality", () => {
|
|
51
|
+
expect(isNodeEqual(node, { ...node })).toBe(true)
|
|
52
|
+
expect(isWayEqual(way, { ...way })).toBe(true)
|
|
53
|
+
expect(isRelationEqual(relation, { ...relation })).toBe(true)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("detects property differences", () => {
|
|
57
|
+
expect(
|
|
58
|
+
entityPropertiesEqual(node, { ...node, tags: { name: "changed" } }),
|
|
59
|
+
).toBe(false)
|
|
60
|
+
expect(entityPropertiesEqual(way, { ...way, refs: [1, 2, 4] })).toBe(false)
|
|
61
|
+
expect(
|
|
62
|
+
entityPropertiesEqual(relation, {
|
|
63
|
+
...relation,
|
|
64
|
+
members: [{ type: "node", ref: 2 }],
|
|
65
|
+
}),
|
|
66
|
+
).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it("provides entity type", () => {
|
|
70
|
+
expect(getEntityType(node)).toBe("node")
|
|
71
|
+
expect(getEntityType(way)).toBe("way")
|
|
72
|
+
expect(getEntityType(relation)).toBe("relation")
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe("isMultipolygonRelation", () => {
|
|
76
|
+
it("identifies multipolygon relations", () => {
|
|
77
|
+
const relation: OsmRelation = {
|
|
78
|
+
id: 1,
|
|
79
|
+
tags: { type: "multipolygon" },
|
|
80
|
+
members: [],
|
|
81
|
+
}
|
|
82
|
+
expect(isMultipolygonRelation(relation)).toBe(true)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it("rejects non-multipolygon relations", () => {
|
|
86
|
+
const relation: OsmRelation = {
|
|
87
|
+
id: 1,
|
|
88
|
+
tags: { type: "route" },
|
|
89
|
+
members: [],
|
|
90
|
+
}
|
|
91
|
+
expect(isMultipolygonRelation(relation)).toBe(false)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("rejects relations without type tag", () => {
|
|
95
|
+
const relation: OsmRelation = {
|
|
96
|
+
id: 1,
|
|
97
|
+
tags: { name: "test" },
|
|
98
|
+
members: [],
|
|
99
|
+
}
|
|
100
|
+
expect(isMultipolygonRelation(relation)).toBe(false)
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
|
+
import { wayIsArea } from "../src/way-is-area"
|
|
3
|
+
|
|
4
|
+
describe("wayIsArea", () => {
|
|
5
|
+
it("returns false for open ways", () => {
|
|
6
|
+
const refs = [1, 2, 3]
|
|
7
|
+
expect(wayIsArea({ id: 0, refs, tags: { building: "yes" } })).toBe(false)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it("returns true for closed way without tags", () => {
|
|
11
|
+
const refs = [1, 2, 3, 1]
|
|
12
|
+
expect(wayIsArea({ id: 0, refs })).toBe(true)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it("honors explicit area override", () => {
|
|
16
|
+
const refs = [1, 2, 3, 1]
|
|
17
|
+
expect(
|
|
18
|
+
wayIsArea({ id: 0, refs, tags: { area: "no", building: "yes" } }),
|
|
19
|
+
).toBe(false)
|
|
20
|
+
expect(wayIsArea({ id: 0, refs, tags: { area: "yes" } })).toBe(true)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it("treats implied tags as areas", () => {
|
|
24
|
+
const refs = [1, 2, 3, 1]
|
|
25
|
+
expect(wayIsArea({ id: 0, refs, tags: { building: "yes" } })).toBe(true)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it("considers included values", () => {
|
|
29
|
+
const refs = [1, 2, 3, 1]
|
|
30
|
+
expect(wayIsArea({ id: 0, refs, tags: { highway: "rest_area" } })).toBe(
|
|
31
|
+
true,
|
|
32
|
+
)
|
|
33
|
+
expect(wayIsArea({ id: 0, refs, tags: { highway: "primary" } })).toBe(false)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("rejects excluded values", () => {
|
|
37
|
+
const refs = [1, 2, 3, 1]
|
|
38
|
+
expect(wayIsArea({ id: 0, refs, tags: { natural: "coastline" } })).toBe(
|
|
39
|
+
false,
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
})
|
package/tsconfig/test.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { SphericalMercator } from "@mapbox/sphericalmercator";
|
|
2
|
-
import type { GeoBbox2D, LonLat, Tile, XY } from "./types";
|
|
3
|
-
/**
|
|
4
|
-
* Extends the SphericalMercator class to provide tile-local pixel coordinate calculations and clamping.
|
|
5
|
-
*/
|
|
6
|
-
export default class SphericalMercatorTile extends SphericalMercator {
|
|
7
|
-
tileSize: number;
|
|
8
|
-
tile?: Tile;
|
|
9
|
-
constructor(options: ConstructorParameters<typeof SphericalMercator>[0] & {
|
|
10
|
-
tile?: Tile;
|
|
11
|
-
});
|
|
12
|
-
llToTilePx(ll: LonLat, tile?: Tile): XY;
|
|
13
|
-
clampAndRoundPx(px: XY, bbox?: GeoBbox2D): XY;
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=spherical-mercator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spherical-mercator.d.ts","sourceRoot":"","sources":["../../src/spherical-mercator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE1D;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,iBAAiB;IACnE,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,IAAI,CAAA;gBAEV,OAAO,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG;QAC7D,IAAI,CAAC,EAAE,IAAI,CAAA;KACX;IAOF,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE;IAUvC,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,EAAE;CAY7C"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { SphericalMercator } from "@mapbox/sphericalmercator";
|
|
2
|
-
/**
|
|
3
|
-
* Extends the SphericalMercator class to provide tile-local pixel coordinate calculations and clamping.
|
|
4
|
-
*/
|
|
5
|
-
export default class SphericalMercatorTile extends SphericalMercator {
|
|
6
|
-
tileSize;
|
|
7
|
-
tile;
|
|
8
|
-
constructor(options) {
|
|
9
|
-
super(options);
|
|
10
|
-
this.tile = options?.tile;
|
|
11
|
-
this.tileSize = options?.size ?? 256;
|
|
12
|
-
}
|
|
13
|
-
llToTilePx(ll, tile) {
|
|
14
|
-
if (tile == null && this.tile == null)
|
|
15
|
-
throw Error("Tile must be set on construction or passed as an argument.");
|
|
16
|
-
const [tx, ty, tz] = (tile ?? this.tile);
|
|
17
|
-
const merc = this.px(ll, tz);
|
|
18
|
-
const x = merc[0] - tx * this.tileSize;
|
|
19
|
-
const y = merc[1] - ty * this.tileSize;
|
|
20
|
-
return [x, y];
|
|
21
|
-
}
|
|
22
|
-
clampAndRoundPx(px, bbox) {
|
|
23
|
-
const [minX, minY, maxX, maxY] = bbox ?? [
|
|
24
|
-
0,
|
|
25
|
-
0,
|
|
26
|
-
this.tileSize,
|
|
27
|
-
this.tileSize,
|
|
28
|
-
];
|
|
29
|
-
return [
|
|
30
|
-
Math.max(minX, Math.min(maxX, Math.round(px[0]))),
|
|
31
|
-
Math.max(minY, Math.min(maxY, Math.round(px[1]))),
|
|
32
|
-
];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=spherical-mercator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spherical-mercator.js","sourceRoot":"","sources":["../../src/spherical-mercator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAG7D;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,iBAAiB;IACnE,QAAQ,CAAQ;IAChB,IAAI,CAAO;IACX,YACC,OAEC;QAED,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,CAAA;QACzB,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,IAAI,IAAI,GAAG,CAAA;IACrC,CAAC;IAED,UAAU,CAAC,EAAU,EAAE,IAAW;QACjC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;YACpC,MAAM,KAAK,CAAC,4DAA4D,CAAC,CAAA;QAC1E,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAE,CAAA;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAA;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAA;QACtC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACd,CAAC;IAED,eAAe,CAAC,EAAM,EAAE,IAAgB;QACvC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;YACxC,CAAC;YACD,CAAC;YACD,IAAI,CAAC,QAAQ;YACb,IAAI,CAAC,QAAQ;SACb,CAAA;QACD,OAAO;YACN,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACjD,CAAA;IACF,CAAC;CACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spherical-mercator.test.d.ts","sourceRoot":"","sources":["../../src/spherical-mercator.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import SphericalMercatorTile from "./spherical-mercator";
|
|
3
|
-
function lonLatForPixel(merc, tileIndex, tileSize, px, py) {
|
|
4
|
-
const [x, y, z] = tileIndex;
|
|
5
|
-
return merc.ll([x * tileSize + px, y * tileSize + py], z);
|
|
6
|
-
}
|
|
7
|
-
describe("SphericalMercatorTile", () => {
|
|
8
|
-
it("projects lon/lat to tile-local pixels", () => {
|
|
9
|
-
const tile = [300, 300, 10];
|
|
10
|
-
const [tx, ty, tz] = tile;
|
|
11
|
-
const tileSize = 256;
|
|
12
|
-
const merc = new SphericalMercatorTile({ size: tileSize, tile });
|
|
13
|
-
const insideLonLat = lonLatForPixel(merc, tile, tileSize, 32, 16);
|
|
14
|
-
expect(merc.llToTilePx(insideLonLat)).toEqual([32, 16]);
|
|
15
|
-
const outsideTopLeft = merc.ll([tx * tileSize - 10, ty * tileSize - 10], tz);
|
|
16
|
-
expect(outsideTopLeft).toEqual([-74.54498291015625, 59.54128017205441]);
|
|
17
|
-
expect(merc.llToTilePx(outsideTopLeft)).toEqual([-10, -10]);
|
|
18
|
-
const outsideBottomRight = merc.ll([(tx + 1) * tileSize + 10, (ty + 1) * tileSize + 10], tz);
|
|
19
|
-
expect(merc.llToTilePx(outsideBottomRight, tile)).toEqual([
|
|
20
|
-
tileSize + 10,
|
|
21
|
-
tileSize + 10,
|
|
22
|
-
]);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
//# sourceMappingURL=spherical-mercator.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spherical-mercator.test.js","sourceRoot":"","sources":["../../src/spherical-mercator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,qBAAqB,MAAM,sBAAsB,CAAA;AAGxD,SAAS,cAAc,CACtB,IAA2B,EAC3B,SAAe,EACf,QAAgB,EAChB,EAAU,EACV,EAAU;IAEV,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAC3B,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,EAAE,EAAE,CAAC,GAAG,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,CAAqB,CAAA;AAC9E,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAChD,MAAM,IAAI,GAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAA;QACjC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAA;QACzB,MAAM,QAAQ,GAAG,GAAG,CAAA;QACpB,MAAM,IAAI,GAAG,IAAI,qBAAqB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QAEhE,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACjE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;QAEvD,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAC7B,CAAC,EAAE,GAAG,QAAQ,GAAG,EAAE,EAAE,EAAE,GAAG,QAAQ,GAAG,EAAE,CAAC,EACxC,EAAE,CACkB,CAAA;QACrB,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAA;QACvE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAE3D,MAAM,kBAAkB,GAAG,IAAI,CAAC,EAAE,CACjC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,GAAG,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,GAAG,EAAE,CAAC,EACpD,EAAE,CACkB,CAAA;QACrB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YACzD,QAAQ,GAAG,EAAE;YACb,QAAQ,GAAG,EAAE;SACb,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest"
|
|
2
|
-
import SphericalMercatorTile from "./spherical-mercator"
|
|
3
|
-
import type { Tile } from "./types"
|
|
4
|
-
|
|
5
|
-
function lonLatForPixel(
|
|
6
|
-
merc: SphericalMercatorTile,
|
|
7
|
-
tileIndex: Tile,
|
|
8
|
-
tileSize: number,
|
|
9
|
-
px: number,
|
|
10
|
-
py: number,
|
|
11
|
-
): [number, number] {
|
|
12
|
-
const [x, y, z] = tileIndex
|
|
13
|
-
return merc.ll([x * tileSize + px, y * tileSize + py], z) as [number, number]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
describe("SphericalMercatorTile", () => {
|
|
17
|
-
it("projects lon/lat to tile-local pixels", () => {
|
|
18
|
-
const tile: Tile = [300, 300, 10]
|
|
19
|
-
const [tx, ty, tz] = tile
|
|
20
|
-
const tileSize = 256
|
|
21
|
-
const merc = new SphericalMercatorTile({ size: tileSize, tile })
|
|
22
|
-
|
|
23
|
-
const insideLonLat = lonLatForPixel(merc, tile, tileSize, 32, 16)
|
|
24
|
-
expect(merc.llToTilePx(insideLonLat)).toEqual([32, 16])
|
|
25
|
-
|
|
26
|
-
const outsideTopLeft = merc.ll(
|
|
27
|
-
[tx * tileSize - 10, ty * tileSize - 10],
|
|
28
|
-
tz,
|
|
29
|
-
) as [number, number]
|
|
30
|
-
expect(outsideTopLeft).toEqual([-74.54498291015625, 59.54128017205441])
|
|
31
|
-
expect(merc.llToTilePx(outsideTopLeft)).toEqual([-10, -10])
|
|
32
|
-
|
|
33
|
-
const outsideBottomRight = merc.ll(
|
|
34
|
-
[(tx + 1) * tileSize + 10, (ty + 1) * tileSize + 10],
|
|
35
|
-
tz,
|
|
36
|
-
) as [number, number]
|
|
37
|
-
expect(merc.llToTilePx(outsideBottomRight, tile)).toEqual([
|
|
38
|
-
tileSize + 10,
|
|
39
|
-
tileSize + 10,
|
|
40
|
-
])
|
|
41
|
-
})
|
|
42
|
-
})
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { SphericalMercator } from "@mapbox/sphericalmercator"
|
|
2
|
-
import type { GeoBbox2D, LonLat, Tile, XY } from "./types"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Extends the SphericalMercator class to provide tile-local pixel coordinate calculations and clamping.
|
|
6
|
-
*/
|
|
7
|
-
export default class SphericalMercatorTile extends SphericalMercator {
|
|
8
|
-
tileSize: number
|
|
9
|
-
tile?: Tile
|
|
10
|
-
constructor(
|
|
11
|
-
options: ConstructorParameters<typeof SphericalMercator>[0] & {
|
|
12
|
-
tile?: Tile
|
|
13
|
-
},
|
|
14
|
-
) {
|
|
15
|
-
super(options)
|
|
16
|
-
this.tile = options?.tile
|
|
17
|
-
this.tileSize = options?.size ?? 256
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
llToTilePx(ll: LonLat, tile?: Tile): XY {
|
|
21
|
-
if (tile == null && this.tile == null)
|
|
22
|
-
throw Error("Tile must be set on construction or passed as an argument.")
|
|
23
|
-
const [tx, ty, tz] = (tile ?? this.tile)!
|
|
24
|
-
const merc = this.px(ll, tz)
|
|
25
|
-
const x = merc[0] - tx * this.tileSize
|
|
26
|
-
const y = merc[1] - ty * this.tileSize
|
|
27
|
-
return [x, y]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
clampAndRoundPx(px: XY, bbox?: GeoBbox2D): XY {
|
|
31
|
-
const [minX, minY, maxX, maxY] = bbox ?? [
|
|
32
|
-
0,
|
|
33
|
-
0,
|
|
34
|
-
this.tileSize,
|
|
35
|
-
this.tileSize,
|
|
36
|
-
]
|
|
37
|
-
return [
|
|
38
|
-
Math.max(minX, Math.min(maxX, Math.round(px[0]))),
|
|
39
|
-
Math.max(minY, Math.min(maxY, Math.round(px[1]))),
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
}
|