点集合の凸包内のn個の点の時計回りのリストが与えられた場合、それは最小面積を囲む矩形を見つけるためのO(n)操作です。
次のpythonプログラムでは、通常のO(n)アルゴリズムと同様の手法を使用して最大値を計算します(最大値を計算するには、O(n log n)時間内に凸包を見つけるにはactivestate.com recipe 66527を参照してください)。凸多角形の直径。つまり、与えられたベースラインに対して左端、反対端、右端の3つのインデックス(iL、iP、iR)を維持します。各インデックスは、最大でnポイント進んでいます。プログラムからのサンプル出力を(追加ヘッダで)次示されている:例えば
i iL iP iR Area
0 6 8 0 203.000
1 6 8 0 211.875
2 6 8 0 205.800
3 6 10 0 206.250
4 7 12 0 190.362
5 8 0 1 203.000
6 10 0 4 201.385
7 0 1 6 203.000
8 0 3 6 205.827
9 0 3 6 205.640
10 0 4 7 187.451
11 0 4 7 189.750
12 1 6 8 203.000
、I = 10のエントリは、ポイント4は、ポイント10から11までのベースラインに対して、点0は左端であることを示し反対側にあり、ポイント7は右端にあり、187.451台の面積が得られます。
コードでは、mostfar()
を使用して各インデックスを進めることに注意してください。 mx, my
のパラメータをmostfar()
に設定すると、テストする極端なことが分かります。一例として、mx,my = -1,0
でmostfar()
は、-rx(ここで、rxは点の回転したx)を最大にしようとします。したがって、最も左の点が見つかります。ただし、浮動小数点数が多い場合は、丸め誤差が問題となり、誤って指数を進ませない可能性がありますので、不正確な算術演算でif mx*rx + my*ry >= best
を実行した場合は、εの余裕が必要です。
コードを以下に示します。船体のデータは上記の質問から得られ、無関係な大きなオフセットと同一の小数点以下の桁は省略されています。
#!/usr/bin/python
import math
hull = [(23.45, 57.39), (23.45, 60.39), (24.45, 63.39),
(26.95, 68.39), (28.45, 69.89), (34.95, 71.89),
(36.45, 71.89), (37.45, 70.39), (37.45, 64.89),
(36.45, 63.39), (34.95, 61.39), (26.95, 57.89),
(25.45, 57.39), (23.45, 57.39)]
def mostfar(j, n, s, c, mx, my): # advance j to extreme point
xn, yn = hull[j][0], hull[j][1]
rx, ry = xn*c - yn*s, xn*s + yn*c
best = mx*rx + my*ry
while True:
x, y = rx, ry
xn, yn = hull[(j+1)%n][0], hull[(j+1)%n][1]
rx, ry = xn*c - yn*s, xn*s + yn*c
if mx*rx + my*ry >= best:
j = (j+1)%n
best = mx*rx + my*ry
else:
return (x, y, j)
n = len(hull)
iL = iR = iP = 1 # indexes left, right, opposite
pi = 4*math.atan(1)
for i in range(n-1):
dx = hull[i+1][0] - hull[i][0]
dy = hull[i+1][1] - hull[i][1]
theta = pi-math.atan2(dy, dx)
s, c = math.sin(theta), math.cos(theta)
yC = hull[i][0]*s + hull[i][1]*c
xP, yP, iP = mostfar(iP, n, s, c, 0, 1)
if i==0: iR = iP
xR, yR, iR = mostfar(iR, n, s, c, 1, 0)
xL, yL, iL = mostfar(iL, n, s, c, -1, 0)
area = (yP-yC)*(xR-xL)
print ' {:2d} {:2d} {:2d} {:2d} {:9.3f}'.format(i, iL, iP, iR, area)
注:が最小面積外接矩形の長さ及び幅を得るために、以下に示すように上記のコードを変更します。これは、第二及び第三の数字は長方形の長さおよび幅を示し、4つの整数はその側面上に位置する点のインデックス番号を与えている
Min rectangle: 187.451 18.037 10.393 10 0 4 7
等出力線を生成します。
# add after pi = ... line:
minRect = (1e33, 0, 0, 0, 0, 0, 0) # area, dx, dy, i, iL, iP, iR
# add after area = ... line:
if area < minRect[0]:
minRect = (area, xR-xL, yP-yC, i, iL, iP, iR)
# add after print ... line:
print 'Min rectangle:', minRect
# or instead of that print, add:
print 'Min rectangle: ',
for x in ['{:3d} '.format(x) if isinstance(x, int) else '{:7.3f} '.format(x) for x in minRect]:
print x,
print
あなたは既にアルゴリズムを見つけました。あなたの質問は何ですか? – Eric
@エリック、リプレイのおかげで。私はPythonでこのアルゴリズムが既に実装されているかどうかを調べています(例:整形式または他のモジュールで) –
あなたの質問は_ "既にこれを行うモジュールが存在しますか?" _ – Eric