使用Java和Proj4j计算两个地理坐标点的最小矩形包围盒

使用Java和Proj4j计算两个地理坐标点的最小矩形包围盒

  • 引言
  • maven引用
  • 代码示例

引言

今天小编碰到个需求,要求通过两个坐标点位向外扩大500米半径,通过这两个500米半径的圆给前端地图提供可画出长方形的四个坐标点

maven引用

        <dependency>
            <groupId>org.osgeo</groupId>
            <artifactId>proj4j</artifactId>
            <version>0.1.0</version>
        </dependency>

代码示例

public class RectangleFromLine {

	/**
	 * 经纬度地理坐标转面坐标
	 * 
	 * @param lat
	 * @param lng
	 * @return
	 */
	public static double[] coordinateTransformation(double lat, double lng) {
		CRSFactory crsFactory = new CRSFactory();
		CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326");
		CoordinateReferenceSystem webMercator = crsFactory.createFromName("EPSG:3857");

		// 创建坐标变换器
		CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
		CoordinateTransform transform = ctFactory.createTransform(wgs84, webMercator);
		ProjCoordinate srcCoord = new ProjCoordinate(lng, lat);

		// 执行转换
		ProjCoordinate destCoord = new ProjCoordinate();
		transform.transform(srcCoord, destCoord);
		return new double[]{destCoord.x, destCoord.y};
	}

	/**
	 * 面坐标转地理坐标
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public static double[] coordinateTransformationReversal(double x, double y) {
		CRSFactory crsFactory = new CRSFactory();
		CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326");
		CoordinateReferenceSystem webMercator = crsFactory.createFromName("EPSG:3857");

		// 创建坐标变换器
		CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();
		CoordinateTransform transform = ctFactory.createTransform(webMercator, wgs84);
		ProjCoordinate srcCoord = new ProjCoordinate(x, y);
		// 执行转换
		ProjCoordinate destCoord = new ProjCoordinate();
		transform.transform(srcCoord, destCoord);
		return new double[]{destCoord.y, destCoord.x};
	}

	/**
	 * 取两圆的最小包围盒(正北方向)
	 * 
	 * @param startLatitude
	 * @param startLongitude
	 * @param endLatitude
	 * @param endLongitude
	 * @param radius
	 * @return
	 */
	public static double[][] calculateRectangleVertices(double startLatitude, double startLongitude, double endLatitude,
			double endLongitude, double radius) {
		double[] p1 = coordinateTransformation(startLatitude, startLongitude);
		double[] p2 = coordinateTransformation(endLatitude, endLongitude);

		double[] leftBottom = new double[]{Math.min(p1[0], p2[0]) - radius, Math.min(p1[1], p2[1]) - radius};
		//面坐标转地理坐标
		double[] leftBottom_1 = coordinateTransformationReversal(leftBottom[0], leftBottom[1]);
		double[] leftTop = new double[]{Math.min(p1[0], p2[0]) - radius, Math.max(p1[1], p2[1]) + radius};
		//面坐标转地理坐标
		double[] leftTop_1 = coordinateTransformationReversal(leftTop[0], leftTop[1]);
		double[] rightTop = new double[]{Math.max(p1[0], p2[0]) + radius, Math.max(p1[1], p2[1]) + radius};
		//面坐标转地理坐标
		double[] rightTop_1 = coordinateTransformationReversal(rightTop[0], rightTop[1]);
		double[] rightBottom = new double[]{Math.max(p1[0], p2[0]) + radius, Math.min(p1[1], p2[1]) - radius};
		//面坐标转地理坐标
		double[] rightBottom_1 = coordinateTransformationReversal(rightBottom[0], rightBottom[1]);
		return new double[][]{leftBottom_1, leftTop_1, rightTop_1, rightBottom_1};
	}

	/**
	 * 取两圆的最小包围盒(轴方向)
	 *
	 * @param startLatitude
	 * @param startLongitude
	 * @param endLatitude
	 * @param endLongitude
	 * @param radius
	 * @return
	 */
	public static double[][] calculateRectangleVertices1(double startLatitude, double startLongitude,
			double endLatitude, double endLongitude, double radius) {
		double[] p1 = coordinateTransformation(startLatitude, startLongitude);
		double[] p2 = coordinateTransformation(endLatitude, endLongitude);

		double minX = Math.min(p1[0], p2[0]) - radius;
		double maxX = Math.max(p1[0], p2[0]) + radius;
		double minY = Math.min(p1[1], p2[1]) - radius;
		double maxY = Math.max(p1[1], p2[1]) + radius;

		// 计算中心点
		double centerX = (minX + maxX) / 2.0;
		double centerY = (minY + maxY) / 2.0;

		// 计算轴方向
		double axisDirection = Math.atan2(maxY - minY, maxX - minX);

		// 计算宽度和高度
		double width = maxX - minX;
		double height = maxY - minY;

		// 计算四个顶点
		double[][] vertices = new double[4][2];
		vertices[0] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, -1, -1);
		vertices[1] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, -1, 1);
		vertices[2] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, 1, 1);
		vertices[3] = calculateVertex(centerX, centerY, width / 2, height / 2, axisDirection, 1, -1);

		// 将顶点从Web Mercator坐标转回地理坐标
		for (int i = 0; i < 4; i++) {
			vertices[i] = coordinateTransformationReversal(vertices[i][0], vertices[i][1]);
		}

		return vertices;
	}

	/**
	 * 计算单个顶点
	 *
	 * @param centerX
	 *            中心点的X坐标
	 * @param centerY
	 *            中心点的Y坐标
	 * @param width
	 *            包围盒的宽度
	 * @param height
	 *            包围盒的高度
	 * @param angle
	 *            轴方向(弧度)
	 * @param dx
	 *            X方向的偏移量(-1或1)
	 * @param dy
	 *            Y方向的偏移量(-1或1)
	 * @return 顶点坐标
	 */
	private static double[] calculateVertex(double centerX, double centerY, double width, double height, double angle,
			int dx, int dy) {
		double x = centerX + dx * width * Math.cos(angle) - dy * height * Math.sin(angle);
		double y = centerY + dx * width * Math.sin(angle) + dy * height * Math.cos(angle);
		return new double[]{x, y};
	}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919243.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring:IOC/DI注解开发管理第三方bean

前面定义bean的时候都是在自己开发的类上面写个注解就完成了&#xff0c;但如果是第三方的类&#xff0c;这些类都是在jar包中&#xff0c;我们没有办法在类上面添加注解&#xff0c;这个时候该怎么办? 遇到上述问题&#xff0c;我们就需要有一种更加灵活的方式来定义bean,这…

单片机学习笔记 5. 数码管静态显示

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~ 目录 0、实现的功能 1、Keil工程 1-1 数码管显示原理 1-2 静态与动态显示 1-3 74HC573锁存器的工作原理 1-…

使用Ollama和Open WebUI管理本地开源大模型

Open WebUI和Ollama介绍 Open WebUI 是一个功能丰富且用户友好的自托管 Web 用户界面&#xff08;WebUI&#xff09;&#xff0c;它被设计用于与大型语言模型&#xff08;LLMs&#xff09;进行交互&#xff0c;特别是那些由 Ollama 或与 OpenAI API 兼容的服务所支持的模型。O…

Debezium-EmbeddedEngine

提示&#xff1a;一个嵌入式的Kafka Connect源连接器的工作机制 文章目录 前言一、控制流图二、代码分析 1.构造函数2.完成回调3.连接器回调4.RUN总结 前言 工作机制&#xff1a; * 独立运行&#xff1a;嵌入式连接器在应用程序进程中独立运行&#xff0c;不需要Kafka、Kafka C…

【网络安全】SSL(二):Keyless SSL技术细节

未经许可,不得转载。 文章目录 TLS双重目标握手过程是什么?TLS 中的握手类型TLS 术语表RSA 握手协议临时 Diffie-Hellman 握手Diffie-Hellman 握手过程保护密钥服务器其他安全考虑性能提升场景分析持久连接精简握手会话恢复的问题Keyless SSL 的会话恢复功能会话票据恢复会话…

vue2侧边导航栏路由

<template><div><!-- :default-active"$route.path" 和index对应其路径 --><el-menu:default-active"active"class"el-menu-vertical-demo"background-color"#545c64"text-color"#fff"active-text-col…

ChatGPT Search VS Kimi探索版:AI搜索哪家强?!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

交换机配置从IP(Switch Configuration from IP)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

【Redis】基于Redis实现秒杀功能

业务的流程大概就是&#xff0c;先判断优惠卷是否过期&#xff0c;然后判断是否有库存&#xff0c;最好进行扣减库存&#xff0c;加入全局唯一id&#xff0c;然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题&#xff0c;比如开200个线程进行抢购&#xff0c;抢100个…

STL——vector(1)

博客ID&#xff1a;LanFuRenC系列专栏&#xff1a;C语言重点部分 C语言注意点 C基础 Linux 数据结构 C注意点 今日好题 声明等级&#xff1a;黑色->蓝色->红色 欢迎新粉加入&#xff0c;会一直努力提供更优质的编程博客&#xff0c;希望大家三连支持一下啦 目录 尾…

【东莞石碣】戴尔R740服务器维修raid硬盘问题

1&#xff1a;石碣某塑料工厂下午报修一台戴尔R740服务器硬盘故障&#xff0c;催的还比较着急。 2&#xff1a;工程师经过跟用户确认故障的问题以及故障服务器型号和故障硬盘型号&#xff0c;产品和配件确认好后&#xff0c;公司仓库确认有该款硬盘现货&#xff0c;DELL 12T S…

使用 .NET 创建新的 WPF 应用

本教程介绍如何使用 Visual Studio 创建新的 Windows Presentation Foundation &#xff08;WPF&#xff09; 应用。 使用 Visual Studio&#xff0c;可以向窗口添加控件以设计应用的 UI&#xff0c;并处理这些控件中的输入事件以与用户交互。 在本教程结束时&#xff0c;你有一…

Shell基础(5)

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…

嵌入式:STM32的启动(Startup)文件解析

相关阅读 嵌入式https://blog.csdn.net/weixin_45791458/category_12768532.html?spm1001.2014.3001.5482 启动文件(Startup File)是嵌入式系统开发中的核心组件之一&#xff0c;它用于初始化系统并为主程序的运行做好准备。在大多数情况下&#xff0c;启动文件是用汇编语言编…

CH03_反射

第3章&#xff1a;反射 本章目标 掌握反射的原理 熟悉反射的基本运用 本章内容 反射是什么 C# 编译运行过程 首先我们在VS点击编译的时候&#xff0c;就会将C#源代码编译成程序集 程序集以可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式实现 程序集中包含有Microsoft …

HAL_UARTEx_ReceiveToIdle_DMA和HAL_UART_Receive_DMA的区别

功能 HAL_UART_Receive_DMA 仅仅是开启的串口的DMA接收&#xff0c;若是想使用空闲中断 DMA接收则需要开启串口的空闲中断&#xff1b; 而HAL_UARTEx_ReceiveToIdle_DMA函数中则包含了开启串口空闲中断&#xff1b; HAL_UART_Receive_DMA 的接收类型是HAL_UART_RECEPTION_ST…

MyBlog(三) -- APP的应用

文章目录 前言一、APP是什么?二、创建APP三、使用APP1. 注册app2. 添加路由3. 运行过程4. 完善视图函数5. 结果展示 总结 前言 前面我们已经学习了如何创建一个新的项目,并且配置好了项目的启动文件,成功将项目启动! 那么接下来我们的主要任务就是需要完善这个项目中应该包含…

tdengine学习笔记-整体架构及docker安装

官方文档&#xff1a;用 Docker 快速体验 TDengine | TDengine 文档 | 涛思数据 整体架构 TDENGINE是分布式&#xff0c;高可靠&#xff0c;支持水平扩展的架构设计 TDengine分布式架构的逻辑结构图如下 一个完整的 TDengine 系统是运行在一到多个物理节点上的&#xff0c;包含…

【支持向量机(SVM)】:相关概念及API使用

文章目录 1 SVM相关概念1.1 SVM引入1.1.1 SVM思想1.1.2 SVM分类1.1.3 线性可分、线性和非线性的区分 1.2 SVM概念1.3 支持向量概念1.4 软间隔和硬间隔1.5 惩罚系数C1.6 核函数 2 SVM API使用2.1 LinearSVC API 说明2.2 鸢尾花数据集案例2.3 惩罚参数C的影响 1 SVM相关概念 1.1…

git 基础之 merge 和 rebase 的比较

在团队软件开发过程中&#xff0c;代码合并是一个基本且频繁执行的任务。 Git 提供了多种合并代码的策略&#xff0c;其中最常用的是 merge 和 rebase。 尽管二者的终极目标是相同的——整合代码变更——它们的方法和推荐的使用场景却有所区别。本文将详细介绍和比较这两种策…