web-dev-qa-db-ja.com

方向を0から360の間で正規化する

私は、オブジェクトの回転を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;
            }
        }
    }
22
JuniorDeveloper

モジュロ演算を使用します。

this.orientation += degrees;

this.orientation = this.orientation % 360;

if (this.orientation < 0)
{
    this.orientation += 360;
}
47
tvanfosson

これは、任意の範囲に正規化するものです。 [-180,180]、[0,180]、または[0,360]間の正規化に役立ちます。

(C++にもありますが)

 //任意の数値を任意の範囲に正規化します
 //範囲が最小値を下回るか最大値を超えると折り返されると想定して
 double normalise(const double value、const double start、 const double end)
 {
 const double width = end-start; // 
 const double offsetValue = value-start; // 0を基準とした値
 
 return(offsetValue-(floor(offsetValue/width)* width))+ start; 
 // +リセットを開始して元の開始に戻す範囲
}

Intの場合

 //任意の数値を任意の範囲に正規化します
 //範囲が最小値を下回るか最大値を超えると折り返されると想定して
 int normalise(const int value、const int start、 const int end)
 {
 const int width = end-start; // 
 const int offsetValue = value-start; // 0を基準にした値
 
 return(offsetValue-((offsetValue/width)* width))+ start; 
 // +リセットして、元の範囲の開始点に戻る
}

基本的には同じですが、床はありません。私が個人的に使用しているバージョンは、すべての数値タイプで機能する汎用バージョンであり、整数タイプの場合は何もしない再定義されたフロアも使用しています。

32
QBziZ

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

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

C#はCおよびC++と同じルールに従い、i % 360は任意の整数に対して-359359の間の値を提供します。2行目は0〜359の範囲にあることを確認します包括的。

シフティになりたい場合は、1行に減らすことができます。

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

これはすべての状況下でそれをポジティブに保ちますが、それはコードの1行を保存するための厄介なハックなので、私はそれをしませんが、私はwill説明します。

degrees % 360からは、-359から359までの数字が表示されます。 360を追加すると、範囲が1から719の範囲に変更されます。 orientationがすでに正の値である場合、これを追加するとそれがまだ有効であることを保証し、最後の% 3600から359の範囲に戻します。

最小限の最小では、ifsとwhilesを組み合わせることができるため、コードを簡略化できます。たとえば、次の2行の条件の結果:

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

is always同じなので、周囲のifは必要ありません。

したがって、そのためには、次のようにします。

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

しかし、ループを回避するため、モジュラスバージョンではstillを使用します。これは、ユーザーがローテーションに360,000,000,000を入力すると(そしてwillこれを実行して、私を信じて)、コードがすり減るときに早めの昼食を取る必要があることがわかります:-)

18
paxdiablo

円形の値の向きを変更するための式、つまり角度を0から359に保つための式は次のとおりです。

angle + Math.ceil( -angle / 360 ) * 360

角度方向をシフトするための一般化された式は次のとおりです。

angle + Math.ceil( (-angle+shift) / 360 ) * 360

たとえばshiftの値が循環シフトを表す場合、たとえば-179〜180の値が必要な場合、次のように表すことができます。angle+ Math.ceil((-angle-179)/ 360)* 360

10
Saad Ahmed

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

private Number clampAngle(Number angle)
{
    return (angle % 360) + (angle < 0 ? 360 : 0);
}
8
enzuguri

ループ、条件、任意のオフセット(3600)、およびMath.____()の呼び出しは避けたい:

var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237
5
Ronnie Overby

角度(度)を間隔[0、360>に正規化するときに便利な関数:

float normalize_angle(float angle)
{
    float k = angle;

    while(k < 0.0)
        k += 360.0;
    while(k >= 360.0)
        k -= 360.0;
    return k;
}
0
Emil

次のように、可能な入力値が可能な360度の倍数を追加し(ゼロより上にするため)、残りを%で取ります。

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

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

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

normalized_angle = (angle+360) %360;
0
sergio

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

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);
}
0
Kris Krej