ts-maps 0.3.2 → 0.3.3
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/dist/core-map/control/FullscreenControl.d.ts +39 -0
- package/dist/core-map/control/GeocoderControl.d.ts +61 -0
- package/dist/core-map/control/LocateControl.d.ts +5 -2
- package/dist/core-map/control/NavigationControl.d.ts +39 -0
- package/dist/core-map/control/index.d.ts +6 -0
- package/dist/core-map/game/TerritoryLog.d.ts +66 -0
- package/dist/core-map/game/TerritoryStore.d.ts +59 -0
- package/dist/core-map/game/index.d.ts +11 -0
- package/dist/core-map/game/loop.d.ts +61 -0
- package/dist/core-map/geo/area.d.ts +52 -0
- package/dist/core-map/geo/index.d.ts +30 -0
- package/dist/core-map/geo/index.js +826 -1
- package/dist/core-map/geo/polygonClip.d.ts +75 -0
- package/dist/core-map/geo/validate.d.ts +54 -0
- package/dist/core-map/index.d.ts +7 -2
- package/dist/core-map/layer/GeoJSONTileSource.d.ts +50 -0
- package/dist/core-map/layer/RunTrailLayer.d.ts +35 -0
- package/dist/core-map/layer/TerritoryLayer.d.ts +62 -0
- package/dist/core-map/layer/index.d.ts +6 -0
- package/dist/core-map/layer/tile/RasterDEMLayer.d.ts +4 -0
- package/dist/core-map/layer/tile/VectorTileMapLayer.d.ts +59 -11
- package/dist/core-map/layer/tile/urlTemplate.d.ts +1 -2
- package/dist/core-map/map/Map.d.ts +32 -1
- package/dist/core-map/mvt/DecodedTile.d.ts +20 -0
- package/dist/core-map/mvt/FlatTile.d.ts +25 -0
- package/dist/core-map/mvt/VectorTileFeature.d.ts +8 -0
- package/dist/core-map/style-spec/expressions/formatted.d.ts +36 -0
- package/dist/core-map/style-spec/expressions/operators/binding.d.ts +1 -0
- package/dist/core-map/style-spec/expressions/operators/geometry.d.ts +19 -0
- package/dist/core-map/style-spec/expressions/types.d.ts +3 -0
- package/dist/core-map/style-spec/index.js +442 -42
- package/dist/core-map/style-spec/schema.d.ts +43 -3
- package/dist/core-map/style-spec/types.d.ts +47 -7
- package/dist/core-map/styles/basemap.d.ts +41 -0
- package/dist/core-map/styles/index.d.ts +5 -0
- package/dist/core-map/styles/palette.d.ts +31 -0
- package/dist/core-map/symbols/CollisionIndex.d.ts +22 -5
- package/dist/core-map/symbols/GlyphAtlas.d.ts +6 -1
- package/dist/core-map/symbols/GlyphProvider.d.ts +21 -0
- package/dist/core-map/symbols/GlyphRenderer.d.ts +48 -0
- package/dist/core-map/symbols/IconAtlas.d.ts +10 -1
- package/dist/core-map/symbols/SymbolOverlay.d.ts +47 -0
- package/dist/core-map/symbols/index.d.ts +4 -0
- package/dist/core-map/symbols/index.js +1071 -67
- package/dist/core-map/symbols/loadGlyphs.d.ts +53 -0
- package/dist/core-map/symbols/loadSprite.d.ts +57 -0
- package/dist/core-map/symbols/placement.d.ts +67 -0
- package/dist/core-map/symbols/sdf.d.ts +37 -0
- package/dist/core-map/symbols/sections.d.ts +32 -0
- package/dist/core-map/workers/WorkerPool.d.ts +40 -0
- package/dist/core-map/workers/decodeMvtFlat.d.ts +52 -0
- package/dist/index.js +11492 -5957
- package/package.json +1 -1
- 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
|
};
|