如何在 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 中,并使用 LineStringLineLayer 绘制路线。我的问题是我不想每三秒或什至每次 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方法将其转换回位置。