【初心者向け】Djangoで「contains_properly」を使って空間データの包含関係を判定する方法


"django.contrib.gis" は、Django フレームワークに空間データ機能を追加する拡張モジュールです。 "gis.geos.PreparedGeometry.contains_properly()" メソッドは、このモジュールで提供される重要な機能の一つであり、空間データの包含関係を判定するために使用されます。

本記事では、"gis.geos.PreparedGeometry.contains_properly()" メソッドの仕組みと使用方法について、分かりやすく詳細に解説します。

"gis.geos.PreparedGeometry.contains_properly()" メソッドは、あるジオメトリが別のジオメトリを完全に包含しているかどうかを判定します。 "完全に包含する" とは、包含されるジオメトリが包含するジオメトリの境界線上に全く触れず、かつ内部に完全に収まっていることを意味します。

このメソッドは、2つの引数を取ります。

  1. self: 判定対象となる包含するジオメトリを表す PreparedGeometry オブジェクト
  2. other: 判定対象となる包含されるジオメトリを表す Geometry オブジェクト

"contains_properly()" メソッドの動作

"contains_properly()" メソッドは、以下の手順で判定を行います。

  1. 包含するジオメトリと包含されるジオメトリの境界線を比較します。
  2. 包含されるジオメトリの境界線が、包含するジオメトリの境界線上に全く触れていないかどうかを確認します。
  3. 包含されるジオメトリの内部点が、包含するジオメトリ内部に完全に収まっているかどうかを確認します。

"contains_properly()" メソッドの返値

判定結果は以下の通りです。

  • 包含されるジオメトリが包含するジオメトリを完全に包含していない場合: False
  • 包含されるジオメトリが包含するジオメトリを完全に包含している場合: True

"contains_properly()" メソッドの利点

"contains_properly()" メソッドは、空間データの包含関係を判定する際に、以下の利点を提供します。

  • 精度の高い判定: "contains_properly()" メソッドは、境界線と内部点の両方を比較するため、より精度の高い判定を行うことができます。
  • 高速な処理: "contains_properly()" メソッドは、内部で空間索引を利用するため、従来の包含判定メソッドよりも高速に処理することができます。

"contains_properly()" メソッドの例

以下の例は、"contains_properly()" メソッドを使用して、ある多角形が別の多角形を完全に包含しているかどうかを判定するコードを示しています。

from django.contrib.gis.geos import GEOSGeometry

# 包含する多角形を作成
containing_poly = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', srid=4326)

# 包含される多角形を作成
contained_poly = GEOSGeometry('POLYGON((5 5, 7 5, 7 7, 5 7, 5 5))', srid=4326)

# 判定結果を出力
if containing_poly.contains_properly(contained_poly):
    print('包含する多角形は、包含される多角形を完全に包含しています。')
else:
    print('包含する多角形は、包含される多角形を完全に包含していません。')

"django.contrib.gis" における "gis.geos.PreparedGeometry.contains_properly()" メソッドは、空間データの包含関係を判定する際に非常に有用なツールです。 本記事で解説した内容を理解することで、このメソッドを効果的に活用し、空間データ解析の精度と効率を向上させることができます。

  • "contains_properly()" メソッドは、"django.contrib.gis" バージョン 1.4 以降で使用できます。


例1: 複数のジオメトリに対する判定

この例では、"contains_properly()" メソッドを使用して、ある多角形が複数の小さな多角形をそれぞれ完全に包含しているかどうかを判定します。

from django.contrib.gis.geos import GEOSGeometry

# 包含する多角形を作成
containing_poly = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', srid=4326)

# 包含される多角形を作成
contained_polys = [
    GEOSGeometry('POLYGON((5 5, 7 5, 7 7, 5 7, 5 5))', srid=4326),
    GEOSGeometry('POLYGON((2 2, 4 2, 4 4, 2 4, 2 2))', srid=4326),
    GEOSGeometry('POLYGON((8 8, 10 8, 10 10, 8 10, 8 8))', srid=4326),
]

# 判定結果を出力
for contained_poly in contained_polys:
    if containing_poly.contains_properly(contained_poly):
        print(f'包含する多角形は、包含される多角形 {contained_poly} を完全に包含しています。')
    else:
        print(f'包含する多角形は、包含される多角形 {contained_poly} を完全に包含していません。')

例2: 空間索引を使用した高速判定

この例では、空間索引を使用して、"contains_properly()" メソッドの処理速度を向上させる方法を示します。

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

# 空間索引付きのモデルを作成
class MyModel(models.Model):
    poly = models.PolygonField(srid=4326)

    # 空間索引を設定
    objects = models.GeoManager(using_spatial_index=True)

# 判定対象となるジオメトリを作成
containing_poly = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', srid=4326)

# 空間索引を使用して、包含される可能性のあるジオメトリを絞り込む
possible_contained_polys = MyModel.objects.filter(poly__intersects=containing_poly)

# 絞り込んだジオメトリに対して "contains_properly()" メソッドを実行
for contained_poly in possible_contained_polys:
    if containing_poly.contains_properly(contained_poly.poly):
        print(f'包含する多角形は、包含される多角形 {contained_poly.poly} を完全に包含しています。')
  • 上記の例は、"django.contrib.gis" の基本的な機能のみを説明しています。実際のアプリケーションでは、より複雑な判定ロジックが必要になる場合があります。


以下に、"gis.geos.PreparedGeometry.contains_properly()" の代替方法として検討すべき3つの方法をご紹介します。

"gis.geos.Geometry.contains()" メソッド

"gis.geos.Geometry.contains()" メソッドは、"gis.geos.PreparedGeometry.contains_properly()" メソッドと類似していますが、境界線を共有するジオメトリも包含関係にあると判定します。

つまり、"gis.geos.PreparedGeometry.contains_properly()" メソッドよりも包含関係の判定基準が緩くなります。

from django.contrib.gis.geos import GEOSGeometry

# 包含する多角形を作成
containing_poly = GEOSGeometry('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', srid=4326)

# 包含される多角形を作成
contained_poly = GEOSGeometry('POLYGON((5 5, 7 5, 7 7, 5 7, 5 5))', srid=4326)

# 判定結果を出力
if containing_poly.contains(contained_poly):
    print('包含する多角形は、包含される多角形を含んでいます。')
else:
    print('包含する多角形は、包含される多角形を含んでいません。')

空間関係演算子

"django.contrib.gis" は、空間関係を表す演算子を提供しています。これらの演算子を使用して、包含関係を判定することができます。

例:

from django.contrib.gis.db import models

# 空間関係演算子を使用した判定
if contained_poly.within(containing_poly):
    print('包含する多角形は、包含される多角形を含んでいます。')
else:
    print('包含する多角形は、包含される多角形を含んでいません。')

空間関数

"django.contrib.gis" は、空間データに関する様々な関数を提供しています。これらの関数を使用して、包含関係を判定することができます。

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

# 空間関数を使用した判定
if GEOSGeometry(contained_poly).difference(containing_poly).area == 0:
    print('包含する多角形は、包含される多角形を完全に包含しています。')
else:
    print('包含する多角形は、包含される多角形を完全に包含していません。')

それぞれの方法の利点と欠点

方法利点欠点
"gis.geos.PreparedGeometry.contains_properly()"高速な処理、精度の高い判定境界線を共有するジオメトリを包含関係にあると判定しない
"gis.geos.Geometry.contains()"境界線を共有するジオメトリも含めて判定できる判定基準が緩いため、不要な結果を含む可能性がある
空間関係演算子シンプルなコードで判定できる演算子の種類によって判定基準が異なる
空間関数柔軟な判定が可能コードが複雑になる可能性がある

"gis.geos.PreparedGeometry.contains_properly()" メソッドは、多くの場合において優れた選択肢ですが、状況によっては代替方法の方が適している場合があります。

それぞれの方法の利点と欠点を理解し、最適な方法を選択することが重要です。

  • 複雑な判定ロジックを構築する場合は、空間関係演算子や空間関数を組み合わせて使用することができます。
  • 上記の代替方法は、あくまでも例であり、状況に応じて様々な方法を組み合わせることもできます。