17

今週末、私は数分かけて、方位 (度) を取り、基本方向の文字列を返すアルゴリズムを一緒にスラッシングします (私が使用している Android コンパス アプリケーションで使用しています)。私が最終的に得たのはこれでした:

private String headingToString(Float heading)
{
    String strHeading = "?";
    Hashtable<String, Float> cardinal = new Hashtable<String, Float>();
    cardinal.put("North_1", new Float(0));
    cardinal.put("Northeast", new Float(45));
    cardinal.put("East", new Float(90));
    cardinal.put("Southeast", new Float(135));
    cardinal.put("South", new Float(180));
    cardinal.put("Southwest", new Float(225));
    cardinal.put("West", new Float(270));
    cardinal.put("Northwest", new Float(315));
    cardinal.put("North_2", new Float(360));

    for (String key: cardinal.keySet())
    {
        Float value = cardinal.get(key);
        if (Math.abs(heading - value) < 30)
        {
            strHeading = key;
            if (key.contains("North_"))
            {
                strHeading = "North";
            }
            break;
        }
    }
    return strHeading;
}

私の質問は、これがこれを行う最良の方法ですか? Web で例を検索したことはまだありませんが、これまでに何度も行われたに違いありません。他の人がこれを試して、より良い解決策を見つけましたか?

The Reverand の Thilo、shinjin、および Chrstoffer の応答を編集します。

ソリューション

public static String headingToString2(double x)
{
    String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"};
    return directions[ (int)Math.round((  ((double)x % 360) / 45)) ];
}
4

5 に答える 5

30

ほとんどの場合、これで問題ありませんが、最適化して (IMO) クリーンにするために、入力見出しをマップで使用されているものに関連付ける関数を見つけることができます。

例:(これは正しいと確信していますが、確認してください)

45* (int)Math.round((  ((double)x % 360) / 45))

これが最初x % 360に行うことは、見出しが有効な範囲内にあることを確認することです。それから

45 * round(.../45)

最も近い 45 の倍数を見つけます。

マップを次のように変更します

  HashMap<Integer, String> map = new HashMap<Integer, String>()
  map.put(0, "North")
  map.put(45, "Northeast")
  etc...

したがって、アルゴリズムは、マップを反復処理するのではなく、高速な数学的計算になります。さらに、ここでは as Hashtable は必要ありません。同時実行の構造を提供するため (私の記憶が正しければ)、実際にパフォーマンスが低下するからです。

繰り返しますが、パフォーマンスへの影響は、ニーズに対して完全に無視できる場合があります。

Thilo と shinjin の提案を編集します。

45 を掛ける代わりに、0 ~ 7 の値を与える式の残りを保持し、文字列の配列を作成します。

String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"}
return directions[ (int)Math.round((  ((double)x % 360) / 45)) % 8 ]

問題は 2 行で解決されます。

1 つの注意: モジュラスは、負の数に対して正しく機能しません。入力見出しが負の場合は、最初に正にする必要があります。

于 2010-01-25T09:31:27.880 に答える
10

ここでの答えのほとんどは、45 度の間隔で 22.5 度ずれており、[337.5-360]、[0-22.5] ではなく、たとえば 0-45 を N としてマッピングします。計算を行う前にオフセットする必要があります。これで正しい。

風向に見られるように、22.5 度の間隔を使用するソリューションを次に示します。

  private String formatBearing(double bearing) {
    if (bearing < 0 && bearing > -180) {
      // Normalize to [0,360]
      bearing = 360.0 + bearing;
    }
    if (bearing > 360 || bearing < -180) {
      return "Unknown";
    }

    String directions[] = {
      "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
      "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW",
      "N"};
    String cardinal = directions[(int) Math.floor(((bearing + 11.25) % 360) / 22.5)];
    return cardinal + " (" + formatBearing.format(bearing) + " deg)";
  }
于 2014-08-17T13:48:42.053 に答える
0

North_1 と North_2 を避けるために、前方に 15 度追加できます。

于 2010-01-25T09:20:04.367 に答える
0

前の例は正確ではありません。JavaScript でのより正確なソリューションを次に示します。

function getCardinalDirection(input) {
    var directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"];
    var index = Math.floor( ((input-22.5)%360) / 45 );
    return directions[index+1];
}
于 2013-10-28T14:45:47.517 に答える
-1

Javaで:

String _directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"};

public String getHeading(int hea) {
  return _directions[(int)Math.floor((hea % 360) / 45)];
}

「Java」の場合、クラスを作成する必要があります。

JavaScriptで:

var _directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"];

function getDirection (hea) {
  return _directions[Math.floor((hea % 360) / 45)];
};
于 2011-03-14T00:12:03.860 に答える