ArcGIS Desktop kullanarak çokgenlerin kenardan kenara minimum mesafesini mi arıyorsunuz?


9

ArcGIS 10'da yaklaşık 3000 çokgenlik bir haritam var. Her biri arasındaki mesafeyi bulmak istiyorum. Centroidin lat ve uzun koordinatlarını kullanarak nasıl yapılacağını biliyorum, ama bir çokgenin en yakın kenarından diğer çokgenin en yakın kenarına kadar en kısa düz çizgi mesafesini arıyorum. Herhangi bir fikir?

Yanıtlar:


11

Bu güzel bir kod parçası, ama neredeyse o kadar hoş değil (tablonuzun coğrafi koordinatlarda olduğunu varsayarsak, sadece coğrafyadaki yayınları kaldırmazsanız)

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;

Uzamsal veritabanlarının sallandığından bahsetmiş miydim? Onlar yapar. Oh, biliyorlar.


Bu, en yakın köşeler arasındaki mesafeyi bulacaktır, ancak kenarların kendileri değil - GEOS bu daha kesin cevabı ortaya koymaz. Yine de, oldukça kullanışlı!
scw

1
Üzgünüm scw, birçok yönden yanılıyorsunuz. PostGIS yerel mesafe hesaplamalarına sahiptir. GOES buna dahil değildir. İkincisi, hem geometri mesafesindeki hem de coğrafya tipi sferoid mesafe hesaplamasındaki köşeleri değil, kenarlar arasındaki kesinlikle en yakın mesafeyi verir. Paul yazdı.
Nicklas Avén

Geometri için görsel olarak görmek için mesafeyi veren çizgiyi döndüren st_shortestline'ı kullanabilirsiniz.
Nicklas Avén

1
Nik haklı, hem geometri hem de coğrafyada uzaklık fonksiyonu kenarlar arasındaki mesafeyi döndürüyor. Örneğin, st_distance'ı seçin ('LINESTRING (0 0, 0 100)', 'LINESTRING (50 1, 51 1)')
Paul Ramsey

2
vay, uzamsal veritabanları kaya yapıyor! Ben ~ 8200 çokgen bir dizi ve ~ 8400 çokgen başka bir sette en yakın komşu arasındaki mesafeyi hesaplıyorum. arcgis 10'da, 10000 m arama yarıçapına sahip 'tabloya yakın üret' aracı 1 saat 15 dakika sürdü (3.4 GHz dört çekirdekli i7 masaüstünde). PostGIS'teki aynı sorgu sadece 3,5 dakika sürdü ve bu daha yavaş bir bilgisayardaydı (2,7 GHz çift çekirdekli i7 macbook pro).
pistachionut

8

A'dan B'ye mesafe B'den A'ya aynıdır ve A'dan A'ya mesafe sıfırdır, bu nedenle yarım matris size biraz iş kazandıracaktır.

IProximityOperator kenardan mesafeyi döndürür. Aşağıdaki kod, her çokgenin sentroidinde ortalanmış bir azimuthal izdüşümü kullanır (çizgilerle de çalışmalıdır). Çokgenler çok karmaşık değilse (veya çok fazla belleğiniz varsa) tüm geometrileri belleğe yüklerseniz, onları yansıtan daha hızlı olur. (Bu ayrıntılı olarak test edilmemiştir).

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

bu güzel bir kod parçası. IproximityOperator hakkında bilmiyordum ve kendim gibi bir şey kodlama sona erdi (tabii ki daha yavaş)
George Silva


2

Sanırım yakın tablo aracı ne istediğinizi işe yarayacak:

Giriş yarıçaplarındaki her bir özellik ile arama özelliğindeki yakın özelliklerde bulunan bir veya daha fazla özelliğe olan mesafeleri belirler. Sonuçlar çıktı tablosuna kaydedilir.

Arama yarıçapını boş bırakmanız yeterlidir.


Bu ilk denemek istiyorum ama Generate Near Table (Analysis) aracının kilidini açmak için bir ArcInfo lisans seviyesine ihtiyacı var.
PolyGeo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.