Ermitteln des minimalen Kantenabstands von Polygonen mithilfe von ArcGIS Desktop?

9

Ich habe eine Karte mit ungefähr 3000 Polygonen in ArcGIS 10. Ich suche nach dem Abstand zwischen jedem von ihnen. Ich weiß, wie man es mit den Lat- und Long-Koordinaten des Schwerpunkts macht, aber ich suche nach dem kürzesten geraden Abstand von der nächsten Kante eines Polygons zur nächsten Kante des anderen Polygons. Irgendwelche Ideen?

Kevin
quelle

Antworten:

11

Das ist ein schönes Stück Code, aber bei weitem nicht so schön wie (vorausgesetzt, Ihre Tabelle hat geografische Koordinaten, wenn Sie nicht nur die geografischen Umwandlungen entfernen)

CREATE TABLE mytable_distances AS
SELECT a.id, b.id, ST_Distance(a.geom::geography, b.geom::geography) as distance
FROM mytable a, mytable b;

Habe ich schon erwähnt, dass Geodatenbanken rocken? Tun sie. Oh, das tun sie.

Paul Ramsey
quelle
Dadurch wird der Abstand zwischen den nächstgelegenen Scheitelpunkten ermittelt, nicht jedoch zwischen den Kanten selbst. Es scheint nicht, dass GEOS diese genauere Antwort verfügbar macht. Trotzdem ganz praktisch!
Scw
1
Sorry scw, du liegst in vielerlei Hinsicht falsch. PostGIS verfügt über native Entfernungsberechnungen. GOES ist daran nicht beteiligt. Zweitens gibt es absolut den engsten Abstand zwischen den Kanten, nicht nur Scheitelpunkte sowohl in Bezug auf den Geometriedistanz als auch in Bezug auf die Berechnung des geografischen Sphäroidabstands. Paul hat es geschrieben.
Nicklas Avén
Um es für die Geometrie visuell anzuzeigen, können Sie st_shortestline verwenden, die die Linie zurückgibt, die den Abstand angibt.
Nicklas Avén
1
Nik hat recht, sowohl in der Geometrie als auch in der Geographie gibt die Abstandsfunktion den Abstand zwischen den Kanten zurück. Wählen Sie beispielsweise st_distance ('LINESTRING (0 0, 0 100)', 'LINESTRING (50 1, 51 1)')
Paul Ramsey
2
Wow, räumliche Datenbanken rocken! Ich berechne den Abstand zwischen einem Satz von ~ 8200 Polygonen und dem nächsten Nachbarn in einem anderen Satz von ~ 8400 Polygonen. In Arcgis 10 dauerte das Tool "Near Table erstellen" mit einem Suchradius von 10000 m 1 Stunde und 15 Minuten (auf einem 3,4-GHz-Quad-Core-i7-Desktop). Die gleiche Abfrage in PostGIS dauerte nur 3,5 Minuten, und zwar auf einem langsameren Computer (einem 2,7-GHz-Dual-Core-i7-MacBook Pro).
Pistazie
8

Der Abstand von A nach B ist der gleiche wie der von B nach A, und der Abstand von A nach A ist Null. Daher erspart Ihnen eine halbe Matrix einige Arbeit.

IProximityOperator gibt die Entfernung von der Kante zurück. Der folgende Code verwendet eine azimutale Projektion, die auf dem Schwerpunkt jedes Polygons zentriert ist (sollte auch mit Linien funktionieren). Wenn die Polygone nicht zu komplex sind (oder wenn Sie viel Speicher haben), werden alle Geometrien schneller in den Speicher geladen und projiziert. (Dies wird nicht gründlich getestet).

public class Pair
{
    public int Oid1;
    public int Oid2;
    public double Dist;
    public static void TestGetDistances()
    {
        IWorkspaceFactory wsf = new ESRI.ArcGIS.DataSourcesGDB.FileGDBWorkspaceFactoryClass();

        string path = @"C:\Program Files\ArcGIS\DeveloperKit10.0\Samples\data\Usa\USA.gdb";
        var fws = wsf.OpenFromFile(path, 0) as IFeatureWorkspace;
        IFeatureClass fc = fws.OpenFeatureClass("states");
        var halfMatrix = Pair.GetPairs(fc);

    }
    /// <summary>
    /// key is oid of each feature, value is pairs for features with smaller oids.
    /// </summary>
    /// <param name="fc"></param>
    /// <returns></returns>
    public static SortedList<int, List<Pair>> GetPairs(IFeatureClass fc)
    {
        ISpatialReferenceFactory3 srf = new SpatialReferenceEnvironmentClass();
        IProjectedCoordinateSystem pcs = 
        srf.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_WGS1984N_PoleAziEqui);

        var outList = new SortedList<int, List<Pair>>();
        IFeatureCursor fCur = fc.Search(null, true);
        IFeature f;
        while ((f = fCur.NextFeature()) != null)
        {
            var pairs = GetDistances(f, pcs);
            Debug.Print("{0} has {1} pairs", f.OID, pairs.Count);
            outList.Add(f.OID, pairs);
        }
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
        return outList;
    }

    private static IPoint GetGCSCentroid(IGeometry geom)
    {
        if (geom.SpatialReference is IProjectedCoordinateSystem)
        {
            geom.Project(((IProjectedCoordinateSystem)geom.SpatialReference).GeographicCoordinateSystem);
        }
        IArea a = geom is IArea ? geom as IArea : geom.Envelope as IArea;
        return a.Centroid;
    }

    /// <summary>
    /// return a list of all other features whose OID is lesser than f1
    /// </summary>
    /// <param name="f1"></param>
    /// <param name="pcs"></param>
    /// <returns></returns>
    private static List<Pair> GetDistances(IFeature f1, IProjectedCoordinateSystem pcs)
    {
        IPoint centroid = GetGCSCentroid(f1.ShapeCopy);

        pcs.set_CentralMeridian(true, centroid.X);
        ((IProjectedCoordinateSystem2)pcs).LatitudeOfOrigin = centroid.Y;
        var g1 = f1.ShapeCopy;
        g1.Project(pcs);

        var outList = new List<Pair>();
        var fc = f1.Class as IFeatureClass;
        var proxOp = g1 as IProximityOperator;
        IFeatureCursor fCur = fc.Search(null, true);
        IFeature f2 = null;
        while ((f2 = fCur.NextFeature()) != null)
        {
            if (f2.OID < f1.OID)
            {
                var g2 = f2.ShapeCopy;
                g2.Project(pcs);
                outList.Add(new Pair()
                {
                    Oid1 = f1.OID,
                    Oid2 = f2.OID,
                    Dist = proxOp.ReturnDistance(g2)
                });
            }
        }
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
        return outList;
    }
}
Kirk Kuykendall
quelle
Das ist ein schönes Stück Code. Ich wusste nichts über IproximityOperator und habe selbst etwas Ähnliches programmiert (offensichtlich ist es langsamer)
George Silva
2

Ich denke, das Near Table-Tool würde für das funktionieren, was Sie wollen:

Bestimmt die Abstände von jedem Feature in den Eingabe-Features zu einem oder mehreren nahe gelegenen Features in den Near-Features innerhalb des Suchradius. Die Ergebnisse werden in der Ausgabetabelle aufgezeichnet.

Lassen Sie einfach den Suchradius leer.

Jason Scheirer
quelle
Dies ist die Lösung, die ich zuerst versuchen würde, für die jedoch eine ArcInfo-Lizenzstufe erforderlich ist, um das Tool "Generate Near Table (Analysis)" freizuschalten.
PolyGeo