Trovare la distanza minima da bordo a bordo dei poligoni usando ArcGIS Desktop?


9

Ho una mappa di circa 3000 poligoni in ArcGIS 10. Sto cercando di trovare la distanza tra ognuno di essi. So come farlo usando il lat e le coordinate lunghe del centroide, ma sto cercando la più breve distanza in linea retta dal bordo più vicino di un poligono al bordo più vicino dell'altro poligono. Qualche idea?

Risposte:


11

Questo è un bel pezzo di codice, ma non così bello come (supponendo che il tuo tavolo sia in coordinate geografiche, se non semplicemente rimuovi i cast in geografia)

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;

Ho già detto che i database spaziali oscillano? Loro fanno. Oh, lo fanno.


Questo troverà la distanza tra i vertici più vicini, ma non i bordi stessi - non sembra che GEOS esponga questa risposta più precisa. Comunque, abbastanza utile!
scw,

1
Scusa scw, ti sbagli in molti modi. PostGIS ha calcoli di distanza nativi. GOES non è coinvolto in questo. In secondo luogo, fornisce assolutamente la distanza più vicina tra i bordi, non solo i vertici sia nella distanza della geometria che nel calcolo della distanza sferoidale del tipo geografico. Paul l'ha scritto.
Nicklas Avén,

Per vederlo visivamente per la geometria puoi usare st_shortestline che restituisce la linea che indica la distanza.
Nicklas Avén,

1
Nik ha ragione, sia in geometria che in geografia la funzione di distanza restituisce la distanza tra i bordi. Ad esempio, selezionare st_distance ('LINESTRING (0 0, 0 100)', 'LINESTRING (50 1, 51 1)')
Paul Ramsey

2
wow, i database spaziali fanno rock! sto calcolando la distanza tra un set di ~ 8200 poligoni e il vicino più vicino in un altro set di ~ 8400 poligoni. in arcgis 10, lo strumento "genera vicino tabella" con un raggio di ricerca di 10000 m impiegava 1 ora e 15 minuti (su desktop i7 quad-core a 3,4 GHz). la stessa query in PostGIS impiegava solo 3,5 minuti e si trovava su un computer più lento (un macbook pro i7 dual-core da 2,7 GHz).
pistacchio

8

La distanza da A a B è uguale a B ad A e la distanza da A ad A è zero, quindi una mezza matrice ti farà risparmiare un po 'di lavoro.

IProximity L'operatore restituisce la distanza dal bordo. Il codice seguente utilizza una proiezione azimutale centrata sul centroide di ciascun poligono (dovrebbe funzionare anche con le linee). Se i poligoni non sono troppo complessi (o se si ha molta memoria) caricare tutte le geometrie in memoria e proiettarle sarebbe più veloce. (Questo non è stato testato a fondo).

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

questo è un bel pezzo di codice. Non sapevo di IproximityOperator e alla fine ho codificato qualcosa di simile a me stesso (ovviamente è più lento)
George Silva,


2

Penso che lo strumento table vicino funzionerebbe per quello che vuoi:

Determina le distanze da ciascuna funzione nelle funzioni di input a una o più funzioni vicine nelle funzioni vicine, nel raggio di ricerca. I risultati sono registrati nella tabella di output.

Lascia vuoto il raggio di ricerca.


Questa è la soluzione che vorrei provare per prima ma ha bisogno di un livello di licenza ArcInfo per sbloccare lo strumento Genera Near Table (Analysis).
PolyGeo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.