EDIT: Veja o violino de ghybs no comentário acima para obter uma solução mais simples e melhor usando turf.js. A resposta original segue:
Aqui está uma versão modificada da rotina de interseção da biblioteca geojson-js-utils que recebe as cadeias de linhas GeoJSON como entrada e produz pontos de GeoJSON de sua interseção como saída:
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;
}
As modificações foram necessárias porque a função original era calcular interseções apenas a partir da latitude e longitude, como se fossem apenas coordenadas em um plano, produzindo resultados imprecisos (especialmente em altas latitudes ou longas distâncias). Usar L.Projection
para converter em um sistema de coordenadas projetado conforme (ou, neste caso, quase conforme ) durante o cálculo corrige isso.
Pode-se modificá-lo ainda mais para aceitar objetos de geometria Leaflet em vez de apenas LineStrings, mas usei essa função bastante pesada para criar LineStrings a serem passados para a função de interseção:
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;
}
e esta função para pegar objetos Leaflet, convertê-los em LineStrings e verificar interseções:
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;
}
Aqui está um exemplo de violino usando isso com o Leaflet.draw:
http://fiddle.jshell.net/nathansnider/egzxw86h/
Quando você terminar de desenhar um objeto, ele colocará marcadores no mapa nos pontos em que o objeto desenhado cruza com a geometria base. Ele não pode verificar interseções enquanto um caminho ainda está sendo desenhado, porque Leaflet.draw não nos fornece manipuladores de eventos para usar enquanto o desenho ainda está em andamento. Ele verificará assim que um evento de empate for concluído.
Observe também que isso não detectará interseções de caminhos que estejam inteiramente dentro de polígonos com os quais estão sendo verificados. Você pode fazer essas verificações usando turf.js (provavelmente combinando turf.explode com turf.within ).