2016-05-16 50 views
6

私は入りませんが、お互いに本質的に逆の2つの関数が必要です。Pythonを使用して、時計回り/反時計回りの方向に、与えられたピクセル座標を返します(逆も同様)。

angle_to()は(p1が回転の中心である。すなわち)clockhandがp2p1を結ぶ線に対して0°から移動する回転しなければならない度の数を返す必要があり、どこp1p2両方がピクセル座標であります

point_pos()は、時計ハンドの長さがamplitudeであるピクセル座標をangleに戻す必要があります。

正のx軸= 0°= 3時、引数rotationは、時計回りまたは反時計回りのいずれかで計算が開始される前にその軸をシフトする必要があります。この計算はこの調整された基準で同じ方向に動くべきである。

それぞれの進捗状況を以下に示します。

時計回り= Falseの場合、時計回りの条件の正解を返します。 clockwise = Trueの場合、angle_between()は丸め誤差の正解を返し、point_pos()は私に間違った答えを与えます。

私はイラストレーターでこれを解決できないためにインターネットに謝罪し、私が求めていることがはっきりしない場合には、私はイラストレーターで嘲笑した視覚的説明を添付しました。

編集:以下の1つの答えに従って不必要に複雑な行をクリーンアップしました。

from math import sin, cos, radians, pi, atan2, degrees 

def angle_to(p1, p2, rotation=0, clockwise=False): 
    if abs(rotation) > 360: 
     rotation %= 360 
    p2 = list(p2) 
    p2[0] = p2[0] - p1[0] 
    p2[1] = p2[1] - p1[1] 

    angle = degrees(atan2(p2[1], p2[0])) 
    if clockwise: 
     angle -= rotation 
     return angle if angle > 0 else angle + 360 
    else: 
     angle = (360 - angle if angle > 0 else -1 * angle) - rotation 
     return angle if angle > 0 else angle + 360 

def point_pos(origin, amplitude, angle, rotation=0, clockwise=False): 
    if abs(rotation) > 360: 
     rotation %= 360 
    if clockwise: 
     rotation *= -1 
    if clockwise: 
     angle -= rotation 
     angle = angle if angle > 0 else angle + 360 
    else: 
     angle = (360 - angle if angle > 0 else -1 * angle) - rotation 
     angle = angle if angle > 0 else angle + 360 

    theta_rad = radians(angle) 
    return int(origin[0] + amplitude * cos(theta_rad)), int(origin[1] + amplitude * sin(theta_rad)) 

angle_to() point_pos()

編集#2:私は終わり、私はそれを修正しようとしたとき

angle_to()は(時計回りを反転し、反時計回りにされています。要求に応じは、ここでいくつかの出力に失敗します時計回りの方向で、回転して異なる方向に計算する。

>>> print angle_to((100,100), (25,25)) # should be 225 
135.0 
>>> print angle_to((100,100), (25,25), 45) # should be 180 
90.0 
>>> print angle_to((100,100), (25,25), clockwise=True) # should be 135 
225.0 
>>> print angle_to((100,100), (25,25), 45, clockwise=True) # should be 90 
180.0 

point_pos()が反時計回りにちょうど間違っている

# dunno what these should be (i'm bad at trig) but when I visually place the 
# given p1 and the output p2 on screen it's obvious that they're wrong 
>>> print point_pos((100,100), 75, 225)    
(46, 153) 
>>> print point_pos((100,100), 75, 225, 45) 
(100, 175) 

# these are basically correct, rounding-errors notwithstanding 
>>> print point_pos((100,100), 75, 225, clockwise=True) 
(46, 46) 
>>> print point_pos((100,100), 75, 225, 45, clockwise=True) 
(99, 25) 
+0

コードの問題点を教えてください。 –

+0

第3段落。時計回り/反時計回りの状態を正しく処理していません。 'clockwise = False'のときは、時計回りの条件に対する正解を返します。 'clockwise = True'のとき、' angle_between() 'は丸め誤差の正解を返し、' point_pos() 'は私に間違った答えを与えます。 – Jonline

+0

入力の例と期待される結果(例えば、90度の回転)を与えることができますか? –

答えて

2

シンプルなルールを使用することで、コードをかなり単純化することができます。単純なコードではバグが発生しにくくなります。

最初に、時計回りと反時計回りの間の変換は、記号:angle = -angleを反転することを意味します。

第2に、角度を[0, 360)の範囲に制限するには、単にangle % 360を使用します。これは、角度が負または正、整数または浮動小数点を開始しても関係なく機能します。

def angle_to(p1, p2, rotation=0, clockwise=False): 
    angle = degrees(atan2(p2[1] - p1[1], p2[0] - p1[0])) - rotation 
    if not clockwise: 
     angle = -angle 
    return angle % 360 
+0

しかし、記号を反転するだけでは意味がありません。時計回りに45°移動すると、同じ位置から反時計回りに315°の角度で有効になります。これは最小限の(360°)360%です。 – Jonline

+1

@Jonline私はあなたに両方をするように言う理由です。 '(360 - angle)%360'は' -angle%360'と同じです。 –

+0

...とjonoがフィニッシュラインを横切っています。ありがとう。 – Jonline

1

再:あなたのコードでは

angle_to()はclockhandがP1からP2に移動する有効にする必要があります度の数を返す必要があります」、 atan2を使用して角度を計算する前に、点p1の座標をp2から減算します。基本的には、p1が時計の中心にあると考えているので、「回転によってp1からp2に移動する」ことについて話す意味はありません。 3つのポイントを指定する必要があります。回転を行う中心、ポイント1、ポイント2を指定する必要があります。あなたの新しい仕様に更新

angle1 = atan2(y1-yc, x1-xc) 
angle2 = atan2(y2-yc, x2-xc) 
relative_angle = angle1 - angle2 
# now convert to degrees and handle +/-360 issues. 

:座標はXC、YC、X1、Y1、X2、Y2ている場合は、このような何かをする必要があると思います「clockhand度の数を返しますP2" とP1とを結ぶ線に対して0°から移動する回転しなければならない:+ Piに範囲-piに(ピクセル座標における)

angle = degrees(atan2(p2[1], p2[0])) 

この時計回りの角度を戻します(-180 +180 deg)。あなたの例では、angle_to((100,100), (25,25))( "want 225、but get 135")では、atan2は-135度になり、反時計回りに+135度を意味します。これは時計の手がcwかccwのどちらを回転させるべきかを指定していないので(360度モジュロ)、3時の位置に対して開始位置がcwかccwかを指定するだけで、 。ただし、clockwiseの値(デフォルトはFalse)に応じて、何か複雑になります。

時計の針が確実にcwになるようにするには、結果角度が負の場合は360度を追加し、角度を戻さないようにします。

(注:私は昔の答えを削除し、最初の2件のコメントが古い答えを参照してください。)

+0

確認済み:まだ動作していないコードを整理してください – Jonline

+1

これは単なる定数ですので、両方の座標に(本来、スケールを実行していた) –

+0

sighを乗算しています。あなたは絶対に正しいですが、これは私の説明の間違いです。私は今変更するでしょう;それはp1がcloの中心であったならば、それは現在0°を指していました。 – Jonline

1

この: angle = (360 - angle if angle > 0 else -1 * angle) - rotation 私はあなたがそこに達成しようとしていたのか分からないが、それは確かにありませんあなたが望むことをしないでください。ただ持っている-angleの角度を反映しています。反時計回りから時計回りに角度の方向を変え、条件の反時計回りの分岐にいることに注目してください。その後、360を追加すると、すべてが壊れてしまいます。 elseブランチは、角度を-1で乗算するだけです。もう一度逆にします。時計回りの枝は、角度を逆にする必要があるところです(また、角度が正であるように360を加えます)。ここ は、余分な回転パラメータなしで固定あなたの関数の簡易版である:

def angle_to(p1, p2, clockwise=False): 
    p2 = list(p2) 
    p2[0] = p2[0] - p1[0] 
    p2[1] = (p2[1] - p1[1]) 
    angle = degrees(atan2(p2[1], p2[0])) 
    angle = 360 + angle if angle < 0 else angle 
    return angle if not clockwise else -angle+360 

あなたの他の機能は、これらの行では正確に同じ問題に苦しんでいる:

if clockwise: 
    angle -= rotation 
    angle = angle if angle > 0 else angle + 360 
else: 
    angle = (360 - angle if angle > 0 else -1 * angle) - rotation 
    angle = angle if angle > 0 else angle + 360 

は次のようになります。

angle -= rotation 
if clockwise: 
    angle = -angle+360 if angle > 0 else -angle 
else: 
    angle = angle if angle > 0 else angle + 360 
+0

これは、in-situが実際に重要な引数 'rotation'を除いてほとんどすべてを解決します(私は認知心理学の実験のために開発しており、時には奇妙な要求を必要とします)。あなたが観察した線のいくつかは、疑問の余地はありませんでした。私は自分の深さから外れています - 計算する前に0回転軸が回転していることを調整することを意図していました。これを説明するソリューションが両者で同じであると仮定すると、それを組み込む方法についてコメントできますか? – Jonline

+0

...実際に正しい角度を返すと、どちらの方向にも 'angle - = rotation'ということが起こります。しかし、私はいつも正の角度を返したいので、私はさらに、「角度が0> 360度+角度の場合は戻り角度が必要です」ということを修正しますか? – Jonline

+0

これは正しいです。代わりに、returnステートメントの後ろにくるものをかっこで囲み、その答えで@MarkRansomのように360で演算子 '%'を使用することもできます。それはあなたがいつも確実に範囲[0、360 [。 –

関連する問題