การค้นหาระยะห่างขั้นต่ำถึงขอบของรูปหลายเหลี่ยมโดยใช้ ArcGIS Desktop หรือไม่


9

ฉันมีแผนที่ประมาณ 3000 รูปหลายเหลี่ยมใน ArcGIS 10 ฉันกำลังมองหาระยะทางระหว่างพวกเขาแต่ละคน ฉันรู้วิธีการใช้พิกัดละติจูดและลองจิจูดของเซนทรอยด์ แต่ฉันกำลังมองหาระยะทางเส้นสั้นที่สั้นที่สุดจากขอบที่ใกล้เคียงที่สุดของรูปหลายเหลี่ยมหนึ่งไปยังขอบที่ใกล้เคียงที่สุดของรูปหลายเหลี่ยมอื่น ๆ ความคิดใด ๆ

คำตอบ:


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
ขออภัย SCW คุณผิดในหลาย ๆ PostGIS มีการคำนวณระยะทางแบบเนทีฟ GOES ไม่เกี่ยวข้องกับเรื่องนั้น ประการที่สองมันให้ระยะทางที่ใกล้ที่สุดระหว่างขอบไม่เพียง แต่จุดยอดทั้งในระยะทางเรขาคณิตและในการคำนวณระยะทางทรงกลมแบบภูมิศาสตร์ พอลเขียนมัน
Nicklas Avén

หากต้องการดูรูปเรขาคณิตให้เห็นคุณสามารถใช้ st_shortestline ที่ส่งคืนเส้นที่ให้ระยะทาง
Nicklas Avén

1
Nik นั้นถูกต้องทั้งในรูปทรงเรขาคณิตและภูมิศาสตร์ฟังก์ชันระยะทางจะคืนค่าระยะห่างระหว่างขอบ ตัวอย่างเช่นเลือก st_distance ('LINESTRING (0 0, 0 100)', 'LINESTRING (50 1, 51 1)')
Paul Ramsey

2
ว้าวฐานข้อมูลเชิงพื้นที่จะสั่นคลอน! ฉันกำลังคำนวณระยะทางระหว่างชุดของ ~ 8200 รูปหลายเหลี่ยมกับเพื่อนบ้านที่ใกล้ที่สุดในอีกชุดของรูป ~ 8400 รูปหลายเหลี่ยม ใน arcgis 10 เครื่องมือ 'สร้างใกล้ตาราง' ด้วยรัศมีการค้นหา 10,000 ม. ใช้เวลา 1 ชั่วโมง 15 นาที (บนเดสก์ท็อป i7 quad-core i7 3.4 GHz) ข้อความค้นหาเดียวกันใน PostGIS ใช้เวลาเพียง 3.5 นาทีและอยู่ในคอมพิวเตอร์ที่ช้ากว่า (2.7 GHz dual-core i7 macbook pro)
pistachionut

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 และจบลงด้วยการเข้ารหัสบางสิ่งบางอย่างบ้างเช่นนี้เอง (เห็นได้ชัดว่ามันช้าลง)
จอร์จซิลวา


2

ฉันคิดว่าเครื่องมือ near tableจะทำงานในสิ่งที่คุณต้องการ:

กำหนดระยะทางจากสถานที่แต่ละแห่งในคุณลักษณะป้อนข้อมูลไปยังสถานที่ใกล้เคียงหนึ่งแห่งขึ้นไปในสถานที่ใกล้เคียงภายในรัศมีการค้นหา ผลลัพธ์จะถูกบันทึกในตารางผลลัพธ์

เพียงแค่ปล่อยให้รัศมีการค้นหาว่างเปล่า


นี่เป็นวิธีแก้ปัญหาที่ฉันจะลองก่อน แต่ต้องการระดับสิทธิ์การใช้งาน ArcInfo เพื่อปลดล็อกเครื่องมือสร้างใกล้ตาราง (การวิเคราะห์)
PolyGeo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.