回答:
これは素晴らしいコードですが、それほど優れていません(テーブルが地理座標にあると仮定し、地理へのキャストを削除しない場合)
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;
空間データベースが揺れ動くと言ったことはありますか?彼らはします。ああ、そうです。
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;
}
}
計算は、ArcGISがネイティブに提供するものではありませんが、Shapely の問題に対する解決策を提供しました。これは、役立つ可能性があります。または、古いArcGISフォーラムのこのスレッドです。