【问题标题】:Cardinal direction algorithm in JavaJava中的基数方向算法
【发布时间】:2010-01-25 09:11:39
【问题描述】:

这个周末我花了几分钟时间研究一个算法,该算法将采用一个航向(以度为单位)并返回一个基本方向的字符串(我在我正在使用的 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;
}

我的问题是,这是最好的方法吗?虽然我还没有在网上搜索过示例,但之前肯定已经做过很多次了。有没有其他人尝试过这个并找到了一个更简洁的解决方案?

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

【问题讨论】:

    标签: java algorithm compass-geolocation


    【解决方案1】:

    这在大多数情况下都很好,但为了使其优化和 (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,因为它提供了并发构造(如果我没记错的话),在您的情况下,它实际上会导致性能下降。

    再一次,对于您的需求,性能损失可能完全可以忽略不计。

    编辑 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 ]
    

    你的问题分两行解决了。

    请注意:模数无法正确处理负数。如果我们的输入标题为负数,您需要先将其设为正数。

    【讨论】:

    • +1。很不错。更进一步,向函数添加另一个小的转换,他可以得到一个字符串数组的索引:String[] directions = { "N", "NE", "E" ... }
    • 如果省略乘以 45,则可以使用简单数组代替哈希映射。
    • 您需要在该数组中添加一个“N”。标题 337.5 及以上将四舍五入为 8。
    • 此解决方案中有两个拼写错误导致不正确的结果和 IndexOutOfBoundsException:1) 数组中缺少“W”:String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"} 2) 索引 8 应该回绕回 0 return directions[ (int)Math.round(( ((double)x % 360) / 45)) % 8 ]
    • @Walmart_Hobo 你的意思是 %7?
    【解决方案2】:

    这里的大多数答案在 45 度的间隔内偏离 22.5 度,并映射例如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)";
      }
    

    【讨论】:

    • 您的方向数组包含两次 N 是否正常?
    【解决方案3】:

    您可以提前增加 15 度以避免 North_1 和 North_2。

    【讨论】:

      【解决方案4】:

      前面的例子不准确,这里有一个更准确的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];
      }
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 2016-06-07
          • 1970-01-01
          • 1970-01-01
          • 2018-02-26
          • 1970-01-01
          • 1970-01-01
          • 2015-11-01
          • 2014-08-22
          • 1970-01-01
          相关资源
          最近更新 更多