Wie kann man feststellen, ob sich ein GeoJSON-Pfad mit einer anderen Funktion in der Broschüre schneidet?


8

Ich habe eine Anwendung, in der der Benutzer einen Pfad (eine Reihe verbundener gerader Linien) zeichnet und dieser Pfad möglicherweise kein Merkmal in einer bestimmten GeoJSON-Ebene schneidet.

Ich muss überprüfen, ob kein Punkt entlang dieser Linien die GeoJSON-Ebene schneidet, nicht nur die Endpunkte.

Wie kann ich diese Prüfung durchführen?


Es könnte mit Turf.js
Ghybs

Was sollte ich mir in Turf.js besonders ansehen?
LavaHot

Ich glaube nicht, dass turf.js das tut. Möglicherweise können Sie einen anderen Kreuzungserkennungscode für Ihre Zwecke anpassen. Zum Beispiel diese , die auf GeoJSON Linienfolgen für den Betrieb konzipiert ist, können Sie die meisten der Art und Weise, aber wenn Sie es an die Arbeit mit Polygon - Layer benötigen, dann würden Sie müssen entweder anpassen Polygoneingabe oder extrahieren Sie die Polygone als akzeptieren , Linestrings von Ihrer GeoJSON-Ebene zuerst.
Nathansnider

2
Wow beeindruckende Arbeit! :-) Ich hätte gedacht, turf.intersect würde den Job machen? (Aufbauend auf Ihrer jsfiddle: fiddle.jshell.net/tyt4oeux/1 ) Aber vielleicht habe ich die Frage übersehen.
Ghybs

Ah-ha, aber das funktioniert natürlich! Ich habe gerade die API-Dokumente beim Wort genommen, dass turf.intersect ein Polygon als Eingabe benötigt. Es tut nie weh, es zu versuchen, denke ich. Da turf.intersect den Vorteil hat, einfacher zu sein und zu erkennen, wann sich eine Linie vollständig innerhalb eines Polygons befindet, ist dies meiner Meinung nach der richtige Weg.
Nathansnider

Antworten:


4

Sie können die Turf-Bibliothek und eine Methode wie intersect ausprobieren: http://turfjs.org/docs/#intersect

Hier ist das Codebeispiel aus dieser Bibliothek:

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

Sie sollten ein Beispiel dafür hinzufügen: Links verrotten im Laufe der Zeit.
Alphabetasoup

Wenn dieser Link im Laufe der Zeit verrottet, wird meine gesamte Antwort ungültig. Das gesamte Beispiel basiert auf der Existenz einer Turf-Bibliothek, und wenn diese nicht vorhanden sein wird ... Ich habe dieses Beispiel jedoch in meine Antwort kopiert.
Adrian Ber

4
Der Link ist verrottet, hier ist der neue turfjs.org/docs/#intersect
Calvein

Link erneut verrotten (oder Fehler); Kein Schrägstrich, nur: turfjs.org/docs#intersect
Hendy

1

BEARBEITEN : Eine einfachere und bessere Lösung mit turf.js finden Sie in Ghybs 'Geige aus dem obigen Kommentar. Die ursprüngliche Antwort folgt:


Hier ist eine modifizierte Version der Schnittroutine aus der Bibliothek geojson-js-utils , die GeoJSON-Linestrings als Eingabe verwendet und GeoJSON-Punkte ihrer Schnittmenge als Ausgabe erzeugt:

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

Die Änderungen waren notwendig, da die ursprüngliche Funktion darin bestand, Schnittpunkte nur aus Breiten- und Längengraden zu berechnen, als wären sie nur Koordinaten in einer Ebene, was zu ungenauen Ergebnissen führte (insbesondere bei hohen Breiten oder über große Entfernungen). Die L.ProjectionKonvertierung in ein konformes (oder in diesem Fall nahezu konformes ) projiziertes Koordinatensystem während der Berechnung behebt dies.

Man könnte es weiter modifizieren, um Leaflet-Geometrieobjekte anstelle von nur LineStrings zu akzeptieren, aber stattdessen habe ich diese ziemlich unhandliche Funktion verwendet, um LineStrings zu erstellen, die an die Schnittpunktfunktion übergeben werden sollen:

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

und diese Funktion, um Leaflet-Objekte zu nehmen, sie in LineStrings zu konvertieren und nach Schnittpunkten zu suchen:

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

Hier ist ein Beispiel für eine Geige, die dies mit Leaflet.draw verwendet:

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

Wenn Sie mit dem Zeichnen eines Objekts fertig sind, werden Markierungen auf der Karte an den Punkten platziert, an denen sich das gezeichnete Objekt mit der Basisgeometrie schneidet. Es kann nicht nach Schnittpunkten suchen, während ein Pfad noch gezeichnet wird, da Leaflet.draw uns keine Ereignishandler zur Verfügung stellt, die verwendet werden können, während die Zeichnung noch ausgeführt wird. Es wird überprüft, sobald ein Ziehungsereignis abgeschlossen ist.

Beachten Sie auch, dass dadurch keine Schnittpunkte für Pfade erkannt werden, die vollständig innerhalb der Polygone liegen, gegen die sie geprüft werden. Sie können diese Überprüfungen mit turf.js durchführen (wahrscheinlich kombinieren Sie turf.explode mit turf.within ).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.