@osimatic/helpers-js 1.4.7 → 1.4.9
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/location.js +102 -3
- package/open_street_map.js +3 -3
- package/package.json +1 -1
package/location.js
CHANGED
|
@@ -447,8 +447,8 @@ class Polygon {
|
|
|
447
447
|
const more = ring0.length > maxShow ? ` … (+${ring0.length - maxShow} sommets)` : '';
|
|
448
448
|
|
|
449
449
|
return {
|
|
450
|
-
label: `Polygon
|
|
451
|
-
title: `Sommets: ${concise}${more}`
|
|
450
|
+
label: `Polygon de ${n} sommets (départ : ${GeographicCoordinates.format(firstLat, firstLon)})`,
|
|
451
|
+
title: `Sommets : ${concise}${more}`
|
|
452
452
|
};
|
|
453
453
|
}
|
|
454
454
|
|
|
@@ -466,12 +466,85 @@ class Polygon {
|
|
|
466
466
|
if (r.length >= 3) {
|
|
467
467
|
const [lon0,lat0] = r[0];
|
|
468
468
|
const [lonL,latL] = r[r.length-1];
|
|
469
|
-
if (lon0 !== lonL || lat0 !== latL)
|
|
469
|
+
if (lon0 !== lonL || lat0 !== latL) {
|
|
470
|
+
r.push([lon0,lat0]);
|
|
471
|
+
}
|
|
470
472
|
}
|
|
471
473
|
return r;
|
|
472
474
|
});
|
|
473
475
|
return { type: 'Polygon', coordinates: rings };
|
|
474
476
|
}
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
// Test "sur le segment" en degrés (plan local) — suffisant pour le bord du polygone
|
|
480
|
+
static isPointOnSegmentDeg(lat, lon, A, B, EPS = 1e-12) {
|
|
481
|
+
const [x, y ] = [lon, lat];
|
|
482
|
+
const [x1, y1] = A; // A = [lon,lat]
|
|
483
|
+
const [x2, y2] = B; // B = [lon,lat]
|
|
484
|
+
const cross = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1);
|
|
485
|
+
if (Math.abs(cross) > EPS) {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const dot = (x - x1)*(x2 - x1) + (y - y1)*(y2 - y1);
|
|
490
|
+
if (dot < -EPS) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const len2 = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1);
|
|
495
|
+
return dot - len2 <= EPS;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Ray-casting + bords inclus pour un anneau (tableau de [lon,lat])
|
|
499
|
+
static isPointInRing(lat, lon, ring) {
|
|
500
|
+
const n0 = ring.length;
|
|
501
|
+
if (n0 < 3) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// fermer si nécessaire
|
|
506
|
+
const closed = ring[n0-1][0] === ring[0][0] && ring[n0-1][1] === ring[0][1];
|
|
507
|
+
const pts = closed ? ring : [...ring, ring[0]];
|
|
508
|
+
const n = pts.length;
|
|
509
|
+
|
|
510
|
+
// bord inclus
|
|
511
|
+
for (let i = 0; i < n - 1; i++) {
|
|
512
|
+
if (Polygon.isPointOnSegmentDeg(lat, lon, pts[i], pts[i+1])) {
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ray casting (x=lon, y=lat)
|
|
518
|
+
let inside = false;
|
|
519
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
520
|
+
const [xi, yi] = pts[i];
|
|
521
|
+
const [xj, yj] = pts[j];
|
|
522
|
+
const intersect = ((yi > lat) !== (yj > lat)) &&
|
|
523
|
+
(lon < ( (xj - xi) * (lat - yi) / ((yj - yi) || 1e-20) + xi ));
|
|
524
|
+
if (intersect) inside = !inside;
|
|
525
|
+
}
|
|
526
|
+
return inside;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Polygone avec trous: inside = dans outer ET pas dans un trou
|
|
530
|
+
static isPointInPolygon(lat, lon, geoJsonPolygon) {
|
|
531
|
+
const rings = geoJsonPolygon.coordinates;
|
|
532
|
+
if (!Array.isArray(rings) || rings.length === 0) {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (!Polygon.isPointInRing(lat, lon, rings[0])) {
|
|
537
|
+
return false; // outer
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
for (let k = 1; k < rings.length; k++) {
|
|
541
|
+
if (Polygon.isPointInRing(lat, lon, rings[k])) {
|
|
542
|
+
return false; // dans un trou
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
475
548
|
}
|
|
476
549
|
|
|
477
550
|
class GeographicCoordinates {
|
|
@@ -553,6 +626,32 @@ class GeographicCoordinates {
|
|
|
553
626
|
return arr;
|
|
554
627
|
}
|
|
555
628
|
|
|
629
|
+
static isPointCorrespondingToLocationsList(lat, lon, locationsList, tolMeters = 1.0) {
|
|
630
|
+
for (const it of locationsList) {
|
|
631
|
+
if (!it) {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (typeof it === 'string') {
|
|
636
|
+
const p = GeographicCoordinates.parse(it);
|
|
637
|
+
if (p && GeographicCoordinates.haversine(lat,lon,p[0],p[1]) <= tolMeters) {
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
else if (it.type === 'Point') {
|
|
642
|
+
const p = it.coordinates || [];
|
|
643
|
+
if (p && GeographicCoordinates.haversine(lat,lon,p[1],p[0]) <= tolMeters) {
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (it.type === 'Polygon' && Array.isArray(it.coordinates)) {
|
|
648
|
+
if (Polygon.isPointInPolygon(lat, lon, it)) {
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
556
655
|
|
|
557
656
|
static haversine(lat1, long1, lat2, long2) {
|
|
558
657
|
const R = 6371000;
|
package/open_street_map.js
CHANGED
|
@@ -125,7 +125,7 @@ class OpenStreetMap {
|
|
|
125
125
|
OpenStreetMap.centerMapToLocations(this.map, this.locations, padding);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
static centerMapToLocations(map, locationsList, padding=[20,20]) {
|
|
128
|
+
static centerMapToLocations(map, locationsList, padding=[20,20], maxZoom=18) {
|
|
129
129
|
if (!map || locationsList.length === 0) {
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
@@ -134,8 +134,8 @@ class OpenStreetMap {
|
|
|
134
134
|
|
|
135
135
|
const bounds = L.latLngBounds(locationsList);
|
|
136
136
|
map.fitBounds(bounds, { padding: padding });
|
|
137
|
-
if (map.getZoom() >
|
|
138
|
-
map.setZoom(
|
|
137
|
+
if (map.getZoom() > maxZoom) {
|
|
138
|
+
map.setZoom(maxZoom);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|