如何在 Android 应用程序中使用 Azure Maps 在原点位置更改后重新绘制路线
How to re-draw a route after the origin location changes using Azure Maps in Android application
我正在构建一个 Android 应用程序来渲染地图。使用 phone 位置和特定目的地,我需要在地图上显示路线,并在用户的 phone 移动时重新绘制路线。很抱歉这么长 post,我正在努力使它尽可能明确。
我要用Azure Maps,用户要走原来的路线,所以我需要在用户走的时候重新画路线。基本上,每次用户移动时,我只需要使原始路线从 phone 位置开始。
我每三秒获取一次 phone 的纬度和经度,当用户选择目的地位置时,我调用 Azure API 用于路线,其中 returns 一个 JSON 包含从起点到终点的点(纬度和经度)的数组。我将这些点保存在 ArrayList 中,并使用 LineString 和 LineLayer 绘制路线。我的问题是我不想每三秒或什至每次 phone 移动时都为路由调用 Azure Api,因为调用真的很慢,这给我带来了很大压力后端服务器。
考虑到 JSON 数组是从起点到终点排序的,我尝试计算 phone 位置与数组中的点之间的绝对差异,并保存差异小于阈值,因为它是从路线到 phone 实际位置的最近点。每三秒钟我计算一次这个差异并将该点保存为新路线的起点,然后重新绘制路线。区别代码是这样的:
private void getStartIndices() {
//r_points is the ArrayList with the points from the route
if(r_points != null)
{
for (int i = 0; i < r_points.length() - 1; i++) {
try {
JSONObject point = r_points.getJSONObject(i);
if( abs(mCurrentLocation.getLongitude() - point.getDouble("longitude")) < 0.00001 && abs(mCurrentLocation.getLatitude() - point.getDouble("latitude")) < 0.00001 )
{
Log.e(TAG, i + " They both change");
returnable = i;
}
else{
if( abs(mCurrentLocation.getLongitude() - point.getDouble("longitude")) < 0.000004 )
{
Log.e(TAG,i + "The longitude is changing");
returnable = i;
}
else{
if(abs(mCurrentLocation.getLatitude() - point.getDouble("latitude")) < 0.000004 )
{
Log.e(TAG,i + " The latitude is changing");
returnable = i;
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
这有效,但不够准确,而且它有一些我无法解决的非常严重的错误。
我的问题是:有没有更好的方法来做到这一点,我真的需要尽可能少地调用,我还需要让这个重绘尽可能准确。
完成此操作的标准方法是遍历每条线段(线上的一对点)并计算该线段上距离您的点最近的点。然后,当你经过时,找出哪一段有最近的点。这是执行此操作的算法:https://softwareengineering.stackexchange.com/questions/270655/efficient-method-for-finding-closest-point-to-a-line-segment-from-a-set-of-point
但是,这个算法是基于像素坐标的。如果您使用 longitude/latitude 坐标,由于纬度和经度尺度不同(它们不是平面 2D 坐标系,而是球坐标系的一部分),将会出现一些不准确的情况。处理此问题的一种简单方法是使用 Azure Maps Android SDK 的 MapMath
命名空间中的内置 mercatorPositionsToPixels
方法将您的位置转换为像素坐标。这会将 longitude/latitude 位置转换为基于墨卡托地图投影的像素坐标,并将导致更高的计算精度。缩放级别指定分辨率。将其设置为 22,这应该始终有效(除非您想开始进入微观精度)。
/**
* Converts an array of positions into an array of global Mercator pixel coordinates at a specified zoom level.
* @param positions Array of positions.
* @param zoom Zoom level.
* @returns Array of global Mercator pixels.
*/
public static Pixel[] mercatorPositionsToPixels(@NonNull Position[] positions, double zoom)
使用此方法转换你的线的所有点,并存储它们,因为听起来你的基线没有改变。然后在每个 GPS ping 上,将 GPS 位置转换为墨卡托像素,并使用该最近点在线算法从所有线段中找到最近的点。这会给你一个可能在其他点之间的点,但在可能更符合你正在寻找的路径上。
就性能而言,除非您的直线中有数百万个点,否则这些计算将 运行 非常快。我在 JavaScript 中以更高的频率使用了相同的算法,它 运行 没问题。
更新:计算出的坐标将以像素为单位,您需要使用mercatorPixelsToPositions
方法将其转换回位置。
我正在构建一个 Android 应用程序来渲染地图。使用 phone 位置和特定目的地,我需要在地图上显示路线,并在用户的 phone 移动时重新绘制路线。很抱歉这么长 post,我正在努力使它尽可能明确。
我要用Azure Maps,用户要走原来的路线,所以我需要在用户走的时候重新画路线。基本上,每次用户移动时,我只需要使原始路线从 phone 位置开始。
我每三秒获取一次 phone 的纬度和经度,当用户选择目的地位置时,我调用 Azure API 用于路线,其中 returns 一个 JSON 包含从起点到终点的点(纬度和经度)的数组。我将这些点保存在 ArrayList 中,并使用 LineString 和 LineLayer 绘制路线。我的问题是我不想每三秒或什至每次 phone 移动时都为路由调用 Azure Api,因为调用真的很慢,这给我带来了很大压力后端服务器。
考虑到 JSON 数组是从起点到终点排序的,我尝试计算 phone 位置与数组中的点之间的绝对差异,并保存差异小于阈值,因为它是从路线到 phone 实际位置的最近点。每三秒钟我计算一次这个差异并将该点保存为新路线的起点,然后重新绘制路线。区别代码是这样的:
private void getStartIndices() {
//r_points is the ArrayList with the points from the route
if(r_points != null)
{
for (int i = 0; i < r_points.length() - 1; i++) {
try {
JSONObject point = r_points.getJSONObject(i);
if( abs(mCurrentLocation.getLongitude() - point.getDouble("longitude")) < 0.00001 && abs(mCurrentLocation.getLatitude() - point.getDouble("latitude")) < 0.00001 )
{
Log.e(TAG, i + " They both change");
returnable = i;
}
else{
if( abs(mCurrentLocation.getLongitude() - point.getDouble("longitude")) < 0.000004 )
{
Log.e(TAG,i + "The longitude is changing");
returnable = i;
}
else{
if(abs(mCurrentLocation.getLatitude() - point.getDouble("latitude")) < 0.000004 )
{
Log.e(TAG,i + " The latitude is changing");
returnable = i;
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
这有效,但不够准确,而且它有一些我无法解决的非常严重的错误。
我的问题是:有没有更好的方法来做到这一点,我真的需要尽可能少地调用,我还需要让这个重绘尽可能准确。
完成此操作的标准方法是遍历每条线段(线上的一对点)并计算该线段上距离您的点最近的点。然后,当你经过时,找出哪一段有最近的点。这是执行此操作的算法:https://softwareengineering.stackexchange.com/questions/270655/efficient-method-for-finding-closest-point-to-a-line-segment-from-a-set-of-point
但是,这个算法是基于像素坐标的。如果您使用 longitude/latitude 坐标,由于纬度和经度尺度不同(它们不是平面 2D 坐标系,而是球坐标系的一部分),将会出现一些不准确的情况。处理此问题的一种简单方法是使用 Azure Maps Android SDK 的 MapMath
命名空间中的内置 mercatorPositionsToPixels
方法将您的位置转换为像素坐标。这会将 longitude/latitude 位置转换为基于墨卡托地图投影的像素坐标,并将导致更高的计算精度。缩放级别指定分辨率。将其设置为 22,这应该始终有效(除非您想开始进入微观精度)。
/**
* Converts an array of positions into an array of global Mercator pixel coordinates at a specified zoom level.
* @param positions Array of positions.
* @param zoom Zoom level.
* @returns Array of global Mercator pixels.
*/
public static Pixel[] mercatorPositionsToPixels(@NonNull Position[] positions, double zoom)
使用此方法转换你的线的所有点,并存储它们,因为听起来你的基线没有改变。然后在每个 GPS ping 上,将 GPS 位置转换为墨卡托像素,并使用该最近点在线算法从所有线段中找到最近的点。这会给你一个可能在其他点之间的点,但在可能更符合你正在寻找的路径上。
就性能而言,除非您的直线中有数百万个点,否则这些计算将 运行 非常快。我在 JavaScript 中以更高的频率使用了相同的算法,它 运行 没问题。
更新:计算出的坐标将以像素为单位,您需要使用mercatorPixelsToPositions
方法将其转换回位置。