2

Pythonベースの描画プログラムWhyteboard(https://launchpad.net/whyteboard)を開発しています

私は、ユーザーが描画するポリゴンを回転およびスケーリングできるようにする機能を開発しています。これが私の問題です:

すべてのポイントのリストを含むPolygonクラスがあり、最後に「閉じられています」。ユーザーは私のプログラムで描画された図形を選択できます。これにより、描画された図形が「強調表示」され、各ポイントで選択ハンドルが描画されます。これらのポイントを「つかんで」位置を変更したり、ポリゴンの形状を変更したりできます。

問題があります。ポリゴンに適用するサイズ変更の「スケール」を計算する方法を理解する必要があります。たとえば、(マウスを押したまま)ユーザーがマウスを図形から遠ざけることは「成長」アクションであり、マウスを図形に近づけると縮小する必要があります。

スケールを実行するためのコードがありますが(これは正しいと思います)、「適切な」スケーリング係数を作成できません。以下のコードは、答えに基づいて私が思いついたものです

/edit-これが解決されたコードです。

def rescale(self, x, y):
    """ 
    x and y are the current mouse positions. the center and "original" mouse 
    coords are calculated below
    """
    if not self.center:
        a = sum([x for x, y in self.points]) / len(self.points)
        b = sum([y for x, y in self.points]) / len(self.points)
        self.center = (a, b)
    if not self.orig_click:  # where the user first clicked on
        self.orig_click = (x, y)
    if not self.original_points:  # the points before applying any scaling
        self.original_points = list(self.points)


    orig_click = self.orig_click
    original_distance = math.sqrt((orig_click[0] - self.center[0]) ** 2 + (orig_click[1] - self.center[1]) ** 2)

    current_distance = (math.sqrt((x - self.center[0]) ** 2 + 
                       (y - self.center[1]) ** 2))
    self.scale_factor = current_distance / original_distance        

    for count, point in enumerate(self.original_points): 
        dist = (point[0] - self.center[0], point[1] - self.center[1]) 
        self.points[count] = (self.scale_factor * dist[0] + self.center[0], self.scale_factor * dist[1] + self.center[1]) 

現在、このコードは私のポリゴンをすぐにゼロに縮小しているようで、マウスを少し動かしてもポリゴンは元に戻りません。時にはそれは反対のことをし、急速に成長します。しかし、縮むことはありません。

4

3 に答える 3

6

まず、スケーリングコードを修正しましょう。

for count, point in enumerate(self.points): 
    dist = (point[0] - self.center[0], point[1] - self.center[1]) 
    self.points[count] = (self.scale_factor * dist[0] + self.center[0], self.scale_factor * dist[1] + self.center[1]) 

整数の切り捨てエラーはすぐに蓄積されるため、ポイントが浮動小数点に保持されることを願っています。ポイントのコピーを2つ用意する方がよい場合があります。1つはスケーリングされ、もう1つはスケーリングされていません。

倍率を決定するには、元のクリックから中心までの距離と、現在のマウスの位置から中心までの距離の比率を取ります。

original_distance = sqrt((click[0] - self.center[0])**2 + (click[1] - self.center[1])**2)
current_distance = sqrt((current_position[0] - self.center[0])**2 + (current_position[1] - self.center[1])**2)
self.scale_factor = current_distance / original_distance

編集:あなたの最新の問題は、元のポイントとスケーリングされたポイントの2つのセットを持つことの重要性を強調しています。倍率は図形の元のサイズを基準にしているため、拡大縮小するたびに、図形の元のポイントから開始する必要があります。ユーザーがマウスでのプレイを終えたら、それを1つのセットに統合することができます。

そしてあなたのコメントに、あなたは中心を再計算する必要はありません。センターは動いてはいけません。

編集2:スケーリングすると、あるサイズから別のサイズスケーリングします。絶えず再スケーリングする場合は、2つの選択肢があります。1つの図形のコピーを元のサイズのままにするか、元のサイズではなく、図形の最後のサイズを基準にして倍率を作成します。浮動小数点を使用している場合でも、エラーが蓄積しやすいため、2コピーアプローチをお勧めします。ロジックを正しくすることも簡単です。

于 2010-01-06T17:56:17.607 に答える
1

最も直感的なスケール係数は、(現在のマウス位置からポリゴンの中心までの距離)と(ドラッグの開始時のマウスの位置からポリゴンの中心までの距離)の比率です。つまり、ポリゴン内のポイントをクリックして2回ドラッグします。中心から離れると、ポリゴンのサイズが2倍になります。

于 2010-01-06T17:32:13.583 に答える
1

私はPythonに精通していないので、擬似コードで答えようとします。

まず、ポリゴンの中心を計算します。これは非常に簡単に実行できます(そして、考えてみると理にかなっています)。すべてのポイントを合計し、ポイント数で割るだけです。

center = (point1 + point2 + point3) / 3

マウスに基づいて拡大縮小したいですよね?それは常に厄介なことになるでしょうが、それは次のようなものでなければなりません:

scale = lengthof(mouse - center) / MAGIC_NUMBER

次に、中心に対する相対点を計算します。グラフの原点を中心点に効果的に設定しています。

relative_point1 = point1 - center
relative_point2 = point2 - center
relative_point3 = point3 - center

次に、相対ポイントをスケールでスケーリングします。

relative_point1 *= scale
relative_point2 *= scale
relative_point3 *= scale

そして、それらを正しい位置に戻します。

point1 = center + relative_point1
point2 = center + relative_point2
point3 = center + relative_point3

丸め誤差を回避するには、ユーザーがスケーリングを完了するまで元のポイントを保持することをお勧めします。

于 2010-01-06T18:06:57.413 に答える