Menemukan jarak minimum ujung ke ujung poligon menggunakan ArcGIS Desktop?

9

Saya memiliki peta sekitar 3000 poligon di ArcGIS 10. Saya mencari untuk menemukan jarak di antara mereka. Saya tahu bagaimana melakukannya dengan menggunakan koordinat lat dan panjang dari centroid, tetapi saya sedang mencari jarak garis lurus terpendek dari tepi terdekat satu poligon ke tepi terdekat dari poligon lain. Ada ide?

Kevin
sumber

Jawaban:

11

Itu adalah sepotong kode yang bagus, tetapi tidak sebagus (dengan asumsi tabel Anda berada dalam koordinat geografis, jika tidak hanya membuang gips ke geografi)

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;

Sudahkah saya menyebutkan bahwa basis data spasial menjadi batu? Mereka melakukannya. Oh, benar.

Paul Ramsey
sumber
Ini akan menemukan jarak antara simpul terdekat, tetapi bukan tepi itu sendiri - sepertinya GEOS tidak mengekspos jawaban yang lebih tepat ini. Tetap saja, cukup berguna!
scw
1
Maaf ya, Anda salah dalam banyak hal. PostGIS memiliki perhitungan jarak asli. GOES tidak terlibat dalam hal itu. Kedua, ini benar-benar memberikan jarak terdekat antara tepi, tidak hanya simpul baik dalam jarak geometri dan dalam perhitungan jarak spheroid tipe geografi. Paulus menulisnya.
Nicklas Avén
Untuk melihatnya secara visual untuk geometri, Anda dapat menggunakan st_shortestline yang mengembalikan garis yang memberi jarak.
Nicklas Avén
1
Nik benar, baik dalam geometri maupun geografi, fungsi jarak mengembalikan jarak antara kedua sisi. Misalnya, pilih st_distance ('LINESTRING (0 0, 0 100)', 'LINESTRING (50 1, 51 1)')
Paul Ramsey
2
wow, database spasial melakukan rock! Saya menghitung jarak antara satu set ~ 8200 poligon dan tetangga terdekat dalam satu set ~ 8400 poligon. pada arcgis 10, alat 'hasilkan dekat tabel' dengan radius pencarian 10.000 m membutuhkan waktu 1 jam 15 menit (pada desktop quad-core i7 3.4 GHz). permintaan yang sama di PostGIS hanya membutuhkan waktu 3,5 menit, dan itu pada komputer yang lebih lambat (2,7 GHz dual-core i7 macbook pro).
pistachionut
8

Jarak dari A ke B sama dengan B ke A, dan jarak dari A ke A adalah nol, oleh karena itu setengah matriks akan menghemat pekerjaan Anda.

IProximityOperator mengembalikan jarak dari tepi. Kode di bawah ini menggunakan proyeksi azimut yang berpusat pada centroid setiap poligon (harus bekerja dengan garis juga). Jika poligon tidak terlalu rumit (atau jika Anda memiliki banyak memori) memuat semua geometri ke dalam memori memproyeksikannya akan lebih cepat. (Ini belum diuji secara menyeluruh).

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
sumber
ini adalah kode yang bagus. Saya tidak tahu tentang IproximityOperator, dan akhirnya mengkodekan sesuatu yang agak seperti ini sendiri (jelas ini lebih lambat)
George Silva
3

Perhitungannya bukan sesuatu yang secara asli disediakan oleh ArcGIS, tetapi saya memberikan solusi untuk masalah di Shapely yang mungkin membantu, atau utas ini di forum ArcGIS lama.

scw
sumber
2

Saya pikir alat tabel dekat akan bekerja untuk apa yang Anda inginkan:

Menentukan jarak dari setiap fitur dalam fitur input ke satu atau lebih fitur terdekat di fitur dekat, dalam radius pencarian. Hasilnya dicatat dalam tabel output.

Biarkan radius pencarian kosong.

Jason Scheirer
sumber
Ini adalah solusi yang akan saya coba pertama tetapi perlu tingkat lisensi ArcInfo untuk membuka kunci alat Generate Near Table (Analysis).
PolyGeo