ts-maps 0.3.2 → 0.3.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.
Files changed (54) hide show
  1. package/dist/core-map/control/FullscreenControl.d.ts +39 -0
  2. package/dist/core-map/control/GeocoderControl.d.ts +61 -0
  3. package/dist/core-map/control/LocateControl.d.ts +5 -2
  4. package/dist/core-map/control/NavigationControl.d.ts +39 -0
  5. package/dist/core-map/control/index.d.ts +6 -0
  6. package/dist/core-map/game/TerritoryLog.d.ts +66 -0
  7. package/dist/core-map/game/TerritoryStore.d.ts +59 -0
  8. package/dist/core-map/game/index.d.ts +11 -0
  9. package/dist/core-map/game/loop.d.ts +61 -0
  10. package/dist/core-map/geo/area.d.ts +52 -0
  11. package/dist/core-map/geo/index.d.ts +30 -0
  12. package/dist/core-map/geo/index.js +826 -1
  13. package/dist/core-map/geo/polygonClip.d.ts +75 -0
  14. package/dist/core-map/geo/validate.d.ts +54 -0
  15. package/dist/core-map/index.d.ts +7 -2
  16. package/dist/core-map/layer/GeoJSONTileSource.d.ts +50 -0
  17. package/dist/core-map/layer/RunTrailLayer.d.ts +35 -0
  18. package/dist/core-map/layer/TerritoryLayer.d.ts +62 -0
  19. package/dist/core-map/layer/index.d.ts +6 -0
  20. package/dist/core-map/layer/tile/RasterDEMLayer.d.ts +4 -0
  21. package/dist/core-map/layer/tile/VectorTileMapLayer.d.ts +59 -11
  22. package/dist/core-map/layer/tile/urlTemplate.d.ts +1 -2
  23. package/dist/core-map/map/Map.d.ts +32 -1
  24. package/dist/core-map/mvt/DecodedTile.d.ts +20 -0
  25. package/dist/core-map/mvt/FlatTile.d.ts +25 -0
  26. package/dist/core-map/mvt/VectorTileFeature.d.ts +8 -0
  27. package/dist/core-map/style-spec/expressions/formatted.d.ts +36 -0
  28. package/dist/core-map/style-spec/expressions/operators/binding.d.ts +1 -0
  29. package/dist/core-map/style-spec/expressions/operators/geometry.d.ts +19 -0
  30. package/dist/core-map/style-spec/expressions/types.d.ts +3 -0
  31. package/dist/core-map/style-spec/index.js +459 -42
  32. package/dist/core-map/style-spec/schema.d.ts +43 -3
  33. package/dist/core-map/style-spec/types.d.ts +47 -7
  34. package/dist/core-map/styles/basemap.d.ts +41 -0
  35. package/dist/core-map/styles/index.d.ts +5 -0
  36. package/dist/core-map/styles/palette.d.ts +31 -0
  37. package/dist/core-map/symbols/CollisionIndex.d.ts +22 -5
  38. package/dist/core-map/symbols/GlyphAtlas.d.ts +6 -1
  39. package/dist/core-map/symbols/GlyphProvider.d.ts +21 -0
  40. package/dist/core-map/symbols/GlyphRenderer.d.ts +48 -0
  41. package/dist/core-map/symbols/IconAtlas.d.ts +10 -1
  42. package/dist/core-map/symbols/SymbolOverlay.d.ts +47 -0
  43. package/dist/core-map/symbols/index.d.ts +4 -0
  44. package/dist/core-map/symbols/index.js +1071 -67
  45. package/dist/core-map/symbols/loadGlyphs.d.ts +53 -0
  46. package/dist/core-map/symbols/loadSprite.d.ts +57 -0
  47. package/dist/core-map/symbols/placement.d.ts +67 -0
  48. package/dist/core-map/symbols/sdf.d.ts +37 -0
  49. package/dist/core-map/symbols/sections.d.ts +32 -0
  50. package/dist/core-map/workers/WorkerPool.d.ts +40 -0
  51. package/dist/core-map/workers/decodeMvtFlat.d.ts +52 -0
  52. package/dist/index.js +11548 -5996
  53. package/package.json +1 -1
  54. package/src/core-map/ts-maps.css +392 -99
@@ -1013,6 +1013,807 @@ var init_EPSG3857 = __esm(() => {
1013
1013
  };
1014
1014
  });
1015
1015
 
1016
+ // src/core-map/geo/area.ts
1017
+ function ringArea(ring) {
1018
+ if (ring.length < 3)
1019
+ return 0;
1020
+ let total = 0;
1021
+ for (let i = 0, len = ring.length;i < len; i++) {
1022
+ const p1 = ring[i];
1023
+ const p2 = ring[(i + 1) % len];
1024
+ let dLng = p2[0] - p1[0];
1025
+ if (dLng > 180)
1026
+ dLng -= 360;
1027
+ else if (dLng < -180)
1028
+ dLng += 360;
1029
+ total += dLng * RAD * (2 + Math.sin(p1[1] * RAD) + Math.sin(p2[1] * RAD));
1030
+ }
1031
+ return total * EARTH_RADIUS * EARTH_RADIUS / 2;
1032
+ }
1033
+ function polygonArea(polygon) {
1034
+ if (polygon.length === 0)
1035
+ return 0;
1036
+ let total = Math.abs(ringArea(polygon[0]));
1037
+ for (let i = 1;i < polygon.length; i++)
1038
+ total -= Math.abs(ringArea(polygon[i]));
1039
+ return Math.max(0, total);
1040
+ }
1041
+ function multiPolygonArea(multi) {
1042
+ let total = 0;
1043
+ for (const polygon of multi)
1044
+ total += polygonArea(polygon);
1045
+ return total;
1046
+ }
1047
+ function ringPerimeter(ring, closed = true) {
1048
+ let total = 0;
1049
+ const end = closed ? ring.length : ring.length - 1;
1050
+ for (let i = 0;i < end; i++)
1051
+ total += haversine(ring[i], ring[(i + 1) % ring.length]);
1052
+ return total;
1053
+ }
1054
+ function haversine(a, b) {
1055
+ const dLat = (b[1] - a[1]) * RAD;
1056
+ const dLng = (b[0] - a[0]) * RAD;
1057
+ const lat1 = a[1] * RAD;
1058
+ const lat2 = b[1] * RAD;
1059
+ const h = Math.sin(dLat / 2) ** 2 + Math.sin(dLng / 2) ** 2 * Math.cos(lat1) * Math.cos(lat2);
1060
+ return 2 * EARTH_RADIUS * Math.asin(Math.min(1, Math.sqrt(h)));
1061
+ }
1062
+ function formatArea(squareMetres, options = {}) {
1063
+ const locale = options.locale;
1064
+ const value = Math.max(0, squareMetres);
1065
+ if (options.units === "imperial") {
1066
+ const squareFeet = value * 10.763910417;
1067
+ if (squareFeet < 43560)
1068
+ return `${round(squareFeet, 0).toLocaleString(locale)} ft²`;
1069
+ const acres = value / 4046.8564224;
1070
+ if (acres < 640)
1071
+ return `${round(acres, acres < 10 ? 2 : 1).toLocaleString(locale)} acres`;
1072
+ return `${round(value / 2589988.110336, 2).toLocaleString(locale)} mi²`;
1073
+ }
1074
+ if (value < 1e4)
1075
+ return `${round(value, 0).toLocaleString(locale)} m²`;
1076
+ if (value < 1e6)
1077
+ return `${round(value / 1e4, value < 1e5 ? 2 : 1).toLocaleString(locale)} ha`;
1078
+ return `${round(value / 1e6, value < 1e7 ? 2 : 1).toLocaleString(locale)} km²`;
1079
+ }
1080
+ function formatDistance(metres, options = {}) {
1081
+ const locale = options.locale;
1082
+ const value = Math.max(0, metres);
1083
+ if (options.units === "imperial") {
1084
+ const miles = value / 1609.344;
1085
+ if (miles < 0.1)
1086
+ return `${round(value * 3.280839895, 0).toLocaleString(locale)} ft`;
1087
+ return `${round(miles, 2).toLocaleString(locale)} mi`;
1088
+ }
1089
+ if (value < 1000)
1090
+ return `${round(value, 0).toLocaleString(locale)} m`;
1091
+ return `${round(value / 1000, 2).toLocaleString(locale)} km`;
1092
+ }
1093
+ function round(value, places) {
1094
+ const factor = 10 ** places;
1095
+ return Math.round(value * factor) / factor;
1096
+ }
1097
+ var EARTH_RADIUS = 6371008.8, RAD;
1098
+ var init_area = __esm(() => {
1099
+ RAD = Math.PI / 180;
1100
+ });
1101
+
1102
+ // src/core-map/geo/polygonClip.ts
1103
+ class SweepEvent {
1104
+ point;
1105
+ left;
1106
+ otherEvent;
1107
+ isSubject;
1108
+ type;
1109
+ inOut;
1110
+ otherInOut;
1111
+ inResult;
1112
+ contourId;
1113
+ constructor(point, left, otherEvent, isSubject, type = NORMAL) {
1114
+ this.point = point;
1115
+ this.left = left;
1116
+ this.otherEvent = otherEvent;
1117
+ this.isSubject = isSubject;
1118
+ this.type = type;
1119
+ this.inOut = false;
1120
+ this.otherInOut = false;
1121
+ this.inResult = false;
1122
+ this.contourId = 0;
1123
+ }
1124
+ isBelow(p) {
1125
+ const a = this.point;
1126
+ const b = this.otherEvent.point;
1127
+ return this.left ? signedArea(a, b, p) > 0 : signedArea(b, a, p) > 0;
1128
+ }
1129
+ isAbove(p) {
1130
+ return !this.isBelow(p);
1131
+ }
1132
+ isVertical() {
1133
+ return this.point[0] === this.otherEvent.point[0];
1134
+ }
1135
+ }
1136
+ function signedArea(p0, p1, p2) {
1137
+ return (p0[0] - p2[0]) * (p1[1] - p2[1]) - (p1[0] - p2[0]) * (p0[1] - p2[1]);
1138
+ }
1139
+ function equals(a, b) {
1140
+ return a[0] === b[0] && a[1] === b[1];
1141
+ }
1142
+ function compareEvents(e1, e2) {
1143
+ const p1 = e1.point;
1144
+ const p2 = e2.point;
1145
+ if (p1[0] > p2[0])
1146
+ return 1;
1147
+ if (p1[0] < p2[0])
1148
+ return -1;
1149
+ if (p1[1] !== p2[1])
1150
+ return p1[1] > p2[1] ? 1 : -1;
1151
+ if (e1.left !== e2.left)
1152
+ return e1.left ? 1 : -1;
1153
+ if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0)
1154
+ return e1.isBelow(e2.otherEvent.point) ? -1 : 1;
1155
+ return !e1.isSubject && e2.isSubject ? 1 : -1;
1156
+ }
1157
+ function compareSegments(le1, le2) {
1158
+ if (le1 === le2)
1159
+ return 0;
1160
+ if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 || signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
1161
+ if (equals(le1.point, le2.point))
1162
+ return le1.isBelow(le2.otherEvent.point) ? -1 : 1;
1163
+ if (le1.point[0] === le2.point[0])
1164
+ return le1.point[1] < le2.point[1] ? -1 : 1;
1165
+ if (compareEvents(le1, le2) === 1)
1166
+ return le2.isAbove(le1.point) ? -1 : 1;
1167
+ return le1.isBelow(le2.point) ? -1 : 1;
1168
+ }
1169
+ if (le1.isSubject === le2.isSubject) {
1170
+ let p1 = le1.point;
1171
+ let p2 = le2.point;
1172
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
1173
+ p1 = le1.otherEvent.point;
1174
+ p2 = le2.otherEvent.point;
1175
+ if (p1[0] === p2[0] && p1[1] === p2[1])
1176
+ return 0;
1177
+ return le1.contourId > le2.contourId ? 1 : -1;
1178
+ }
1179
+ return compareEvents(le1, le2) === 1 ? 1 : -1;
1180
+ }
1181
+ return le1.isSubject ? -1 : 1;
1182
+ }
1183
+
1184
+ class EventQueue {
1185
+ _data = [];
1186
+ get length() {
1187
+ return this._data.length;
1188
+ }
1189
+ push(event) {
1190
+ const data = this._data;
1191
+ data.push(event);
1192
+ let pos = data.length - 1;
1193
+ while (pos > 0) {
1194
+ const parent = pos - 1 >> 1;
1195
+ if (compareEvents(data[pos], data[parent]) >= 0)
1196
+ break;
1197
+ const tmp = data[parent];
1198
+ data[parent] = data[pos];
1199
+ data[pos] = tmp;
1200
+ pos = parent;
1201
+ }
1202
+ }
1203
+ pop() {
1204
+ const data = this._data;
1205
+ const top = data[0];
1206
+ const last = data.pop();
1207
+ if (data.length === 0)
1208
+ return top;
1209
+ data[0] = last;
1210
+ let pos = 0;
1211
+ const half = data.length >> 1;
1212
+ while (pos < half) {
1213
+ let child = 2 * pos + 1;
1214
+ const right = child + 1;
1215
+ if (right < data.length && compareEvents(data[right], data[child]) < 0)
1216
+ child = right;
1217
+ if (compareEvents(data[child], data[pos]) >= 0)
1218
+ break;
1219
+ const tmp = data[child];
1220
+ data[child] = data[pos];
1221
+ data[pos] = tmp;
1222
+ pos = child;
1223
+ }
1224
+ return top;
1225
+ }
1226
+ }
1227
+
1228
+ class SweepStatus {
1229
+ _items = [];
1230
+ insert(event) {
1231
+ let low = 0;
1232
+ let high = this._items.length;
1233
+ while (low < high) {
1234
+ const mid = low + high >> 1;
1235
+ if (compareSegments(this._items[mid], event) < 0)
1236
+ low = mid + 1;
1237
+ else
1238
+ high = mid;
1239
+ }
1240
+ this._items.splice(low, 0, event);
1241
+ return low;
1242
+ }
1243
+ remove(event) {
1244
+ const index = this._items.indexOf(event);
1245
+ if (index !== -1)
1246
+ this._items.splice(index, 1);
1247
+ }
1248
+ indexOf(event) {
1249
+ return this._items.indexOf(event);
1250
+ }
1251
+ at(index) {
1252
+ return index >= 0 && index < this._items.length ? this._items[index] : null;
1253
+ }
1254
+ }
1255
+ function segmentIntersection(a1, a2, b1, b2) {
1256
+ const va = [a2[0] - a1[0], a2[1] - a1[1]];
1257
+ const vb = [b2[0] - b1[0], b2[1] - b1[1]];
1258
+ const e = [b1[0] - a1[0], b1[1] - a1[1]];
1259
+ const cross = (u, v) => u[0] * v[1] - u[1] * v[0];
1260
+ const dot = (u, v) => u[0] * v[0] + u[1] * v[1];
1261
+ const at = (base, s, v) => [base[0] + s * v[0], base[1] + s * v[1]];
1262
+ const kross = cross(va, vb);
1263
+ if (kross * kross > 0) {
1264
+ const s = cross(e, vb) / kross;
1265
+ if (s < 0 || s > 1)
1266
+ return null;
1267
+ const t = cross(e, va) / kross;
1268
+ if (t < 0 || t > 1)
1269
+ return null;
1270
+ if (s === 0 || s === 1)
1271
+ return [at(a1, s, va)];
1272
+ if (t === 0 || t === 1)
1273
+ return [at(b1, t, vb)];
1274
+ return [at(a1, s, va)];
1275
+ }
1276
+ if (cross(e, va) ** 2 > 0)
1277
+ return null;
1278
+ const sqrLenA = dot(va, va);
1279
+ if (sqrLenA === 0)
1280
+ return null;
1281
+ const sa = dot(e, va) / sqrLenA;
1282
+ const sb = sa + dot(vb, va) / sqrLenA;
1283
+ const s0 = Math.max(Math.min(sa, sb), 0);
1284
+ const s1 = Math.min(Math.max(sa, sb), 1);
1285
+ if (s0 > s1)
1286
+ return null;
1287
+ if (s0 === s1)
1288
+ return [at(a1, s0, va)];
1289
+ return [at(a1, s0, va), at(a1, s1, va)];
1290
+ }
1291
+ function divideSegment(se, p, queue) {
1292
+ const right = new SweepEvent(p, false, se, se.isSubject);
1293
+ const left = new SweepEvent(p, true, se.otherEvent, se.isSubject);
1294
+ right.contourId = se.contourId;
1295
+ left.contourId = se.contourId;
1296
+ if (compareEvents(left, se.otherEvent) > 0) {
1297
+ se.otherEvent.left = true;
1298
+ left.left = false;
1299
+ }
1300
+ se.otherEvent.otherEvent = left;
1301
+ se.otherEvent = right;
1302
+ queue.push(left);
1303
+ queue.push(right);
1304
+ }
1305
+ function possibleIntersection(se1, se2, queue) {
1306
+ const inter = segmentIntersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
1307
+ if (!inter)
1308
+ return 0;
1309
+ const count = inter.length;
1310
+ if (count === 1 && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point)))
1311
+ return 0;
1312
+ if (count === 2 && se1.isSubject === se2.isSubject)
1313
+ return 0;
1314
+ if (count === 1) {
1315
+ if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0]))
1316
+ divideSegment(se1, inter[0], queue);
1317
+ if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0]))
1318
+ divideSegment(se2, inter[0], queue);
1319
+ return 1;
1320
+ }
1321
+ const events = [];
1322
+ let leftCoincide = false;
1323
+ let rightCoincide = false;
1324
+ if (equals(se1.point, se2.point))
1325
+ leftCoincide = true;
1326
+ else if (compareEvents(se1, se2) === 1)
1327
+ events.push(se2, se1);
1328
+ else
1329
+ events.push(se1, se2);
1330
+ if (equals(se1.otherEvent.point, se2.otherEvent.point))
1331
+ rightCoincide = true;
1332
+ else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1)
1333
+ events.push(se2.otherEvent, se1.otherEvent);
1334
+ else
1335
+ events.push(se1.otherEvent, se2.otherEvent);
1336
+ if (leftCoincide) {
1337
+ se2.type = NON_CONTRIBUTING;
1338
+ se1.type = se2.inOut === se1.inOut ? SAME_TRANSITION : DIFFERENT_TRANSITION;
1339
+ if (!rightCoincide)
1340
+ divideSegment(events[1].otherEvent, events[0].point, queue);
1341
+ return 2;
1342
+ }
1343
+ if (rightCoincide) {
1344
+ divideSegment(events[0], events[1].point, queue);
1345
+ return 3;
1346
+ }
1347
+ if (events[0] !== events[3].otherEvent) {
1348
+ divideSegment(events[0], events[1].point, queue);
1349
+ divideSegment(events[1], events[2].point, queue);
1350
+ return 3;
1351
+ }
1352
+ divideSegment(events[0], events[1].point, queue);
1353
+ divideSegment(events[3].otherEvent, events[2].point, queue);
1354
+ return 3;
1355
+ }
1356
+ function edgeInResult(event, operation) {
1357
+ switch (event.type) {
1358
+ case NORMAL:
1359
+ switch (operation) {
1360
+ case INTERSECTION:
1361
+ return !event.otherInOut;
1362
+ case UNION:
1363
+ return event.otherInOut;
1364
+ case DIFFERENCE:
1365
+ return event.isSubject && event.otherInOut || !event.isSubject && !event.otherInOut;
1366
+ case XOR:
1367
+ return true;
1368
+ }
1369
+ return false;
1370
+ case SAME_TRANSITION:
1371
+ return operation === INTERSECTION || operation === UNION;
1372
+ case DIFFERENT_TRANSITION:
1373
+ return operation === DIFFERENCE;
1374
+ default:
1375
+ return false;
1376
+ }
1377
+ }
1378
+ function computeFields(event, prev, operation) {
1379
+ if (prev === null) {
1380
+ event.inOut = false;
1381
+ event.otherInOut = true;
1382
+ } else if (event.isSubject === prev.isSubject) {
1383
+ event.inOut = !prev.inOut;
1384
+ event.otherInOut = prev.otherInOut;
1385
+ } else {
1386
+ event.inOut = !prev.otherInOut;
1387
+ event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
1388
+ }
1389
+ event.inResult = edgeInResult(event, operation);
1390
+ }
1391
+ function sweep(subject, clip, operation) {
1392
+ const queue = new EventQueue;
1393
+ let contourId = 0;
1394
+ const addPolygonSet = (polygons, isSubject) => {
1395
+ for (const polygon of polygons) {
1396
+ for (const ring of polygon) {
1397
+ contourId++;
1398
+ const points = normaliseRing(ring);
1399
+ for (let i = 0;i < points.length; i++) {
1400
+ const a = points[i];
1401
+ const b = points[(i + 1) % points.length];
1402
+ if (equals(a, b))
1403
+ continue;
1404
+ const e1 = new SweepEvent(a, false, null, isSubject);
1405
+ const e2 = new SweepEvent(b, false, e1, isSubject);
1406
+ e1.otherEvent = e2;
1407
+ e1.contourId = contourId;
1408
+ e2.contourId = contourId;
1409
+ if (compareEvents(e1, e2) > 0)
1410
+ e2.left = true;
1411
+ else
1412
+ e1.left = true;
1413
+ queue.push(e1);
1414
+ queue.push(e2);
1415
+ }
1416
+ }
1417
+ }
1418
+ };
1419
+ addPolygonSet(subject, true);
1420
+ addPolygonSet(clip, false);
1421
+ const status = new SweepStatus;
1422
+ const results = [];
1423
+ while (queue.length > 0) {
1424
+ const event = queue.pop();
1425
+ if (event.left) {
1426
+ const position = status.insert(event);
1427
+ const prev = status.at(position - 1);
1428
+ const next = status.at(position + 1);
1429
+ computeFields(event, prev, operation);
1430
+ if (next && possibleIntersection(event, next, queue) === 2) {
1431
+ computeFields(event, prev, operation);
1432
+ computeFields(next, event, operation);
1433
+ }
1434
+ if (prev && possibleIntersection(prev, event, queue) === 2) {
1435
+ const prevOfPrev = status.at(status.indexOf(prev) - 1);
1436
+ computeFields(prev, prevOfPrev, operation);
1437
+ computeFields(event, prev, operation);
1438
+ }
1439
+ results.push(event);
1440
+ } else {
1441
+ const left = event.otherEvent;
1442
+ const position = status.indexOf(left);
1443
+ if (position !== -1) {
1444
+ const prev = status.at(position - 1);
1445
+ const next = status.at(position + 1);
1446
+ status.remove(left);
1447
+ if (prev && next)
1448
+ possibleIntersection(prev, next, queue);
1449
+ }
1450
+ }
1451
+ }
1452
+ const edges = [];
1453
+ for (const event of results) {
1454
+ if (event.inResult && event.type !== NON_CONTRIBUTING)
1455
+ edges.push({ from: event.point, to: event.otherEvent.point });
1456
+ }
1457
+ return edges;
1458
+ }
1459
+ function normaliseRing(ring) {
1460
+ const points = [];
1461
+ for (const point of ring) {
1462
+ const last = points[points.length - 1];
1463
+ if (!last || !equals(last, point))
1464
+ points.push([point[0], point[1]]);
1465
+ }
1466
+ while (points.length > 1 && equals(points[0], points[points.length - 1]))
1467
+ points.pop();
1468
+ return points;
1469
+ }
1470
+ function key2(p) {
1471
+ return `${p[0]},${p[1]}`;
1472
+ }
1473
+ function buildRings(edges) {
1474
+ const used = Array.from({ length: edges.length }, () => false);
1475
+ const outgoing = new Map;
1476
+ const link = (from, to, edge) => {
1477
+ const arc = { edge, to, angle: Math.atan2(to[1] - from[1], to[0] - from[0]) };
1478
+ const k = key2(from);
1479
+ const list = outgoing.get(k);
1480
+ if (list)
1481
+ list.push(arc);
1482
+ else
1483
+ outgoing.set(k, [arc]);
1484
+ };
1485
+ for (let i = 0;i < edges.length; i++) {
1486
+ const { from, to } = edges[i];
1487
+ if (equals(from, to)) {
1488
+ used[i] = true;
1489
+ continue;
1490
+ }
1491
+ link(from, to, i);
1492
+ link(to, from, i);
1493
+ }
1494
+ const rings = [];
1495
+ for (let seed = 0;seed < edges.length; seed++) {
1496
+ if (used[seed])
1497
+ continue;
1498
+ const origin = edges[seed].from;
1499
+ const ring = [origin];
1500
+ let from = origin;
1501
+ let to = edges[seed].to;
1502
+ used[seed] = true;
1503
+ for (let guard = 0;guard <= edges.length + 1; guard++) {
1504
+ ring.push(to);
1505
+ if (equals(to, origin))
1506
+ break;
1507
+ const candidates = outgoing.get(key2(to));
1508
+ if (!candidates)
1509
+ break;
1510
+ const back = Math.atan2(from[1] - to[1], from[0] - to[0]);
1511
+ let best = null;
1512
+ let bestTurn = Infinity;
1513
+ for (const candidate of candidates) {
1514
+ if (used[candidate.edge])
1515
+ continue;
1516
+ let turn = back - candidate.angle;
1517
+ while (turn <= 0)
1518
+ turn += Math.PI * 2;
1519
+ while (turn > Math.PI * 2)
1520
+ turn -= Math.PI * 2;
1521
+ if (turn < bestTurn) {
1522
+ bestTurn = turn;
1523
+ best = candidate;
1524
+ }
1525
+ }
1526
+ if (!best)
1527
+ break;
1528
+ used[best.edge] = true;
1529
+ from = to;
1530
+ to = best.to;
1531
+ }
1532
+ if (ring.length >= 4 && equals(ring[0], ring[ring.length - 1]))
1533
+ rings.push(ring);
1534
+ }
1535
+ return rings;
1536
+ }
1537
+ function ringSignedArea(ring) {
1538
+ let sum = 0;
1539
+ for (let i = 0, len = ring.length - 1;i < len; i++)
1540
+ sum += (ring[i + 1][0] - ring[i][0]) * (ring[i + 1][1] + ring[i][1]);
1541
+ return sum;
1542
+ }
1543
+ function pointInRing(point, ring) {
1544
+ let inside = false;
1545
+ for (let i = 0, j = ring.length - 2;i < ring.length - 1; j = i++) {
1546
+ const xi = ring[i][0];
1547
+ const yi = ring[i][1];
1548
+ const xj = ring[j][0];
1549
+ const yj = ring[j][1];
1550
+ if (yi > point[1] !== yj > point[1] && point[0] < (xj - xi) * (point[1] - yi) / (yj - yi) + xi) {
1551
+ inside = !inside;
1552
+ }
1553
+ }
1554
+ return inside;
1555
+ }
1556
+ function interiorPoint(ring) {
1557
+ for (let i = 0;i < ring.length - 1; i++) {
1558
+ const a = ring[i];
1559
+ const b = ring[(i + 1) % (ring.length - 1)];
1560
+ const candidate = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
1561
+ const dx = b[0] - a[0];
1562
+ const dy = b[1] - a[1];
1563
+ const len = Math.hypot(dx, dy);
1564
+ if (len === 0)
1565
+ continue;
1566
+ const scale = len * 0.000001;
1567
+ const inward = [candidate[0] - dy / len * scale, candidate[1] + dx / len * scale];
1568
+ if (pointInRing(inward, ring))
1569
+ return inward;
1570
+ const other = [candidate[0] + dy / len * scale, candidate[1] - dx / len * scale];
1571
+ if (pointInRing(other, ring))
1572
+ return other;
1573
+ }
1574
+ return ring[0];
1575
+ }
1576
+ function assemblePolygons(rings) {
1577
+ const kept = rings.filter((ring) => Math.abs(ringSignedArea(ring)) > 0);
1578
+ const samples = kept.map(interiorPoint);
1579
+ const parents = kept.map(() => -1);
1580
+ const depths = kept.map(() => 0);
1581
+ for (let i = 0;i < kept.length; i++) {
1582
+ let bestParent = -1;
1583
+ let bestArea = Infinity;
1584
+ for (let j = 0;j < kept.length; j++) {
1585
+ if (i === j)
1586
+ continue;
1587
+ if (!pointInRing(samples[i], kept[j]))
1588
+ continue;
1589
+ const area = Math.abs(ringSignedArea(kept[j]));
1590
+ if (area < bestArea) {
1591
+ bestArea = area;
1592
+ bestParent = j;
1593
+ }
1594
+ depths[i]++;
1595
+ }
1596
+ parents[i] = bestParent;
1597
+ }
1598
+ const polygons = [];
1599
+ const polygonOf = new Map;
1600
+ for (let i = 0;i < kept.length; i++) {
1601
+ if (depths[i] % 2 !== 0)
1602
+ continue;
1603
+ polygonOf.set(i, polygons.length);
1604
+ polygons.push([orient(kept[i], true)]);
1605
+ }
1606
+ for (let i = 0;i < kept.length; i++) {
1607
+ if (depths[i] % 2 === 0)
1608
+ continue;
1609
+ const target = parents[i] === -1 ? undefined : polygonOf.get(parents[i]);
1610
+ if (target === undefined) {
1611
+ continue;
1612
+ }
1613
+ polygons[target].push(orient(kept[i], false));
1614
+ }
1615
+ return polygons;
1616
+ }
1617
+ function orient(ring, outer) {
1618
+ const clockwise = ringSignedArea(ring) > 0;
1619
+ const copy = ring.map((p) => [p[0], p[1]]);
1620
+ if (clockwise === outer)
1621
+ copy.reverse();
1622
+ return copy;
1623
+ }
1624
+ function run(subject, clip, operation) {
1625
+ if (subject.length === 0) {
1626
+ if (operation === UNION || operation === XOR)
1627
+ return clone(clip);
1628
+ return [];
1629
+ }
1630
+ if (clip.length === 0) {
1631
+ if (operation === UNION || operation === DIFFERENCE || operation === XOR)
1632
+ return clone(subject);
1633
+ return [];
1634
+ }
1635
+ return assemblePolygons(buildRings(sweep(subject, clip, operation)));
1636
+ }
1637
+ function clone(multi) {
1638
+ return multi.map((polygon) => polygon.map((ring) => ring.map((p) => [p[0], p[1]])));
1639
+ }
1640
+ function union(subject, clip) {
1641
+ return run(subject, clip, UNION);
1642
+ }
1643
+ function intersection(subject, clip) {
1644
+ return run(subject, clip, INTERSECTION);
1645
+ }
1646
+ function difference(subject, clip) {
1647
+ return run(subject, clip, DIFFERENCE);
1648
+ }
1649
+ function xor(subject, clip) {
1650
+ return run(subject, clip, XOR);
1651
+ }
1652
+ function intersects(subject, clip) {
1653
+ return intersection(subject, clip).length > 0;
1654
+ }
1655
+ function contains(multi, point) {
1656
+ for (const polygon of multi) {
1657
+ if (polygon.length === 0 || !pointInRing(point, closeRing(polygon[0])))
1658
+ continue;
1659
+ let inHole = false;
1660
+ for (let i = 1;i < polygon.length; i++) {
1661
+ if (pointInRing(point, closeRing(polygon[i]))) {
1662
+ inHole = true;
1663
+ break;
1664
+ }
1665
+ }
1666
+ if (!inHole)
1667
+ return true;
1668
+ }
1669
+ return false;
1670
+ }
1671
+ function closeRing(ring) {
1672
+ if (ring.length > 0 && !equals(ring[0], ring[ring.length - 1]))
1673
+ return [...ring, ring[0]];
1674
+ return ring;
1675
+ }
1676
+ var INTERSECTION = 0, UNION = 1, DIFFERENCE = 2, XOR = 3, NORMAL = 0, NON_CONTRIBUTING = 1, SAME_TRANSITION = 2, DIFFERENT_TRANSITION = 3;
1677
+
1678
+ // src/core-map/geo/validate.ts
1679
+ function validateRing(ring) {
1680
+ if (!Array.isArray(ring))
1681
+ throw new InvalidGeometryError("ring must be an array of positions");
1682
+ if (ring.length < 4)
1683
+ throw new InvalidGeometryError(`ring needs at least 4 positions to enclose an area, got ${ring.length}`);
1684
+ for (let i = 0;i < ring.length; i++) {
1685
+ const position = ring[i];
1686
+ if (!Array.isArray(position) || position.length < 2)
1687
+ throw new InvalidGeometryError(`position ${i} is not a [lng, lat] pair`);
1688
+ const [lng, lat] = position;
1689
+ if (!Number.isFinite(lng) || !Number.isFinite(lat))
1690
+ throw new InvalidGeometryError(`position ${i} is not finite: [${lng}, ${lat}] — a receiver losing lock reports this`);
1691
+ if (lat < -90 || lat > 90)
1692
+ throw new InvalidGeometryError(`position ${i} has latitude ${lat}, outside [-90, 90]`);
1693
+ }
1694
+ }
1695
+ function unwrapRing(ring) {
1696
+ let crosses = false;
1697
+ for (let i = 1;i < ring.length; i++) {
1698
+ if (Math.abs(ring[i][0] - ring[i - 1][0]) > 180) {
1699
+ crosses = true;
1700
+ break;
1701
+ }
1702
+ }
1703
+ if (!crosses)
1704
+ return ring;
1705
+ const out = [[ring[0][0], ring[0][1]]];
1706
+ let offset = 0;
1707
+ for (let i = 1;i < ring.length; i++) {
1708
+ const delta = ring[i][0] - ring[i - 1][0];
1709
+ if (delta > 180)
1710
+ offset -= 360;
1711
+ else if (delta < -180)
1712
+ offset += 360;
1713
+ out.push([ring[i][0] + offset, ring[i][1]]);
1714
+ }
1715
+ return out;
1716
+ }
1717
+ function splitSelfIntersecting(ring) {
1718
+ const points = closeRing2(ring).slice(0, -1);
1719
+ const count = points.length;
1720
+ if (count < 3)
1721
+ return [closeRing2(ring)];
1722
+ const loops = [];
1723
+ const open = [];
1724
+ for (let i = 0;i < count; i++) {
1725
+ const a1 = points[i];
1726
+ const a2 = points[(i + 1) % count];
1727
+ open.push(a1);
1728
+ for (let j = 0;j + 2 < open.length; j++) {
1729
+ const point = crossingPoint(a1, a2, open[j], open[j + 1]);
1730
+ if (!point)
1731
+ continue;
1732
+ loops.push([point, ...open.slice(j + 1), point]);
1733
+ open.length = j + 1;
1734
+ open.push(point);
1735
+ break;
1736
+ }
1737
+ }
1738
+ loops.push([...open, open[0]]);
1739
+ return loops.filter((loop) => loop.length >= 4);
1740
+ }
1741
+ function resolveSelfIntersections(ring) {
1742
+ const single = [[closeRing2(ring)]];
1743
+ if (!selfIntersects(ring))
1744
+ return single;
1745
+ const loops = splitSelfIntersecting(ring);
1746
+ if (loops.length <= 1)
1747
+ return single;
1748
+ let result = [];
1749
+ for (const loop of loops)
1750
+ result = union(result, [[loop]]);
1751
+ return result;
1752
+ }
1753
+ function crossingPoint(a1, a2, b1, b2) {
1754
+ const ax = a2[0] - a1[0];
1755
+ const ay = a2[1] - a1[1];
1756
+ const bx = b2[0] - b1[0];
1757
+ const by = b2[1] - b1[1];
1758
+ const denominator = ax * by - ay * bx;
1759
+ if (denominator === 0)
1760
+ return null;
1761
+ const dx = b1[0] - a1[0];
1762
+ const dy = b1[1] - a1[1];
1763
+ const t = (dx * by - dy * bx) / denominator;
1764
+ const u = (dx * ay - dy * ax) / denominator;
1765
+ if (t <= 0 || t >= 1 || u <= 0 || u >= 1)
1766
+ return null;
1767
+ return [a1[0] + ax * t, a1[1] + ay * t];
1768
+ }
1769
+ function selfIntersects(ring) {
1770
+ const points = closeRing2(ring);
1771
+ const count = points.length - 1;
1772
+ if (count < 4)
1773
+ return false;
1774
+ for (let i = 0;i < count; i++) {
1775
+ for (let j = i + 2;j < count; j++) {
1776
+ if (i === 0 && j === count - 1)
1777
+ continue;
1778
+ if (segmentsCross(points[i], points[i + 1], points[j], points[j + 1]))
1779
+ return true;
1780
+ }
1781
+ }
1782
+ return false;
1783
+ }
1784
+ function segmentsCross(a1, a2, b1, b2) {
1785
+ const d1 = cross(a1, a2, b1);
1786
+ const d2 = cross(a1, a2, b2);
1787
+ const d3 = cross(b1, b2, a1);
1788
+ const d4 = cross(b1, b2, a2);
1789
+ return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
1790
+ }
1791
+ function cross(o, a, b) {
1792
+ return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
1793
+ }
1794
+ function closeRing2(ring) {
1795
+ if (ring.length === 0)
1796
+ return ring;
1797
+ const first = ring[0];
1798
+ const last = ring[ring.length - 1];
1799
+ if (first[0] === last[0] && first[1] === last[1])
1800
+ return ring;
1801
+ return [...ring, first];
1802
+ }
1803
+ function prepareClaim(ring) {
1804
+ validateRing(ring);
1805
+ return resolveSelfIntersections(unwrapRing(ring));
1806
+ }
1807
+ var InvalidGeometryError;
1808
+ var init_validate = __esm(() => {
1809
+ InvalidGeometryError = class InvalidGeometryError extends Error {
1810
+ constructor(message) {
1811
+ super(message);
1812
+ this.name = "InvalidGeometryError";
1813
+ }
1814
+ };
1815
+ });
1816
+
1016
1817
  // src/core-map/geo/index.ts
1017
1818
  init_LatLng();
1018
1819
  init_LatLngBounds();
@@ -1181,24 +1982,48 @@ class SimpleCRS extends CRS {
1181
1982
  return Math.sqrt(dx * dx + dy * dy);
1182
1983
  }
1183
1984
  }
1985
+ // src/core-map/geo/index.ts
1986
+ init_area();
1987
+ init_validate();
1184
1988
  export {
1185
1989
  CRS,
1990
+ EARTH_RADIUS,
1186
1991
  EPSG3395,
1187
1992
  EPSG3857,
1188
1993
  EPSG4326,
1189
1994
  EPSG900913,
1190
1995
  EarthCRS,
1996
+ InvalidGeometryError,
1191
1997
  LatLng,
1192
1998
  LatLngBounds,
1193
1999
  exports_projection as Projection,
1194
2000
  SimpleCRS,
1195
2001
  TerrainSource,
1196
2002
  buildTerrainMesh,
2003
+ contains,
1197
2004
  decodeElevationGrid,
1198
2005
  decodeMapboxRGB,
1199
2006
  decodeTerrariumRGB,
2007
+ difference,
2008
+ formatArea,
2009
+ formatDistance,
1200
2010
  getElevationDecoder,
2011
+ haversine,
2012
+ intersection,
2013
+ intersects,
2014
+ multiPolygonArea,
2015
+ polygonArea,
2016
+ prepareClaim,
2017
+ resolveSelfIntersections,
2018
+ ringArea,
2019
+ ringPerimeter,
1201
2020
  sampleElevationBilinear,
2021
+ selfIntersects,
2022
+ splitSelfIntersecting,
1202
2023
  toLatLng,
1203
- toLatLngBounds
2024
+ toLatLngBounds,
2025
+ union,
2026
+ unwrapRing,
2027
+ validateRing,
2028
+ xor
1204
2029
  };