Mat*_*tyW 15 java algorithm compass-geolocation
本周末,我花了几分钟时间将一个算法打包在一个标题中(以度为单位)并返回一个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;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是最好的方法吗?虽然我还没有在网上搜索过例子,但它必须已经多次完成.还有其他人试过这个并找到了一个更整洁的解决方案吗?
编辑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)) ];
}
Run Code Online (Sandbox Code Playgroud)
Rev*_*nzo 30
在大多数情况下这很好,但为了使其更优化和(IMO)更清洁,你可以做的是找到一个函数来将输入标题与地图中使用的标题相关联.
例如:(我很确定这是对的,但你要检查一下)
45* (int)Math.round(( ((double)x % 360) / 45))
Run Code Online (Sandbox Code Playgroud)
这样做首先x % 360
要确保标题在有效范围内.然后
45 * round(.../45)
Run Code Online (Sandbox Code Playgroud)
找到45的最接近的倍数.
现在将地图更改为
HashMap<Integer, String> map = new HashMap<Integer, String>()
map.put(0, "North")
map.put(45, "Northeast")
etc...
Run Code Online (Sandbox Code Playgroud)
所以,现在你的算法变成了一个快速的数学计算而不是遍历地图.此外,您不需要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 ]
Run Code Online (Sandbox Code Playgroud)
你已经用两行解决了问题.
一个注意事项:对于负数,模数将无法正常工作.如果我们的输入标题为负数,您需要先将其设为正数.
小智 9
这里的大多数答案以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)";
}
Run Code Online (Sandbox Code Playgroud)