EDIT: Voir le violon de ghybs dans le commentaire ci-dessus pour une solution plus simple et meilleure en utilisant turf.js. La réponse originale suit:
Voici une version modifiée de la routine d'intersection de la bibliothèque geojson-js-utils qui prend les lignes de ligne GeoJSON en entrée et produit les points GeoJSON de leur intersection en sortie:
function lineStringsIntersect(l1, l2) {
var intersects = [];
for (var i = 0; i <= l1.coordinates.length - 2; ++i) {
for (var j = 0; j <= l2.coordinates.length - 2; ++j) {
var a1Latlon = L.latLng(l1.coordinates[i][1], l1.coordinates[i][0]),
a2Latlon = L.latLng(l1.coordinates[i + 1][1], l1.coordinates[i + 1][0]),
b1Latlon = L.latLng(l2.coordinates[j][1], l2.coordinates[j][0]),
b2Latlon = L.latLng(l2.coordinates[j + 1][1], l2.coordinates[j + 1][0]),
a1 = L.Projection.SphericalMercator.project(a1Latlon),
a2 = L.Projection.SphericalMercator.project(a2Latlon),
b1 = L.Projection.SphericalMercator.project(b1Latlon),
b2 = L.Projection.SphericalMercator.project(b2Latlon),
ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),
ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),
u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
if (u_b != 0) {
var ua = ua_t / u_b,
ub = ub_t / u_b;
if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
var pt_x = a1.x + ua * (a2.x - a1.x),
pt_y = a1.y + ua * (a2.y - a1.y),
pt_xy = {"x": pt_x, "y": pt_y},
pt_latlon = L.Projection.SphericalMercator.unproject(pt_xy);
intersects.push({
'type': 'Point',
'coordinates': [pt_latlon.lng, pt_latlon.lat]
});
}
}
}
}
if (intersects.length == 0) intersects = false;
return intersects;
}
Les modifications étaient nécessaires parce que la fonction d'origine calculait les intersections à partir de la latitude et de la longitude seules, comme si elles n'étaient que des coordonnées sur un plan, produisant des résultats inexacts (en particulier à des latitudes élevées ou sur de longues distances). L'utilisation L.Projection
de la conversion en système de coordonnées projeté conforme (ou, dans ce cas, presque conforme ) pendant le calcul corrige ce problème.
On pourrait le modifier davantage pour accepter les objets de géométrie Leaflet au lieu de simplement LineStrings, mais à la place, j'ai utilisé cette fonction plutôt lourde pour créer des LineStrings à passer à la fonction d'intersection:
function lineify(inputGeom) {
var outputLines = {
"type": "GeometryCollection",
"geometries": []
}
switch (inputGeom.type) {
case "GeometryCollection":
for (var i in inputGeom.geometries) {
var geomLines = lineify(inputGeom.geometries[i]);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
}
break;
case "Feature":
var geomLines = lineify(inputGeom.geometry);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
break;
case "FeatureCollection":
for (var i in inputGeom.features) {
var geomLines = lineify(inputGeom.features[i].geometry);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
}
break;
case "LineString":
outputLines.geometries.push(inputGeom);
break;
case "MultiLineString":
case "Polygon":
for (var i in inputGeom.coordinates) {
outputLines.geometries.push({
"type": "LineString",
"coordinates": inputGeom.coordinates[i]
});
}
break;
case "MultiPolygon":
for (var i in inputGeom.coordinates) {
for (var j in inputGeom.coordinates[i]) {
outputLines.geometries.push({
"type": "LineString",
"coordinates": inputGeom.coordinates[i][j]
});
}
}
break;
default:
outputLines = false;
}
return outputLines;
}
et cette fonction pour prendre des objets Leaflet, les convertir en LineStrings et vérifier les intersections:
function crossCheck(baseLayer, drawLayer) {
var baseJson = baseLayer.toGeoJSON(),
drawJson = drawLayer.toGeoJSON(),
baseLines = lineify(baseJson),
drawLines = lineify(drawJson),
crossPoints = {
type: "GeometryCollection",
geometries: []
};
if (baseLines && drawLines) {
for (var i in drawLines.geometries) {
for (var j in baseLines.geometries) {
var crossTest = lineStringsIntersect(drawLines.geometries[i], baseLines.geometries[j]);
if (crossTest) {
for (var k in crossTest) {
crossPoints.geometries.push(crossTest[k]);
}
}
}
}
}
return crossPoints;
}
Voici un exemple de violon utilisant ceci avec Leaflet.draw:
http://fiddle.jshell.net/nathansnider/egzxw86h/
Lorsque vous avez terminé de dessiner un objet, il place des marqueurs sur la carte aux points où l'objet dessiné croise la géométrie de base. Il ne peut pas vérifier les intersections alors qu'un chemin est toujours en cours de dessin, car Leaflet.draw ne nous donne aucun gestionnaire d'événements à utiliser pendant que le dessin est en cours. Il sera vérifié dès qu'un tirage au sort sera terminé.
Notez également que cela ne détectera pas les intersections pour les chemins qui se trouvent entièrement dans les polygones par rapport auxquels ils sont vérifiés. Vous pouvez faire ces vérifications en utilisant turf.js (en combinant probablement turf.explode avec turf.within ).