Django で GIS データの周囲の長さを計算する方法: `django.contrib.gis.db.models.functions.Perimeter` 関数チュートリアル


構文

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

perimeter = Perimeter(field)

ここで、field は、周囲の長さを計算したいジオメトリフィールドまたは式です。


from django.contrib.gis.db.models import fields

class MyModel(models.Model):
    polygon = fields.PolygonField()

# MyModel インスタンスの 'polygon' フィールドの周囲の長さを計算する
perimeter = Perimeter(MyModel.objects.get(pk=1).polygon)
print(perimeter)

この例では、MyModel モデルの polygon フィールドの周囲の長さを計算し、結果をコンソールに出力します。

注意事項

  • SRID が指定されていない場合、Perimeter 関数はジオメトリフィールドの SRID を使用します。SRID が指定されていない場合、またはジオメトリフィールドに SRID が設定されていない場合は、DEFAULT_SRID 設定値が使用されます。
  • 計算される周囲の長さは、メートル単位で表現されます。
  • Perimeter 関数は、ジオメトリフィールドのみで使用できます。他のタイプのフィールドで使用すると、TypeError 例外が発生します。

Perimeter 関数は、さまざまな目的に使用できます。たとえば、土地の面積を計算したり、フェンスの長さを計算したり、地図上のオブジェクト間の距離を計算したりするために使用できます。



長方形の周囲の長さを計算する

from django.contrib.gis.db.models import fields
from django.contrib.gis.db.models.functions import Perimeter

class MyModel(models.Model):
    rectangle = fields.PolygonField()

# MyModel インスタンスの 'rectangle' フィールドの周囲の長さを計算する
rectangle = MyModel.objects.get(pk=1).rectangle
perimeter = Perimeter(rectangle)
print(perimeter)

この例では、MyModel モデルの rectangle フィールドの周囲の長さを計算し、結果をコンソールに出力します。

円の周囲の長さを計算する

from django.contrib.gis.db.models import fields
from django.contrib.gis.db.models.functions import Perimeter
from django.contrib.gis.geos import Point, Circle

# 円を作成する
center = Point(2, 3)
radius = 5

circle = Circle(center, radius)

# 円の周囲の長さを計算する
perimeter = Perimeter(circle)
print(perimeter)

この例では、半径が 5 の円を作成し、その周囲の長さを計算します。

多角形の周囲の長さを計算する

from django.contrib.gis.db.models import fields
from django.contrib.gis.db.models.functions import Perimeter
from django.contrib.gis.geos import Polygon

# 多角形を作成する
points = [
    (0, 0),
    (5, 0),
    (5, 5),
    (0, 5),
]

polygon = Polygon(points)

# 多角形の周囲の長さを計算する
perimeter = Perimeter(polygon)
print(perimeter)

この例では、5 つの点で構成される多角形を作成し、その周囲の長さを計算します。

from django.contrib.gis.db.models import fields
from django.contrib.gis.db.models.functions import Perimeter
from django.contrib.gis.geos import LineString

# 線分を作成する
start_point = Point(0, 0)
end_point = Point(5, 5)

line_string = LineString([start_point, end_point])

# 線分の長さを計算する
perimeter = Perimeter(line_string)
print(perimeter)

この例では、2 つの点で構成される線分を作成し、その長さを計算します。



math.pi と math.sqrt を使用して手動で計算する

この方法は、単純な形状 (円、正方形など) の場合に役立ちます。

from math import pi

def calculate_perimeter(geometry):
    if geometry.geom_type == 'Polygon':
        return sum(segment.length for segment in geometry.boundary)
    elif geometry.geom_type == 'Circle':
        return 2 * pi * geometry.radius
    else:
        raise NotImplementedError('Unsupported geometry type: {}'.format(geometry.geom_type))

# 円の周囲の長さを計算する
geometry = Circle((0, 0), 5)
perimeter = calculate_perimeter(geometry)
print(perimeter)

長所

  • シンプルで理解しやすいコード

短所

  • 誤差が発生する可能性がある
  • 複雑な形状には対応していない

GeoJSON を使用して JavaScript で計算する

この方法は、Web アプリケーションでジオメトリの周囲の長さを計算する場合に役立ちます。

function calculatePerimeter(geometry) {
  if (geometry.type === 'Polygon') {
    return geometry.coordinates[0].reduce((acc, curr, i) => {
      if (i === 0) return acc;
      const prev = geometry.coordinates[0][i - 1];
      const dx = curr[0] - prev[0];
      const dy = curr[1] - prev[1];
      return acc + Math.sqrt(dx * dx + dy * dy);
    }, 0);
  } else if (geometry.type === 'Circle') {
    return 2 * Math.PI * geometry.radius;
  } else {
    throw new Error('Unsupported geometry type: ' + geometry.type);
  }
}

// 円の周囲の長さを計算する
const geometry = {
  type: 'Circle',
  coordinates: [0, 0],
  radius: 5
};

const perimeter = calculatePerimeter(geometry);
console.log(perimeter);

長所

  • 複雑な形状にも対応している
  • Web アプリケーションで使いやすい

短所

  • クライアント側で計算を行うため、パフォーマンスが低下する可能性がある
  • JavaScript の知識が必要

GDAL ライブラリを使用して C++ で計算する

この方法は、高性能で精度の高い計算が必要な場合に役立ちます。

#include <gdal_priv.h>

double calculatePerimeter(GDALGeometryPtr geometry) {
  if (geometry->getGeometryType() == wkbPolygon) {
    GDALMultiLineStringPtr linestring = geometry->castToMultiLineString();
    double perimeter = 0;
    for (int i = 0; i < linestring->getNumGeometries(); ++i) {
      GDALLineStringPtr line = linestring->getGeometryRef(i);
      perimeter += line->getLength();
    }
    return perimeter;
  } else if (geometry->getGeometryType() == wkbCircle) {
    GDALCirclePtr circle = geometry->castToCircle();
    return 2 * M_PI * circle->getRadius();
  } else {
    throw std::runtime_error("Unsupported geometry type");
  }
}

int main() {
  // 円の周囲の長さを計算する
  GDALGeometryPtr geometry = GDALCreateFromWkt("CIRCLE(0, 0, 5)");
  double perimeter = calculatePerimeter(geometry);
  std::cout << perimeter << std::endl;

  return 0;
}

長所

  • 複雑な形状にも対応している
  • 高性能で精度の高い計算が可能
  • GDAL ライブラリのインストールと設定が必要
  • C++ の知識が必要