ArcGIS Desktopを使用してポリゴンのエッジ間の最小距離を見つけますか?


9

ArcGIS 10に約3000のポリゴンのマップがあります。それぞれのポリゴン間の距離を探しています。重心の緯度と経度の座標を使用してそれを行う方法を知っていますが、1つのポリゴンの最も近いエッジから他のポリゴンの最も近いエッジまでの最短直線距離を探しています。何か案は?

回答:


11

これは素晴らしいコードですが、それほど優れていません(テーブルが地理座標にあると仮定し、地理へのキャストを削除しない場合)

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;

空間データベースが揺れ動くと言ったことはありますか?彼らはします。ああ、そうです。


これにより、最も近い頂点間の距離が見つかりますが、エッジ自体は見つかりません。GEOSがこのより正確な答えを公開しているようには見えません。それでも、かなり便利です!
scw

1
申し訳ありませんが、多くの点で間違っています。PostGISにはネイティブの距離計算があります。GOESはそれに関与していません。第2に、ジオメトリ距離と地理タイプの回転楕円体距離計算の両方で頂点だけでなく、エッジ間の最も近い距離を絶対的に与えます。パウロが書いた。
NicklasAvén2010年

ジオメトリを視覚的に確認するには、距離を示す線を返すst_shortestlineを使用できます。
NicklasAvén2010年

1
Nikは正しいです。ジオメトリと地理の両方で、distance関数はエッジ間の距離を返します。たとえば、st_distance( 'LINESTRING(0 0、0 100)'、 'LINESTRING(50 1、51 1)')を選択します
Paul Ramsey

2
すごい、空間データベースは素晴らしいです!〜8200ポリゴンのセットと〜8400ポリゴンの別のセットの最近傍の距離を計算しています。Arcgis 10では、検索半径10000 mの「生成ニアテーブル」ツールは1時間15分かかりました(3.4 GHzクアッドコアi7デスクトップ上)。PostGISでの同じクエリは3.5分しかかかりませんでしたが、それは遅いコンピューター(2.7 GHzデュアルコアi7 macbook pro)で行われました。
ピスタチオナット2012年

8

AからBへの距離はBからAと同じであり、AからAへの距離はゼロであるため、半分の行列を使用すると作業が軽減されます。

IProximityOperatorはエッジからの距離を返します。以下のコードは、各ポリゴンの重心を中心とした方位角投影を使用しています(ラインでも機能するはずです)。ポリゴンが複雑すぎない場合(またはメモリが大量にある場合)、すべてのジオメトリをメモリにロードすると、投影が速くなります。(これは完全にテストされていません)。

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

これは素晴らしいコードです。私はIproximityOperatorについて知らなかったので、自分でこのようなものをコーディングしました(明らかに遅いです)
George Silva


2

ニアテーブルツールはあなたが望むもののために働くと思います:

検索範囲内で、入力フィーチャの各フィーチャから近接フィーチャの1つ以上の近接フィーチャまでの距離を決定します。結果は出力テーブルに記録されます。

検索範囲を空白のままにしてください。


これは私が最初に試すソリューションですが、[ニアテーブルの生成(分析)]ツールのロックを解除するには、ArcInfoライセンスレベルが必要です。
PolyGeo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.