円形ポリゴン生成の定番ツール、BoundingCircle 関数をマスターしよう! Django で空間データを可視化する


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

bounding_circle = BoundingCircle(expression, num_seg=48, **extra)
  • **extra**: オプション引数として、データベースバックエンドに固有の引数を渡すことができます。
  • num_seg: 円形ポリゴンの分割数(PostGIS のみ)を指定します。デフォルトは 48 です。
  • expression: 対象となるジオメトリフィールドまたは式を指定します。

動作

BoundingCircle 関数は、入力ジオメトリの最小外接円を計算します。この円は、入力ジオメトリを完全に包含する最小の円形ポリゴンです。

以下の例では、City モデルの location フィールドに含まれる各都市の最小外接円を計算し、結果を bounding_circle フィールドに格納します。

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

City.objects.annotate(
    bounding_circle=BoundingCircle('location')
)
  • BoundingCircle 関数は、PostGIS、SpatiaLite、MySQL Spatial などのデータベースバックエンドでサポートされています。


最小外接円の可視化

from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.db.models.functions import BoundingCircle
from django.template.loader import get_template
from django.template import Context

cities = City.objects.annotate(
    bounding_circle=BoundingCircle('location')
)

template = get_template('template.html')
context = {'cities': cities}
content = template.render(context)
print(content)

template.html テンプレートには、以下のコードが含まれます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>最小外接円</title>
  <script src="https://leafletjs.com/"></script>
  <link rel="stylesheet" href="https://leafletjs.com/">
</head>
<body>
  <div id="map"></div>

  <script>
    var map = L.map('map').setView([51.505, -0.09], 13);

    L.tileLayer('https://www.mapbox.com/mts', {
      attribution: '&copy; <a href="https://mapbox.com/">Mapbox</a> &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
    }).addTo(map);

    {% for city in cities %}
      var circle = L.circle([{{ city.location.y }}, {{ city.location.x }}], {{ city.bounding_circle.radius }}).addTo(map);

      circle.bindPopup('{{ city.name }}');
    {% endfor %}
  </script>
</body>
</html>

このコードは、各都市の最小外接円を Leaflet マップに表示します。

この例では、BoundingCircle 関数を使用して、特定のポイントを含む都市を検索する方法を示します。

from django.contrib.gis.db.models.functions import BoundingCircle
from django.contrib.gis.geos import Point

point = Point(40.7128, -74.0060)  # ニューヨーク市の座標

cities_in_nyc = City.objects.filter(
    location__within=BoundingCircle(point)
)

このコードは、ニューヨーク市 (指定されたポイント) を含む円形ポリゴン内に位置するすべての都市を含む QuerySet を返します。

上記の例は、BoundingCircle 関数の基本的な使用方法を示しています。この関数は、さまざまな方法で使用できます。

  • ジオメトリの面積を計算する
  • ジオメトリの重心を計算する
  • 特定の距離以内に位置するジオメトリを検索する

これらのタスクを実行するには、BoundingCircle 関数を他の GIS 関数と組み合わせて使用します。



Geometry.envelope メソッド

Geometry オブジェクトは、envelope メソッドを提供します。このメソッドは、入力ジオメトリを含む最小の矩形を返します。矩形は、円形ポリゴンよりも効率的に計算できますが、円形ポリゴンよりも大きな面積になる可能性があります。

from django.contrib.gis.geos import Point, Polygon

point = Point(40.7128, -74.0060)
rectangle = point.envelope()

print(rectangle.area)  # 矩形の面積を出力

カスタム関数

特定のニーズに合わない場合は、カスタム関数を作成することもできます。たとえば、特定の精度で円形ポリゴンを生成したい場合は、次のコードを使用できます。

from django.contrib.gis.geos import GEOSGeometry, Point

def bounding_circle_with_precision(point, precision):
    # 円の半径を計算する
    radius = point.distance(point.buffer(precision))

    # 円形ポリゴンを生成する
    circle = GEOSGeometry('Circle', point, radius)

    return circle

point = Point(40.7128, -74.0060)
circle = bounding_circle_with_precision(point, 0.01)

print(circle.area)  # 円形ポリゴンの面積を出力

上記以外にも、状況に応じて様々な代替方法が考えられます。

  • Geometry.union メソッド: 2 つのジオメトリを結合します。
  • Geometry.intersection メソッド: 2 つのジオメトリの共通部分を計算します。
  • Geometry.buffer メソッド: ジオメトリを指定された距離だけ拡張します。

どの代替方法が適切かは、具体的なニーズによって異なります。以下の点を考慮する必要があります。

  • メモリ使用量
  • 処理速度
  • 必要な精度