Алгоритм кардинального направления в Java - PullRequest
15 голосов
/ 25 января 2010

В эти выходные я провожу несколько минут, составляя алгоритм, который будет принимать заголовок (в градусах) и возвращать строку для кардинального направления (я использую его в приложении для 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;
}

Мой вопрос: это лучший способ сделать это? Должно быть, это было сделано много раз, хотя я еще не выполнил поиск примеров в Интернете. Кто-нибудь еще пробовал это и нашел более точное решение?

Изменить для ответов Тивера, Синдзина и Хрстоффера:

Решение

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)) ];
}

Ответы [ 5 ]

29 голосов
/ 25 января 2010

Это нормально в большинстве случаев, хотя, чтобы сделать его оптимизированным и (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...

Итак, теперь ваш алгоритм становится быстрым математическим вычислением, а не итерацией по карте. Кроме того, вам здесь не нужен Hashtable, поскольку он предоставляет конструкции для параллелизма (если я правильно помню), и в вашем случае это фактически приведет к снижению производительности.

Еще раз, производительность может быть совершенно незначительной для ваших нужд.

Правка для предложений Тило и Синдзина:

Вместо умножения на 45, просто оставьте остаток уравнения, который дает значения от 0 до 7, и создайте массив из ваших строк.

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

и ваша проблема решена в две строки.

Одно примечание: модуль не будет работать правильно для отрицательных чисел. Если заголовок нашего ввода отрицательный, сначала нужно сделать его положительным.

9 голосов
/ 17 августа 2014

Большинство ответов здесь отклонены на 22,5 градуса для их 45-градусных интервалов, и карта, например, 0-45 как N, а не [337.5-360], [0-22.5] до 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)";
  }
0 голосов
/ 28 октября 2013

Предыдущие примеры не точны, вот более точное решение в 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];
}
0 голосов
/ 14 марта 2011

в 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)];
};
0 голосов
/ 25 января 2010

Вы можете добавить 15 градусов вперед, чтобы избежать север_1 и север_2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...