• 作者:老汪软件技巧
  • 发表时间:2024-11-28 21:07
  • 浏览量:

最近做了一个项目,有一个需求要展示人员轨迹,定位数据是高德的,每分钟定位一次。开发过程中,后端负责数据接收入库,前端调后端接口查点位数据,再用高德轨迹功能绘制轨迹。完事部署到测试环境发现,只有轨迹中间的线贴合人员实际运动情况,轨迹两端带有很多尖刺形状,像高中生物课本上的神经末梢,枝枝杈杈不美观,没办法给客户交差。

从网上的查信息结合定位测试人员活动情况,了解到人员在静止状态时,GPS定位漂移情况会比较严重,运动过程中的点位倒没什么问题。先去看了高德开放平台的轨迹纠正功能,需要每个定位点的经纬度、速度和方向,我们没有速度和方向,用不了。这时候没办法回想起了大学时玩过的平移居中平均法算法,用窗口范围内点位经纬度求平均值作为当前点位的经纬度值,去平滑异常定位数据,实现很简单,样例代码如下

public static void applyCenteredMovingAverage(List data, int window) {
    if (window % 2 == 1) {
        throw new IllegalArgumentException("窗口大小必须是奇数");
    }
    int halfWindow = window / 2;
    // 遍历数据,从能够完整包含窗口的位置开始到结束
    for (int i = halfWindow; i < data.size() - halfWindow; i++) {
        double laSum = 0.000000;
        double lonSum = 0.000000;
        for (int j = -halfWindow; j <= halfWindow; j++) {
            laSum += data.get(i + j).getLatitude();
            lonSum += data.get(i + j).getLongitude();
        }
        data.get(i).setLocation(df.format(lonSum / (window + 1)) + "," + df.format(laSum / (window + 1)));
    }
}

跑出来的结果不是很理想,轨迹毛刺长度有所缓解,但还是枝枝杈杈,并且原本带有转弯的轨迹被算平均后,转弯的直角变成了倒圆角,异常数据没处理好,正常数据给搞乱了,不适合用来处理我的数据,遂舍弃。

后面盯着轨迹两端观察,觉得这个尖尖点位应该算作错误定位,不应该想着去缓解尖刺,而是应该舍弃,然后毛刺那个尖尖的点位左右两侧的直线,如果用向量表示的话,向量夹角是个钝角,大概在135°,可以用这个来判断异常点位,样例代码如下:

public static List applyVectorAngle(List data) {
    for (int i = 1; i < data.size() - 1; i++) {
        double[] v1 = new double[]{data.get(i).getLongitude() - findPre(data, i).getLongitude(), data.get(i).getLatitude() - findPre(data, i).getLatitude()};
        double[] v2 = new double[]{data.get(i + 1).getLongitude() - data.get(i).getLongitude(), data.get(i + 1).getLatitude() - data.get(i).getLatitude()};
        Double angle = angleBetweenVectors(v1, v2);
        if (angle.isNaN() || angle > 135) {
            data.get(i).setFlag(false);
        }
    }
    return data;
}
//寻找前一个点位
private static DeviceLocationRecord findPre(List data, int currentIndex) {
    DeviceLocationRecord pre = data.get(currentIndex - 1);
    while (!pre.isFlag()) {
        currentIndex--;

高德轨迹纠偏_高精度轨迹记录_

if (currentIndex < 1) { break; } pre = data.get(currentIndex - 1); } return pre; } // 计算两个向量之间的夹角(返回角度制) private static double angleBetweenVectors(double[] v1, double[] v2) { double dotProduct = dotProduct(v1, v2); double normV1 = norm(v1); double normV2 = norm(v2); double angle = Math.acos(dotProduct / (normV1 * normV2)); return Math.toDegrees(angle); // 转换为角度制 } // 计算向量的范数(L2范数) private static double norm(double[] v) { return Math.sqrt(dotProduct(v, v)); } // 计算两个向量的点积 private static double dotProduct(double[] v1, double[] v2) { if (v1.length != v2.length) { throw new IllegalArgumentException("向量长度不相等"); } double product = 0.0; for (int i = 0; i < v1.length; i++) { product += v1[i] * v2[i]; } return product; }

定位数据经此处理后,过滤掉flag为false的返回给前端,效果很好,基本没影响到正常轨迹,且全部删掉了尖刺定位,堪称完美。这段代码中有个角度参数135,大家使用的过程中可结合自己的数据情况做修改。

以上,希望对大家有所帮助。


上一条查看详情 +种值得一看的前后端鉴权方案
下一条 查看详情 +没有了