繁体   English   中英

Java中的基数方向算法

[英]Cardinal direction algorithm in Java

本周末,我花了几分钟时间将一个算法打包在一个标题中(以度为单位)并返回一个String作为基本方向(我在我正在使用的安卓指南针应用程序中使用它)。 我最终得到的是:

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

我的问题是,这是最好的方法吗? 虽然我还没有在网上搜索过例子,但它必须已经多次完成。 还有其他人试过这个并找到了一个更整洁的解决方案吗?

编辑Reverand的Thilo's,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)) ];
}

在大多数情况下这很好,但为了使其更优化和(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作为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 ]

你已经用两行解决了问题。

一个注意事项:对于负数,模数将无法正常工作。 如果我们的输入标题为负数,您需要先将其设为正数。

这里的大多数答案以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)";
  }

前面的示例不准确,这是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];
}

您可以向前添加15度以避免North_1和North_2。

在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”情况下,您必须创建一个Class。

在javascript中:

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

function getDirection (hea) {
  return _directions[Math.floor((hea % 360) / 45)];
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM