leaflet-polydraw 0.9.4 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/leaflet-polydraw.css +1 -1
- package/dist/polydraw.es.js +1035 -655
- package/dist/polydraw.es.js.map +1 -1
- package/dist/polydraw.umd.min.js +1 -1
- package/dist/polydraw.umd.min.js.map +1 -1
- package/dist/styles/polydraw.css +58 -0
- package/dist/types/constants.d.ts +67 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/geojson-helpers.d.ts +92 -0
- package/dist/types/geojson-helpers.d.ts.map +1 -0
- package/dist/types/managers/polygon-draw-manager.d.ts.map +1 -1
- package/dist/types/managers/polygon-interaction-manager.d.ts.map +1 -1
- package/dist/types/managers/polygon-mutation-manager.d.ts +15 -0
- package/dist/types/managers/polygon-mutation-manager.d.ts.map +1 -1
- package/dist/types/polydraw.d.ts +5 -0
- package/dist/types/polydraw.d.ts.map +1 -1
- package/dist/types/polygon.util.d.ts.map +1 -1
- package/dist/types/turf-helper.d.ts +11 -2
- package/dist/types/turf-helper.d.ts.map +1 -1
- package/dist/types/types/polydraw-interfaces.d.ts +1 -0
- package/dist/types/types/polydraw-interfaces.d.ts.map +1 -1
- package/dist/types/utils.d.ts +1 -0
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +11 -15
package/dist/polydraw.es.js
CHANGED
|
@@ -14,11 +14,11 @@ const subtractLineOptions = { "opacity": 1, "smoothFactor": 0, "noClip": true, "
|
|
|
14
14
|
const polygonOptions = { "smoothFactor": 0.3, "noClip": true };
|
|
15
15
|
const holeOptions = { "weight": 2, "opacity": 1, "fillOpacity": 0.5 };
|
|
16
16
|
const polygonCreation = { "method": "concaveman", "simplification": { "mode": "simple", "tolerance": 1e-5, "highQuality": false } };
|
|
17
|
-
const simplification = { "simplifyTolerance": { "tolerance": 1e-4, "highQuality": false, "mutate": false }, "dynamicMode": { "fractionGuard": 0.9, "
|
|
17
|
+
const simplification = { "simplifyTolerance": { "tolerance": 1e-4, "highQuality": false, "mutate": false }, "dynamicMode": { "fractionGuard": 0.9, "multiplier": 2 } };
|
|
18
18
|
const menuOperations = { "simplify": { "processHoles": true }, "doubleElbows": { "processHoles": true }, "bbox": { "processHoles": true } };
|
|
19
19
|
const boundingBox = { "addMidPointMarkers": true };
|
|
20
20
|
const bezier$1 = { "resolution": 1e4, "sharpness": 0.75 };
|
|
21
|
-
const colors = { "dragPolygons": { "subtract": "#D9460F" }, "p2p": { "closingMarker": "#4CAF50" }, "edgeHover": "#7a9441", "edgeDeletion": { "hover": "#D9460F" }, "polyline": "#50622b", "subtractLine": "#
|
|
21
|
+
const colors = { "dragPolygons": { "subtract": "#D9460F" }, "p2p": { "closingMarker": "#4CAF50" }, "edgeHover": "#7a9441", "edgeDeletion": { "hover": "#D9460F" }, "polyline": "#50622b", "subtractLine": "#D9460F", "polygon": { "border": "#50622b", "fill": "#b4cd8a" }, "hole": { "border": "#aa0000", "fill": "#ffcccc" }, "styles": { "controlButton": { "backgroundColor": "#fff", "color": "#000" }, "controlButtonHover": { "backgroundColor": "#f4f4f4" }, "controlButtonActive": { "backgroundColor": "rgb(128, 218, 255)", "color": "#fff" }, "indicatorActive": { "backgroundColor": "#ffcc00" }, "p2pMarker": { "backgroundColor": "#fff", "borderColor": "#50622b" } } };
|
|
22
22
|
const defaultConfig = {
|
|
23
23
|
mergePolygons,
|
|
24
24
|
kinks: kinks$1,
|
|
@@ -59,6 +59,174 @@ var MarkerPosition = /* @__PURE__ */ ((MarkerPosition2) => {
|
|
|
59
59
|
MarkerPosition2[MarkerPosition2["Hole"] = 8] = "Hole";
|
|
60
60
|
return MarkerPosition2;
|
|
61
61
|
})(MarkerPosition || {});
|
|
62
|
+
const EARTH_RADIUS = {
|
|
63
|
+
/**
|
|
64
|
+
* Mean radius in meters - good enough for this tool's precision requirements
|
|
65
|
+
* Used for distance calculations and area conversions
|
|
66
|
+
*/
|
|
67
|
+
MEAN_METERS: 6371e3,
|
|
68
|
+
/** Mean radius in kilometers */
|
|
69
|
+
MEAN_KILOMETERS: 6371,
|
|
70
|
+
/** Mean radius in miles */
|
|
71
|
+
MEAN_MILES: 3959
|
|
72
|
+
// WGS84 ellipsoid values (more precise but overkill for this application)
|
|
73
|
+
// WGS84_SEMI_MAJOR_AXIS: 6378137.0, // meters
|
|
74
|
+
// WGS84_SEMI_MINOR_AXIS: 6356752.314245, // meters
|
|
75
|
+
// WGS84_FLATTENING: 1 / 298.257223563,
|
|
76
|
+
};
|
|
77
|
+
const MATH = {
|
|
78
|
+
/** Degrees to radians conversion factor */
|
|
79
|
+
DEG_TO_RAD: Math.PI / 180,
|
|
80
|
+
/** Radians to degrees conversion factor */
|
|
81
|
+
RAD_TO_DEG: 180 / Math.PI
|
|
82
|
+
};
|
|
83
|
+
function point$1(coordinates, properties = {}) {
|
|
84
|
+
return {
|
|
85
|
+
type: "Feature",
|
|
86
|
+
geometry: {
|
|
87
|
+
type: "Point",
|
|
88
|
+
coordinates
|
|
89
|
+
},
|
|
90
|
+
properties
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function lineString$1(coordinates, properties = {}) {
|
|
94
|
+
return {
|
|
95
|
+
type: "Feature",
|
|
96
|
+
geometry: {
|
|
97
|
+
type: "LineString",
|
|
98
|
+
coordinates
|
|
99
|
+
},
|
|
100
|
+
properties
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function polygon$1(coordinates, properties = {}) {
|
|
104
|
+
return {
|
|
105
|
+
type: "Feature",
|
|
106
|
+
geometry: {
|
|
107
|
+
type: "Polygon",
|
|
108
|
+
coordinates
|
|
109
|
+
},
|
|
110
|
+
properties
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function multiPolygon$1(coordinates, properties = {}) {
|
|
114
|
+
return {
|
|
115
|
+
type: "Feature",
|
|
116
|
+
geometry: {
|
|
117
|
+
type: "MultiPolygon",
|
|
118
|
+
coordinates
|
|
119
|
+
},
|
|
120
|
+
properties
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function featureCollection$1(features) {
|
|
124
|
+
return {
|
|
125
|
+
type: "FeatureCollection",
|
|
126
|
+
features
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function getCoords$1(feature2) {
|
|
130
|
+
if (feature2.geometry.type === "Polygon") {
|
|
131
|
+
return [feature2.geometry.coordinates];
|
|
132
|
+
} else if (feature2.geometry.type === "MultiPolygon") {
|
|
133
|
+
return feature2.geometry.coordinates;
|
|
134
|
+
}
|
|
135
|
+
throw new Error("Feature must be a Polygon or MultiPolygon");
|
|
136
|
+
}
|
|
137
|
+
function bbox$1(feature2) {
|
|
138
|
+
let minX = Infinity;
|
|
139
|
+
let minY = Infinity;
|
|
140
|
+
let maxX = -Infinity;
|
|
141
|
+
let maxY = -Infinity;
|
|
142
|
+
const processCoordinates = (coords) => {
|
|
143
|
+
if (Array.isArray(coords[0])) {
|
|
144
|
+
coords.forEach(processCoordinates);
|
|
145
|
+
} else {
|
|
146
|
+
const [x, y] = coords;
|
|
147
|
+
minX = Math.min(minX, x);
|
|
148
|
+
minY = Math.min(minY, y);
|
|
149
|
+
maxX = Math.max(maxX, x);
|
|
150
|
+
maxY = Math.max(maxY, y);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
processCoordinates(feature2.geometry.coordinates);
|
|
154
|
+
return [minX, minY, maxX, maxY];
|
|
155
|
+
}
|
|
156
|
+
function bboxPolygon(bboxCoords) {
|
|
157
|
+
const [minX, minY, maxX, maxY] = bboxCoords;
|
|
158
|
+
return polygon$1([
|
|
159
|
+
[
|
|
160
|
+
[minX, minY],
|
|
161
|
+
[maxX, minY],
|
|
162
|
+
[maxX, maxY],
|
|
163
|
+
[minX, maxY],
|
|
164
|
+
[minX, minY]
|
|
165
|
+
]
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
function distance$1(from, to, units = "kilometers") {
|
|
169
|
+
const fromCoords = Array.isArray(from) ? from : from.geometry.coordinates;
|
|
170
|
+
const toCoords = Array.isArray(to) ? to : to.geometry.coordinates;
|
|
171
|
+
const [lon1, lat1] = fromCoords;
|
|
172
|
+
const [lon2, lat2] = toCoords;
|
|
173
|
+
const R = units === "miles" ? EARTH_RADIUS.MEAN_MILES : units === "meters" ? EARTH_RADIUS.MEAN_METERS : EARTH_RADIUS.MEAN_KILOMETERS;
|
|
174
|
+
const dLat = toRadians(lat2 - lat1);
|
|
175
|
+
const dLon = toRadians(lon2 - lon1);
|
|
176
|
+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
177
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
178
|
+
return R * c;
|
|
179
|
+
}
|
|
180
|
+
function midpoint(point1, point2) {
|
|
181
|
+
const coords1 = Array.isArray(point1) ? point1 : point1.geometry.coordinates;
|
|
182
|
+
const coords2 = Array.isArray(point2) ? point2 : point2.geometry.coordinates;
|
|
183
|
+
const [lon1, lat1] = coords1;
|
|
184
|
+
const [lon2, lat2] = coords2;
|
|
185
|
+
const midLon = (lon1 + lon2) / 2;
|
|
186
|
+
const midLat = (lat1 + lat2) / 2;
|
|
187
|
+
return point$1([midLon, midLat]);
|
|
188
|
+
}
|
|
189
|
+
function area$1(feature2) {
|
|
190
|
+
const coords = getCoords$1(feature2);
|
|
191
|
+
let totalArea = 0;
|
|
192
|
+
for (const polygon2 of coords) {
|
|
193
|
+
for (let i = 0; i < polygon2.length; i++) {
|
|
194
|
+
const ring = polygon2[i];
|
|
195
|
+
const ringArea2 = calculateRingArea(ring);
|
|
196
|
+
totalArea += i === 0 ? Math.abs(ringArea2) : -Math.abs(ringArea2);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return Math.abs(totalArea);
|
|
200
|
+
}
|
|
201
|
+
function centroid$1(feature2) {
|
|
202
|
+
const coords = getCoords$1(feature2);
|
|
203
|
+
let totalX = 0;
|
|
204
|
+
let totalY = 0;
|
|
205
|
+
let totalPoints = 0;
|
|
206
|
+
for (const polygon2 of coords) {
|
|
207
|
+
for (const ring of polygon2) {
|
|
208
|
+
for (const coord of ring) {
|
|
209
|
+
totalX += coord[0];
|
|
210
|
+
totalY += coord[1];
|
|
211
|
+
totalPoints++;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return point$1([totalX / totalPoints, totalY / totalPoints]);
|
|
216
|
+
}
|
|
217
|
+
function toRadians(degrees2) {
|
|
218
|
+
return degrees2 * MATH.DEG_TO_RAD;
|
|
219
|
+
}
|
|
220
|
+
function calculateRingArea(ring) {
|
|
221
|
+
let area2 = 0;
|
|
222
|
+
const n = ring.length;
|
|
223
|
+
for (let i = 0; i < n - 1; i++) {
|
|
224
|
+
const [x12, y12] = ring[i];
|
|
225
|
+
const [x2, y2] = ring[i + 1];
|
|
226
|
+
area2 += x12 * y2 - x2 * y12;
|
|
227
|
+
}
|
|
228
|
+
return Math.abs(area2) * 0.5 * Math.pow(EARTH_RADIUS.MEAN_METERS * MATH.DEG_TO_RAD, 2);
|
|
229
|
+
}
|
|
62
230
|
var earthRadius = 63710088e-1;
|
|
63
231
|
var factors = {
|
|
64
232
|
centimeters: earthRadius * 100,
|
|
@@ -179,10 +347,6 @@ function lengthToRadians(distance2, units = "kilometers") {
|
|
|
179
347
|
}
|
|
180
348
|
return distance2 / factor;
|
|
181
349
|
}
|
|
182
|
-
function radiansToDegrees(radians2) {
|
|
183
|
-
const normalisedRadians = radians2 % (2 * Math.PI);
|
|
184
|
-
return normalisedRadians * 180 / Math.PI;
|
|
185
|
-
}
|
|
186
350
|
function degreesToRadians(degrees2) {
|
|
187
351
|
const normalisedDegrees = degrees2 % 360;
|
|
188
352
|
return normalisedDegrees * Math.PI / 180;
|
|
@@ -1221,7 +1385,6 @@ function centroid(geojson, options = {}) {
|
|
|
1221
1385
|
);
|
|
1222
1386
|
return point([xSum / len, ySum / len], options.properties);
|
|
1223
1387
|
}
|
|
1224
|
-
var turf_centroid_default = centroid;
|
|
1225
1388
|
function getCoord(coord) {
|
|
1226
1389
|
if (!coord) {
|
|
1227
1390
|
throw new Error("coord is required");
|
|
@@ -4517,7 +4680,6 @@ function bbox(geojson, options = {}) {
|
|
|
4517
4680
|
});
|
|
4518
4681
|
return result;
|
|
4519
4682
|
}
|
|
4520
|
-
var turf_bbox_default = bbox;
|
|
4521
4683
|
function center(geojson, options = {}) {
|
|
4522
4684
|
const ext = bbox(geojson);
|
|
4523
4685
|
const x = (ext[0] + ext[2]) / 2;
|
|
@@ -14140,7 +14302,6 @@ function ringArea(coords) {
|
|
|
14140
14302
|
}
|
|
14141
14303
|
return total * FACTOR;
|
|
14142
14304
|
}
|
|
14143
|
-
var turf_area_default = area;
|
|
14144
14305
|
const epsilon = 11102230246251565e-32;
|
|
14145
14306
|
const splitter = 134217729;
|
|
14146
14307
|
const resulterrbound = (3 + 8 * epsilon) * epsilon;
|
|
@@ -15027,63 +15188,6 @@ function unkinkPolygon(geojson) {
|
|
|
15027
15188
|
return featureCollection(features);
|
|
15028
15189
|
}
|
|
15029
15190
|
var turf_unkink_polygon_default = unkinkPolygon;
|
|
15030
|
-
function bearing(start, end, options = {}) {
|
|
15031
|
-
if (options.final === true) {
|
|
15032
|
-
return calculateFinalBearing(start, end);
|
|
15033
|
-
}
|
|
15034
|
-
const coordinates1 = getCoord(start);
|
|
15035
|
-
const coordinates2 = getCoord(end);
|
|
15036
|
-
const lon1 = degreesToRadians(coordinates1[0]);
|
|
15037
|
-
const lon2 = degreesToRadians(coordinates2[0]);
|
|
15038
|
-
const lat1 = degreesToRadians(coordinates1[1]);
|
|
15039
|
-
const lat2 = degreesToRadians(coordinates2[1]);
|
|
15040
|
-
const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
|
|
15041
|
-
const b = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
|
|
15042
|
-
return radiansToDegrees(Math.atan2(a, b));
|
|
15043
|
-
}
|
|
15044
|
-
function calculateFinalBearing(start, end) {
|
|
15045
|
-
let bear = bearing(end, start);
|
|
15046
|
-
bear = (bear + 180) % 360;
|
|
15047
|
-
return bear;
|
|
15048
|
-
}
|
|
15049
|
-
function destination(origin, distance2, bearing2, options = {}) {
|
|
15050
|
-
const coordinates1 = getCoord(origin);
|
|
15051
|
-
const longitude1 = degreesToRadians(coordinates1[0]);
|
|
15052
|
-
const latitude1 = degreesToRadians(coordinates1[1]);
|
|
15053
|
-
const bearingRad = degreesToRadians(bearing2);
|
|
15054
|
-
const radians2 = lengthToRadians(distance2, options.units);
|
|
15055
|
-
const latitude2 = Math.asin(
|
|
15056
|
-
Math.sin(latitude1) * Math.cos(radians2) + Math.cos(latitude1) * Math.sin(radians2) * Math.cos(bearingRad)
|
|
15057
|
-
);
|
|
15058
|
-
const longitude2 = longitude1 + Math.atan2(
|
|
15059
|
-
Math.sin(bearingRad) * Math.sin(radians2) * Math.cos(latitude1),
|
|
15060
|
-
Math.cos(radians2) - Math.sin(latitude1) * Math.sin(latitude2)
|
|
15061
|
-
);
|
|
15062
|
-
const lng = radiansToDegrees(longitude2);
|
|
15063
|
-
const lat = radiansToDegrees(latitude2);
|
|
15064
|
-
return point([lng, lat], options.properties);
|
|
15065
|
-
}
|
|
15066
|
-
function distance(from, to, options = {}) {
|
|
15067
|
-
var coordinates1 = getCoord(from);
|
|
15068
|
-
var coordinates2 = getCoord(to);
|
|
15069
|
-
var dLat = degreesToRadians(coordinates2[1] - coordinates1[1]);
|
|
15070
|
-
var dLon = degreesToRadians(coordinates2[0] - coordinates1[0]);
|
|
15071
|
-
var lat1 = degreesToRadians(coordinates1[1]);
|
|
15072
|
-
var lat2 = degreesToRadians(coordinates2[1]);
|
|
15073
|
-
var a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
|
|
15074
|
-
return radiansToLength(
|
|
15075
|
-
2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)),
|
|
15076
|
-
options.units
|
|
15077
|
-
);
|
|
15078
|
-
}
|
|
15079
|
-
var turf_distance_default = distance;
|
|
15080
|
-
function midpoint(point1, point2) {
|
|
15081
|
-
const dist = distance(point1, point2);
|
|
15082
|
-
const heading = bearing(point1, point2);
|
|
15083
|
-
const midpoint2 = destination(point1, dist / 2, heading);
|
|
15084
|
-
return midpoint2;
|
|
15085
|
-
}
|
|
15086
|
-
var turf_midpoint_default = midpoint;
|
|
15087
15191
|
function booleanPointOnLine(pt, line, options = {}) {
|
|
15088
15192
|
const ptCoords = getCoord(pt);
|
|
15089
15193
|
const lineCoords = getCoords(line);
|
|
@@ -15508,27 +15612,19 @@ function booleanEqual(feature1, feature2, options = {}) {
|
|
|
15508
15612
|
});
|
|
15509
15613
|
}
|
|
15510
15614
|
var turf_boolean_equal_default = booleanEqual;
|
|
15511
|
-
function
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15515
|
-
|
|
15516
|
-
|
|
15517
|
-
|
|
15518
|
-
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
const topLeft = [west, north];
|
|
15523
|
-
const topRight = [east, north];
|
|
15524
|
-
const lowRight = [east, south];
|
|
15525
|
-
return polygon(
|
|
15526
|
-
[[lowLeft, lowRight, topRight, topLeft, lowLeft]],
|
|
15527
|
-
options.properties,
|
|
15528
|
-
{ bbox: bbox2, id: options.id }
|
|
15615
|
+
function distance(from, to, options = {}) {
|
|
15616
|
+
var coordinates1 = getCoord(from);
|
|
15617
|
+
var coordinates2 = getCoord(to);
|
|
15618
|
+
var dLat = degreesToRadians(coordinates2[1] - coordinates1[1]);
|
|
15619
|
+
var dLon = degreesToRadians(coordinates2[0] - coordinates1[0]);
|
|
15620
|
+
var lat1 = degreesToRadians(coordinates1[1]);
|
|
15621
|
+
var lat2 = degreesToRadians(coordinates2[1]);
|
|
15622
|
+
var a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
|
|
15623
|
+
return radiansToLength(
|
|
15624
|
+
2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)),
|
|
15625
|
+
options.units
|
|
15529
15626
|
);
|
|
15530
15627
|
}
|
|
15531
|
-
var turf_bbox_polygon_default = bboxPolygon;
|
|
15532
15628
|
var __defProp2 = Object.defineProperty;
|
|
15533
15629
|
var __defProps = Object.defineProperties;
|
|
15534
15630
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
@@ -15842,113 +15938,366 @@ function length(geojson, options = {}) {
|
|
|
15842
15938
|
);
|
|
15843
15939
|
}
|
|
15844
15940
|
var turf_length_default = length;
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
union(poly1, poly2) {
|
|
15851
|
-
try {
|
|
15852
|
-
const fc = featureCollection([poly1, poly2]);
|
|
15853
|
-
const u2 = turf_union_default(fc);
|
|
15854
|
-
return u2 ? this.getTurfPolygon(u2) : null;
|
|
15855
|
-
} catch (error) {
|
|
15856
|
-
console.warn("Error in union:", error instanceof Error ? error.message : String(error));
|
|
15857
|
-
return null;
|
|
15858
|
-
}
|
|
15859
|
-
}
|
|
15941
|
+
const isTouchDevice = () => "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
15942
|
+
function isTestEnvironment() {
|
|
15943
|
+
return typeof vitest !== "undefined";
|
|
15944
|
+
}
|
|
15945
|
+
class PolyDrawUtil {
|
|
15860
15946
|
/**
|
|
15861
|
-
*
|
|
15947
|
+
* Gets the bounds of the polygon with optional padding.
|
|
15948
|
+
* @param polygon Array of LatLng points.
|
|
15949
|
+
* @param padding Padding factor.
|
|
15950
|
+
* @returns The LatLngBounds.
|
|
15862
15951
|
*/
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
return this.createDirectPolygon(feature2);
|
|
15874
|
-
case "buffer":
|
|
15875
|
-
return this.createBufferedPolygon(feature2);
|
|
15876
|
-
default:
|
|
15877
|
-
console.warn(`Unknown polygon creation method: ${method}, falling back to concaveman`);
|
|
15878
|
-
return this.turfConcaveman(feature2);
|
|
15952
|
+
static getBounds(polygon2, padding = 0) {
|
|
15953
|
+
const tmpLatLng = [];
|
|
15954
|
+
polygon2.forEach((ll) => {
|
|
15955
|
+
if (isNaN(ll.lat) || isNaN(ll.lng)) ;
|
|
15956
|
+
tmpLatLng.push(ll);
|
|
15957
|
+
});
|
|
15958
|
+
const polyLine = new L.Polyline(tmpLatLng);
|
|
15959
|
+
const bounds = polyLine.getBounds();
|
|
15960
|
+
if (padding !== 0) {
|
|
15961
|
+
return bounds.pad(padding);
|
|
15879
15962
|
}
|
|
15963
|
+
return bounds;
|
|
15880
15964
|
}
|
|
15881
|
-
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
15965
|
+
}
|
|
15966
|
+
class Compass {
|
|
15967
|
+
constructor(minLat = 0, minLng = 0, maxLat = 0, maxLng = 0) {
|
|
15968
|
+
__publicField(this, "direction", {
|
|
15969
|
+
East: new L.LatLng(0, 0),
|
|
15970
|
+
North: new L.LatLng(0, 0),
|
|
15971
|
+
NorthEast: new L.LatLng(0, 0),
|
|
15972
|
+
NorthWest: new L.LatLng(0, 0),
|
|
15973
|
+
South: new L.LatLng(0, 0),
|
|
15974
|
+
SouthEast: new L.LatLng(0, 0),
|
|
15975
|
+
SouthWest: new L.LatLng(0, 0),
|
|
15976
|
+
West: new L.LatLng(0, 0)
|
|
15977
|
+
});
|
|
15978
|
+
this.direction.North = new L.LatLng(maxLat, (minLng + maxLng) / 2);
|
|
15979
|
+
this.direction.NorthEast = new L.LatLng(maxLat, maxLng);
|
|
15980
|
+
this.direction.East = new L.LatLng((minLat + maxLat) / 2, maxLng);
|
|
15981
|
+
this.direction.SouthEast = new L.LatLng(minLat, maxLng);
|
|
15982
|
+
this.direction.South = new L.LatLng(minLat, (minLng + maxLng) / 2);
|
|
15983
|
+
this.direction.SouthWest = new L.LatLng(minLat, minLng);
|
|
15984
|
+
this.direction.West = new L.LatLng((minLat + maxLat) / 2, minLng);
|
|
15985
|
+
this.direction.NorthWest = new L.LatLng(maxLat, minLng);
|
|
15888
15986
|
}
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15987
|
+
getDirection(direction) {
|
|
15988
|
+
switch (direction) {
|
|
15989
|
+
case MarkerPosition.SouthWest:
|
|
15990
|
+
return this.direction.SouthWest;
|
|
15991
|
+
case MarkerPosition.West:
|
|
15992
|
+
return this.direction.West;
|
|
15993
|
+
case MarkerPosition.NorthWest:
|
|
15994
|
+
return this.direction.NorthWest;
|
|
15995
|
+
case MarkerPosition.North:
|
|
15996
|
+
return this.direction.North;
|
|
15997
|
+
case MarkerPosition.NorthEast:
|
|
15998
|
+
return this.direction.NorthEast;
|
|
15999
|
+
case MarkerPosition.East:
|
|
16000
|
+
return this.direction.East;
|
|
16001
|
+
case MarkerPosition.SouthEast:
|
|
16002
|
+
return this.direction.SouthEast;
|
|
16003
|
+
case MarkerPosition.South:
|
|
16004
|
+
return this.direction.South;
|
|
16005
|
+
default:
|
|
16006
|
+
throw new Error();
|
|
15898
16007
|
}
|
|
15899
|
-
return this.getTurfPolygon(convexHull);
|
|
15900
16008
|
}
|
|
15901
|
-
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
if (
|
|
15908
|
-
|
|
15909
|
-
} else if (feature2.geometry.type === "Polygon") {
|
|
15910
|
-
coordinates = feature2.geometry.coordinates[0];
|
|
15911
|
-
} else {
|
|
15912
|
-
const points = turf_explode_default(feature2);
|
|
15913
|
-
coordinates = points.features.map((f) => f.geometry.coordinates);
|
|
16009
|
+
getPositions(startPosition = MarkerPosition.SouthWest, clockwise = false, addClosingNode = true) {
|
|
16010
|
+
const positions = [];
|
|
16011
|
+
const posArray = this.getPositionAsArray(startPosition, clockwise);
|
|
16012
|
+
posArray.forEach((v) => {
|
|
16013
|
+
positions.push([v.lng, v.lat]);
|
|
16014
|
+
});
|
|
16015
|
+
if (addClosingNode) {
|
|
16016
|
+
positions.push([posArray[0].lng, posArray[0].lat]);
|
|
15914
16017
|
}
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
16018
|
+
return positions;
|
|
16019
|
+
}
|
|
16020
|
+
getPositionAsArray(startPosition = MarkerPosition.NorthEast, clockwise = false) {
|
|
16021
|
+
const positions = [];
|
|
16022
|
+
if (clockwise) {
|
|
16023
|
+
positions.push(this.direction.SouthWest);
|
|
16024
|
+
positions.push(this.direction.West);
|
|
16025
|
+
positions.push(this.direction.NorthWest);
|
|
16026
|
+
positions.push(this.direction.North);
|
|
16027
|
+
positions.push(this.direction.NorthEast);
|
|
16028
|
+
positions.push(this.direction.East);
|
|
16029
|
+
positions.push(this.direction.SouthEast);
|
|
16030
|
+
positions.push(this.direction.South);
|
|
16031
|
+
} else {
|
|
16032
|
+
positions.push(this.direction.SouthWest);
|
|
16033
|
+
positions.push(this.direction.South);
|
|
16034
|
+
positions.push(this.direction.SouthEast);
|
|
16035
|
+
positions.push(this.direction.East);
|
|
16036
|
+
positions.push(this.direction.NorthEast);
|
|
16037
|
+
positions.push(this.direction.North);
|
|
16038
|
+
positions.push(this.direction.NorthWest);
|
|
16039
|
+
positions.push(this.direction.West);
|
|
15921
16040
|
}
|
|
15922
|
-
if (
|
|
15923
|
-
|
|
15924
|
-
|
|
16041
|
+
if (startPosition !== MarkerPosition.SouthWest) {
|
|
16042
|
+
const chunk = positions.splice(0, startPosition);
|
|
16043
|
+
chunk.forEach((v, i) => {
|
|
16044
|
+
positions.splice(startPosition + i, 0, v);
|
|
16045
|
+
});
|
|
15925
16046
|
}
|
|
15926
|
-
return
|
|
16047
|
+
return positions;
|
|
15927
16048
|
}
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
16049
|
+
}
|
|
16050
|
+
class Perimeter {
|
|
16051
|
+
constructor(length2, config) {
|
|
16052
|
+
__publicField(this, "metricLength", "");
|
|
16053
|
+
__publicField(this, "metricUnit", "");
|
|
16054
|
+
__publicField(this, "imperialLength", "");
|
|
16055
|
+
__publicField(this, "imperialUnit", "");
|
|
16056
|
+
if (length2 !== null || length2 !== void 0) {
|
|
16057
|
+
if (length2 === 0) {
|
|
16058
|
+
if (config.markers.markerInfoIcon.usePerimeterMinValue) {
|
|
16059
|
+
this.metricLength = config.markers.markerInfoIcon.values.min.metric;
|
|
16060
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16061
|
+
this.imperialLength = config.markers.markerInfoIcon.values.min.imperial;
|
|
16062
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.feet;
|
|
16063
|
+
} else {
|
|
16064
|
+
this.metricLength = config.markers.markerInfoIcon.values.unknown.metric;
|
|
16065
|
+
this.metricUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16066
|
+
this.imperialLength = config.markers.markerInfoIcon.values.unknown.imperial;
|
|
16067
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16068
|
+
}
|
|
16069
|
+
} else if (length2 < 100) {
|
|
16070
|
+
this.metricLength = (Math.ceil(length2 / 10) * 10).toString();
|
|
16071
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16072
|
+
} else if (length2 < 500) {
|
|
16073
|
+
this.metricLength = (Math.ceil(length2 / 50) * 50).toString();
|
|
16074
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16075
|
+
} else if (length2 < 1e3) {
|
|
16076
|
+
this.metricLength = (Math.ceil(length2 / 100) * 100).toString();
|
|
16077
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16078
|
+
} else if (length2 < 1e4) {
|
|
16079
|
+
this.metricLength = (Math.ceil(length2 / 100) * 100 / 1e3).toFixed(1);
|
|
16080
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.km;
|
|
16081
|
+
} else {
|
|
16082
|
+
this.metricLength = (Math.ceil(length2 / 1e3) * 1e3 / 1e3).toString();
|
|
16083
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.km;
|
|
16084
|
+
}
|
|
16085
|
+
const inch = length2 / 0.0254;
|
|
16086
|
+
const feet = inch / 12;
|
|
16087
|
+
const yards = feet / 3;
|
|
16088
|
+
const miles = yards / 1760;
|
|
16089
|
+
if (length2 < 1e3 / 2.54) {
|
|
16090
|
+
this.imperialLength = (Math.ceil(feet / 10) * 10).toString();
|
|
16091
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.feet;
|
|
16092
|
+
} else if (length2 < 1e3 / 2.54 * 3) {
|
|
16093
|
+
this.imperialLength = (Math.ceil(yards / 10) * 10).toString();
|
|
16094
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.yards;
|
|
16095
|
+
} else if (length2 < 1609) {
|
|
16096
|
+
this.imperialLength = miles.toFixed(2);
|
|
16097
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
16098
|
+
} else if (length2 < 16093) {
|
|
16099
|
+
this.imperialLength = miles.toFixed(1);
|
|
16100
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
16101
|
+
} else {
|
|
16102
|
+
this.imperialLength = miles.toFixed(0);
|
|
16103
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
16104
|
+
}
|
|
16105
|
+
}
|
|
16106
|
+
}
|
|
16107
|
+
}
|
|
16108
|
+
class Area {
|
|
16109
|
+
constructor(sqrMeterArea, config) {
|
|
16110
|
+
__publicField(this, "metricArea", "");
|
|
16111
|
+
__publicField(this, "metricUnit", "");
|
|
16112
|
+
__publicField(this, "imperialArea", "");
|
|
16113
|
+
__publicField(this, "imperialUnit", "");
|
|
16114
|
+
const area2 = sqrMeterArea;
|
|
16115
|
+
const onlyMetrics = config.markers.markerInfoIcon.units.metric.onlyMetrics;
|
|
16116
|
+
if (area2 !== null || area2 !== void 0) {
|
|
16117
|
+
if (area2 === 0) {
|
|
16118
|
+
this.metricArea = "-";
|
|
16119
|
+
this.metricUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16120
|
+
this.imperialArea = "-";
|
|
16121
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16122
|
+
} else if (area2 < 1e4) {
|
|
16123
|
+
this.metricArea = Math.round(area2).toString();
|
|
16124
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.m2;
|
|
16125
|
+
} else if (area2 < 1e5) {
|
|
16126
|
+
if (onlyMetrics) {
|
|
16127
|
+
this.metricArea = (area2 / 1e6).toFixed(2);
|
|
16128
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
16129
|
+
} else {
|
|
16130
|
+
this.metricArea = (area2 / 1e3).toFixed(1);
|
|
16131
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.daa;
|
|
16132
|
+
}
|
|
16133
|
+
} else if (area2 < 1e7) {
|
|
16134
|
+
if (onlyMetrics) {
|
|
16135
|
+
this.metricArea = (area2 / 1e6).toFixed(2);
|
|
16136
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
16137
|
+
} else {
|
|
16138
|
+
this.metricArea = Math.round(area2 / 1e3).toString();
|
|
16139
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.daa;
|
|
16140
|
+
}
|
|
16141
|
+
} else if (area2 < 1e8) {
|
|
16142
|
+
if (onlyMetrics) {
|
|
16143
|
+
this.metricArea = (area2 / 1e6).toFixed(1);
|
|
16144
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
16145
|
+
} else {
|
|
16146
|
+
this.metricArea = Math.round(area2 / 1e4).toString();
|
|
16147
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.ha;
|
|
16148
|
+
}
|
|
16149
|
+
} else {
|
|
16150
|
+
this.metricArea = Math.round(area2 / 1e6).toString();
|
|
16151
|
+
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
16152
|
+
}
|
|
16153
|
+
const inch2 = area2 * 1550;
|
|
16154
|
+
const feet2 = inch2 * 69444e-7;
|
|
16155
|
+
const yards2 = feet2 * 0.11111;
|
|
16156
|
+
const acres = yards2 * 20661e-8;
|
|
16157
|
+
const miles2 = yards2 * 32283e-11;
|
|
16158
|
+
if (area2 < 92.9) {
|
|
16159
|
+
this.imperialArea = Math.round(feet2).toString();
|
|
16160
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.feet2;
|
|
16161
|
+
} else if (area2 < 836.14) {
|
|
16162
|
+
this.imperialArea = yards2.toFixed(0);
|
|
16163
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.yards2;
|
|
16164
|
+
} else if (area2 < 40469.6) {
|
|
16165
|
+
this.imperialArea = acres.toFixed(2);
|
|
16166
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.acres;
|
|
16167
|
+
} else if (area2 < 404696) {
|
|
16168
|
+
this.imperialArea = acres.toFixed(1);
|
|
16169
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.acres;
|
|
16170
|
+
} else if (area2 < 4046960) {
|
|
16171
|
+
this.imperialArea = acres.toFixed(0);
|
|
16172
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.acres;
|
|
16173
|
+
} else if (area2 < 25900404) {
|
|
16174
|
+
this.imperialArea = miles2.toFixed(2);
|
|
16175
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.miles2;
|
|
16176
|
+
} else if (area2 < 259004040) {
|
|
16177
|
+
this.imperialArea = miles2.toFixed(1);
|
|
16178
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.miles2;
|
|
16179
|
+
} else {
|
|
16180
|
+
this.imperialArea = miles2.toFixed(0);
|
|
16181
|
+
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.area.miles2;
|
|
16182
|
+
}
|
|
16183
|
+
}
|
|
16184
|
+
}
|
|
16185
|
+
}
|
|
16186
|
+
class TurfHelper {
|
|
16187
|
+
constructor(config) {
|
|
16188
|
+
__publicField(this, "config", defaultConfig);
|
|
16189
|
+
this.config = { ...defaultConfig, ...config };
|
|
16190
|
+
}
|
|
16191
|
+
union(poly1, poly2) {
|
|
16192
|
+
try {
|
|
16193
|
+
const fc = featureCollection$1([poly1, poly2]);
|
|
16194
|
+
const u2 = turf_union_default(fc);
|
|
16195
|
+
return u2 ? this.getTurfPolygon(u2) : null;
|
|
15947
16196
|
} catch (error) {
|
|
15948
|
-
|
|
15949
|
-
"
|
|
15950
|
-
|
|
15951
|
-
|
|
16197
|
+
if (!isTestEnvironment()) {
|
|
16198
|
+
console.warn("Error in union:", error instanceof Error ? error.message : String(error));
|
|
16199
|
+
}
|
|
16200
|
+
return null;
|
|
16201
|
+
}
|
|
16202
|
+
}
|
|
16203
|
+
/**
|
|
16204
|
+
* Create polygon from drawing trace using configured method
|
|
16205
|
+
*/
|
|
16206
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16207
|
+
createPolygonFromTrace(feature2) {
|
|
16208
|
+
var _a2;
|
|
16209
|
+
const method = ((_a2 = this.config.polygonCreation) == null ? void 0 : _a2.method) || "concaveman";
|
|
16210
|
+
switch (method) {
|
|
16211
|
+
case "concaveman":
|
|
16212
|
+
return this.turfConcaveman(feature2);
|
|
16213
|
+
case "convex":
|
|
16214
|
+
return this.createConvexPolygon(feature2);
|
|
16215
|
+
case "direct":
|
|
16216
|
+
return this.createDirectPolygon(feature2);
|
|
16217
|
+
case "buffer":
|
|
16218
|
+
return this.createBufferedPolygon(feature2);
|
|
16219
|
+
default:
|
|
16220
|
+
if (!isTestEnvironment()) {
|
|
16221
|
+
console.warn(`Unknown polygon creation method: ${method}, falling back to concaveman`);
|
|
16222
|
+
}
|
|
16223
|
+
return this.turfConcaveman(feature2);
|
|
16224
|
+
}
|
|
16225
|
+
}
|
|
16226
|
+
/**
|
|
16227
|
+
* Original concaveman implementation
|
|
16228
|
+
*/
|
|
16229
|
+
turfConcaveman(feature2) {
|
|
16230
|
+
const points = turf_explode_default(feature2);
|
|
16231
|
+
const coordinates = points.features.map((f) => f.geometry.coordinates);
|
|
16232
|
+
return multiPolygon$1([[concaveman(coordinates)]]);
|
|
16233
|
+
}
|
|
16234
|
+
/**
|
|
16235
|
+
* Create convex hull polygon (simplest, fewest edges)
|
|
16236
|
+
*/
|
|
16237
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16238
|
+
createConvexPolygon(feature2) {
|
|
16239
|
+
const points = turf_explode_default(feature2);
|
|
16240
|
+
const convexHull = turf_convex_default(points);
|
|
16241
|
+
if (!convexHull) {
|
|
16242
|
+
return this.createDirectPolygon(feature2);
|
|
16243
|
+
}
|
|
16244
|
+
return this.getTurfPolygon(convexHull);
|
|
16245
|
+
}
|
|
16246
|
+
/**
|
|
16247
|
+
* Create polygon directly from line coordinates (moderate edge count)
|
|
16248
|
+
*/
|
|
16249
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16250
|
+
createDirectPolygon(feature2) {
|
|
16251
|
+
let coordinates;
|
|
16252
|
+
if (feature2.geometry.type === "LineString") {
|
|
16253
|
+
coordinates = feature2.geometry.coordinates;
|
|
16254
|
+
} else if (feature2.geometry.type === "Polygon") {
|
|
16255
|
+
coordinates = feature2.geometry.coordinates[0];
|
|
16256
|
+
} else {
|
|
16257
|
+
const points = turf_explode_default(feature2);
|
|
16258
|
+
coordinates = points.features.map((f) => f.geometry.coordinates);
|
|
16259
|
+
}
|
|
16260
|
+
if (coordinates.length > 0) {
|
|
16261
|
+
const first = coordinates[0];
|
|
16262
|
+
const last = coordinates[coordinates.length - 1];
|
|
16263
|
+
if (first[0] !== last[0] || first[1] !== last[1]) {
|
|
16264
|
+
coordinates.push([first[0], first[1]]);
|
|
16265
|
+
}
|
|
16266
|
+
}
|
|
16267
|
+
if (coordinates.length < 4) {
|
|
16268
|
+
if (!isTestEnvironment()) {
|
|
16269
|
+
console.warn("Not enough points for direct polygon, falling back to concaveman");
|
|
16270
|
+
}
|
|
16271
|
+
return this.turfConcaveman(feature2);
|
|
16272
|
+
}
|
|
16273
|
+
return multiPolygon$1([[coordinates]]);
|
|
16274
|
+
}
|
|
16275
|
+
/**
|
|
16276
|
+
* Create polygon using buffer method (smooth curves)
|
|
16277
|
+
*/
|
|
16278
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16279
|
+
createBufferedPolygon(feature2) {
|
|
16280
|
+
try {
|
|
16281
|
+
let line;
|
|
16282
|
+
if (feature2.geometry.type === "LineString") {
|
|
16283
|
+
line = feature2;
|
|
16284
|
+
} else {
|
|
16285
|
+
const points = turf_explode_default(feature2);
|
|
16286
|
+
const coordinates = points.features.map((f) => f.geometry.coordinates);
|
|
16287
|
+
line = lineString$1(coordinates);
|
|
16288
|
+
}
|
|
16289
|
+
const buffered = turf_buffer_default(line, 1e-3, { units: "kilometers" });
|
|
16290
|
+
if (!buffered) {
|
|
16291
|
+
return this.createDirectPolygon(feature2);
|
|
16292
|
+
}
|
|
16293
|
+
return this.getTurfPolygon(buffered);
|
|
16294
|
+
} catch (error) {
|
|
16295
|
+
if (!isTestEnvironment()) {
|
|
16296
|
+
console.warn(
|
|
16297
|
+
"Buffer polygon creation failed:",
|
|
16298
|
+
error instanceof Error ? error.message : String(error)
|
|
16299
|
+
);
|
|
16300
|
+
}
|
|
15952
16301
|
return this.createDirectPolygon(feature2);
|
|
15953
16302
|
}
|
|
15954
16303
|
}
|
|
@@ -15972,9 +16321,9 @@ class TurfHelper {
|
|
|
15972
16321
|
} else {
|
|
15973
16322
|
let simplified = turf_simplify_default(polygon2, tolerance);
|
|
15974
16323
|
const fractionGuard = this.config.simplification.dynamicMode.fractionGuard;
|
|
15975
|
-
const
|
|
16324
|
+
const multiplier = this.config.simplification.dynamicMode.multiplier;
|
|
15976
16325
|
while (simplified.geometry.coordinates[0][0].length > 4 && simplified.geometry.coordinates[0][0].length / (numOfEdges + 2) > fractionGuard) {
|
|
15977
|
-
tolerance.tolerance = tolerance.tolerance *
|
|
16326
|
+
tolerance.tolerance = tolerance.tolerance * multiplier;
|
|
15978
16327
|
simplified = turf_simplify_default(polygon2, tolerance);
|
|
15979
16328
|
}
|
|
15980
16329
|
return simplified;
|
|
@@ -15982,7 +16331,9 @@ class TurfHelper {
|
|
|
15982
16331
|
} else if (simplificationMode === "none") {
|
|
15983
16332
|
return polygon2;
|
|
15984
16333
|
} else {
|
|
15985
|
-
|
|
16334
|
+
if (!isTestEnvironment()) {
|
|
16335
|
+
console.warn(`Unknown simplification mode: ${simplificationMode}, falling back to simple`);
|
|
16336
|
+
}
|
|
15986
16337
|
const tolerance = {
|
|
15987
16338
|
tolerance: 1e-4,
|
|
15988
16339
|
highQuality: false,
|
|
@@ -15994,14 +16345,14 @@ class TurfHelper {
|
|
|
15994
16345
|
getTurfPolygon(polygon2) {
|
|
15995
16346
|
let turfPolygon;
|
|
15996
16347
|
if (polygon2.geometry.type === "Polygon") {
|
|
15997
|
-
turfPolygon = multiPolygon([polygon2.geometry.coordinates]);
|
|
16348
|
+
turfPolygon = multiPolygon$1([polygon2.geometry.coordinates]);
|
|
15998
16349
|
} else {
|
|
15999
|
-
turfPolygon = multiPolygon(polygon2.geometry.coordinates);
|
|
16350
|
+
turfPolygon = multiPolygon$1(polygon2.geometry.coordinates);
|
|
16000
16351
|
}
|
|
16001
16352
|
return turfPolygon;
|
|
16002
16353
|
}
|
|
16003
16354
|
getMultiPolygon(polygonArray) {
|
|
16004
|
-
return multiPolygon(polygonArray);
|
|
16355
|
+
return multiPolygon$1(polygonArray);
|
|
16005
16356
|
}
|
|
16006
16357
|
getKinks(feature2) {
|
|
16007
16358
|
try {
|
|
@@ -16010,7 +16361,9 @@ class TurfHelper {
|
|
|
16010
16361
|
}
|
|
16011
16362
|
const cleanedFeature = this.removeDuplicateVertices(feature2);
|
|
16012
16363
|
if (!cleanedFeature || !cleanedFeature.geometry || !cleanedFeature.geometry.coordinates) {
|
|
16013
|
-
|
|
16364
|
+
if (!isTestEnvironment()) {
|
|
16365
|
+
console.warn("Feature became invalid after cleaning in getKinks");
|
|
16366
|
+
}
|
|
16014
16367
|
return [feature2];
|
|
16015
16368
|
}
|
|
16016
16369
|
const hasHoles = this.polygonHasHoles(cleanedFeature);
|
|
@@ -16025,15 +16378,17 @@ class TurfHelper {
|
|
|
16025
16378
|
return coordinates;
|
|
16026
16379
|
}
|
|
16027
16380
|
} catch (error) {
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16381
|
+
if (!isTestEnvironment()) {
|
|
16382
|
+
console.warn(
|
|
16383
|
+
"Error processing kinks:",
|
|
16384
|
+
error instanceof Error ? error.message : String(error)
|
|
16385
|
+
);
|
|
16386
|
+
}
|
|
16032
16387
|
return [feature2];
|
|
16033
16388
|
}
|
|
16034
16389
|
}
|
|
16035
16390
|
getCoords(feature2) {
|
|
16036
|
-
return getCoords(feature2);
|
|
16391
|
+
return getCoords$1(feature2);
|
|
16037
16392
|
}
|
|
16038
16393
|
hasKinks(feature2) {
|
|
16039
16394
|
const k = turf_kinks_default(feature2);
|
|
@@ -16044,13 +16399,15 @@ class TurfHelper {
|
|
|
16044
16399
|
*/
|
|
16045
16400
|
getConvexHull(polygon2) {
|
|
16046
16401
|
try {
|
|
16047
|
-
const fc = featureCollection([polygon2]);
|
|
16402
|
+
const fc = featureCollection$1([polygon2]);
|
|
16048
16403
|
return turf_convex_default(fc);
|
|
16049
16404
|
} catch (error) {
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16405
|
+
if (!isTestEnvironment()) {
|
|
16406
|
+
console.warn(
|
|
16407
|
+
"Error in getConvexHull:",
|
|
16408
|
+
error instanceof Error ? error.message : String(error)
|
|
16409
|
+
);
|
|
16410
|
+
}
|
|
16054
16411
|
return null;
|
|
16055
16412
|
}
|
|
16056
16413
|
}
|
|
@@ -16058,9 +16415,9 @@ class TurfHelper {
|
|
|
16058
16415
|
* Calculate midpoint between two LatLngLiteral points
|
|
16059
16416
|
*/
|
|
16060
16417
|
getMidpoint(point1, point2) {
|
|
16061
|
-
const p1 = point([point1.lng, point1.lat]);
|
|
16062
|
-
const p2 = point([point2.lng, point2.lat]);
|
|
16063
|
-
const mp =
|
|
16418
|
+
const p1 = point$1([point1.lng, point1.lat]);
|
|
16419
|
+
const p2 = point$1([point2.lng, point2.lat]);
|
|
16420
|
+
const mp = midpoint(p1, p2);
|
|
16064
16421
|
return {
|
|
16065
16422
|
lat: mp.geometry.coordinates[1],
|
|
16066
16423
|
lng: mp.geometry.coordinates[0]
|
|
@@ -16069,14 +16426,32 @@ class TurfHelper {
|
|
|
16069
16426
|
polygonIntersect(polygon2, latlngs) {
|
|
16070
16427
|
try {
|
|
16071
16428
|
if (!polygon2 || !polygon2.geometry || !polygon2.geometry.coordinates || !latlngs || !latlngs.geometry || !latlngs.geometry.coordinates) {
|
|
16072
|
-
|
|
16429
|
+
if (!isTestEnvironment()) {
|
|
16430
|
+
console.warn("Invalid features passed to polygonIntersect");
|
|
16431
|
+
}
|
|
16432
|
+
return false;
|
|
16433
|
+
}
|
|
16434
|
+
const validateCoordinates = (coords) => {
|
|
16435
|
+
if (!Array.isArray(coords)) return false;
|
|
16436
|
+
for (const ring of coords) {
|
|
16437
|
+
if (!Array.isArray(ring)) return false;
|
|
16438
|
+
for (const coord of ring) {
|
|
16439
|
+
if (!Array.isArray(coord) || coord.length < 2) return false;
|
|
16440
|
+
if (coord.some((c) => c === null || c === void 0 || !isFinite(c))) {
|
|
16441
|
+
return false;
|
|
16442
|
+
}
|
|
16443
|
+
}
|
|
16444
|
+
}
|
|
16445
|
+
return true;
|
|
16446
|
+
};
|
|
16447
|
+
if (!validateCoordinates(polygon2.geometry.coordinates) || !validateCoordinates(latlngs.geometry.coordinates)) {
|
|
16073
16448
|
return false;
|
|
16074
16449
|
}
|
|
16075
16450
|
try {
|
|
16076
|
-
const fc = featureCollection([polygon2, latlngs]);
|
|
16451
|
+
const fc = featureCollection$1([polygon2, latlngs]);
|
|
16077
16452
|
const intersection3 = turf_intersect_default(fc);
|
|
16078
16453
|
if (intersection3 && intersection3.geometry && (intersection3.geometry.type === "Polygon" || intersection3.geometry.type === "MultiPolygon")) {
|
|
16079
|
-
const polygonArea2 =
|
|
16454
|
+
const polygonArea2 = area$1(intersection3);
|
|
16080
16455
|
if (polygonArea2 > 1e-6) {
|
|
16081
16456
|
return true;
|
|
16082
16457
|
}
|
|
@@ -16099,16 +16474,28 @@ class TurfHelper {
|
|
|
16099
16474
|
} catch (error) {
|
|
16100
16475
|
}
|
|
16101
16476
|
try {
|
|
16102
|
-
const coords1 = getCoords(polygon2);
|
|
16103
|
-
const coords2 = getCoords(latlngs);
|
|
16477
|
+
const coords1 = getCoords$1(polygon2);
|
|
16478
|
+
const coords2 = getCoords$1(latlngs);
|
|
16104
16479
|
for (const ring1 of coords1) {
|
|
16105
16480
|
const outerRing1 = ring1[0];
|
|
16481
|
+
if (!outerRing1 || outerRing1.length < 2) continue;
|
|
16106
16482
|
for (let i = 0; i < outerRing1.length - 1; i++) {
|
|
16107
|
-
const
|
|
16483
|
+
const coord1 = outerRing1[i];
|
|
16484
|
+
const coord2 = outerRing1[i + 1];
|
|
16485
|
+
if (!coord1 || !coord2 || !Array.isArray(coord1) || !Array.isArray(coord2) || coord1.length < 2 || coord2.length < 2 || coord1.some((c) => c === null || c === void 0 || !isFinite(c)) || coord2.some((c) => c === null || c === void 0 || !isFinite(c))) {
|
|
16486
|
+
continue;
|
|
16487
|
+
}
|
|
16488
|
+
const line1 = lineString$1([coord1, coord2]);
|
|
16108
16489
|
for (const ring2 of coords2) {
|
|
16109
16490
|
const outerRing2 = ring2[0];
|
|
16491
|
+
if (!outerRing2 || outerRing2.length < 2) continue;
|
|
16110
16492
|
for (let j = 0; j < outerRing2.length - 1; j++) {
|
|
16111
|
-
const
|
|
16493
|
+
const coord3 = outerRing2[j];
|
|
16494
|
+
const coord4 = outerRing2[j + 1];
|
|
16495
|
+
if (!coord3 || !coord4 || !Array.isArray(coord3) || !Array.isArray(coord4) || coord3.length < 2 || coord4.length < 2 || coord3.some((c) => c === null || c === void 0 || !isFinite(c)) || coord4.some((c) => c === null || c === void 0 || !isFinite(c))) {
|
|
16496
|
+
continue;
|
|
16497
|
+
}
|
|
16498
|
+
const line2 = lineString$1([coord3, coord4]);
|
|
16112
16499
|
try {
|
|
16113
16500
|
const intersection3 = turf_line_intersect_default(line1, line2);
|
|
16114
16501
|
if (intersection3 && intersection3.features && intersection3.features.length > 0) {
|
|
@@ -16124,42 +16511,48 @@ class TurfHelper {
|
|
|
16124
16511
|
}
|
|
16125
16512
|
try {
|
|
16126
16513
|
} catch (error) {
|
|
16514
|
+
if (!isTestEnvironment()) {
|
|
16515
|
+
console.warn(
|
|
16516
|
+
"Error in bounding box check:",
|
|
16517
|
+
error instanceof Error ? error.message : String(error)
|
|
16518
|
+
);
|
|
16519
|
+
}
|
|
16520
|
+
}
|
|
16521
|
+
return false;
|
|
16522
|
+
} catch (error) {
|
|
16523
|
+
if (!isTestEnvironment()) {
|
|
16127
16524
|
console.warn(
|
|
16128
|
-
"Error in
|
|
16525
|
+
"Error in polygonIntersect:",
|
|
16129
16526
|
error instanceof Error ? error.message : String(error)
|
|
16130
16527
|
);
|
|
16131
16528
|
}
|
|
16132
16529
|
return false;
|
|
16133
|
-
} catch (error) {
|
|
16134
|
-
console.warn(
|
|
16135
|
-
"Error in polygonIntersect:",
|
|
16136
|
-
error instanceof Error ? error.message : String(error)
|
|
16137
|
-
);
|
|
16138
|
-
return false;
|
|
16139
16530
|
}
|
|
16140
16531
|
}
|
|
16141
16532
|
getIntersection(poly1, poly2) {
|
|
16142
16533
|
try {
|
|
16143
|
-
const fc = featureCollection([poly1, poly2]);
|
|
16534
|
+
const fc = featureCollection$1([poly1, poly2]);
|
|
16144
16535
|
const result = turf_intersect_default(fc);
|
|
16145
16536
|
if (result && result.geometry && (result.geometry.type === "Polygon" || result.geometry.type === "MultiPolygon")) {
|
|
16146
16537
|
return result;
|
|
16147
16538
|
}
|
|
16148
16539
|
return null;
|
|
16149
16540
|
} catch (error) {
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16541
|
+
if (!isTestEnvironment()) {
|
|
16542
|
+
console.warn(
|
|
16543
|
+
"Error in getIntersection:",
|
|
16544
|
+
error instanceof Error ? error.message : String(error)
|
|
16545
|
+
);
|
|
16546
|
+
}
|
|
16154
16547
|
return null;
|
|
16155
16548
|
}
|
|
16156
16549
|
}
|
|
16157
16550
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16158
16551
|
getDistance(point1, point2) {
|
|
16159
|
-
return
|
|
16552
|
+
return distance$1(point1, point2);
|
|
16160
16553
|
}
|
|
16161
16554
|
isWithin(polygon1, polygon2) {
|
|
16162
|
-
return turf_boolean_within_default(polygon([polygon1]), polygon([polygon2]));
|
|
16555
|
+
return turf_boolean_within_default(polygon$1([polygon1]), polygon$1([polygon2]));
|
|
16163
16556
|
}
|
|
16164
16557
|
/**
|
|
16165
16558
|
* Check if one polygon is completely within another polygon
|
|
@@ -16168,16 +16561,16 @@ class TurfHelper {
|
|
|
16168
16561
|
try {
|
|
16169
16562
|
return turf_boolean_within_default(innerPolygon, outerPolygon);
|
|
16170
16563
|
} catch (error) {
|
|
16171
|
-
const innerCoords = getCoords(innerPolygon);
|
|
16172
|
-
const outerCoords = getCoords(outerPolygon);
|
|
16564
|
+
const innerCoords = getCoords$1(innerPolygon);
|
|
16565
|
+
const outerCoords = getCoords$1(outerPolygon);
|
|
16173
16566
|
for (const innerRing of innerCoords) {
|
|
16174
16567
|
for (const ring of innerRing) {
|
|
16175
16568
|
for (const coord of ring) {
|
|
16176
|
-
const pt = point(coord);
|
|
16569
|
+
const pt = point$1(coord);
|
|
16177
16570
|
let isInside = false;
|
|
16178
16571
|
for (const outerRing of outerCoords) {
|
|
16179
16572
|
for (const outerRingCoords of outerRing) {
|
|
16180
|
-
const outerPoly = polygon([outerRingCoords]);
|
|
16573
|
+
const outerPoly = polygon$1([outerRingCoords]);
|
|
16181
16574
|
if (turf_boolean_point_in_polygon_default(pt, outerPoly)) {
|
|
16182
16575
|
isInside = true;
|
|
16183
16576
|
break;
|
|
@@ -16204,14 +16597,14 @@ class TurfHelper {
|
|
|
16204
16597
|
return pt;
|
|
16205
16598
|
}
|
|
16206
16599
|
if (Array.isArray(pt) && pt.length >= 2 && typeof pt[0] === "number" && typeof pt[1] === "number") {
|
|
16207
|
-
return point(pt);
|
|
16600
|
+
return point$1(pt);
|
|
16208
16601
|
}
|
|
16209
16602
|
if (typeof (pt == null ? void 0 : pt.lat) === "number" && typeof (pt == null ? void 0 : pt.lng) === "number") {
|
|
16210
16603
|
const p = pt;
|
|
16211
|
-
return point([p.lng, p.lat]);
|
|
16604
|
+
return point$1([p.lng, p.lat]);
|
|
16212
16605
|
}
|
|
16213
16606
|
if (((_b2 = pt == null ? void 0 : pt.geometry) == null ? void 0 : _b2.coordinates) && Array.isArray(pt.geometry.coordinates)) {
|
|
16214
|
-
return point(pt.geometry.coordinates);
|
|
16607
|
+
return point$1(pt.geometry.coordinates);
|
|
16215
16608
|
}
|
|
16216
16609
|
throw new Error("Unsupported point format provided to toPointFeature");
|
|
16217
16610
|
}
|
|
@@ -16237,12 +16630,12 @@ class TurfHelper {
|
|
|
16237
16630
|
return turf_boolean_equal_default(polygon1, polygon2);
|
|
16238
16631
|
}
|
|
16239
16632
|
convertToBoundingBoxPolygon(polygon2) {
|
|
16240
|
-
const bboxCoords =
|
|
16241
|
-
const bboxPoly =
|
|
16633
|
+
const bboxCoords = bbox$1(polygon2);
|
|
16634
|
+
const bboxPoly = bboxPolygon(bboxCoords);
|
|
16242
16635
|
return bboxPoly;
|
|
16243
16636
|
}
|
|
16244
16637
|
polygonToMultiPolygon(poly) {
|
|
16245
|
-
const multi = multiPolygon([poly.geometry.coordinates]);
|
|
16638
|
+
const multi = multiPolygon$1([poly.geometry.coordinates]);
|
|
16246
16639
|
return multi;
|
|
16247
16640
|
}
|
|
16248
16641
|
injectPointToPolygon(polygon2, point2, ringIndex) {
|
|
@@ -16298,15 +16691,17 @@ class TurfHelper {
|
|
|
16298
16691
|
}
|
|
16299
16692
|
polygonDifference(polygon1, polygon2) {
|
|
16300
16693
|
try {
|
|
16301
|
-
const fc = featureCollection([polygon1, polygon2]);
|
|
16694
|
+
const fc = featureCollection$1([polygon1, polygon2]);
|
|
16302
16695
|
const diff = turf_difference_default(fc);
|
|
16303
16696
|
const result = diff ? this.getTurfPolygon(diff) : null;
|
|
16304
16697
|
return result;
|
|
16305
16698
|
} catch (error) {
|
|
16306
|
-
|
|
16307
|
-
|
|
16308
|
-
|
|
16309
|
-
|
|
16699
|
+
if (!isTestEnvironment()) {
|
|
16700
|
+
console.warn(
|
|
16701
|
+
"Error in polygonDifference:",
|
|
16702
|
+
error instanceof Error ? error.message : String(error)
|
|
16703
|
+
);
|
|
16704
|
+
}
|
|
16310
16705
|
return null;
|
|
16311
16706
|
}
|
|
16312
16707
|
}
|
|
@@ -16332,18 +16727,29 @@ class TurfHelper {
|
|
|
16332
16727
|
getCoord(point2) {
|
|
16333
16728
|
return [point2.lng, point2.lat];
|
|
16334
16729
|
}
|
|
16730
|
+
/**
|
|
16731
|
+
* Create a GeoJSON polygon feature from coordinates.
|
|
16732
|
+
* This method provides access to the turf polygon helper function
|
|
16733
|
+
* while keeping all turf imports centralized in this file.
|
|
16734
|
+
*
|
|
16735
|
+
* @param coordinates - Array of coordinate rings (outer ring + holes)
|
|
16736
|
+
* @returns GeoJSON Feature<Polygon>
|
|
16737
|
+
*/
|
|
16738
|
+
createPolygon(coordinates) {
|
|
16739
|
+
return polygon$1(coordinates);
|
|
16740
|
+
}
|
|
16335
16741
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16336
16742
|
getFeaturePointCollection(points) {
|
|
16337
16743
|
const pts = [];
|
|
16338
16744
|
points.forEach((v) => {
|
|
16339
|
-
const p = point([v.lng, v.lat], {});
|
|
16745
|
+
const p = point$1([v.lng, v.lat], {});
|
|
16340
16746
|
pts.push(p);
|
|
16341
16747
|
});
|
|
16342
|
-
const fc = featureCollection(pts);
|
|
16748
|
+
const fc = featureCollection$1(pts);
|
|
16343
16749
|
return fc;
|
|
16344
16750
|
}
|
|
16345
16751
|
getPolygonArea(poly) {
|
|
16346
|
-
const polygonArea2 =
|
|
16752
|
+
const polygonArea2 = area$1(poly);
|
|
16347
16753
|
return polygonArea2;
|
|
16348
16754
|
}
|
|
16349
16755
|
getPolygonPerimeter(poly) {
|
|
@@ -16361,7 +16767,7 @@ class TurfHelper {
|
|
|
16361
16767
|
const p1 = points[i];
|
|
16362
16768
|
const p2 = points[(i + 1) % effectiveLen];
|
|
16363
16769
|
doubleized.push(new L.LatLng(p1.lat, p1.lng));
|
|
16364
|
-
const midPoint =
|
|
16770
|
+
const midPoint = midpoint(point$1([p1.lng, p1.lat]), point$1([p2.lng, p2.lat]));
|
|
16365
16771
|
doubleized.push(
|
|
16366
16772
|
new L.LatLng(midPoint.geometry.coordinates[1], midPoint.geometry.coordinates[0])
|
|
16367
16773
|
);
|
|
@@ -16393,10 +16799,12 @@ class TurfHelper {
|
|
|
16393
16799
|
}
|
|
16394
16800
|
return false;
|
|
16395
16801
|
} catch (error) {
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16802
|
+
if (!isTestEnvironment()) {
|
|
16803
|
+
console.warn(
|
|
16804
|
+
"Error checking for holes:",
|
|
16805
|
+
error instanceof Error ? error.message : String(error)
|
|
16806
|
+
);
|
|
16807
|
+
}
|
|
16400
16808
|
return false;
|
|
16401
16809
|
}
|
|
16402
16810
|
}
|
|
@@ -16458,10 +16866,12 @@ class TurfHelper {
|
|
|
16458
16866
|
}
|
|
16459
16867
|
return [feature2];
|
|
16460
16868
|
} catch (error) {
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16869
|
+
if (!isTestEnvironment()) {
|
|
16870
|
+
console.warn(
|
|
16871
|
+
"Error in getKinksWithHolePreservation:",
|
|
16872
|
+
error instanceof Error ? error.message : String(error)
|
|
16873
|
+
);
|
|
16874
|
+
}
|
|
16465
16875
|
return [feature2];
|
|
16466
16876
|
}
|
|
16467
16877
|
}
|
|
@@ -16495,10 +16905,12 @@ class TurfHelper {
|
|
|
16495
16905
|
}
|
|
16496
16906
|
return false;
|
|
16497
16907
|
} catch (error) {
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16908
|
+
if (!isTestEnvironment()) {
|
|
16909
|
+
console.warn(
|
|
16910
|
+
"Error checking complete hole traversal:",
|
|
16911
|
+
error instanceof Error ? error.message : String(error)
|
|
16912
|
+
);
|
|
16913
|
+
}
|
|
16502
16914
|
return false;
|
|
16503
16915
|
}
|
|
16504
16916
|
}
|
|
@@ -16530,10 +16942,12 @@ class TurfHelper {
|
|
|
16530
16942
|
}
|
|
16531
16943
|
return null;
|
|
16532
16944
|
} catch (error) {
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16945
|
+
if (!isTestEnvironment()) {
|
|
16946
|
+
console.warn(
|
|
16947
|
+
"Error finding self-intersection line:",
|
|
16948
|
+
error instanceof Error ? error.message : String(error)
|
|
16949
|
+
);
|
|
16950
|
+
}
|
|
16537
16951
|
return null;
|
|
16538
16952
|
}
|
|
16539
16953
|
}
|
|
@@ -16545,18 +16959,20 @@ class TurfHelper {
|
|
|
16545
16959
|
if (line.length < 2) return false;
|
|
16546
16960
|
const lineStart = line[0];
|
|
16547
16961
|
const lineEnd = line[line.length - 1];
|
|
16548
|
-
const holePolygon = polygon([hole]);
|
|
16549
|
-
const startInHole = turf_boolean_point_in_polygon_default(point(lineStart), holePolygon);
|
|
16550
|
-
const endInHole = turf_boolean_point_in_polygon_default(point(lineEnd), holePolygon);
|
|
16962
|
+
const holePolygon = polygon$1([hole]);
|
|
16963
|
+
const startInHole = turf_boolean_point_in_polygon_default(point$1(lineStart), holePolygon);
|
|
16964
|
+
const endInHole = turf_boolean_point_in_polygon_default(point$1(lineEnd), holePolygon);
|
|
16551
16965
|
if (startInHole !== endInHole) {
|
|
16552
16966
|
return true;
|
|
16553
16967
|
}
|
|
16554
16968
|
return false;
|
|
16555
16969
|
} catch (error) {
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16970
|
+
if (!isTestEnvironment()) {
|
|
16971
|
+
console.warn(
|
|
16972
|
+
"Error checking line hole traversal:",
|
|
16973
|
+
error instanceof Error ? error.message : String(error)
|
|
16974
|
+
);
|
|
16975
|
+
}
|
|
16560
16976
|
return false;
|
|
16561
16977
|
}
|
|
16562
16978
|
}
|
|
@@ -16565,29 +16981,31 @@ class TurfHelper {
|
|
|
16565
16981
|
*/
|
|
16566
16982
|
holeIsCutByKinks(outerRing, hole) {
|
|
16567
16983
|
try {
|
|
16568
|
-
const outerPolygon = polygon([outerRing]);
|
|
16569
|
-
const holePolygon = polygon([hole]);
|
|
16984
|
+
const outerPolygon = polygon$1([outerRing]);
|
|
16985
|
+
const holePolygon = polygon$1([hole]);
|
|
16570
16986
|
const kinkFeatures = turf_kinks_default(outerPolygon);
|
|
16571
16987
|
if (kinkFeatures.features.length === 0) return false;
|
|
16572
16988
|
for (const kink of kinkFeatures.features) {
|
|
16573
16989
|
const kinkPt = kink.geometry.coordinates;
|
|
16574
16990
|
try {
|
|
16575
|
-
const d =
|
|
16991
|
+
const d = distance$1(point$1(kinkPt), centroid$1(holePolygon));
|
|
16576
16992
|
if (d < 0.01) {
|
|
16577
16993
|
return true;
|
|
16578
16994
|
}
|
|
16579
|
-
if (turf_boolean_point_in_polygon_default(point(kinkPt), holePolygon)) {
|
|
16995
|
+
if (turf_boolean_point_in_polygon_default(point$1(kinkPt), holePolygon)) {
|
|
16580
16996
|
return true;
|
|
16581
16997
|
}
|
|
16582
16998
|
} catch {
|
|
16583
|
-
if (turf_boolean_point_in_polygon_default(point(kinkPt), holePolygon)) {
|
|
16999
|
+
if (turf_boolean_point_in_polygon_default(point$1(kinkPt), holePolygon)) {
|
|
16584
17000
|
return true;
|
|
16585
17001
|
}
|
|
16586
17002
|
}
|
|
16587
17003
|
}
|
|
16588
17004
|
return false;
|
|
16589
17005
|
} catch (error) {
|
|
16590
|
-
|
|
17006
|
+
if (!isTestEnvironment()) {
|
|
17007
|
+
console.warn("Error checking hole cut by kinks:", error.message);
|
|
17008
|
+
}
|
|
16591
17009
|
return false;
|
|
16592
17010
|
}
|
|
16593
17011
|
}
|
|
@@ -16616,16 +17034,16 @@ class TurfHelper {
|
|
|
16616
17034
|
if (holes.length === 0) {
|
|
16617
17035
|
return false;
|
|
16618
17036
|
}
|
|
16619
|
-
const outerPolygon = polygon([outerRing]);
|
|
17037
|
+
const outerPolygon = polygon$1([outerRing]);
|
|
16620
17038
|
for (const hole of holes) {
|
|
16621
|
-
const holePolygon = polygon([hole]);
|
|
17039
|
+
const holePolygon = polygon$1([hole]);
|
|
16622
17040
|
const intersection3 = this.getIntersection(outerPolygon, holePolygon);
|
|
16623
17041
|
if (intersection3) {
|
|
16624
17042
|
return true;
|
|
16625
17043
|
}
|
|
16626
17044
|
for (let i = 0; i < outerRing.length - 1; i++) {
|
|
16627
17045
|
const pt = outerRing[i];
|
|
16628
|
-
const pointInHole = turf_boolean_point_in_polygon_default(point(pt), holePolygon);
|
|
17046
|
+
const pointInHole = turf_boolean_point_in_polygon_default(point$1(pt), holePolygon);
|
|
16629
17047
|
if (pointInHole) {
|
|
16630
17048
|
return true;
|
|
16631
17049
|
}
|
|
@@ -16658,10 +17076,12 @@ class TurfHelper {
|
|
|
16658
17076
|
});
|
|
16659
17077
|
return resultPolygons;
|
|
16660
17078
|
} catch (error) {
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
|
|
17079
|
+
if (!isTestEnvironment()) {
|
|
17080
|
+
console.warn(
|
|
17081
|
+
"Error handling complete hole traversal:",
|
|
17082
|
+
error instanceof Error ? error.message : String(error)
|
|
17083
|
+
);
|
|
17084
|
+
}
|
|
16665
17085
|
try {
|
|
16666
17086
|
const fallbackPolygon = {
|
|
16667
17087
|
...outerPolygon,
|
|
@@ -16685,7 +17105,7 @@ class TurfHelper {
|
|
|
16685
17105
|
try {
|
|
16686
17106
|
let resultPolygon = basePolygon;
|
|
16687
17107
|
for (const hole of holes) {
|
|
16688
|
-
const holePolygon = polygon([hole]);
|
|
17108
|
+
const holePolygon = polygon$1([hole]);
|
|
16689
17109
|
const intersection3 = this.getIntersection(holePolygon, resultPolygon);
|
|
16690
17110
|
if (intersection3) {
|
|
16691
17111
|
const difference22 = this.polygonDifference(resultPolygon, holePolygon);
|
|
@@ -16702,7 +17122,7 @@ class TurfHelper {
|
|
|
16702
17122
|
geometry: { type: "Polygon", coordinates: coords },
|
|
16703
17123
|
properties: {}
|
|
16704
17124
|
};
|
|
16705
|
-
const polygonArea2 =
|
|
17125
|
+
const polygonArea2 = area$1(poly);
|
|
16706
17126
|
if (polygonArea2 > largestArea) {
|
|
16707
17127
|
largestArea = polygonArea2;
|
|
16708
17128
|
largestPolygon = poly;
|
|
@@ -16713,341 +17133,113 @@ class TurfHelper {
|
|
|
16713
17133
|
}
|
|
16714
17134
|
}
|
|
16715
17135
|
} else {
|
|
16716
|
-
}
|
|
16717
|
-
} else {
|
|
16718
|
-
}
|
|
16719
|
-
}
|
|
16720
|
-
return resultPolygon;
|
|
16721
|
-
} catch (error) {
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
|
|
16727
|
-
}
|
|
16728
|
-
}
|
|
16729
|
-
/**
|
|
16730
|
-
* Remove duplicate vertices from a polygon to prevent turf errors
|
|
16731
|
-
*/
|
|
16732
|
-
removeDuplicateVertices(feature2) {
|
|
16733
|
-
if (!feature2 || !feature2.geometry || !feature2.geometry.coordinates) {
|
|
16734
|
-
console.warn("Invalid feature passed to removeDuplicateVertices");
|
|
16735
|
-
return feature2;
|
|
16736
|
-
}
|
|
16737
|
-
const cleanCoordinates = (coords) => {
|
|
16738
|
-
if (!coords || coords.length < 3) {
|
|
16739
|
-
console.warn("Invalid coordinates array - need at least 3 points for a polygon");
|
|
16740
|
-
return coords || [];
|
|
16741
|
-
}
|
|
16742
|
-
const cleaned = [];
|
|
16743
|
-
const tolerance = 1e-6;
|
|
16744
|
-
for (let i = 0; i < coords.length; i++) {
|
|
16745
|
-
const current = coords[i];
|
|
16746
|
-
const next = coords[(i + 1) % coords.length];
|
|
16747
|
-
if (!current || !Array.isArray(current) || current.length < 2 || !next || !Array.isArray(next) || next.length < 2) {
|
|
16748
|
-
continue;
|
|
16749
|
-
}
|
|
16750
|
-
const latDiff = Math.abs(current[1] - next[1]);
|
|
16751
|
-
const lngDiff = Math.abs(current[0] - next[0]);
|
|
16752
|
-
if (latDiff > tolerance || lngDiff > tolerance) {
|
|
16753
|
-
cleaned.push(current);
|
|
16754
|
-
}
|
|
16755
|
-
}
|
|
16756
|
-
if (cleaned.length < 3) {
|
|
16757
|
-
console.warn("After cleaning, polygon has less than 3 points");
|
|
16758
|
-
return coords;
|
|
16759
|
-
}
|
|
16760
|
-
if (cleaned.length > 0) {
|
|
16761
|
-
const first = cleaned[0];
|
|
16762
|
-
const last = cleaned[cleaned.length - 1];
|
|
16763
|
-
const latDiff = Math.abs(first[1] - last[1]);
|
|
16764
|
-
const lngDiff = Math.abs(first[0] - last[0]);
|
|
16765
|
-
if (latDiff > tolerance || lngDiff > tolerance) {
|
|
16766
|
-
cleaned.push([first[0], first[1]]);
|
|
16767
|
-
}
|
|
16768
|
-
}
|
|
16769
|
-
return cleaned;
|
|
16770
|
-
};
|
|
16771
|
-
try {
|
|
16772
|
-
if (feature2.geometry.type === "Polygon") {
|
|
16773
|
-
const cleanedCoords = feature2.geometry.coordinates.map((ring) => cleanCoordinates(ring));
|
|
16774
|
-
if (cleanedCoords.some((ring) => ring.length < 4)) {
|
|
16775
|
-
console.warn("Cleaned polygon has invalid ring with less than 4 coordinates");
|
|
16776
|
-
return feature2;
|
|
16777
|
-
}
|
|
16778
|
-
return {
|
|
16779
|
-
...feature2,
|
|
16780
|
-
geometry: {
|
|
16781
|
-
...feature2.geometry,
|
|
16782
|
-
coordinates: cleanedCoords
|
|
16783
|
-
}
|
|
16784
|
-
};
|
|
16785
|
-
} else if (feature2.geometry.type === "MultiPolygon") {
|
|
16786
|
-
const cleanedCoords = feature2.geometry.coordinates.map(
|
|
16787
|
-
(polygon2) => polygon2.map((ring) => cleanCoordinates(ring))
|
|
16788
|
-
);
|
|
16789
|
-
if (cleanedCoords.some((polygon2) => polygon2.some((ring) => ring.length < 4))) {
|
|
16790
|
-
console.warn("Cleaned multipolygon has invalid ring with less than 4 coordinates");
|
|
16791
|
-
return feature2;
|
|
16792
|
-
}
|
|
16793
|
-
return {
|
|
16794
|
-
...feature2,
|
|
16795
|
-
geometry: {
|
|
16796
|
-
...feature2.geometry,
|
|
16797
|
-
coordinates: cleanedCoords
|
|
16798
|
-
}
|
|
16799
|
-
};
|
|
16800
|
-
}
|
|
16801
|
-
} catch (error) {
|
|
16802
|
-
console.warn(
|
|
16803
|
-
"Error in removeDuplicateVertices:",
|
|
16804
|
-
error instanceof Error ? error.message : String(error)
|
|
16805
|
-
);
|
|
16806
|
-
return feature2;
|
|
16807
|
-
}
|
|
16808
|
-
return feature2;
|
|
16809
|
-
}
|
|
16810
|
-
}
|
|
16811
|
-
const isTouchDevice = () => "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
16812
|
-
class PolyDrawUtil {
|
|
16813
|
-
/**
|
|
16814
|
-
* Gets the bounds of the polygon with optional padding.
|
|
16815
|
-
* @param polygon Array of LatLng points.
|
|
16816
|
-
* @param padding Padding factor.
|
|
16817
|
-
* @returns The LatLngBounds.
|
|
16818
|
-
*/
|
|
16819
|
-
static getBounds(polygon2, padding = 0) {
|
|
16820
|
-
const tmpLatLng = [];
|
|
16821
|
-
polygon2.forEach((ll) => {
|
|
16822
|
-
if (isNaN(ll.lat) || isNaN(ll.lng)) ;
|
|
16823
|
-
tmpLatLng.push(ll);
|
|
16824
|
-
});
|
|
16825
|
-
const polyLine = new L.Polyline(tmpLatLng);
|
|
16826
|
-
const bounds = polyLine.getBounds();
|
|
16827
|
-
if (padding !== 0) {
|
|
16828
|
-
return bounds.pad(padding);
|
|
16829
|
-
}
|
|
16830
|
-
return bounds;
|
|
16831
|
-
}
|
|
16832
|
-
}
|
|
16833
|
-
class Compass {
|
|
16834
|
-
constructor(minLat = 0, minLng = 0, maxLat = 0, maxLng = 0) {
|
|
16835
|
-
__publicField(this, "direction", {
|
|
16836
|
-
East: new L.LatLng(0, 0),
|
|
16837
|
-
North: new L.LatLng(0, 0),
|
|
16838
|
-
NorthEast: new L.LatLng(0, 0),
|
|
16839
|
-
NorthWest: new L.LatLng(0, 0),
|
|
16840
|
-
South: new L.LatLng(0, 0),
|
|
16841
|
-
SouthEast: new L.LatLng(0, 0),
|
|
16842
|
-
SouthWest: new L.LatLng(0, 0),
|
|
16843
|
-
West: new L.LatLng(0, 0)
|
|
16844
|
-
});
|
|
16845
|
-
this.direction.North = new L.LatLng(maxLat, (minLng + maxLng) / 2);
|
|
16846
|
-
this.direction.NorthEast = new L.LatLng(maxLat, maxLng);
|
|
16847
|
-
this.direction.East = new L.LatLng((minLat + maxLat) / 2, maxLng);
|
|
16848
|
-
this.direction.SouthEast = new L.LatLng(minLat, maxLng);
|
|
16849
|
-
this.direction.South = new L.LatLng(minLat, (minLng + maxLng) / 2);
|
|
16850
|
-
this.direction.SouthWest = new L.LatLng(minLat, minLng);
|
|
16851
|
-
this.direction.West = new L.LatLng((minLat + maxLat) / 2, minLng);
|
|
16852
|
-
this.direction.NorthWest = new L.LatLng(maxLat, minLng);
|
|
16853
|
-
}
|
|
16854
|
-
getDirection(direction) {
|
|
16855
|
-
switch (direction) {
|
|
16856
|
-
case MarkerPosition.SouthWest:
|
|
16857
|
-
return this.direction.SouthWest;
|
|
16858
|
-
case MarkerPosition.West:
|
|
16859
|
-
return this.direction.West;
|
|
16860
|
-
case MarkerPosition.NorthWest:
|
|
16861
|
-
return this.direction.NorthWest;
|
|
16862
|
-
case MarkerPosition.North:
|
|
16863
|
-
return this.direction.North;
|
|
16864
|
-
case MarkerPosition.NorthEast:
|
|
16865
|
-
return this.direction.NorthEast;
|
|
16866
|
-
case MarkerPosition.East:
|
|
16867
|
-
return this.direction.East;
|
|
16868
|
-
case MarkerPosition.SouthEast:
|
|
16869
|
-
return this.direction.SouthEast;
|
|
16870
|
-
case MarkerPosition.South:
|
|
16871
|
-
return this.direction.South;
|
|
16872
|
-
default:
|
|
16873
|
-
throw new Error();
|
|
16874
|
-
}
|
|
16875
|
-
}
|
|
16876
|
-
getPositions(startPosition = MarkerPosition.SouthWest, clockwise = false, addClosingNode = true) {
|
|
16877
|
-
const positions = [];
|
|
16878
|
-
const posArray = this.getPositionAsArray(startPosition, clockwise);
|
|
16879
|
-
posArray.forEach((v) => {
|
|
16880
|
-
positions.push([v.lng, v.lat]);
|
|
16881
|
-
});
|
|
16882
|
-
if (addClosingNode) {
|
|
16883
|
-
positions.push([posArray[0].lng, posArray[0].lat]);
|
|
16884
|
-
}
|
|
16885
|
-
return positions;
|
|
16886
|
-
}
|
|
16887
|
-
getPositionAsArray(startPosition = MarkerPosition.NorthEast, clockwise = false) {
|
|
16888
|
-
const positions = [];
|
|
16889
|
-
if (clockwise) {
|
|
16890
|
-
positions.push(this.direction.SouthWest);
|
|
16891
|
-
positions.push(this.direction.West);
|
|
16892
|
-
positions.push(this.direction.NorthWest);
|
|
16893
|
-
positions.push(this.direction.North);
|
|
16894
|
-
positions.push(this.direction.NorthEast);
|
|
16895
|
-
positions.push(this.direction.East);
|
|
16896
|
-
positions.push(this.direction.SouthEast);
|
|
16897
|
-
positions.push(this.direction.South);
|
|
16898
|
-
} else {
|
|
16899
|
-
positions.push(this.direction.SouthWest);
|
|
16900
|
-
positions.push(this.direction.South);
|
|
16901
|
-
positions.push(this.direction.SouthEast);
|
|
16902
|
-
positions.push(this.direction.East);
|
|
16903
|
-
positions.push(this.direction.NorthEast);
|
|
16904
|
-
positions.push(this.direction.North);
|
|
16905
|
-
positions.push(this.direction.NorthWest);
|
|
16906
|
-
positions.push(this.direction.West);
|
|
16907
|
-
}
|
|
16908
|
-
if (startPosition !== MarkerPosition.SouthWest) {
|
|
16909
|
-
const chunk = positions.splice(0, startPosition);
|
|
16910
|
-
chunk.forEach((v, i) => {
|
|
16911
|
-
positions.splice(startPosition + i, 0, v);
|
|
16912
|
-
});
|
|
16913
|
-
}
|
|
16914
|
-
return positions;
|
|
16915
|
-
}
|
|
16916
|
-
}
|
|
16917
|
-
class Perimeter {
|
|
16918
|
-
constructor(length2, config) {
|
|
16919
|
-
__publicField(this, "metricLength", "");
|
|
16920
|
-
__publicField(this, "metricUnit", "");
|
|
16921
|
-
__publicField(this, "imperialLength", "");
|
|
16922
|
-
__publicField(this, "imperialUnit", "");
|
|
16923
|
-
if (length2 !== null || length2 !== void 0) {
|
|
16924
|
-
if (length2 === 0) {
|
|
16925
|
-
if (config.markers.markerInfoIcon.usePerimeterMinValue) {
|
|
16926
|
-
this.metricLength = config.markers.markerInfoIcon.values.min.metric;
|
|
16927
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16928
|
-
this.imperialLength = config.markers.markerInfoIcon.values.min.imperial;
|
|
16929
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.feet;
|
|
16930
|
-
} else {
|
|
16931
|
-
this.metricLength = config.markers.markerInfoIcon.values.unknown.metric;
|
|
16932
|
-
this.metricUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16933
|
-
this.imperialLength = config.markers.markerInfoIcon.values.unknown.imperial;
|
|
16934
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16935
|
-
}
|
|
16936
|
-
} else if (length2 < 100) {
|
|
16937
|
-
this.metricLength = (Math.ceil(length2 / 10) * 10).toString();
|
|
16938
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16939
|
-
} else if (length2 < 500) {
|
|
16940
|
-
this.metricLength = (Math.ceil(length2 / 50) * 50).toString();
|
|
16941
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16942
|
-
} else if (length2 < 1e3) {
|
|
16943
|
-
this.metricLength = (Math.ceil(length2 / 100) * 100).toString();
|
|
16944
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.m;
|
|
16945
|
-
} else if (length2 < 1e4) {
|
|
16946
|
-
this.metricLength = (Math.ceil(length2 / 100) * 100 / 1e3).toFixed(1);
|
|
16947
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.km;
|
|
16948
|
-
} else {
|
|
16949
|
-
this.metricLength = (Math.ceil(length2 / 1e3) * 1e3 / 1e3).toString();
|
|
16950
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.perimeter.km;
|
|
16951
|
-
}
|
|
16952
|
-
const inch = length2 / 0.0254;
|
|
16953
|
-
const feet = inch / 12;
|
|
16954
|
-
const yards = feet / 3;
|
|
16955
|
-
const miles = yards / 1760;
|
|
16956
|
-
if (length2 < 1e3 / 2.54) {
|
|
16957
|
-
this.imperialLength = (Math.ceil(feet / 10) * 10).toString();
|
|
16958
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.feet;
|
|
16959
|
-
} else if (length2 < 1e3 / 2.54 * 3) {
|
|
16960
|
-
this.imperialLength = (Math.ceil(yards / 10) * 10).toString();
|
|
16961
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.yards;
|
|
16962
|
-
} else if (length2 < 1609) {
|
|
16963
|
-
this.imperialLength = miles.toFixed(2);
|
|
16964
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
16965
|
-
} else if (length2 < 16093) {
|
|
16966
|
-
this.imperialLength = miles.toFixed(1);
|
|
16967
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
16968
|
-
} else {
|
|
16969
|
-
this.imperialLength = miles.toFixed(0);
|
|
16970
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.imperial.perimeter.miles;
|
|
17136
|
+
}
|
|
17137
|
+
} else {
|
|
17138
|
+
}
|
|
17139
|
+
}
|
|
17140
|
+
return resultPolygon;
|
|
17141
|
+
} catch (error) {
|
|
17142
|
+
if (!isTestEnvironment()) {
|
|
17143
|
+
console.warn(
|
|
17144
|
+
"Error subtracting intersecting holes:",
|
|
17145
|
+
error instanceof Error ? error.message : String(error)
|
|
17146
|
+
);
|
|
16971
17147
|
}
|
|
17148
|
+
return basePolygon;
|
|
16972
17149
|
}
|
|
16973
17150
|
}
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
this.imperialUnit = config.markers.markerInfoIcon.units.unknownUnit;
|
|
16989
|
-
} else if (area2 < 1e4) {
|
|
16990
|
-
this.metricArea = Math.round(area2).toString();
|
|
16991
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.m2;
|
|
16992
|
-
} else if (area2 < 1e5) {
|
|
16993
|
-
if (onlyMetrics) {
|
|
16994
|
-
this.metricArea = (area2 / 1e6).toFixed(2);
|
|
16995
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
16996
|
-
} else {
|
|
16997
|
-
this.metricArea = (area2 / 1e3).toFixed(1);
|
|
16998
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.daa;
|
|
17151
|
+
/**
|
|
17152
|
+
* Remove duplicate vertices from a polygon to prevent turf errors
|
|
17153
|
+
*/
|
|
17154
|
+
removeDuplicateVertices(feature2) {
|
|
17155
|
+
if (!feature2 || !feature2.geometry || !feature2.geometry.coordinates) {
|
|
17156
|
+
if (!isTestEnvironment()) {
|
|
17157
|
+
console.warn("Invalid feature passed to removeDuplicateVertices");
|
|
17158
|
+
}
|
|
17159
|
+
return feature2;
|
|
17160
|
+
}
|
|
17161
|
+
const cleanCoordinates = (coords) => {
|
|
17162
|
+
if (!coords || coords.length < 3) {
|
|
17163
|
+
if (!isTestEnvironment()) {
|
|
17164
|
+
console.warn("Invalid coordinates array - need at least 3 points for a polygon");
|
|
16999
17165
|
}
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17166
|
+
return coords || [];
|
|
17167
|
+
}
|
|
17168
|
+
const cleaned = [];
|
|
17169
|
+
const tolerance = 1e-6;
|
|
17170
|
+
for (let i = 0; i < coords.length; i++) {
|
|
17171
|
+
const current = coords[i];
|
|
17172
|
+
const next = coords[(i + 1) % coords.length];
|
|
17173
|
+
if (!current || !Array.isArray(current) || current.length < 2 || !next || !Array.isArray(next) || next.length < 2) {
|
|
17174
|
+
continue;
|
|
17007
17175
|
}
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
} else {
|
|
17013
|
-
this.metricArea = Math.round(area2 / 1e4).toString();
|
|
17014
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.ha;
|
|
17176
|
+
const latDiff = Math.abs(current[1] - next[1]);
|
|
17177
|
+
const lngDiff = Math.abs(current[0] - next[0]);
|
|
17178
|
+
if (latDiff > tolerance || lngDiff > tolerance) {
|
|
17179
|
+
cleaned.push(current);
|
|
17015
17180
|
}
|
|
17016
|
-
} else {
|
|
17017
|
-
this.metricArea = Math.round(area2 / 1e6).toString();
|
|
17018
|
-
this.metricUnit = config.markers.markerInfoIcon.units.metric.area.km2;
|
|
17019
17181
|
}
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
}
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17182
|
+
if (cleaned.length < 3) {
|
|
17183
|
+
if (!isTestEnvironment()) {
|
|
17184
|
+
console.warn("After cleaning, polygon has less than 3 points");
|
|
17185
|
+
}
|
|
17186
|
+
return coords;
|
|
17187
|
+
}
|
|
17188
|
+
if (cleaned.length > 0) {
|
|
17189
|
+
const first = cleaned[0];
|
|
17190
|
+
const last = cleaned[cleaned.length - 1];
|
|
17191
|
+
const latDiff = Math.abs(first[1] - last[1]);
|
|
17192
|
+
const lngDiff = Math.abs(first[0] - last[0]);
|
|
17193
|
+
if (latDiff > tolerance || lngDiff > tolerance) {
|
|
17194
|
+
cleaned.push([first[0], first[1]]);
|
|
17195
|
+
}
|
|
17196
|
+
}
|
|
17197
|
+
return cleaned;
|
|
17198
|
+
};
|
|
17199
|
+
try {
|
|
17200
|
+
if (feature2.geometry.type === "Polygon") {
|
|
17201
|
+
const cleanedCoords = feature2.geometry.coordinates.map((ring) => cleanCoordinates(ring));
|
|
17202
|
+
if (cleanedCoords.some((ring) => ring.length < 4)) {
|
|
17203
|
+
if (!isTestEnvironment()) {
|
|
17204
|
+
console.warn("Cleaned polygon has invalid ring with less than 4 coordinates");
|
|
17205
|
+
}
|
|
17206
|
+
return feature2;
|
|
17207
|
+
}
|
|
17208
|
+
return {
|
|
17209
|
+
...feature2,
|
|
17210
|
+
geometry: {
|
|
17211
|
+
...feature2.geometry,
|
|
17212
|
+
coordinates: cleanedCoords
|
|
17213
|
+
}
|
|
17214
|
+
};
|
|
17215
|
+
} else if (feature2.geometry.type === "MultiPolygon") {
|
|
17216
|
+
const cleanedCoords = feature2.geometry.coordinates.map(
|
|
17217
|
+
(polygon2) => polygon2.map((ring) => cleanCoordinates(ring))
|
|
17218
|
+
);
|
|
17219
|
+
if (cleanedCoords.some((polygon2) => polygon2.some((ring) => ring.length < 4))) {
|
|
17220
|
+
if (!isTestEnvironment()) {
|
|
17221
|
+
console.warn("Cleaned multipolygon has invalid ring with less than 4 coordinates");
|
|
17222
|
+
}
|
|
17223
|
+
return feature2;
|
|
17224
|
+
}
|
|
17225
|
+
return {
|
|
17226
|
+
...feature2,
|
|
17227
|
+
geometry: {
|
|
17228
|
+
...feature2.geometry,
|
|
17229
|
+
coordinates: cleanedCoords
|
|
17230
|
+
}
|
|
17231
|
+
};
|
|
17232
|
+
}
|
|
17233
|
+
} catch (error) {
|
|
17234
|
+
if (!isTestEnvironment()) {
|
|
17235
|
+
console.warn(
|
|
17236
|
+
"Error in removeDuplicateVertices:",
|
|
17237
|
+
error instanceof Error ? error.message : String(error)
|
|
17238
|
+
);
|
|
17049
17239
|
}
|
|
17240
|
+
return feature2;
|
|
17050
17241
|
}
|
|
17242
|
+
return feature2;
|
|
17051
17243
|
}
|
|
17052
17244
|
}
|
|
17053
17245
|
function createButtons(container, subContainer, config, onActivateToggle, onDrawClick, onSubtractClick, onEraseClick, onPointToPointClick) {
|
|
@@ -17117,15 +17309,14 @@ class PolygonUtil {
|
|
|
17117
17309
|
* @returns The center LatLng.
|
|
17118
17310
|
*/
|
|
17119
17311
|
static getCenter(polygon2) {
|
|
17120
|
-
const pi2 = Math.PI;
|
|
17121
17312
|
let x = 0;
|
|
17122
17313
|
let y = 0;
|
|
17123
17314
|
let z = 0;
|
|
17124
17315
|
polygon2.forEach((v) => {
|
|
17125
17316
|
let lat1 = v.lat;
|
|
17126
17317
|
let lon1 = v.lng;
|
|
17127
|
-
lat1 = lat1 *
|
|
17128
|
-
lon1 = lon1 *
|
|
17318
|
+
lat1 = lat1 * MATH.DEG_TO_RAD;
|
|
17319
|
+
lon1 = lon1 * MATH.DEG_TO_RAD;
|
|
17129
17320
|
x += Math.cos(lat1) * Math.cos(lon1);
|
|
17130
17321
|
y += Math.cos(lat1) * Math.sin(lon1);
|
|
17131
17322
|
z += Math.sin(lat1);
|
|
@@ -17133,8 +17324,8 @@ class PolygonUtil {
|
|
|
17133
17324
|
let lng = Math.atan2(y, x);
|
|
17134
17325
|
const hyp = Math.sqrt(x * x + y * y);
|
|
17135
17326
|
let lat = Math.atan2(z, hyp);
|
|
17136
|
-
lat = lat *
|
|
17137
|
-
lng = lng *
|
|
17327
|
+
lat = lat * MATH.RAD_TO_DEG;
|
|
17328
|
+
lng = lng * MATH.RAD_TO_DEG;
|
|
17138
17329
|
const center2 = { lat, lng };
|
|
17139
17330
|
return center2;
|
|
17140
17331
|
}
|
|
@@ -17690,9 +17881,10 @@ class PolygonDrawManager {
|
|
|
17690
17881
|
if ("latlng" in event && event.latlng) {
|
|
17691
17882
|
this.tracer.addLatLng(event.latlng);
|
|
17692
17883
|
} else if ("touches" in event && event.touches && event.touches.length > 0) {
|
|
17884
|
+
const rect = this.map.getContainer().getBoundingClientRect();
|
|
17693
17885
|
const latlng = this.map.containerPointToLatLng([
|
|
17694
|
-
event.touches[0].clientX,
|
|
17695
|
-
event.touches[0].clientY
|
|
17886
|
+
event.touches[0].clientX - rect.x,
|
|
17887
|
+
event.touches[0].clientY - rect.y
|
|
17696
17888
|
]);
|
|
17697
17889
|
this.tracer.addLatLng(latlng);
|
|
17698
17890
|
}
|
|
@@ -17855,7 +18047,9 @@ class PolygonDrawManager {
|
|
|
17855
18047
|
isPointToPoint: true
|
|
17856
18048
|
});
|
|
17857
18049
|
} catch (error) {
|
|
17858
|
-
|
|
18050
|
+
if (!isTestEnvironment()) {
|
|
18051
|
+
console.warn("Error completing point-to-point polygon:", error);
|
|
18052
|
+
}
|
|
17859
18053
|
this.clearP2pMarkers();
|
|
17860
18054
|
this.resetTracer();
|
|
17861
18055
|
}
|
|
@@ -19228,7 +19422,9 @@ class PolygonInteractionManager {
|
|
|
19228
19422
|
}
|
|
19229
19423
|
markerDrag(featureGroup) {
|
|
19230
19424
|
if (!this._activeMarker) {
|
|
19231
|
-
|
|
19425
|
+
if (!isTestEnvironment()) {
|
|
19426
|
+
console.warn("No active marker set for dragging.");
|
|
19427
|
+
}
|
|
19232
19428
|
return;
|
|
19233
19429
|
}
|
|
19234
19430
|
const newPos = [];
|
|
@@ -19236,6 +19432,12 @@ class PolygonInteractionManager {
|
|
|
19236
19432
|
let hole = [];
|
|
19237
19433
|
const layers = featureGroup.getLayers();
|
|
19238
19434
|
const polygonLayer = layers.find((l) => l instanceof L.Polygon);
|
|
19435
|
+
if (!polygonLayer) {
|
|
19436
|
+
if (!isTestEnvironment()) {
|
|
19437
|
+
console.warn("No polygon found in feature group for marker drag.");
|
|
19438
|
+
}
|
|
19439
|
+
return;
|
|
19440
|
+
}
|
|
19239
19441
|
const posarrays = polygonLayer.getLatLngs();
|
|
19240
19442
|
let length2 = 0;
|
|
19241
19443
|
const markers2 = layers.filter((layer) => layer instanceof L.Marker);
|
|
@@ -19322,14 +19524,20 @@ class PolygonInteractionManager {
|
|
|
19322
19524
|
this.eventManager.emit("polydraw:polygon:updated", {
|
|
19323
19525
|
operation: "markerDrag",
|
|
19324
19526
|
polygon: this.turfHelper.getTurfPolygon(polygon2),
|
|
19325
|
-
allowMerge: true
|
|
19527
|
+
allowMerge: true,
|
|
19528
|
+
// Allow intelligent merging for intersections
|
|
19529
|
+
intelligentMerge: true
|
|
19530
|
+
// Flag for smart merging logic
|
|
19326
19531
|
});
|
|
19327
19532
|
}
|
|
19328
19533
|
} else {
|
|
19329
19534
|
this.eventManager.emit("polydraw:polygon:updated", {
|
|
19330
19535
|
operation: "markerDrag",
|
|
19331
19536
|
polygon: feature2,
|
|
19332
|
-
allowMerge: true
|
|
19537
|
+
allowMerge: true,
|
|
19538
|
+
// Allow intelligent merging for intersections
|
|
19539
|
+
intelligentMerge: true
|
|
19540
|
+
// Flag for smart merging logic
|
|
19333
19541
|
});
|
|
19334
19542
|
}
|
|
19335
19543
|
}
|
|
@@ -19343,14 +19551,16 @@ class PolygonInteractionManager {
|
|
|
19343
19551
|
this.eventManager.emit("polydraw:polygon:updated", {
|
|
19344
19552
|
operation: "markerDrag",
|
|
19345
19553
|
polygon: this.turfHelper.getTurfPolygon(polygon2),
|
|
19346
|
-
allowMerge:
|
|
19554
|
+
allowMerge: false
|
|
19555
|
+
// Fixed: prevent merging during vertex drag
|
|
19347
19556
|
});
|
|
19348
19557
|
}
|
|
19349
19558
|
} else {
|
|
19350
19559
|
this.eventManager.emit("polydraw:polygon:updated", {
|
|
19351
19560
|
operation: "markerDrag",
|
|
19352
19561
|
polygon: feature2,
|
|
19353
|
-
allowMerge:
|
|
19562
|
+
allowMerge: false
|
|
19563
|
+
// Fixed: prevent merging during vertex drag
|
|
19354
19564
|
});
|
|
19355
19565
|
}
|
|
19356
19566
|
}
|
|
@@ -19612,7 +19822,9 @@ class PolygonInteractionManager {
|
|
|
19612
19822
|
}
|
|
19613
19823
|
}
|
|
19614
19824
|
} catch (differenceError) {
|
|
19615
|
-
|
|
19825
|
+
if (!isTestEnvironment()) {
|
|
19826
|
+
console.warn("Failed to perform difference operation:", differenceError);
|
|
19827
|
+
}
|
|
19616
19828
|
this.eventManager.emit("polydraw:polygon:updated", {
|
|
19617
19829
|
operation: "modifierSubtractFallback",
|
|
19618
19830
|
polygon: existingPolygon,
|
|
@@ -19620,12 +19832,16 @@ class PolygonInteractionManager {
|
|
|
19620
19832
|
});
|
|
19621
19833
|
}
|
|
19622
19834
|
} catch (error) {
|
|
19623
|
-
|
|
19835
|
+
if (!isTestEnvironment()) {
|
|
19836
|
+
console.warn("Error in modifier subtract operation:", error);
|
|
19837
|
+
}
|
|
19624
19838
|
}
|
|
19625
19839
|
});
|
|
19626
19840
|
this.polygonInformation.createPolygonInformationStorage(this.getFeatureGroups());
|
|
19627
19841
|
} catch (error) {
|
|
19628
|
-
|
|
19842
|
+
if (!isTestEnvironment()) {
|
|
19843
|
+
console.warn("Error in performModifierSubtract:", error);
|
|
19844
|
+
}
|
|
19629
19845
|
}
|
|
19630
19846
|
}
|
|
19631
19847
|
getEdgeDeletionModifierKey() {
|
|
@@ -19944,10 +20160,12 @@ class PolygonInteractionManager {
|
|
|
19944
20160
|
}
|
|
19945
20161
|
return polygonLayer.toGeoJSON();
|
|
19946
20162
|
} catch (error) {
|
|
19947
|
-
if (
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
20163
|
+
if (!isTestEnvironment()) {
|
|
20164
|
+
if (error instanceof Error) {
|
|
20165
|
+
console.warn("Error getting polygon GeoJSON from feature group:", error.message);
|
|
20166
|
+
} else {
|
|
20167
|
+
console.warn("Error getting polygon GeoJSON from feature group:", error);
|
|
20168
|
+
}
|
|
19951
20169
|
}
|
|
19952
20170
|
return {
|
|
19953
20171
|
type: "Feature",
|
|
@@ -20006,10 +20224,12 @@ class PolygonInteractionManager {
|
|
|
20006
20224
|
}
|
|
20007
20225
|
return totalPerimeter * 1e3;
|
|
20008
20226
|
} catch (error) {
|
|
20009
|
-
if (
|
|
20010
|
-
|
|
20011
|
-
|
|
20012
|
-
|
|
20227
|
+
if (!isTestEnvironment()) {
|
|
20228
|
+
if (error instanceof Error) {
|
|
20229
|
+
console.warn("Error calculating total polygon perimeter:", error.message);
|
|
20230
|
+
} else {
|
|
20231
|
+
console.warn("Error calculating total polygon perimeter:", error);
|
|
20232
|
+
}
|
|
20013
20233
|
}
|
|
20014
20234
|
return this.turfHelper.getPolygonPerimeter(polygonGeoJSON) * 1e3;
|
|
20015
20235
|
}
|
|
@@ -20125,9 +20345,13 @@ class PolygonMutationManager {
|
|
|
20125
20345
|
*/
|
|
20126
20346
|
async handlePolygonModified(data) {
|
|
20127
20347
|
const shouldSimplify = data.operation !== "addVertex" && data.operation !== "markerDrag" && data.operation !== "polygonDrag";
|
|
20348
|
+
let allowMerge = data.allowMerge;
|
|
20349
|
+
if (data.intelligentMerge && data.operation === "markerDrag") {
|
|
20350
|
+
allowMerge = this.shouldAllowIntelligentMerge(data.polygon);
|
|
20351
|
+
}
|
|
20128
20352
|
const options = {
|
|
20129
20353
|
simplify: shouldSimplify,
|
|
20130
|
-
noMerge: !
|
|
20354
|
+
noMerge: !allowMerge,
|
|
20131
20355
|
visualOptimizationLevel: data.optimizationLevel || 0
|
|
20132
20356
|
};
|
|
20133
20357
|
await this.addPolygon(data.polygon, options);
|
|
@@ -20187,6 +20411,10 @@ class PolygonMutationManager {
|
|
|
20187
20411
|
async addPolygon(latlngs, options = {}) {
|
|
20188
20412
|
const { noMerge = false } = options;
|
|
20189
20413
|
try {
|
|
20414
|
+
const isInsideHole = this.isPolygonInsideExistingHole(latlngs);
|
|
20415
|
+
if (isInsideHole) {
|
|
20416
|
+
return await this.addPolygonLayer(latlngs, options);
|
|
20417
|
+
}
|
|
20190
20418
|
if (this.config.mergePolygons && !noMerge && this.getFeatureGroups().length > 0 && !this.config.kinks) {
|
|
20191
20419
|
return await this.mergePolygon(latlngs, options);
|
|
20192
20420
|
} else {
|
|
@@ -20290,19 +20518,7 @@ class PolygonMutationManager {
|
|
|
20290
20518
|
let markerLatlngs;
|
|
20291
20519
|
try {
|
|
20292
20520
|
const rawLatLngs = polygon2.getLatLngs();
|
|
20293
|
-
|
|
20294
|
-
if (Array.isArray(rawLatLngs[0])) {
|
|
20295
|
-
if (Array.isArray(rawLatLngs[0][0])) {
|
|
20296
|
-
markerLatlngs = rawLatLngs[0];
|
|
20297
|
-
} else {
|
|
20298
|
-
markerLatlngs = rawLatLngs;
|
|
20299
|
-
}
|
|
20300
|
-
} else {
|
|
20301
|
-
markerLatlngs = [rawLatLngs];
|
|
20302
|
-
}
|
|
20303
|
-
} else {
|
|
20304
|
-
markerLatlngs = [];
|
|
20305
|
-
}
|
|
20521
|
+
markerLatlngs = this.normalizePolygonCoordinates(rawLatLngs);
|
|
20306
20522
|
} catch (error) {
|
|
20307
20523
|
markerLatlngs = [];
|
|
20308
20524
|
}
|
|
@@ -20326,7 +20542,7 @@ class PolygonMutationManager {
|
|
|
20326
20542
|
if (ringIndex === 0) {
|
|
20327
20543
|
this.interactionManager.addMarkers(latLngLiterals, featureGroup);
|
|
20328
20544
|
} else {
|
|
20329
|
-
const holePolyline = L.polyline(
|
|
20545
|
+
const holePolyline = L.polyline(latLngLiterals, {
|
|
20330
20546
|
color: this.config.colors.hole.border,
|
|
20331
20547
|
weight: this.config.holeOptions.weight || 2,
|
|
20332
20548
|
opacity: this.config.holeOptions.opacity || 1,
|
|
@@ -20459,6 +20675,124 @@ class PolygonMutationManager {
|
|
|
20459
20675
|
};
|
|
20460
20676
|
}
|
|
20461
20677
|
}
|
|
20678
|
+
/**
|
|
20679
|
+
* Determine if intelligent merging should be allowed for a polygon
|
|
20680
|
+
* This checks if the polygon actually intersects with existing polygons
|
|
20681
|
+
*/
|
|
20682
|
+
shouldAllowIntelligentMerge(polygon2) {
|
|
20683
|
+
try {
|
|
20684
|
+
for (const featureGroup of this.getFeatureGroups()) {
|
|
20685
|
+
try {
|
|
20686
|
+
const featureCollection2 = featureGroup.toGeoJSON();
|
|
20687
|
+
if (!featureCollection2 || !featureCollection2.features || !featureCollection2.features[0]) {
|
|
20688
|
+
continue;
|
|
20689
|
+
}
|
|
20690
|
+
const existingFeature = featureCollection2.features[0];
|
|
20691
|
+
if (!existingFeature.geometry || !existingFeature.geometry.coordinates) {
|
|
20692
|
+
continue;
|
|
20693
|
+
}
|
|
20694
|
+
const existingPolygon = this.turfHelper.getTurfPolygon(existingFeature);
|
|
20695
|
+
if (this.geometryManager.checkPolygonIntersection(existingPolygon, polygon2)) {
|
|
20696
|
+
return true;
|
|
20697
|
+
}
|
|
20698
|
+
} catch (error) {
|
|
20699
|
+
continue;
|
|
20700
|
+
}
|
|
20701
|
+
}
|
|
20702
|
+
return false;
|
|
20703
|
+
} catch (error) {
|
|
20704
|
+
return false;
|
|
20705
|
+
}
|
|
20706
|
+
}
|
|
20707
|
+
/**
|
|
20708
|
+
* Check if a polygon is completely inside a hole of an existing polygon
|
|
20709
|
+
* This prevents incorrect merging when drawing polygons inside holes
|
|
20710
|
+
*/
|
|
20711
|
+
isPolygonInsideExistingHole(newPolygon) {
|
|
20712
|
+
try {
|
|
20713
|
+
for (const featureGroup of this.getFeatureGroups()) {
|
|
20714
|
+
try {
|
|
20715
|
+
const featureCollection2 = featureGroup.toGeoJSON();
|
|
20716
|
+
if (!featureCollection2 || !featureCollection2.features || !featureCollection2.features[0]) {
|
|
20717
|
+
continue;
|
|
20718
|
+
}
|
|
20719
|
+
const existingFeature = featureCollection2.features[0];
|
|
20720
|
+
if (!existingFeature.geometry || !existingFeature.geometry.coordinates) {
|
|
20721
|
+
continue;
|
|
20722
|
+
}
|
|
20723
|
+
let hasHoles = false;
|
|
20724
|
+
let holes = [];
|
|
20725
|
+
if (existingFeature.geometry.type === "Polygon") {
|
|
20726
|
+
hasHoles = existingFeature.geometry.coordinates.length > 1;
|
|
20727
|
+
if (hasHoles) {
|
|
20728
|
+
holes = existingFeature.geometry.coordinates.slice(1);
|
|
20729
|
+
}
|
|
20730
|
+
} else if (existingFeature.geometry.type === "MultiPolygon") {
|
|
20731
|
+
for (const polygonCoords of existingFeature.geometry.coordinates) {
|
|
20732
|
+
if (polygonCoords.length > 1) {
|
|
20733
|
+
hasHoles = true;
|
|
20734
|
+
holes.push(...polygonCoords.slice(1));
|
|
20735
|
+
}
|
|
20736
|
+
}
|
|
20737
|
+
}
|
|
20738
|
+
if (hasHoles && holes.length > 0) {
|
|
20739
|
+
for (const holeCoords of holes) {
|
|
20740
|
+
try {
|
|
20741
|
+
const holePolygon = this.turfHelper.createPolygon([holeCoords]);
|
|
20742
|
+
if (this.turfHelper.isPolygonCompletelyWithin(newPolygon, holePolygon)) {
|
|
20743
|
+
return true;
|
|
20744
|
+
}
|
|
20745
|
+
} catch (error) {
|
|
20746
|
+
continue;
|
|
20747
|
+
}
|
|
20748
|
+
}
|
|
20749
|
+
}
|
|
20750
|
+
} catch (error) {
|
|
20751
|
+
continue;
|
|
20752
|
+
}
|
|
20753
|
+
}
|
|
20754
|
+
return false;
|
|
20755
|
+
} catch (error) {
|
|
20756
|
+
return false;
|
|
20757
|
+
}
|
|
20758
|
+
}
|
|
20759
|
+
/**
|
|
20760
|
+
* Normalize polygon coordinates to handle complex nested structures
|
|
20761
|
+
* This fixes the bug where markers are missing when drawing polygons inside holes
|
|
20762
|
+
*/
|
|
20763
|
+
normalizePolygonCoordinates(rawLatLngs) {
|
|
20764
|
+
if (!Array.isArray(rawLatLngs) || rawLatLngs.length === 0) {
|
|
20765
|
+
return [];
|
|
20766
|
+
}
|
|
20767
|
+
const isLatLngLike = (obj) => {
|
|
20768
|
+
return obj !== null && typeof obj === "object" && "lat" in obj && "lng" in obj && typeof obj.lat === "number" && typeof obj.lng === "number";
|
|
20769
|
+
};
|
|
20770
|
+
const flattenToRings = (coords) => {
|
|
20771
|
+
if (!Array.isArray(coords)) {
|
|
20772
|
+
return [];
|
|
20773
|
+
}
|
|
20774
|
+
if (coords.length > 0 && isLatLngLike(coords[0])) {
|
|
20775
|
+
return [coords];
|
|
20776
|
+
}
|
|
20777
|
+
const result = [];
|
|
20778
|
+
for (const item of coords) {
|
|
20779
|
+
if (Array.isArray(item)) {
|
|
20780
|
+
if (item.length > 0 && isLatLngLike(item[0])) {
|
|
20781
|
+
result.push(item);
|
|
20782
|
+
} else {
|
|
20783
|
+
const flattened = flattenToRings(item);
|
|
20784
|
+
result.push(...flattened);
|
|
20785
|
+
}
|
|
20786
|
+
}
|
|
20787
|
+
}
|
|
20788
|
+
return result;
|
|
20789
|
+
};
|
|
20790
|
+
try {
|
|
20791
|
+
return flattenToRings(rawLatLngs);
|
|
20792
|
+
} catch (error) {
|
|
20793
|
+
return [];
|
|
20794
|
+
}
|
|
20795
|
+
}
|
|
20462
20796
|
/**
|
|
20463
20797
|
* Create a polygon from GeoJSON feature
|
|
20464
20798
|
*/
|
|
@@ -20479,11 +20813,16 @@ class PolygonMutationManager {
|
|
|
20479
20813
|
*/
|
|
20480
20814
|
getPolygon(latlngs) {
|
|
20481
20815
|
const polygon2 = L.GeoJSON.geometryToLayer(latlngs);
|
|
20482
|
-
|
|
20816
|
+
const polygonStyle = {
|
|
20483
20817
|
...this.config.polygonOptions,
|
|
20484
20818
|
color: this.config.colors.polygon.border,
|
|
20485
|
-
fillColor: this.config.colors.polygon.fill
|
|
20486
|
-
|
|
20819
|
+
fillColor: this.config.colors.polygon.fill,
|
|
20820
|
+
// Force these values to ensure they override any default styling
|
|
20821
|
+
weight: this.config.polygonOptions.weight || 2,
|
|
20822
|
+
opacity: this.config.polygonOptions.opacity || 1,
|
|
20823
|
+
fillOpacity: this.config.polygonOptions.fillOpacity || 0.2
|
|
20824
|
+
};
|
|
20825
|
+
polygon2.setStyle(polygonStyle);
|
|
20487
20826
|
polygon2._polydrawUniqueId = L.Util.stamp(polygon2) + "_" + Date.now();
|
|
20488
20827
|
delete polygon2._polydrawDragData;
|
|
20489
20828
|
delete polygon2._polydrawOriginalLatLngs;
|
|
@@ -20529,8 +20868,10 @@ class PolygonMutationManager {
|
|
|
20529
20868
|
}
|
|
20530
20869
|
return polygon2.toGeoJSON();
|
|
20531
20870
|
} catch (error) {
|
|
20532
|
-
if (
|
|
20533
|
-
|
|
20871
|
+
if (!isTestEnvironment()) {
|
|
20872
|
+
if (error instanceof Error) {
|
|
20873
|
+
console.warn("Error getting complete polygon GeoJSON from feature group:", error.message);
|
|
20874
|
+
}
|
|
20534
20875
|
}
|
|
20535
20876
|
return {
|
|
20536
20877
|
type: "Feature",
|
|
@@ -21093,10 +21434,15 @@ class Polydraw extends L.Control {
|
|
|
21093
21434
|
L.DomEvent.on(container, "click", L.DomEvent.stopPropagation);
|
|
21094
21435
|
container.style.display = "flex";
|
|
21095
21436
|
container.style.flexDirection = "column-reverse";
|
|
21437
|
+
container.style.pointerEvents = "auto";
|
|
21438
|
+
container.style.position = "relative";
|
|
21439
|
+
container.style.zIndex = "1000";
|
|
21096
21440
|
this.subContainer = L.DomUtil.create("div", "sub-buttons", container);
|
|
21097
21441
|
this.subContainer.style.maxHeight = "0px";
|
|
21098
21442
|
this.subContainer.style.overflow = "hidden";
|
|
21099
21443
|
this.subContainer.style.transition = "max-height 0.3s ease";
|
|
21444
|
+
this.subContainer.style.pointerEvents = "auto";
|
|
21445
|
+
this.subContainer.style.position = "relative";
|
|
21100
21446
|
createButtons(
|
|
21101
21447
|
container,
|
|
21102
21448
|
this.subContainer,
|
|
@@ -21107,6 +21453,7 @@ class Polydraw extends L.Control {
|
|
|
21107
21453
|
this._handleEraseClick,
|
|
21108
21454
|
this._handlePointToPointClick
|
|
21109
21455
|
);
|
|
21456
|
+
this.ensureButtonTouchResponsiveness(container);
|
|
21110
21457
|
const uiUpdateListener = (mode) => {
|
|
21111
21458
|
const drawButton = container.querySelector(".icon-draw");
|
|
21112
21459
|
const subtractButton = container.querySelector(".icon-subtract");
|
|
@@ -21345,9 +21692,21 @@ class Polydraw extends L.Control {
|
|
|
21345
21692
|
* @param enableScrollWheelZoom - Whether to enable scroll wheel zoom.
|
|
21346
21693
|
*/
|
|
21347
21694
|
setLeafletMapEvents(enableDragging, enableDoubleClickZoom, enableScrollWheelZoom) {
|
|
21348
|
-
|
|
21349
|
-
|
|
21350
|
-
|
|
21695
|
+
if (enableDragging) {
|
|
21696
|
+
this.map.dragging.enable();
|
|
21697
|
+
} else {
|
|
21698
|
+
this.map.dragging.disable();
|
|
21699
|
+
}
|
|
21700
|
+
if (enableDoubleClickZoom) {
|
|
21701
|
+
this.map.doubleClickZoom.enable();
|
|
21702
|
+
} else {
|
|
21703
|
+
this.map.doubleClickZoom.disable();
|
|
21704
|
+
}
|
|
21705
|
+
if (enableScrollWheelZoom) {
|
|
21706
|
+
this.map.scrollWheelZoom.enable();
|
|
21707
|
+
} else {
|
|
21708
|
+
this.map.scrollWheelZoom.disable();
|
|
21709
|
+
}
|
|
21351
21710
|
}
|
|
21352
21711
|
/**
|
|
21353
21712
|
* Resets the tracer polyline by clearing its LatLngs.
|
|
@@ -21409,9 +21768,10 @@ class Polydraw extends L.Control {
|
|
|
21409
21768
|
if ("latlng" in event && event.latlng) {
|
|
21410
21769
|
clickLatLng = event.latlng;
|
|
21411
21770
|
} else if ("touches" in event && event.touches && event.touches.length > 0) {
|
|
21771
|
+
const rect = this.map.getContainer().getBoundingClientRect();
|
|
21412
21772
|
clickLatLng = this.map.containerPointToLatLng([
|
|
21413
|
-
event.touches[0].clientX,
|
|
21414
|
-
event.touches[0].clientY
|
|
21773
|
+
event.touches[0].clientX - rect.x,
|
|
21774
|
+
event.touches[0].clientY - rect.y
|
|
21415
21775
|
]);
|
|
21416
21776
|
}
|
|
21417
21777
|
if (!clickLatLng) {
|
|
@@ -21435,9 +21795,10 @@ class Polydraw extends L.Control {
|
|
|
21435
21795
|
if ("latlng" in event && event.latlng) {
|
|
21436
21796
|
this.tracer.addLatLng(event.latlng);
|
|
21437
21797
|
} else if ("touches" in event && event.touches && event.touches.length > 0) {
|
|
21798
|
+
const rect = this.map.getContainer().getBoundingClientRect();
|
|
21438
21799
|
const latlng = this.map.containerPointToLatLng([
|
|
21439
|
-
event.touches[0].clientX,
|
|
21440
|
-
event.touches[0].clientY
|
|
21800
|
+
event.touches[0].clientX - rect.x,
|
|
21801
|
+
event.touches[0].clientY - rect.y
|
|
21441
21802
|
]);
|
|
21442
21803
|
this.tracer.addLatLng(latlng);
|
|
21443
21804
|
}
|
|
@@ -21626,6 +21987,25 @@ class Polydraw extends L.Control {
|
|
|
21626
21987
|
return event.ctrlKey;
|
|
21627
21988
|
}
|
|
21628
21989
|
}
|
|
21990
|
+
/**
|
|
21991
|
+
* Ensures all buttons have proper touch responsiveness for Firefox Android
|
|
21992
|
+
* @param container - The main control container element
|
|
21993
|
+
*/
|
|
21994
|
+
ensureButtonTouchResponsiveness(container) {
|
|
21995
|
+
const buttons = container.querySelectorAll("a");
|
|
21996
|
+
buttons.forEach((button) => {
|
|
21997
|
+
button.style.pointerEvents = "auto";
|
|
21998
|
+
button.style.touchAction = "manipulation";
|
|
21999
|
+
button.style.position = "relative";
|
|
22000
|
+
button.style.zIndex = "1";
|
|
22001
|
+
const touchHandler = (e) => {
|
|
22002
|
+
e.stopPropagation();
|
|
22003
|
+
e.target.style.pointerEvents = "auto";
|
|
22004
|
+
};
|
|
22005
|
+
button.addEventListener("touchstart", touchHandler, { passive: true });
|
|
22006
|
+
button.addEventListener("touchend", touchHandler, { passive: true });
|
|
22007
|
+
});
|
|
22008
|
+
}
|
|
21629
22009
|
/**
|
|
21630
22010
|
* Updates the visual indicator on the activate button to show if there are active polygons.
|
|
21631
22011
|
*/
|