0

まず第一に、私はPython(プログラミング領域)にまったく慣れていませんが、 jwpat7によって開発された関数を学び変換したいと思っています。凸包から派生した点のセットが与えられます

hull= [(560023.44957588764,6362057.3904932579), 
      (560023.44957588764,6362060.3904932579), 
      (560024.44957588764,6362063.3904932579), 
      (560026.94957588764,6362068.3904932579), 
      (560028.44957588764,6362069.8904932579), 
      (560034.94957588764,6362071.8904932579), 
      (560036.44957588764,6362071.8904932579), 
      (560037.44957588764,6362070.3904932579), 
      (560037.44957588764,6362064.8904932579), 
      (560036.44957588764,6362063.3904932579), 
      (560034.94957588764,6362061.3904932579), 
      (560026.94957588764,6362057.8904932579), 
      (560025.44957588764,6362057.3904932579), 
      (560023.44957588764,6362057.3904932579)]

このスクリプトは、この投稿の問題に続いて、考えられるすべての領域の印刷を返します。jwpat7によって開発されたコードは次のとおりです。

import math

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)

結果は次のとおりです。

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

最小の長方形の長さ、幅、面積を返す単一の関数を作成したいと思います。元:

Length, Width, Area = get_minimum_area_rectangle(hull)
print Length, Width, Area
18.036, 10.392, 187.451

私の質問は次のとおりです。

  1. 1つまたは2つの関数を作成する必要がありますか。例:defmostfarおよびget_minimum_area_rectangle
  2. 船体は価値のリストです。最高のフォーマットですか?
    1. 1つの機能のアプローチに従って、私は最も内側に統合するのに問題があります

前もって感謝します

1)解決策:Scott Hunterによって提案された最初の解決策に続く1つの関数、get_minimum_area_rectangle()内にmostfar()を統合するのに問題があります。私は学ぶことができるので、どんな提案や助けも本当にありがたいです。

#!/usr/bin/python
import math

def get_minimum_area_rectangle(hull):
    # get pi greek
    pi = 4*math.atan(1)
    # number of points
    n = len(hull)
     # indexes left, right, opposite
    iL = iR = iP = 1
    # work clockwise direction
    for i in range(n-1):
        # distance on x axis
        dx = hull[i+1][0] - hull[i][0]
        # distance on y axis
        dy = hull[i+1][1] - hull[i][1]
        # get orientation angle of the edge
        theta = pi-math.atan2(dy, dx)
        s, c = math.sin(theta), math.cos(theta)
        yC = hull[i][0]*s + hull[i][1]*c

ここから、上記のjwpat7の例に従って、mostfar()を使用する必要があります。この時点で、どのように統合するか(正しくない用語で申し訳ありません)を理解するのに問題があります

4

4 に答える 4

2
  1. 1 つまたは 2 つの関数を使用できますが、おそらく 2 つの関数を使用する方がクリーンで簡単です。mostfar機能をそのままにしておくことができます。次に、関数定義行を追加して、コードの後半を関数に変換します。

    def get_minimum_area_rectangle(hull):
    

    …そして、残りのコード ( で始まるn = len(hull)) をインデントして、関数の本体を形成します。また、取得したい値 (長さ、幅、面積) を返すように関数を変更することもできます。これにより、コードをモジュール化してクリーンに保つことができ、変更はほとんど必要ありません。

  2. hullこの目的には、値のリストを使用しても問題ないようです。別の方法として、配列 (NumPy 配列など) を使用することもできますが、この場合、データを一度に 1 項目ずつ繰り返し処理し、多数のデータ ポイントで同時に計算を行うことはありません。したがって、リストは問題ないはずです。リスト内のアイテムへのアクセスは高速であり、実行しなければならない計算と比較してボトルネックになることはありません。

于 2012-11-25T18:30:51.207 に答える
1

コードからファンクターオブジェクトを作成して使用する方法の例を次に示します。また、私が価値があると感じた他のいくつかの変更を加えています。ファンクターは、関数の役割を果たしますが、オブジェクトのように操作できるエンティティです。

Python では、関数は既にシングルトン オブジェクトであるため、この 2 つの違いはあまりありませんが、1 つに特化したクラスを作成すると便利な場合があります。この場合、ヘルパー関数をグローバルまたはネストするのではなく、プライベート クラス メソッドにすることができます。

from math import atan2, cos, pi, sin

class GetMinimumAreaRectangle(object):
    """ functor to find length, width, and area of the smallest rectangular
        area of the given convex hull """
    def __call__(self, hull):
        self.hull = hull
        mostfar = self._mostfar  # local reference
        n = len(hull)
        min_area = 10**100  # huge value
        iL = iR = iP = 1  # indexes left, right, opposite
#        print '    {:>2s} {:>2s} {:>2s} {:>2s} {:>9s}'.format(
#                   'i', 'iL', 'iP', 'iR', 'area')
        for i in xrange(n-1):
            dx = hull[i+1][0] - hull[i][0]  # distance on x axis
            dy = hull[i+1][1] - hull[i][1]  # distance on y axis
            theta = pi-atan2(dy, dx)   # get orientation angle of the edge
            s, c = sin(theta), 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)
            l, w = (yP-yC), (xR-xL)
            area = l*w
#            print '    {:2d} {:2d} {:2d} {:2d} {:9.3f}'.format(i, iL, iP, iR, area)
            if area < min_area:
                min_area, min_length, min_width = area, l, w
        return (min_length, min_width, min_area)

    def _mostfar(self, j, n, s, c, mx, my):
        """ advance j to extreme point """
        hull = self.hull  # local reference
        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)

if __name__ == '__main__':

    hull= [(560023.44957588764, 6362057.3904932579),
           (560023.44957588764, 6362060.3904932579),
           (560024.44957588764, 6362063.3904932579),
           (560026.94957588764, 6362068.3904932579),
           (560028.44957588764, 6362069.8904932579),
           (560034.94957588764, 6362071.8904932579),
           (560036.44957588764, 6362071.8904932579),
           (560037.44957588764, 6362070.3904932579),
           (560037.44957588764, 6362064.8904932579),
           (560036.44957588764, 6362063.3904932579),
           (560034.94957588764, 6362061.3904932579),
           (560026.94957588764, 6362057.8904932579),
           (560025.44957588764, 6362057.3904932579),
           (560023.44957588764, 6362057.3904932579)]

    gmar = GetMinimumAreaRectangle()  # create functor object
    print "dimensions and area of smallest enclosing rectangular area:"
    print "  {:.3f}(L) x {:.3f}(W) = {:.3f} area".format(*gmar(hull))  # use it

出力:

dimensions and area of smallest enclosing rectangular area:
  10.393(L) x 18.037(W) = 187.451 area
于 2012-11-26T03:32:15.913 に答える
1

私(および他の人)が提案した方法を示す別の回答を投稿しています。これは、mostfar()呼び出されるメイン関数内にヘルパー関数をネストすることでした。ネストされた関数は、それを囲むスコープのローカル変数にアクセスできるため (hullこの場合のように)、Python でこれを行うのは非常に簡単です。_mostfar()また、慣習に従って関数の名前を変更して、何かがプライベートであることを示しましたが、それは厳密には必要ではありません (これまで、そして間違いなくここでは必要ありません)。

ご覧のとおり、ほとんどのコードは他の回答のコードと非常に似ていますが、関数のネストとは関係のないいくつかのことを単純化しました (そのため、選択した回答に統合される可能性があります)。

from math import atan2, cos, pi, sin

def get_minimum_area_rectangle(hull):
    """ find length, width, and area of the smallest rectangular
        area of the given convex hull """

    def _mostfar(j, n, s, c, mx, my):
        """ advance j to extreme point """
        xn, yn = hull[j]
        rx, ry = xn*c - yn*s, xn*s + yn*c
        best = mx*rx + my*ry
        k = j + 1
        while True:
            x, y = rx, ry
            xn, yn = hull[k % n]
            rx, ry = xn*c - yn*s, xn*s + yn*c
            if mx*rx + my*ry < best:
                return (x, y, j)
            else:
                j, k = k % n, j + 1
                best = mx*rx + my*ry

    n = len(hull)
    min_area = 10**100
    iL = iR = iP = 1  # indexes left, right, opposite
#   print '    {:>2s} {:>2s} {:>2s} {:>2s} {:>9s}'.format(
#              'i', 'iL', 'iP', 'iR', 'area')
    for i in xrange(n-1):
        dx = hull[i+1][0] - hull[i][0]  # distance on x axis
        dy = hull[i+1][1] - hull[i][1]  # distance on y axis
        theta = pi-atan2(dy, dx)   # get orientation angle of the edge
        s, c = sin(theta), 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)
        l, w = (yP-yC), (xR-xL)
        area = l*w
#       print '    {:2d} {:2d} {:2d} {:2d} {:9.3f}'.format(i, iL, iP, iR, area)
        if area < min_area:
            min_area, min_length, min_width = area, l, w
    return (min_length, min_width, min_area)

if __name__ == '__main__':

    hull= [(560023.44957588764, 6362057.3904932579),
           (560023.44957588764, 6362060.3904932579),
           (560024.44957588764, 6362063.3904932579),
           (560026.94957588764, 6362068.3904932579),
           (560028.44957588764, 6362069.8904932579),
           (560034.94957588764, 6362071.8904932579),
           (560036.44957588764, 6362071.8904932579),
           (560037.44957588764, 6362070.3904932579),
           (560037.44957588764, 6362064.8904932579),
           (560036.44957588764, 6362063.3904932579),
           (560034.94957588764, 6362061.3904932579),
           (560026.94957588764, 6362057.8904932579),
           (560025.44957588764, 6362057.3904932579),
           (560023.44957588764, 6362057.3904932579)]

    print "dimensions and area of smallest enclosing rectangular area:"
    print "  {:.3f}(L) x {:.3f}(W) = {:.3f} area".format(
             *get_minimum_area_rectangle(hull))
于 2012-11-26T15:56:54.670 に答える
1
  1. あなたは確かにそれを単一の機能として行うことができます.mostfarをわずかに変更して、見つかった領域を印刷する代わりに、最小のものとそれに付随する情報を追跡します. または、出力している値を lst に収集して、GEAR が最小値を見つけるために使用することもできます。

編集: (一部のコードが mostfar の外側にあることを見逃していました)「スクリプト」部分 (mostfar の後のコード) を関数にラップし、上記のようにそれを変更します。あなたの「スクリプト」はその関数を呼び出すか、2番目の変更を使用する場合は、返されたリストから分を見つけます。

  1. 船体の表現に問題はありません。
于 2012-11-25T18:17:40.710 に答える