Bagaimana cara mengetahui apakah jalur GeoJSON berpotongan dengan fitur lain di Leaflet?

8

Saya memiliki aplikasi tempat pengguna menggambar jalur (serangkaian garis lurus yang terhubung) dan jalur ini mungkin tidak memotong fitur apa pun di lapisan GeoJSON tertentu.

Saya perlu memeriksa bahwa tidak ada titik di sepanjang garis ini memotong lapisan GeoJSON, bukan hanya titik akhir.

Bagaimana saya bisa melakukan pemeriksaan ini?

LavaHot
sumber
Itu bisa dilakukan dengan Turf.js
ghybs
Adakah yang harus saya perhatikan di Turf.js?
LavaHot
Saya tidak berpikir turf. Saya melakukan ini. Anda mungkin dapat mengadaptasi beberapa kode deteksi persimpangan lainnya untuk keperluan Anda. Misalnya, ini , yang dirancang untuk beroperasi di GeoJSON linestrings, dapat membantu Anda, tetapi jika Anda membutuhkannya untuk bekerja dengan lapisan poligon, Anda harus menyesuaikannya untuk menerima input poligon atau mengekstrak poligon sebagai linestrings dari lapisan GeoJSON Anda terlebih dahulu.
nathansnider
2
Wow, pekerjaan yang mengesankan! :-) Saya akan berpikir turf.intersect akan melakukan pekerjaan itu? (membangun jsfiddle Anda: fiddle.jshell.net/tyt4oeux/1 ) Tapi mungkin saya mengabaikan pertanyaan itu.
ghybs
Ah-ha, tapi tentu saja itu berhasil! Saya baru saja mengambil dokumen API di kata mereka bahwa turf.intersect membutuhkan poligon sebagai input. Tidak ada salahnya mencoba, kurasa. Karena turf.intersect memiliki keuntungan menjadi lebih sederhana serta mendeteksi ketika garis sepenuhnya dalam poligon, itu jelas cara untuk pergi ke sini, saya pikir.
nathansnider

Jawaban:

4

Anda dapat mencoba pustaka Turf dan metode seperti intersect: http://turfjs.org/docs/#intersect

Berikut contoh kode dari perpustakaan itu:

var poly1 = {
    "type": "Feature",
    "geometry": {
        "type": "Polygon",
        "coordinates": [[
            [-122.801742, 45.48565],
            [-122.801742, 45.60491],
            [-122.584762, 45.60491],
            [-122.584762, 45.48565],
            [-122.801742, 45.48565]
        ]]
    }
}
var poly2 = {
    "type": "Feature",
    "geometry": {
        "type": "Polygon",
        "coordinates": [[
            [-122.520217, 45.535693],
            [-122.64038, 45.553967],
            [-122.720031, 45.526554],
            [-122.669906, 45.507309],
            [-122.723464, 45.446643],
            [-122.532577, 45.408574],
            [-122.487258, 45.477466],
            [-122.520217, 45.535693]
         ]]
     }
}

var intersection = turf.intersect(poly1, poly2);
Adrian Ber
sumber
Anda harus menambahkan contoh cara melakukan ini: tautan membusuk dari waktu ke waktu.
alphabetasoup
Jika tautan itu akan membusuk seiring waktu, maka seluruh jawaban saya akan batal. Seluruh contoh didasarkan pada keberadaan perpustakaan Turf, dan jika itu tidak akan ada ... Namun saya menyalin contoh itu ke jawaban saya.
Adrian Ber
4
Tautan membusuk, inilah turfjs.org/docs/#intersect yang baru
Calvein
Tautan membusuk lagi (atau kesalahan); tanpa tebasan, cukup: turfjs.org/docs#intersect
Hendy
1

EDIT: Lihat biola ghybs dari komentar di atas untuk solusi yang lebih sederhana dan lebih baik menggunakan turf.js. Jawaban asli berikut:


Berikut ini adalah versi modifikasi dari persimpangan rutin dari pustaka geojson-js-utils yang mengambil GeoJSON linestrings sebagai input dan menghasilkan poin GeoJSON dari persimpangan mereka sebagai output:

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;
}

Modifikasi diperlukan karena fungsi asli menghitung persimpangan dari lintang dan bujur saja, seolah-olah mereka hanya koordinat pada pesawat, menghasilkan hasil yang tidak akurat (terutama di lintang tinggi atau jarak jauh). Menggunakan L.Projectionuntuk mengkonversi ke sistem koordinat yang diproyeksikan konformal (atau, dalam hal ini, hampir konformal ) selama perhitungan perbaikan ini.

Orang bisa memodifikasinya lebih jauh untuk menerima objek geometri Leaflet bukan hanya LineStrings, tetapi sebaliknya saya menggunakan fungsi yang agak sulit ini untuk membuat LineStrings untuk diteruskan ke fungsi persimpangan:

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;
}

dan fungsi ini untuk mengambil objek Leaflet, mengkonversikannya ke LineStrings dan memeriksa persimpangan:

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;
}

Berikut ini contoh biola yang menggunakan ini dengan Leaflet.draw:

http://fiddle.jshell.net/nathansnider/egzxw86h/

Ketika Anda selesai menggambar objek, itu akan menempatkan penanda pada peta di titik-titik di mana objek yang digambar bersinggungan dengan geometri dasar. Ia tidak dapat memeriksa persimpangan saat jalan masih digambar, karena Leaflet.draw tidak memberi kami penangan acara untuk digunakan saat gambar masih berlangsung. Akan diperiksa segera setelah acara pengundian selesai.

Perhatikan juga bahwa ini tidak akan mendeteksi persimpangan untuk jalur yang seluruhnya berada dalam poligon yang sedang diperiksa. Anda dapat melakukan pemeriksaan tersebut menggunakan turf.js (mungkin menggabungkan turf.explode dengan turf.within ).

nathansnider
sumber