@osimatic/helpers-js 1.4.14 → 1.4.16
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 +45 -46
- package/package.json +1 -1
package/location.js
CHANGED
|
@@ -429,9 +429,7 @@ class PostalAddress {
|
|
|
429
429
|
|
|
430
430
|
class Polygon {
|
|
431
431
|
static format(geoJsonPolygon) {
|
|
432
|
-
|
|
433
|
-
geoJsonPolygon = JSON.parse(geoJsonPolygon);
|
|
434
|
-
}
|
|
432
|
+
geoJsonPolygon = typeof geoJsonPolygon == 'string' ? JSON.parse(geoJsonPolygon) : geoJsonPolygon;
|
|
435
433
|
|
|
436
434
|
const rings = geoJsonPolygon.coordinates || [];
|
|
437
435
|
const ring0 = rings[0] || [];
|
|
@@ -443,7 +441,7 @@ class Polygon {
|
|
|
443
441
|
const [firstLon, firstLat] = ring0[0];
|
|
444
442
|
|
|
445
443
|
const maxShow = Math.min(5, ring0.length);
|
|
446
|
-
const concise = ring0.slice(0, maxShow).map(([
|
|
444
|
+
const concise = ring0.slice(0, maxShow).map(([long,lat]) => GeographicCoordinates.format(lat, long)).join(' · ');
|
|
447
445
|
const more = ring0.length > maxShow ? ` … (+${ring0.length - maxShow} sommets)` : '';
|
|
448
446
|
|
|
449
447
|
return {
|
|
@@ -452,10 +450,8 @@ class Polygon {
|
|
|
452
450
|
};
|
|
453
451
|
}
|
|
454
452
|
|
|
455
|
-
static getStartCoordinates(geoJsonPolygon) {
|
|
456
|
-
|
|
457
|
-
geoJsonPolygon = JSON.parse(geoJsonPolygon);
|
|
458
|
-
}
|
|
453
|
+
static getStartCoordinates(geoJsonPolygon, asString=false) {
|
|
454
|
+
geoJsonPolygon = typeof geoJsonPolygon == 'string' ? JSON.parse(geoJsonPolygon) : geoJsonPolygon;
|
|
459
455
|
|
|
460
456
|
const rings = geoJsonPolygon.coordinates || [];
|
|
461
457
|
const ring0 = rings[0] || [];
|
|
@@ -464,7 +460,7 @@ class Polygon {
|
|
|
464
460
|
}
|
|
465
461
|
|
|
466
462
|
const [firstLon, firstLat] = ring0[0];
|
|
467
|
-
return [firstLat, firstLon];
|
|
463
|
+
return asString ? str.join(',') : [firstLat, firstLon];
|
|
468
464
|
}
|
|
469
465
|
|
|
470
466
|
static convertToGeoJson(latlngs) {
|
|
@@ -491,16 +487,14 @@ class Polygon {
|
|
|
491
487
|
}
|
|
492
488
|
|
|
493
489
|
static toLatLngRings(geoJsonPolygon) {
|
|
494
|
-
|
|
495
|
-
geoJsonPolygon = JSON.parse(geoJsonPolygon);
|
|
496
|
-
}
|
|
490
|
+
geoJsonPolygon = typeof geoJsonPolygon == 'string' ? JSON.parse(geoJsonPolygon) : geoJsonPolygon;
|
|
497
491
|
|
|
498
492
|
const polygonCoords = geoJsonPolygon.coordinates;
|
|
499
493
|
if (!Array.isArray(polygonCoords) || polygonCoords.length === 0) {
|
|
500
494
|
return false;
|
|
501
495
|
}
|
|
502
496
|
|
|
503
|
-
// polygonCoords: [ [ [
|
|
497
|
+
// polygonCoords: [ [ [long,lat], ... ] , ... ]
|
|
504
498
|
const rings = [];
|
|
505
499
|
for (const ring of polygonCoords) {
|
|
506
500
|
const latlngRing = [];
|
|
@@ -508,8 +502,8 @@ class Polygon {
|
|
|
508
502
|
if (!Array.isArray(coord) || coord.length < 2) {
|
|
509
503
|
continue;
|
|
510
504
|
}
|
|
511
|
-
const [
|
|
512
|
-
latlngRing.push([lat,
|
|
505
|
+
const [long, lat] = coord;
|
|
506
|
+
latlngRing.push([lat, long]);
|
|
513
507
|
}
|
|
514
508
|
if (latlngRing.length > 0) {
|
|
515
509
|
// Fermer l'anneau si nécessaire (Leaflet accepte ouvert/fermé, on nettoie par sécurité)
|
|
@@ -526,10 +520,10 @@ class Polygon {
|
|
|
526
520
|
|
|
527
521
|
|
|
528
522
|
// Test "sur le segment" en degrés (plan local) — suffisant pour le bord du polygone
|
|
529
|
-
static isPointOnSegmentDeg(lat,
|
|
530
|
-
const [x, y ] = [
|
|
531
|
-
const [x1, y1] = A; // A = [
|
|
532
|
-
const [x2, y2] = B; // B = [
|
|
523
|
+
static isPointOnSegmentDeg(lat, long, A, B, EPS = 1e-12) {
|
|
524
|
+
const [x, y ] = [long, lat];
|
|
525
|
+
const [x1, y1] = A; // A = [long,lat]
|
|
526
|
+
const [x2, y2] = B; // B = [long,lat]
|
|
533
527
|
const cross = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1);
|
|
534
528
|
if (Math.abs(cross) > EPS) {
|
|
535
529
|
return false;
|
|
@@ -544,8 +538,8 @@ class Polygon {
|
|
|
544
538
|
return dot - len2 <= EPS;
|
|
545
539
|
}
|
|
546
540
|
|
|
547
|
-
// Ray-casting + bords inclus pour un anneau (tableau de [
|
|
548
|
-
static isPointInRing(lat,
|
|
541
|
+
// Ray-casting + bords inclus pour un anneau (tableau de [long,lat])
|
|
542
|
+
static isPointInRing(lat, long, ring) {
|
|
549
543
|
const n0 = ring.length;
|
|
550
544
|
if (n0 < 3) {
|
|
551
545
|
return false;
|
|
@@ -558,36 +552,36 @@ class Polygon {
|
|
|
558
552
|
|
|
559
553
|
// bord inclus
|
|
560
554
|
for (let i = 0; i < n - 1; i++) {
|
|
561
|
-
if (Polygon.isPointOnSegmentDeg(lat,
|
|
555
|
+
if (Polygon.isPointOnSegmentDeg(lat, long, pts[i], pts[i+1])) {
|
|
562
556
|
return true;
|
|
563
557
|
}
|
|
564
558
|
}
|
|
565
559
|
|
|
566
|
-
// ray casting (x=
|
|
560
|
+
// ray casting (x=long, y=lat)
|
|
567
561
|
let inside = false;
|
|
568
562
|
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
569
563
|
const [xi, yi] = pts[i];
|
|
570
564
|
const [xj, yj] = pts[j];
|
|
571
565
|
const intersect = ((yi > lat) !== (yj > lat)) &&
|
|
572
|
-
(
|
|
566
|
+
(long < ( (xj - xi) * (lat - yi) / ((yj - yi) || 1e-20) + xi ));
|
|
573
567
|
if (intersect) inside = !inside;
|
|
574
568
|
}
|
|
575
569
|
return inside;
|
|
576
570
|
}
|
|
577
571
|
|
|
578
572
|
// Polygone avec trous: inside = dans outer ET pas dans un trou
|
|
579
|
-
static isPointInPolygon(lat,
|
|
573
|
+
static isPointInPolygon(lat, long, geoJsonPolygon) {
|
|
580
574
|
const rings = geoJsonPolygon.coordinates;
|
|
581
575
|
if (!Array.isArray(rings) || rings.length === 0) {
|
|
582
576
|
return false;
|
|
583
577
|
}
|
|
584
578
|
|
|
585
|
-
if (!Polygon.isPointInRing(lat,
|
|
579
|
+
if (!Polygon.isPointInRing(lat, long, rings[0])) {
|
|
586
580
|
return false; // outer
|
|
587
581
|
}
|
|
588
582
|
|
|
589
583
|
for (let k = 1; k < rings.length; k++) {
|
|
590
|
-
if (Polygon.isPointInRing(lat,
|
|
584
|
+
if (Polygon.isPointInRing(lat, long, rings[k])) {
|
|
591
585
|
return false; // dans un trou
|
|
592
586
|
}
|
|
593
587
|
}
|
|
@@ -614,12 +608,12 @@ class GeographicCoordinates {
|
|
|
614
608
|
}
|
|
615
609
|
|
|
616
610
|
const lat = parseFloat(parts[0]);
|
|
617
|
-
const
|
|
618
|
-
if (!isFinite(lat) || !isFinite(
|
|
611
|
+
const long = parseFloat(parts[1]);
|
|
612
|
+
if (!isFinite(lat) || !isFinite(long)) {
|
|
619
613
|
return null;
|
|
620
614
|
}
|
|
621
615
|
|
|
622
|
-
return asString ? str.join(',') : [lat,
|
|
616
|
+
return asString ? str.join(',') : [lat, long];
|
|
623
617
|
}
|
|
624
618
|
|
|
625
619
|
static toFixed(latOrLong, fractionDigit=6) {
|
|
@@ -631,11 +625,7 @@ class GeographicCoordinates {
|
|
|
631
625
|
}
|
|
632
626
|
|
|
633
627
|
static formatPoint(geoJsonPoint, fractionDigit=6) {
|
|
634
|
-
|
|
635
|
-
geoJsonPoint = JSON.parse(geoJsonPoint);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const [long, lat] = geoJsonPoint.coordinates || [];
|
|
628
|
+
const [long, lat] = GeographicCoordinates.parseFromGeoJson(geoJsonPoint);
|
|
639
629
|
if (typeof long == 'undefined' || typeof lat == 'undefined') {
|
|
640
630
|
return '';
|
|
641
631
|
}
|
|
@@ -646,11 +636,20 @@ class GeographicCoordinates {
|
|
|
646
636
|
return { type: 'Point', coordinates: [Number(long), Number(lat)] };
|
|
647
637
|
}
|
|
648
638
|
|
|
649
|
-
static
|
|
650
|
-
|
|
651
|
-
|
|
639
|
+
static parseFromGeoJson(geoJsonPoint, asString=false) {
|
|
640
|
+
geoJsonPoint = typeof geoJsonPoint == 'string' ? JSON.parse(geoJsonPoint) : geoJsonPoint;
|
|
641
|
+
|
|
642
|
+
const [long, lat] = geoJsonPoint.coordinates || [];
|
|
643
|
+
if (typeof long == 'undefined' || typeof lat == 'undefined') {
|
|
644
|
+
return null;
|
|
652
645
|
}
|
|
653
646
|
|
|
647
|
+
return asString ? str.join(',') : [lat, long];
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
static getAllLatLongsFromGeoJsonList(geoJsonList) {
|
|
651
|
+
geoJsonList = typeof geoJsonList == 'string' ? JSON.parse(geoJsonList) : geoJsonList;
|
|
652
|
+
|
|
654
653
|
const arr = [];
|
|
655
654
|
for (const geoJsonItem of geoJsonList) {
|
|
656
655
|
if (!geoJsonItem) {
|
|
@@ -658,15 +657,15 @@ class GeographicCoordinates {
|
|
|
658
657
|
}
|
|
659
658
|
|
|
660
659
|
if (geoJsonItem.type === 'Point') {
|
|
661
|
-
const [
|
|
662
|
-
arr.push([lat,
|
|
660
|
+
const [long, lat] = geoJsonItem.coordinates || [];
|
|
661
|
+
arr.push([lat, long]);
|
|
663
662
|
continue;
|
|
664
663
|
}
|
|
665
664
|
|
|
666
665
|
if (geoJsonItem.type === 'Polygon') {
|
|
667
666
|
for (const ring of geoJsonItem.coordinates || []) {
|
|
668
|
-
for (const [
|
|
669
|
-
arr.push([lat,
|
|
667
|
+
for (const [long,lat] of ring) {
|
|
668
|
+
arr.push([lat, long]);
|
|
670
669
|
}
|
|
671
670
|
}
|
|
672
671
|
continue;
|
|
@@ -676,7 +675,7 @@ class GeographicCoordinates {
|
|
|
676
675
|
return arr;
|
|
677
676
|
}
|
|
678
677
|
|
|
679
|
-
static isPointCorrespondingToLocationsList(lat,
|
|
678
|
+
static isPointCorrespondingToLocationsList(lat, long, locationsList, tolMeters = 1.0) {
|
|
680
679
|
for (const it of locationsList) {
|
|
681
680
|
if (!it) {
|
|
682
681
|
continue;
|
|
@@ -684,18 +683,18 @@ class GeographicCoordinates {
|
|
|
684
683
|
|
|
685
684
|
if (typeof it === 'string') {
|
|
686
685
|
const p = GeographicCoordinates.parse(it);
|
|
687
|
-
if (p && GeographicCoordinates.haversine(lat,
|
|
686
|
+
if (p && GeographicCoordinates.haversine(lat,long,p[0],p[1]) <= tolMeters) {
|
|
688
687
|
return true;
|
|
689
688
|
}
|
|
690
689
|
}
|
|
691
690
|
else if (it.type === 'Point') {
|
|
692
691
|
const p = it.coordinates || [];
|
|
693
|
-
if (p && GeographicCoordinates.haversine(lat,
|
|
692
|
+
if (p && GeographicCoordinates.haversine(lat,long,p[1],p[0]) <= tolMeters) {
|
|
694
693
|
return true;
|
|
695
694
|
}
|
|
696
695
|
}
|
|
697
696
|
else if (it.type === 'Polygon' && Array.isArray(it.coordinates)) {
|
|
698
|
-
if (Polygon.isPointInPolygon(lat,
|
|
697
|
+
if (Polygon.isPointInPolygon(lat, long, it)) {
|
|
699
698
|
return true;
|
|
700
699
|
}
|
|
701
700
|
}
|