Django で GeoJSON データを操作する: gis.db.models.functions.SymDifference 関数の詳細解説


gis.db.models.functions.SymDifference 関数は、2つのジオメトリの対称差を求めるための関数です。対称差とは、2つのジオメトリを重ね合わせた部分を除いた領域のことを指します。

構文

from django.contrib.gis.db.models.functions import SymDifference

symdiff = SymDifference(geom1, geom2)
  • geom1geom2 は、いずれも django.contrib.gis.db.models.fields.GeometryField 型のフィールドまたはジオメトリオブジェクトである必要があります。

戻り値

  • 2つのジオメトリの対称差を表す django.contrib.gis.geos.Geometry オブジェクトが返されます。

from django.contrib.gis.geos import GEOSGeometry

# 2つのジオメトリを作成
geom1 = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))')
geom2 = GEOSGeometry('POLYGON((5 0, 15 0, 15 10, 5 10, 5 0))')

# 対称差を求める
symdiff = SymDifference(geom1, geom2)

# 結果を表示
print(symdiff.wkt)

この例では、以下の結果が出力されます。

POLYGON((0 0, 10 0, 15 0, 15 10, 10 10, 5 10, 5 5, 0 5, 0 0))
  • 2つのジオメトリが完全に重なる場合は、その結果として最初のジオメトリが返されます。
  • 2つのジオメトリが重ならない場合は、その結果として空のジオメトリが返されます。
  • SymDifference 関数は、PostGIS 2.0以降のデータベースでのみ使用できます。
  • 2つの建物の建蔽面積を比較する
  • 2つの湖の面積の差を計算する
  • 2つの土地の所有権の境界線を比較する


from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.db.models.functions import Area

# 2つの土地の所有権の境界線を作成
land1_boundary = GEOSGeometry('POLYGON((0 0, 100 0, 100 50, 0 50, 0 0))')
land2_boundary = GEOSGeometry('POLYGON((50 0, 150 0, 150 60, 50 60, 50 0))')

# 土地の面積を計算する
land1_area = Area(land1_boundary)
land2_area = Area(land2_boundary)

# 対称差を求める
symdiff = SymDifference(land1_boundary, land2_boundary)

# 結果を表示
print(f"Land 1 area: {land1_area.m**2}")
print(f"Land 2 area: {land2_area.m**2}")
print(f"Symmetric difference area: {symdiff.area.m**2}")
Land 1 area: 2500.0
Land 2 area: 3000.0
Symmetric difference area: 1000.0

例 2:2つの湖の面積の差を計算する

この例では、2つの湖の面積を計算し、その差を求めます。

from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.db.models.functions import Area

# 2つの湖の形状を作成
lake1_shape = GEOSGeometry('POLYGON((50 40, 60 40, 60 50, 50 50, 50 40))')
lake2_shape = GEOSGeometry('POLYGON((40 30, 70 30, 70 40, 40 40, 40 30))')

# 湖の面積を計算する
lake1_area = Area(lake1_shape)
lake2_area = Area(lake2_shape)

# 面積差を求める
area_diff = lake1_area - lake2_area

# 結果を表示
print(f"Lake 1 area: {lake1_area.m**2}")
print(f"Lake 2 area: {lake2_area.m**2}")
print(f"Area difference: {area_diff.m**2}")
Lake 1 area: 100.0
Lake 2 area: 140.0
Area difference: -40.0

例 3:2つの建物の建蔽面積を比較する

この例では、2つの建物の建蔽面積を比較します。

from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.db.models.functions import Area

# 2つの建物の建蔽面積を作成
building1_footprint = GEOSGeometry('POLYGON((0 0, 10 0, 10 20, 0 20, 0 0))')
building2_footprint = GEOSGeometry('POLYGON((5 5, 15 5, 15 15, 5 15, 5 5))')

# 建蔽面積を計算する
building1_area = Area(building1_footprint)
building2_area = Area(building2_footprint)

# 対称差を求める
symdiff = SymDifference(building1_footprint, building2_footprint)

# 結果を表示
print(f"Building 1 footprint area: {building1_area.m**2}")
print(f"Building 2 footprint area: {building2_area.m**2}")
print(f"Symmetric difference area: {symdiff.area.m**2}")
Building 1 footprint area: 200.0


ST_Difference 関数と ST_Union 関数の組み合わせ

PostGIS 2.0以降のデータベースを使用している場合は、ST_Difference 関数と ST_Union 関数を組み合わせて、SymDifference 関数と同じ結果を得ることができます。

from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.db.models.functions import Difference, Union

# 2つのジオメトリを作成
geom1 = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))')
geom2 = GEOSGeometry('POLYGON((5 0, 15 0, 15 10, 5 10, 5 0))')

# 対称差を求める
symdiff1 = Difference(geom1, Union(geom1, geom2))
symdiff2 = Difference(Union(geom1, geom2), geom2)

# 結果を表示
print(symdiff1.wkt)
print(symdiff2.wkt)
POLYGON((0 0, 10 0, 15 0, 15 10, 10 10, 5 10, 5 5, 0 5, 0 0))
POLYGON((0 0, 10 0, 15 0, 15 10, 10 10, 5 10, 5 5, 0 5, 0 0))

GEOSGeometry メソッドの使用

GEOSGeometry オブジェクトには、difference() メソッドと union() メソッドが用意されており、これらのメソッドを使用して SymDifference 関数と同じ結果を得ることができます。

from django.contrib.gis.geos import GEOSGeometry

# 2つのジオメトリを作成
geom1 = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))')
geom2 = GEOSGeometry('POLYGON((5 0, 15 0, 15 10, 5 10, 5 0))')

# 対称差を求める
symdiff1 = geom1.difference(geom1.union(geom2))
symdiff2 = geom1.union(geom2).difference(geom2)

# 結果を表示
print(symdiff1.wkt)
print(symdiff2.wkt)
POLYGON((0 0, 10 0, 15 0, 15 10, 10 10, 5 10, 5 5, 0 5, 0 0))
POLYGON((0 0, 10 0, 15 0, 15 10, 10 10, 5 10, 5 5, 0 5, 0 0))

カスタム SQL クエリ

PostGIS 2.0以降のデータベースを使用している場合は、カスタム SQL クエリを使用して SymDifference 関数と同じ結果を得ることができます。

SELECT ST_SymDifference(geom1, geom2) AS symdiff
FROM django_gis_geographyfield AS geom1, django_gis_geographyfield AS geom2
WHERE geom1.id = 1 AND geom2.id = 2;

このクエリは、geom1geom2 という名前のジオメトリフィールドを持つ 2 つのテーブルからデータを抽出し、ST_SymDifference 関数を使用して対称差を求めます。

最適な方法の選択

上記の代替方法のうち、最適な方法は、使用するデータベースの種類と、処理するジオメトリの複雑さによって異なります。

  • より単純なジオメトリを処理する場合は、
  • PostGIS 2.0以降のデータベースを使用している場合は、ST_Difference 関数と ST_Union 関数の組み合わせが最も効率的な方法です。