使用Java对轨迹进行抽稀,并生成mvt(Map Vector Tile)瓦片

2023-11-03

1. 原理

  • Java对轨迹抽稀:道格拉斯普克算法
  • 生成mvt瓦片:VectorTileEncoder.addFeature

2. pom依赖

 <!-- geometry相关类 -->
<dependency>
     <groupId>com.vividsolutions</groupId>
     <artifactId>jts-core</artifactId>
     <version>1.17.1</version>
 </dependency>
<dependency>
    <groupId>com.vividsolutions</groupId>
    <artifactId>jts-core</artifactId>
    <version>1.14.0</version>
</dependency>
 <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.70</version>
 </dependency>
  <!-- vectorTile -->
  <dependency>
      <groupId>no.ecc.vectortile</groupId>
      <artifactId>java-vector-tile</artifactId>
      <version>1.2.1</version>
  </dependency>

注意 locationtech 和 vividsolutions有的类名完全一致
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Point;

3. Java对轨迹道格拉斯普克抽稀源码

package no.ecc.vectortile;

import com.alibaba.fastjson.JSON;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier;

import java.util.*;

/*************************************
 *Class Name:Doulag
 *Description:<道格拉斯普克抽稀>
 *@author:Seminar
 *@create:2021/1/14
 *@since 1.0.0
 *************************************/
public class Doulag {

    /**
     * 计算两点距离
     *
     * @param point1
     * @param point2
     * @return
     */
    private static double calculationDistance(double[] point1, double[] point2) {
        double lat1 = point1[0];
        double lat2 = point2[0];
        double lng1 = point1[1];
        double lng2 = point2[1];
        double radLat1 = lat1 * Math.PI / 180.0;
        double radLat2 = lat2 * Math.PI / 180.0;
        double a = radLat1 - radLat2;
        double b = (lng1 * Math.PI / 180.0) - (lng2 * Math.PI / 180.0);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        return s * 6370996.81;

    }

    /**
     * 计算点pX到点pA和pB所确定的直线的距离
     *
     * @param start
     * @param end
     * @param center
     * @return
     */
    private static double distToSegment(double[] start, double[] end, double[] center) {
        double a = Math.abs(calculationDistance(start, end));
        double b = Math.abs(calculationDistance(start, center));
        double c = Math.abs(calculationDistance(end, center));
        double p = (a + b + c) / 2.0;
        double s = Math.sqrt(Math.abs(p * (p - a) * (p - b) * (p - c)));
        return s * 2.0 / a;
    }

    /**
     * 递归方式压缩轨迹
     *
     * @param coordinate
     * @param result
     * @param start
     * @param end
     * @param dMax
     * @return
     */
    private static List<double[]> compressLine(List<double[]> coordinate, List<double[]> result, int start, int end, int dMax) {
        if (start < end) {
            double maxDist = 0;
            int currentIndex = 0;
            double[] startPoint = coordinate.get(start);
            double[] endPoint = coordinate.get(end);
            for (int i = start + 1; i < end; i++) {
                double currentDist = distToSegment(startPoint, endPoint, coordinate.get(i));
                if (currentDist > maxDist) {
                    maxDist = currentDist;
                    currentIndex = i;
                }
            }
            if (maxDist >= dMax) {
                //将当前点加入到过滤数组中
                result.add(coordinate.get(currentIndex));
                //将原来的线段以当前点为中心拆成两段,分别进行递归处理
                compressLine(coordinate, result, start, currentIndex, dMax);
                compressLine(coordinate, result, currentIndex + 1, end, dMax);
            } else {
                result.remove(endPoint);
            }
        }
        return result;
    }

    /**
     * @param coordinate 原始轨迹Array<{latitude,longitude}>
     * @param dMax       允许最大距离误差
     * @return douglasResult 抽稀后的轨迹
     */
    public static List<double[]> douglasPeucker(List<double[]> coordinate, int dMax) {
        //抽稀点数量需要大于2
        if (coordinate == null || coordinate.size() <= 2) {
            return null;
        }

        List<double[]> coordinate2 = new ArrayList<>();
        for (int i = 0; i < coordinate.size(); i++) {
            double[] point = Arrays.copyOf(coordinate.get(i), 3);
            point[2] = i;
            coordinate2.add(point);
        }
        List<double[]> result = new ArrayList<>();
        result = compressLine(coordinate2, result, 0, coordinate2.size() - 1, dMax);
        result.add(coordinate2.get(0));
        result.add(coordinate2.get(coordinate.size() - 1));
        Collections.sort(result, new Comparator<double[]>() {
            @Override
            public int compare(double[] u1, double[] u2) {
                if (u1[2] > u2[2]) {
                    return 1;
                } else if (u1[2] < u2[2]) {
                    return -1;
                }
                return 0; //相等为0
            }
        });

        return result;
    }

    public static void main(String[] args) {
        GeometryFactory gf = new GeometryFactory();
        Coordinate c1 = new Coordinate(1, 1.4);
        Coordinate c2 = new Coordinate(1, 1.5);
        Coordinate c3 = new Coordinate(1, 1.6);
        Coordinate c4 = new Coordinate(10, 100);
        Coordinate c5 = new Coordinate(100, 200);
        double dinstanceTolerance = 1;
        Geometry geometry = gf.createLineString(new Coordinate[]{c1, c2, c3, c4, c5});
        // 使用原来jar包中带的方法
        Geometry g1 = DouglasPeuckerSimplifier.simplify(geometry, dinstanceTolerance);  // 1米范围内的点抽稀掉,还可为其他值double类型
        System.out.println("g1: " + g1.getGeometryType().toString());
        System.out.println("g1Coordinates size: " + g1.getCoordinates().length);
        System.out.println("g1Coordinates: " + JSON.toJSONString(g1.getCoordinates()));


        // 使用自己写的方法
        List<double[]> coordinates = new ArrayList<>();
        coordinates.add(new double[]{1d, 1.4d});
        coordinates.add(new double[]{1d, 1.5d});
        coordinates.add(new double[]{1d, 1.6d});
        coordinates.add(new double[]{10d, 100d});
        coordinates.add(new double[]{100d, 200d});
        List<double[]> res = douglasPeucker(coordinates, 1);
        System.out.println("douglasPeucker size: " + res.size());
        System.out.println("g1Coordinates: " + JSON.toJSONString(res));
    }

}

4. Java生成线瓦片源码

package no.ecc.vectortile;

import junit.framework.TestCase;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class VectorTileDecoderTest extends TestCase {

    private GeometryFactory gf = new GeometryFactory();

    public void testLineString() throws IOException {
        Coordinate c1 = new Coordinate(1, 2);
        Coordinate c2 = new Coordinate(10, 20);
        Coordinate c3 = new Coordinate(100, 200);
        Geometry geometry = gf.createLineString(new Coordinate[]{c1, c2, c3});

        Map<String, Object> attributes = new HashMap<String, Object>();
        attributes.put("aa", "bb");
        attributes.put("cc", "bb");

        String layerName = "layer";

        VectorTileEncoder e = new VectorTileEncoder(4096, 16, false);
        e.addFeature(layerName, attributes, geometry);
        byte[] encoded = e.encode();

        VectorTileDecoder d = new VectorTileDecoder();
        assertEquals(1, d.decode(encoded).getLayerNames().size());
        assertEquals(layerName, d.decode(encoded).getLayerNames().iterator().next());

        assertEquals(attributes, d.decode(encoded, layerName).asList().get(0).getAttributes());
        assertEquals(geometry, d.decode(encoded, layerName).asList().get(0).getGeometry());
    }
}

参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用Java对轨迹进行抽稀,并生成mvt(Map Vector Tile)瓦片 的相关文章

  • Maven 2:如何将当前项目版本打包在WAR文件中?

    我正在使用 Maven 2 构建我的 Java 项目 并且正在寻找一种向用户呈现 pom xml 当前版本号的方法 例如使用 Servlet 或 JSP 据我所知 最好的方法是 Maven 将版本号作为文本文件打包到 WAR 中 这使我能够
  • Hashmap并发问题

    我有一个哈希图 出于速度原因 我希望不需要锁定 假设我不介意过时的数据 同时更新它和访问它会导致任何问题吗 我的访问是获取 而不是迭代 删除是更新的一部分 是的 这会导致重大问题 一个例子是向散列映射添加值时可能发生的情况 这可能会导致表重
  • JavaFX 图像未在舞台中显示

    我尝试了很多次 尝试了很多方法 但都无法让自己的形象在舞台上如我所愿 我认为这可能与java寻找资源的路径有关 但我不确定 因为我刚刚开始使用视觉库 在本例中为JavaFX 这是我的目录结构 MyProject assets img myI
  • 在哪里可以获得有关 Java FitNesse 和 Slim 的一些教程? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 无法使用 json 架构验证器根据预定义的 yaml 文件验证查询参数

    我需要根据预定义的 yaml 文件架构验证查询参数的架构 因此我使用 json 架构验证器 验证如何失败 我正在执行以下步骤 填充参数和相应的架构 final List
  • Junit maven构建错误(maven-surefire-plugin:2.19.1:测试失败:分叉进程中出现错误)[重复]

    这个问题在这里已经有答案了 我通过引用创建了一个示例 struts 2 项目和 J unit 测试用例link http self learning java tutorial blogspot com au 2015 04 struts2
  • Java-如何将黑白图像加载到二进制中?

    我在 FSE 模式下使用 Java 和 swing 我想将完全黑白图像加载为二进制格式 最好是二维数组 并将其用于基于掩码的每像素碰撞检测 我什至不知道从哪里开始 过去一个小时我一直在研究 但没有找到任何相关的东西 只需将其读入Buffer
  • Intellij 中的 Google OR-Tools:UnsatisfiedLinkError

    我正在建立一个应该使用 Google OR Tools 的 java 框架 下面的代码编译成功 但在运行时抛出异常 Exception in thread main java lang UnsatisfiedLinkError com go
  • 异步迭代器

    我有以下代码 while slowIterator hasNext performLengthTask slowIterator next 由于迭代器和任务都很慢 因此将它们放入单独的线程中是有意义的 这是对迭代器包装器的快速而肮脏的尝试
  • 如何将 Observable>> 转换为 Observable>

    我陷入了如何将以下可观察类型转换 转换为我的目标类型的困境 我有以下类型的可观察值 Observable
  • 当您在数组列表上调用remove(object o)时,它如何比较对象?

    当您在 java 中的数组列表上调用remove object o 时 它如何比较对象以找到要删除的正确对象 它使用指针吗 或者它使用 Comparable 接口来比较对象吗 ArrayList remove 依赖于对象的实现Equal方法
  • 改变for循环的顺序?

    我遇到一种情况 我需要根据用户输入以不同的顺序循环遍历 xyz 坐标 所以我是 3D 空间中的一个区域 然后是一组像这样的 for 循环 for int x 0 x lt build getWidth x for int y 0 y lt
  • 如何在Java媒体框架中学习.wav持续时间?

    我正在尝试使用 java 媒体框架将 mov 文件与 wav 文件合并 因此我需要知道它们的持续时间 我怎样才能做到这一点 任何想法 将不胜感激 您可以使用以下方式了解声音文件的持续时间 即 VitalyVal 的第二种方式 import
  • JavaFX - 为什么多次将节点添加到窗格或不同的窗格会导致错误?

    我现在正在学习基本的 JavaFX 我不明白我正在阅读的书中的这一说法 不 诸如文本字段之类的节点只能添加到一个窗格中一次 将节点添加到多次窗格或不同的窗格将导致运行时错误 我可以从书中提供的UML图看出它是一个组合 但我不明白为什么 库类
  • Java中的回调接口是什么?

    SetObserver 接口的代码片段取自有效的Java 避免过度同步第67条 public interface SetObserver
  • 警告:无法更改每个人的权限:

    当运行 Java 快速入门示例时https developers google com drive web quickstart java hl hu https developers google com drive web quicks
  • 对于当前月份和日期但年份不同的日期,经过的月份计算未给出正确的结果

    我正在尝试计算自特定日期以来经过的月份 该函数工作正常 尽管如果我将今天的日期与过去的不同年份放在一起 它会给我一个月的差异 不到一个月 假设对于所有日期 该函数都运行良好 除了 如果今天是 2014 03 06 YYYY MM DD 并且
  • 摩尔斯电码 至 英语

    我现在的问题是让 摩尔斯电码转英语 正常工作 将英语转换为莫尔斯电码的第一部分工作正常 我知道以前已经有人问过这个问题 但我不知道我做错了什么 我知道我需要在某个地方进行拆分 但我只是不确定将其放在代码中的何处 现在 莫尔斯电码到英语的部分
  • 为什么应该首选 Java 类的接口?

    PMD https pmd github io 将举报以下违规行为 ArrayList list new ArrayList 违规行为是 避免使用 ArrayList 等实现类型 而是使用接口 以下行将纠正违规行为 List list ne
  • 为什么范围为“provided”的依赖项会隐藏 Maven 中的传递依赖项?

    我的 Maven 项目中有三个模块 这稍微简化了 model包含JPA注释的实体类 坚持实例化一个实体管理器并调用它的方法 应用创建类的实例model 设置一些值并将它们传递给坚持 model and 坚持显然取决于javax persis

随机推荐

  • win7 系统盘如何瘦身! 可整理出4-5G。

    1 移走虚拟内存文件到非系统盘 大家都知道 为了加快系统的运行 Windows提供了虚拟内存机制 而在Windows7中 默认是开启这项功能的 而且虚拟内存文件在系统盘 比如一台2G内存的机器 虚拟内存文件大小就是2G 我们完全可以将他移走
  • Eclipse优化,关闭不必要的验证,简单粗暴!

    路径 Window gt Preferences gt Validation 如下图所示 只需勾选这几项即可
  • 半夜睡不着,MFC搞起来!

    一 MFC的概念和作用 1 什么是MFC 全称 Microsoft Foundation Class Library 我们称之为微软基础类库 封装了各种windowsAPI函数 C 语法 中的一些数据结构 1 MFC就是一个类库 2 MFC
  • Android Calendar的运用

    pre class java package com iwode common import java text DateFormat import java text ParsePosition import java text Simp
  • 毕业设计---用算法实现OCR文字识别(基于java实现的文字识别技术)

    文末附源码 识别效果如下图 由于是自己实现算法所以识别率不算太高 但是这个相比较一般的模型 识别这么多还是可以的 如果需要做的只是识别率比较高 不关注谁去实现的算法 可以采用第三方的API 百度智能云就很不错 使用方式和前面的百度AI实现人
  • 数据分析:利用gpt进行归因分析

    prompt 你是某电商平台的一名数据分析师 发现昨日的GMV环比下降了5 请对这数据变动做出归因 output 在电商行业中 GMV 总销售额 是一个非常重要的指标 用于衡量业务的整体健康状况 当GMV出现环比下降时 这通常意味着需要进行
  • ThinkPHP中模型的创建和实例化操作

    https blog csdn net qq 41630218 article details 80920289 https www cnblogs com 457248499 qq com p 7388270 html
  • webpack模块分写导出与导入配置 -9

    1 确保自己的电脑已经安装了node和Git软件 2 自己在盘里随便创建一个文件夹一般为英文 也就是你自己的项目名称 3 在新创建好的文件夹里面右键点击调出git指令窗口在窗口里面输入如下指令 1 npm install webpack g
  • Electron 判断互联网网络连接

    项目场景 Electron 实现桌面程序 问题描述 尝试使用原生的 EventTarget addEventListener 监听 window online 和 window offline 事件 但是在调用函数并手动断网之后 却发现并没
  • Acwing 5. 多重背包问题 II

    本题朴素做法与完全背包类似 那么优化解法是不是也可以借鉴完全背包那样呢 答案是否定的 因为完全背包中的物品有无限个 而多重背包中的物品是有限个 两个公式不能进行合并 有点级数的意思 也就是说 max函数不能通过总体的最大值减去最后一项的最大
  • Tomcat的安装与配置

    Tomcat的安装与配置 一 准备与安装 1 在下载安装tomcat之前请确保计算机上已有java环境 可以通过键盘Windows R 输入cmd 输入java version来确定JDK版本 我使用的是JDK1 8 2 进入Tomcat官
  • 众享比特未来融合研究院执行院长王陈慧子博士以第一作者在IEEE TCSS上发表论文

    近日 众享比特未来融合研究院执行院长王陈慧子博士为第一作者 通讯作者的学术论文 Toward Understanding Attention Economy in Metaverse A Case Study of NFT Value 探究
  • nvidia-smi 无进程占用GPU,但GPU显存却被占用了很多

    下图是我当时遇到的问题 如上图 GPU1 显示占用了10G多的显存 但是却没有相应的进程 此时可使用如下命令查看进程 fuser v dev nvidia 显示如下图 此时把这些进程全部 kill 掉 kill 9 5142 5143 51
  • win10误删的注册表能还原吗_win10注册表删错了怎么办_win10注册表删错东西如何恢复-win7之家...

    我们要知道 注册表是Microsoft Windows中的一个重要的数据库 用于存储系统和应用程序的设置信息 在win10系统中 用户可以通过修改注册表来保证电脑的安全 可是近日有的用户在修改注册表时不小心删错了 那么win10注册表删错了
  • 分页居中显示

    div class page number div div div page number width 100 height 80px padding top 10px text align center page number1 disp
  • 如何阅读芯片手册

    原视频链接 如何快速阅读芯片数据手册 初学者和外行进 1 芯片手册的结构 1 Features 特性 对芯片的特点进行了总结 2 General Description 概述 把芯片的功能进行了一个大概的总结 这部分对新手来说很重要 每一个
  • SDIO接口(4)——SDIO通信

    SDIO通信 SD总线上的通信基于命令和数据位流 这些命令和数据位流由起始位启动 并由停止位终止 SDIO总线上的设置和控制都是通过命令来实现 SDIO总线上都是HOST端发起请求 然后DEVICE端回应请求 其中请求和应答中会包含数据信息
  • 香橙派4和树莓派4B构建K8S集群实践之八: TiDB

    目录 1 说明 2 准备工作 3 安装 3 1 参考Tidb官方 v1 5安装说明 3 2 准备存储类 3 3 创建crd 3 4 执行operator 3 5 创建cluster dashboard monitor容器组 3 6 设置访问
  • Android BottomNavigationView的使用

    BottomNavigationView大于3个menu文字和icon都显示 代码中设置 public static void disableShiftMode BottomNavigationView view int count vie
  • 使用Java对轨迹进行抽稀,并生成mvt(Map Vector Tile)瓦片

    Java对轨迹进行抽稀 并生成mvt线瓦片 1 原理 2 pom依赖 3 Java对轨迹道格拉斯普克抽稀源码 4 Java生成线瓦片源码 参考 1 原理 Java对轨迹抽稀 道格拉斯普克算法 生成mvt瓦片 VectorTileEncode