EDITAR: Vea el violín de ghybs del comentario anterior para obtener una solución más simple y mejor usando turf.js. La respuesta original sigue:
Aquí hay una versión modificada de la rutina de intersección de la biblioteca geojson-js-utils que toma las cadenas de líneas GeoJSON como entrada y produce puntos GeoJSON de su intersección como salida:
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;
}
Las modificaciones fueron necesarias porque la función original era calcular las intersecciones solo de latitud y longitud, como si fueran solo coordenadas en un plano, produciendo resultados inexactos (especialmente en latitudes altas o largas distancias). El uso L.Projection
de convertir a un sistema de coordenadas proyectadas conforme (o, en este caso, casi conforme ) durante el cálculo corrige esto.
Se podría modificar aún más para aceptar objetos de geometría de folleto en lugar de solo LineStrings, pero en su lugar utilicé esta función bastante difícil de manejar para crear LineStrings para pasar a la función de intersección:
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;
}
y esta función para tomar objetos Leaflet, convertirlos en LineStrings y verificar intersecciones:
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;
}
Aquí hay un ejemplo de violín que usa esto con Leaflet.draw:
http://fiddle.jshell.net/nathansnider/egzxw86h/
Cuando termine de dibujar un objeto, colocará marcadores en el mapa en los puntos donde el objeto dibujado se cruza con la geometría base. No puede verificar las intersecciones mientras todavía se está dibujando un camino, porque Leaflet.draw no nos da ningún controlador de eventos para usar mientras el dibujo aún está en progreso. Sin embargo, se comprobará tan pronto como se complete un evento de sorteo.
También tenga en cuenta que esto no detectará las intersecciones para las rutas que se encuentran completamente dentro de los polígonos con los que se están comprobando. Podrías hacer esas comprobaciones usando turf.js (probablemente combinando turf.explode con turf.within ).