32

オブジェクトの回転を 0 ~ 360 度に正規化する単純な回転ルーチンに取り組んでいます。私の C# コードは機能しているようですが、完全に満足しているわけではありません。以下のコードを改善して、もう少し堅牢にすることはできますか?

public void Rotate(int degrees)
    {
        this.orientation += degrees;

        if (this.orientation < 0)
        {
            while (this.orientation < 0)
            {
                this.orientation += 360;
            }
        }
        else if (this.orientation >= 360)
        {
            while (this.orientation >= 360)
            {
                this.orientation -= 360;
            }
        }
    }
4

9 に答える 9

55

モジュロ演算を使用する:

this.orientation += degrees;

this.orientation = this.orientation % 360;

if (this.orientation < 0)
{
    this.orientation += 360;
}
于 2009-10-27T02:06:06.713 に答える
22

これは次のように簡略化できます。

public void Rotate (int degrees) {
    this.orientation = (this.orientation + degrees) % 360;
    if (this.orientation < 0) this.orientation += 360;
}

C# は C および C++ と同じ規則に従い、任意の整数に対して~angle % 360の間の値を返します。次に、2 行目で、範囲内にあることを確認します。-3593590359

「賢く」なりたい場合は、1 行にまとめることができます。

this.orientation = (this.orientation + (degrees % 360) + 360) % 360;

これにより、すべての条件下でポジティブな状態が維持されますが、コードを 1 行節約するための厄介なハックであるため、私は実行しませんが、説明します。

からとdegrees % 360の間の番号を取得します。を追加すると、範囲が ~ の間に変更されます。がすでに正である場合、これを追加すると依然として正であることが保証され、最終的に までの範囲に戻ります。-3593593601719orientation% 3600359

最低限、とを組み合わせることができるため、コードを単純化できますたとえば、次の 2 行の条件の結果は常に同じであるため、周囲の は必要ありません。ifwhileif

if (this.orientation < 0) {
   while (this.orientation < 0) {

したがって、そのためには、次のことができます。

public void Rotate (int degrees) {
    this.orientation += degrees;
    while (this.orientation <   0) this.orientation += 360;
    while (this.orientation > 359) this.orientation -= 360;
}

しかし、潜在的に高価なループを回避するため、モジュラス バージョンを使用します

これは、ユーザーがローテーションに 360,000,000,000 を入力したときに重要になります (そして、ユーザーはこれを実行します。私を信じてください)。その後、コードがすり減っている間、早めの昼食をとる必要があることに気付きます :-)

于 2009-10-27T02:08:54.040 に答える
9

私はこれを AS3 で簡単にモックアップしましたが、動作するはずです (+=角度が必要になる場合があります)。

private Number clampAngle(Number angle)
{
    return (angle % 360) + (angle < 0 ? 360 : 0);
}
于 2009-10-27T02:23:18.660 に答える
1

角度を正規化するために別の関数を作成することをお勧めします-それはよりクリーンなソリューションです。

public static float NormalizeEulerAngle(float angle){
    var normalized = angle % 360;
    if(normalized < 0)
        normalized += 360;
    return normalized;
}

そのような機能が意図したとおりに機能することを証明するフィドル: https://dotnetfiddle.net/Vh4CUa

そして、次のように使用できます。

public void Rotate(int degrees){
    orientation = NormalizeEulerAngle(orientation + degrees);
}
于 2020-03-07T09:35:49.933 に答える
-1

360 度の任意の倍数を追加して、可能な入力値を (0 より大きくするために) 取り、次のように % で残りを取得します。

angle = 382;
normalized_angle = (angle+3600) %360;
//result = 22

上記のケースでは、入力角度を -3600 まで下げることができます。入力値が最初に正になるような非常に高い任意の数値 (360 の倍数) を追加できます。

通常、アニメーション中、前のフレーム/ステップ値はおそらく前のステップによってすでに正規化されているため、360 を追加するだけで問題ありません。

normalized_angle = (angle+360) %360;
于 2014-02-09T02:10:12.633 に答える