EDIT: Xem fiddle của ghybs từ nhận xét ở trên để biết giải pháp đơn giản và tốt hơn bằng cách sử dụng turf.js. Câu trả lời gốc sau:
Dưới đây là phiên bản sửa đổi của thói quen giao cắt từ thư viện Geojson-js-utils , lấy các dòng của GeoJSON làm đầu vào và tạo các điểm GeoJSON của giao lộ làm đầu ra:
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;
}
Việc sửa đổi là cần thiết bởi vì chức năng ban đầu là tính toán các giao điểm từ vĩ độ và kinh độ, như thể chúng chỉ là tọa độ trên một mặt phẳng, tạo ra kết quả không chính xác (đặc biệt là ở vĩ độ cao hoặc trên khoảng cách xa). Việc sử dụng L.Projection
để chuyển đổi sang hệ tọa độ dự kiến phù hợp (hoặc, trong trường hợp này, gần như phù hợp ) trong quá trình tính toán sẽ khắc phục điều này.
Người ta có thể sửa đổi nó hơn nữa để chấp nhận các đối tượng hình học Leaflet thay vì chỉ LineStrings, nhưng thay vào đó tôi đã sử dụng hàm khá khó sử dụng này để tạo LineStrings được chuyển đến chức năng giao nhau:
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;
}
và chức năng này để lấy các đối tượng Leaflet, chuyển đổi chúng thành LineStrings và kiểm tra các giao điểm:
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;
}
Dưới đây là một ví dụ sử dụng điều này với Leaflet.draw:
http://fiddle.jshell.net/nathansnider/egzxw86h/
Khi bạn vẽ xong một đối tượng, nó sẽ đặt các điểm đánh dấu trên bản đồ tại các điểm mà đối tượng được vẽ giao với hình dạng cơ sở. Nó không thể kiểm tra các giao lộ trong khi một đường dẫn vẫn đang được vẽ, bởi vì Leaflet.draw không cung cấp cho chúng tôi bất kỳ trình xử lý sự kiện nào để sử dụng trong khi bản vẽ vẫn đang được tiến hành. Nó sẽ kiểm tra ngay khi một sự kiện bốc thăm được hoàn thành.
Cũng lưu ý rằng điều này sẽ không phát hiện các giao lộ cho các đường dẫn nằm hoàn toàn trong đa giác mà chúng đang được kiểm tra. Bạn có thể thực hiện các kiểm tra đó bằng cách sử dụng turf.js (có thể kết hợp turf.explode với turf.within ).