@mailwoman/resolver-wof-sqlite 8.0.0 → 8.2.0
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/address-point-interpolation.ts +9 -3
- package/address-point-schema.ts +32 -10
- package/address-point.ts +3 -0
- package/ancestry-backfill.ts +18 -5
- package/ancestry.ts +7 -2
- package/build-candidate.ts +29 -6
- package/build-slim.ts +40 -11
- package/candidate-fts.ts +1 -0
- package/candidate-lookup.ts +49 -15
- package/candidate-schema.ts +35 -11
- package/coincident-roles.ts +28 -6
- package/convention.ts +3 -1
- package/coverage-manifest-schema.ts +243 -0
- package/fst-autocomplete.ts +15 -9
- package/fst-builder.ts +65 -9
- package/fst-deserialize-web.ts +46 -9
- package/fst-matcher.ts +12 -5
- package/fst-serialize.ts +83 -9
- package/fst-types.ts +43 -0
- package/fts-query.ts +84 -0
- package/fts.ts +35 -9
- package/geo.ts +9 -3
- package/geonames-aliases.ts +116 -79
- package/geonames-postal.ts +25 -5
- package/index.ts +19 -0
- package/interpolation.ts +59 -55
- package/lookup.ts +103 -292
- package/name-score.ts +76 -0
- package/out/address-point-interpolation.d.ts.map +1 -1
- package/out/address-point-interpolation.js +4 -2
- package/out/address-point-interpolation.js.map +1 -1
- package/out/address-point-schema.d.ts +30 -10
- package/out/address-point-schema.d.ts.map +1 -1
- package/out/address-point-schema.js +6 -2
- package/out/address-point-schema.js.map +1 -1
- package/out/address-point.d.ts.map +1 -1
- package/out/address-point.js.map +1 -1
- package/out/ancestry-backfill.d.ts +6 -2
- package/out/ancestry-backfill.d.ts.map +1 -1
- package/out/ancestry-backfill.js +7 -3
- package/out/ancestry-backfill.js.map +1 -1
- package/out/ancestry.d.ts +6 -2
- package/out/ancestry.d.ts.map +1 -1
- package/out/ancestry.js +3 -1
- package/out/ancestry.js.map +1 -1
- package/out/build-candidate.d.ts +9 -3
- package/out/build-candidate.d.ts.map +1 -1
- package/out/build-candidate.js +5 -3
- package/out/build-candidate.js.map +1 -1
- package/out/build-slim.d.ts +15 -5
- package/out/build-slim.d.ts.map +1 -1
- package/out/build-slim.js +11 -5
- package/out/build-slim.js.map +1 -1
- package/out/candidate-fts.d.ts.map +1 -1
- package/out/candidate-fts.js.map +1 -1
- package/out/candidate-lookup.d.ts +16 -3
- package/out/candidate-lookup.d.ts.map +1 -1
- package/out/candidate-lookup.js +27 -11
- package/out/candidate-lookup.js.map +1 -1
- package/out/candidate-schema.d.ts +33 -11
- package/out/candidate-schema.d.ts.map +1 -1
- package/out/candidate-schema.js.map +1 -1
- package/out/coincident-roles.d.ts +16 -4
- package/out/coincident-roles.d.ts.map +1 -1
- package/out/coincident-roles.js +9 -3
- package/out/coincident-roles.js.map +1 -1
- package/out/convention.d.ts +3 -1
- package/out/convention.d.ts.map +1 -1
- package/out/convention.js.map +1 -1
- package/out/coverage-manifest-schema.d.ts +112 -0
- package/out/coverage-manifest-schema.d.ts.map +1 -0
- package/out/coverage-manifest-schema.js +154 -0
- package/out/coverage-manifest-schema.js.map +1 -0
- package/out/fst-autocomplete.d.ts +1 -1
- package/out/fst-autocomplete.d.ts.map +1 -1
- package/out/fst-autocomplete.js +11 -9
- package/out/fst-autocomplete.js.map +1 -1
- package/out/fst-builder.d.ts.map +1 -1
- package/out/fst-builder.js +42 -9
- package/out/fst-builder.js.map +1 -1
- package/out/fst-deserialize-web.d.ts.map +1 -1
- package/out/fst-deserialize-web.js +34 -9
- package/out/fst-deserialize-web.js.map +1 -1
- package/out/fst-matcher.d.ts +6 -2
- package/out/fst-matcher.d.ts.map +1 -1
- package/out/fst-matcher.js +9 -5
- package/out/fst-matcher.js.map +1 -1
- package/out/fst-serialize.d.ts.map +1 -1
- package/out/fst-serialize.js +62 -9
- package/out/fst-serialize.js.map +1 -1
- package/out/fst-types.d.ts +43 -0
- package/out/fst-types.d.ts.map +1 -1
- package/out/fts-query.d.ts +41 -0
- package/out/fts-query.d.ts.map +1 -0
- package/out/fts-query.js +75 -0
- package/out/fts-query.js.map +1 -0
- package/out/fts.d.ts +21 -7
- package/out/fts.d.ts.map +1 -1
- package/out/fts.js +10 -4
- package/out/fts.js.map +1 -1
- package/out/geo.d.ts +6 -2
- package/out/geo.d.ts.map +1 -1
- package/out/geo.js +3 -1
- package/out/geo.js.map +1 -1
- package/out/geonames-aliases.d.ts +12 -4
- package/out/geonames-aliases.d.ts.map +1 -1
- package/out/geonames-aliases.js +72 -67
- package/out/geonames-aliases.js.map +1 -1
- package/out/geonames-postal.d.ts +9 -3
- package/out/geonames-postal.d.ts.map +1 -1
- package/out/geonames-postal.js +7 -2
- package/out/geonames-postal.js.map +1 -1
- package/out/index.d.ts +2 -0
- package/out/index.d.ts.map +1 -1
- package/out/index.js +1 -0
- package/out/index.js.map +1 -1
- package/out/interpolation.d.ts +24 -6
- package/out/interpolation.d.ts.map +1 -1
- package/out/interpolation.js +32 -40
- package/out/interpolation.js.map +1 -1
- package/out/lookup.d.ts +3 -97
- package/out/lookup.d.ts.map +1 -1
- package/out/lookup.js +52 -184
- package/out/lookup.js.map +1 -1
- package/out/name-score.d.ts +28 -0
- package/out/name-score.d.ts.map +1 -0
- package/out/name-score.js +67 -0
- package/out/name-score.js.map +1 -0
- package/out/poi-lookup.d.ts +24 -8
- package/out/poi-lookup.d.ts.map +1 -1
- package/out/poi-lookup.js +27 -13
- package/out/poi-lookup.js.map +1 -1
- package/out/poi-schema.d.ts +42 -13
- package/out/poi-schema.d.ts.map +1 -1
- package/out/poi-schema.js +12 -3
- package/out/poi-schema.js.map +1 -1
- package/out/postal-city-alias-lookup.d.ts +18 -6
- package/out/postal-city-alias-lookup.d.ts.map +1 -1
- package/out/postal-city-alias-lookup.js.map +1 -1
- package/out/postal-city-alias-schema.d.ts +27 -9
- package/out/postal-city-alias-schema.d.ts.map +1 -1
- package/out/postal-city-alias-schema.js +3 -1
- package/out/postal-city-alias-schema.js.map +1 -1
- package/out/postal-city-candidate-schema.d.ts +15 -5
- package/out/postal-city-candidate-schema.d.ts.map +1 -1
- package/out/postal-city-candidate-schema.js +3 -1
- package/out/postal-city-candidate-schema.js.map +1 -1
- package/out/postcode-point-lookup.d.ts +6 -2
- package/out/postcode-point-lookup.d.ts.map +1 -1
- package/out/postcode-point-lookup.js +6 -2
- package/out/postcode-point-lookup.js.map +1 -1
- package/out/ranking-weights.d.ts +118 -0
- package/out/ranking-weights.d.ts.map +1 -0
- package/out/ranking-weights.js +44 -0
- package/out/ranking-weights.js.map +1 -0
- package/out/reverse.d.ts +9 -3
- package/out/reverse.d.ts.map +1 -1
- package/out/reverse.js +20 -6
- package/out/reverse.js.map +1 -1
- package/out/sharding.d.ts +3 -1
- package/out/sharding.d.ts.map +1 -1
- package/out/sharding.js +7 -5
- package/out/sharding.js.map +1 -1
- package/out/sqlite-convention-source.d.ts.map +1 -1
- package/out/sqlite-convention-source.js +3 -1
- package/out/sqlite-convention-source.js.map +1 -1
- package/out/street-centroid-schema.d.ts +33 -11
- package/out/street-centroid-schema.d.ts.map +1 -1
- package/out/street-centroid-schema.js +3 -1
- package/out/street-centroid-schema.js.map +1 -1
- package/out/street-centroid.d.ts.map +1 -1
- package/out/street-centroid.js +6 -2
- package/out/street-centroid.js.map +1 -1
- package/out/street-morphology-fst-builder.d.ts +6 -2
- package/out/street-morphology-fst-builder.d.ts.map +1 -1
- package/out/street-morphology-fst-builder.js +8 -7
- package/out/street-morphology-fst-builder.js.map +1 -1
- package/out/street-morphology-fst-loader.d.ts +67 -0
- package/out/street-morphology-fst-loader.d.ts.map +1 -0
- package/out/street-morphology-fst-loader.js +59 -0
- package/out/street-morphology-fst-loader.js.map +1 -0
- package/out/street-name-lookup.d.ts +9 -3
- package/out/street-name-lookup.d.ts.map +1 -1
- package/out/street-name-lookup.js +9 -7
- package/out/street-name-lookup.js.map +1 -1
- package/out/street-normalize.d.ts +3 -1
- package/out/street-normalize.d.ts.map +1 -1
- package/out/street-normalize.js +23 -13
- package/out/street-normalize.js.map +1 -1
- package/out/street-segment-schema.d.ts +68 -13
- package/out/street-segment-schema.d.ts.map +1 -1
- package/out/street-segment-schema.js +21 -2
- package/out/street-segment-schema.js.map +1 -1
- package/out/types.d.ts +18 -6
- package/out/types.d.ts.map +1 -1
- package/out/unified-schema.d.ts +1 -1
- package/out/unified-schema.d.ts.map +1 -1
- package/out/unified-schema.js +2 -2
- package/out/unified-schema.js.map +1 -1
- package/package.json +13 -5
- package/poi-lookup.ts +53 -21
- package/poi-schema.ts +43 -13
- package/postal-city-alias-lookup.ts +20 -6
- package/postal-city-alias-schema.ts +28 -9
- package/postal-city-candidate-schema.ts +15 -5
- package/postcode-point-lookup.ts +6 -2
- package/ranking-weights.ts +148 -0
- package/reverse.ts +47 -10
- package/sharding.ts +13 -6
- package/sqlite-convention-source.ts +4 -1
- package/street-centroid-schema.ts +35 -11
- package/street-centroid.ts +10 -3
- package/street-morphology-fst-builder.ts +25 -9
- package/street-morphology-fst-loader.ts +103 -0
- package/street-name-lookup.ts +19 -7
- package/street-normalize.ts +28 -13
- package/street-segment-schema.ts +83 -13
- package/types.ts +18 -6
- package/unified-schema.ts +11 -2
package/index.ts
CHANGED
|
@@ -23,23 +23,38 @@ export { WOFSqlitePlaceLookup, type RankingWeights, type WOFSqlitePlaceLookupOpt
|
|
|
23
23
|
|
|
24
24
|
export { CANDIDATE_FTS_TABLE, createCandidateFTS } from "./candidate-fts.ts"
|
|
25
25
|
export { WOFCandidateTableLookup, type WOFCandidateTableLookupOpts } from "./candidate-lookup.ts"
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
COUNTRY_BBOX_TABLE,
|
|
29
|
+
COUNTRY_COVERAGE_TABLE,
|
|
30
|
+
createCountryBBoxTable,
|
|
31
|
+
createCountryCoverageTable,
|
|
32
|
+
readGazetteerCoverageManifest,
|
|
33
|
+
writeGazetteerCoverageManifest,
|
|
34
|
+
} from "./coverage-manifest-schema.ts"
|
|
35
|
+
|
|
36
|
+
export type { CountryBBoxTable, CountryCoverageTable, GazetteerCoverageDatabase } from "./coverage-manifest-schema.ts"
|
|
26
37
|
export { SQLiteStreetNameLookup, type SQLiteStreetNameLookupOpts } from "./street-name-lookup.ts"
|
|
27
38
|
|
|
28
39
|
export { GEONAMES_ID_BASE, ingestGeonamesAliases, type GeonamesIngestProgress } from "./geonames-aliases.ts"
|
|
29
40
|
|
|
30
41
|
export { ADDRESS_POINT_COLUMNS, createAddressPointIndexes, createAddressPointTable } from "./address-point-schema.ts"
|
|
31
42
|
export type { AddressPointDatabase, AddressPointTable } from "./address-point-schema.ts"
|
|
43
|
+
|
|
32
44
|
export {
|
|
33
45
|
WOFPostalCityAliasLookup,
|
|
34
46
|
type PostalCityAlias,
|
|
35
47
|
type WOFPostalCityAliasLookupOpts,
|
|
36
48
|
} from "./postal-city-alias-lookup.ts"
|
|
49
|
+
|
|
37
50
|
export type { PostalCityAliasDatabase, PostalCityAliasTable } from "./postal-city-alias-schema.ts"
|
|
51
|
+
|
|
38
52
|
export {
|
|
39
53
|
POSTAL_CITY_CANDIDATE_COLUMNS,
|
|
40
54
|
POSTAL_CITY_CANDIDATE_TABLE,
|
|
41
55
|
createPostalCityCandidateTable,
|
|
42
56
|
} from "./postal-city-candidate-schema.ts"
|
|
57
|
+
|
|
43
58
|
export type { PostalCityCandidateDatabase, PostalCityCandidateTable } from "./postal-city-candidate-schema.ts"
|
|
44
59
|
|
|
45
60
|
export {
|
|
@@ -95,19 +110,23 @@ export {
|
|
|
95
110
|
|
|
96
111
|
export { AddressPointInterpolator } from "./address-point-interpolation.ts"
|
|
97
112
|
export { AddressPointSqliteLookup } from "./address-point.ts"
|
|
113
|
+
|
|
98
114
|
export {
|
|
99
115
|
STREET_CENTROID_COLUMNS,
|
|
100
116
|
createStreetCentroidIndexes,
|
|
101
117
|
createStreetCentroidTable,
|
|
102
118
|
} from "./street-centroid-schema.ts"
|
|
119
|
+
|
|
103
120
|
export type { StreetCentroidDatabase, StreetCentroidTable } from "./street-centroid-schema.ts"
|
|
104
121
|
export { StreetCentroidSqliteLookup } from "./street-centroid.ts"
|
|
122
|
+
|
|
105
123
|
export {
|
|
106
124
|
StreetInterpolator,
|
|
107
125
|
type InterpolatedHit,
|
|
108
126
|
type InterpolationMethod,
|
|
109
127
|
type InterpolationQuery,
|
|
110
128
|
} from "./interpolation.ts"
|
|
129
|
+
|
|
111
130
|
export {
|
|
112
131
|
deriveSchemaName,
|
|
113
132
|
pickShardForPlacetype,
|
package/interpolation.ts
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
import { DatabaseSync } from "node:sqlite"
|
|
30
30
|
|
|
31
31
|
import type { InterpolationLookup } from "@mailwoman/resolver"
|
|
32
|
+
import { clampFraction, pointAlong } from "@mailwoman/spatial"
|
|
32
33
|
|
|
33
34
|
import { haversineKm } from "./geo.ts"
|
|
34
35
|
import { hasTable } from "./sqlite-utils.ts"
|
|
@@ -44,13 +45,19 @@ import { canonicalizeRouteKey, normalizeStreetForKey } from "./street-normalize.
|
|
|
44
45
|
*/
|
|
45
46
|
export type InterpolationMethod = "address_point" | "tiger_range"
|
|
46
47
|
|
|
47
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* One interpolated coordinate estimate. Never an exact situs point — see `uncertaintyM`.
|
|
50
|
+
*/
|
|
48
51
|
export interface InterpolatedHit {
|
|
49
52
|
lat: number
|
|
50
53
|
lon: number
|
|
51
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Always true — the tier's honesty flag, mirrored into `resolution_tier` when wired.
|
|
56
|
+
*/
|
|
52
57
|
interpolated: true
|
|
53
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Which rung answered — see {@link InterpolationMethod}.
|
|
60
|
+
*/
|
|
54
61
|
method: InterpolationMethod
|
|
55
62
|
/**
|
|
56
63
|
* `tiger_range` only. True when the matched segment side's parity agrees with the house number (or the side is
|
|
@@ -67,16 +74,22 @@ export interface InterpolatedHit {
|
|
|
67
74
|
* span (`address_point`/`both`), or the explicitly larger extrapolation penalty (`address_point`/`single`).
|
|
68
75
|
*/
|
|
69
76
|
uncertaintyM: number
|
|
70
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Provenance, e.g. `"tiger:edges"`.
|
|
79
|
+
*/
|
|
71
80
|
source: string
|
|
72
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Pinned data vintage, e.g. `"TIGER2023"`.
|
|
83
|
+
*/
|
|
73
84
|
release: string
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
export interface InterpolationQuery {
|
|
77
88
|
street: string
|
|
78
89
|
number: string
|
|
79
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* ZIP scope — strongly preferred; without it common street names abstain (see module doc).
|
|
92
|
+
*/
|
|
80
93
|
postcode?: string
|
|
81
94
|
}
|
|
82
95
|
|
|
@@ -97,6 +110,7 @@ export class StreetInterpolator implements InterpolationLookup {
|
|
|
97
110
|
readonly #ownsDB: boolean
|
|
98
111
|
readonly #byPostcode: ReturnType<DatabaseSync["prepare"]> | undefined
|
|
99
112
|
readonly #byStreet: ReturnType<DatabaseSync["prepare"]> | undefined
|
|
113
|
+
readonly #radiusCalibration: number | undefined
|
|
100
114
|
|
|
101
115
|
constructor(opts: { dbPath?: string; database?: DatabaseSync }) {
|
|
102
116
|
if (opts.database) {
|
|
@@ -113,15 +127,43 @@ export class StreetInterpolator implements InterpolationLookup {
|
|
|
113
127
|
// `street_segment` table this interpolator is a no-op miss, not a crash that loses the state (#568).
|
|
114
128
|
if (hasTable(this.#db, "street_segment")) {
|
|
115
129
|
const columns = `from_hn, to_hn, min_hn, max_hn, parity, postcode, geometry, source, release`
|
|
130
|
+
|
|
116
131
|
this.#byPostcode = this.#db.prepare(
|
|
117
132
|
`SELECT ${columns} FROM street_segment
|
|
118
133
|
WHERE postcode = ? AND street_norm = ? AND min_hn <= ? AND max_hn >= ?`
|
|
119
134
|
)
|
|
135
|
+
|
|
120
136
|
this.#byStreet = this.#db.prepare(
|
|
121
137
|
`SELECT ${columns} FROM street_segment
|
|
122
138
|
WHERE street_norm = ? AND min_hn <= ? AND max_hn >= ?`
|
|
123
139
|
)
|
|
124
140
|
}
|
|
141
|
+
|
|
142
|
+
// #374 doctrine: the conformal radius multiplier is a property of the calibration set the ARTIFACT was
|
|
143
|
+
// built against, so it ships in the shard's `interp_calibration` metadata table (street-segment-schema.ts)
|
|
144
|
+
// and is read here, once, at open time — sync raw `.prepare()` per the sync-by-interface doctrine
|
|
145
|
+
// (AGENTS.md). Shards predating the table (the pre-2026-07 fleet) yield `undefined`; callers then fall
|
|
146
|
+
// back to their in-code table, byte-identically.
|
|
147
|
+
if (hasTable(this.#db, "interp_calibration")) {
|
|
148
|
+
const row = this.#db.prepare("SELECT radius_multiplier FROM interp_calibration LIMIT 1").get() as
|
|
149
|
+
| { radius_multiplier: unknown }
|
|
150
|
+
| undefined
|
|
151
|
+
|
|
152
|
+
const value = row?.radius_multiplier
|
|
153
|
+
|
|
154
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
155
|
+
this.#radiusCalibration = value
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The artifact's own conformal radius multiplier (#374), read from the shard's `interp_calibration` metadata table at
|
|
162
|
+
* construction. `undefined` = the shard predates the table (or carries no valid row) — the resolver then applies no
|
|
163
|
+
* artifact default and callers may supply a legacy fallback.
|
|
164
|
+
*/
|
|
165
|
+
get radiusCalibration(): number | undefined {
|
|
166
|
+
return this.#radiusCalibration
|
|
125
167
|
}
|
|
126
168
|
|
|
127
169
|
find(query: InterpolationQuery): InterpolatedHit | null {
|
|
@@ -149,23 +191,29 @@ export class StreetInterpolator implements InterpolationLookup {
|
|
|
149
191
|
if (postcodes.size > 1) return null
|
|
150
192
|
}
|
|
151
193
|
|
|
152
|
-
if (rows.length
|
|
194
|
+
if (!rows.length) return null
|
|
153
195
|
|
|
154
196
|
// Parity preference: exact side first, then 'mixed' (matches either), then the
|
|
155
197
|
// opposite side as a flagged fallback.
|
|
156
198
|
const wantOdd = n % 2 === 1
|
|
157
199
|
const exact = rows.filter((r) => r.parity === (wantOdd ? "odd" : "even"))
|
|
158
200
|
const mixed = rows.filter((r) => r.parity === "mixed")
|
|
159
|
-
const preferred = exact.length
|
|
160
|
-
const pool = preferred.length
|
|
201
|
+
const preferred = exact.length ? exact : mixed
|
|
202
|
+
const pool = preferred.length ? preferred : rows
|
|
161
203
|
const parityMatched = preferred.length > 0
|
|
162
204
|
|
|
163
205
|
// Tightest range wins — the most specific claim about where this number lives.
|
|
164
|
-
|
|
206
|
+
let best = pool[0]!
|
|
207
|
+
|
|
208
|
+
for (const candidate of pool) {
|
|
209
|
+
if (candidate.max_hn - candidate.min_hn < best.max_hn - best.min_hn) {
|
|
210
|
+
best = candidate
|
|
211
|
+
}
|
|
212
|
+
}
|
|
165
213
|
|
|
166
214
|
const polyline = JSON.parse(best.geometry) as [number, number][]
|
|
167
215
|
const span = best.to_hn - best.from_hn
|
|
168
|
-
const t = span === 0 ? 0.5 :
|
|
216
|
+
const t = span === 0 ? 0.5 : clampFraction((n - best.from_hn) / span)
|
|
169
217
|
const [lon, lat, lengthKm] = pointAlong(polyline, t)
|
|
170
218
|
|
|
171
219
|
return {
|
|
@@ -186,47 +234,3 @@ export class StreetInterpolator implements InterpolationLookup {
|
|
|
186
234
|
}
|
|
187
235
|
}
|
|
188
236
|
}
|
|
189
|
-
|
|
190
|
-
function clamp01(t: number): number {
|
|
191
|
-
return t < 0 ? 0 : t > 1 ? 1 : t
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Point at fraction `t` of the polyline's total arc length (haversine), plus the total length in km. `t` is assumed
|
|
196
|
-
* clamped to [0, 1].
|
|
197
|
-
*/
|
|
198
|
-
function pointAlong(polyline: readonly [number, number][], t: number): [lon: number, lat: number, lengthKm: number] {
|
|
199
|
-
const legs: number[] = []
|
|
200
|
-
let total = 0
|
|
201
|
-
|
|
202
|
-
for (let i = 1; i < polyline.length; i++) {
|
|
203
|
-
const [aLon, aLat] = polyline[i - 1]!
|
|
204
|
-
const [bLon, bLat] = polyline[i]!
|
|
205
|
-
const d = haversineKm(aLat, aLon, bLat, bLon)
|
|
206
|
-
legs.push(d)
|
|
207
|
-
total += d
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (total === 0) {
|
|
211
|
-
const [lon, lat] = polyline[0]!
|
|
212
|
-
|
|
213
|
-
return [lon, lat, 0]
|
|
214
|
-
}
|
|
215
|
-
let remaining = t * total
|
|
216
|
-
|
|
217
|
-
for (let i = 0; i < legs.length; i++) {
|
|
218
|
-
const leg = legs[i]!
|
|
219
|
-
|
|
220
|
-
if (remaining <= leg || i === legs.length - 1) {
|
|
221
|
-
const f = leg === 0 ? 0 : clamp01(remaining / leg)
|
|
222
|
-
const [aLon, aLat] = polyline[i]!
|
|
223
|
-
const [bLon, bLat] = polyline[i + 1]!
|
|
224
|
-
|
|
225
|
-
return [aLon + (bLon - aLon) * f, aLat + (bLat - aLat) * f, total]
|
|
226
|
-
}
|
|
227
|
-
remaining -= leg
|
|
228
|
-
}
|
|
229
|
-
const [lon, lat] = polyline[polyline.length - 1]!
|
|
230
|
-
|
|
231
|
-
return [lon, lat, total]
|
|
232
|
-
}
|