基于Leaflet和天地图的细直箭头和突击方向标绘实战

目录

前言

一、细直箭头和突击方向的类设计

1、总体类图

2、对象区别

二、标绘绘制的具体实现

 1、绘制时序图

2、相关点的具体绘制

3、最终的成果

三、总结


前言

        今天是10月1日国庆节,迎来我们伟大祖国75周年的华诞。有国才有家,在这里首先祝我们伟大的祖国繁荣昌盛。放眼这个世界,俄乌战争时至今日,尚未结束,中东战场现在火药味浓烈,简直就是一个巨大的火药桶。国际局势很紧张,感恩在华夏,可以安心放假休假。祝各位小伙伴们假期愉快。

        在之前的博客中分享了一次关于如何在Leaflet中进行直箭头的对象标绘。在实际的标绘过程中,我们需要展示一定宽度的箭头,基于Leaflet和天地图的直箭头标绘实战-源码分析。如下面的图片展示的效果:

        在上图中,有两种类型的标绘对象,第一个是细直箭头;第二个是突击方向。这两类对象其实是差不多的,在后面的讲解过程中,你就会发现。突击方向是细直箭头的子类,具体内容在后续的章节中进行介绍。

        本文将重点讲解在Leaflet中如何进行细直箭头和突击方向的绘制,首先使用面向对象的方法对细直箭头和突击方向的属性和方法进行介绍,然后重点介绍在绘制细直箭头和突击方向对象的各个绘制点的计算过程,最后给出一个实例过程。如果您对这两种标绘对象的绘制有兴趣,不妨来看看。

一、细直箭头和突击方向的类设计

        在前面的内容中,我们介绍了细直箭头和突击方向这两种标绘对象。突击方向是细直箭头的子类,为了更详细展示两者的区别和联系。我们使用面向对象的方式来简单介绍一下。

1、总体类图

        根据源代码,我们把这两个对象的总体类图绘制如下,供大家参考:

        通过以上的图中,我们可以看到,L.PlotUtils是公共的绘制对象,提供了很多的计算方法,比如:把地理坐标和平面坐标的互相转换,计算贝塞尔曲线,计算相关点等方法。这些方法在进行相应的对象绘制时非常重要。

2、对象区别

        L.Plot是所有标绘对象的基类,包含了各个点的信息,包括控制点信息。基于L.Plot对象,扩展两个箭头对象,细直箭头和突击方向。

/*** 突击方向*/
L.Plot.AssaultDirection = L.Plot.FineArrow.extend({options: {tailWidthFactor: 0.2,neckWidthFactor: 0.25,headWidthFactor: 0.3,headAngle: Math.PI / 4,neckAngle: Math.PI * 0.17741,fixPointCount: 2},initialize: function (latlngs, options) {L.setOptions(this, options);this.type = L.PlotTypes.ASSAULT_DIRECTION;this.setPoints(latlngs)}
});L.Plot.assaultDirection = function (latlngs, options) {return new L.Plot.AssaultDirection(latlngs, options);
};

        以上简单介绍细直箭头和突击方向的类继承关系。了解继承关系对于理解对象和构造有很大的作用。通过上面的类定义可以看到,细直箭头与突击方向的最大区别就是箭头对象的宽度和角度有一定的区别。当然,大家可以通过参数传入的方式来进行属性的控制。两者的区别就是:

options: {tailWidthFactor: 0.15,//尾部宽度倍数neckWidthFactor: 0.2,//颈部宽度倍数headWidthFactor: 0.25,//头部宽度倍数headAngle: Math.PI / 8.5,//头部角度neckAngle: Math.PI / 13,//颈部角度fixPointCount: 2}

二、标绘绘制的具体实现

        我们仔细来看细直箭头,可以发现。在绘制过程中,我们只需要确定两个点,即开始位置和结束位置,下图中的pnt1和pnt2。而构成整体面的点为不包括pnt1以外的所有点。绘制原理如下:

直箭头是有两个点组成的,左下角为起点(pnt1),右上角为终点(pnt2)。那么,这个直箭头是如何来的?其实,这个直箭头就是通过起止两个点计算得到的一个由七个点连成的多边形Polygon。

        通过两个点创建标绘对象的方法可以使用以下公式来表达:

其中:polygon(pnt1,pnt2)表示求解根据起始位置构建箭头对象;

        tailLeft表示尾部左边点坐标,neckLeft表示颈部左边点位置,headLeft表示头部左边点位置,pnt2表示结束点位置,headRight 表示头部右边点位置,neckRight表示颈部右边点位置,tailRight表示尾部右边点位置。从尾部左边点位置开始,按照顺时针的顺序连接这7个点即完成一个面的构建。然后把平面左边转为地理左边面,最后叠加在地图上展示。突击方向除了箭头的方向扁平程度与细直箭头有所区别,绘制方式是一样的。后续内容中以细直箭头绘制为例。

 1、绘制时序图

        为了让大家对标绘对象的绘制时序有一个基本的了解,因此这里结合一些关键步骤来讲解相关类的调用过程。

        在上图中清晰的展示了在界面中各个对象如何进行调用。涉及的对象有PlotUtils和具体的箭头对象。 那么具体细直箭头是如何根据两个点来生成另外的七个点的过程,我们将在后续的内容中进行详细介绍。

2、相关点的具体绘制

        了解了绘制时序及相关的对象之后,我们来具体看一下如何使用两个点生成面的七个关键点。其它的辅助代码再此不再赘述,重点叙述7个点的计算过程。计算方法源码如下所示:

//生成图形
generate: function () {if (this.getPointCount() < 2) {this._setLatLngs([])return;}var pnts = this._proPoints;var pnt1 = pnts[0];var pnt2 = pnts[1];var len = L.PlotUtils.getBaseLength(pnts);//pnt1和pnt2的距离的0.99次幂var tailWidth = len * this.options.tailWidthFactor;//尾部的宽度var neckWidth = len * this.options.neckWidthFactor;//颈部宽度var headWidth = len * this.options.headWidthFactor;//头部宽度var tailLeft = L.PlotUtils.getThirdPoint(pnt2, pnt1, L.PlotConstants.HALF_PI, tailWidth, true);var tailRight = L.PlotUtils.getThirdPoint(pnt2, pnt1, L.PlotConstants.HALF_PI, tailWidth, false);var headLeft = L.PlotUtils.getThirdPoint(pnt1, pnt2, this.options.headAngle, headWidth, false);var headRight = L.PlotUtils.getThirdPoint(pnt1, pnt2, this.options.headAngle, headWidth, true);var neckLeft = L.PlotUtils.getThirdPoint(pnt1, pnt2, this.options.neckAngle, neckWidth, false);var neckRight = L.PlotUtils.getThirdPoint(pnt1, pnt2, this.options.neckAngle, neckWidth, true);var pList = [tailLeft, neckLeft, headLeft, pnt2, headRight, neckRight, tailRight];this._setLatLngs([L.PlotUtils.unProPoints(pList)]);this.redraw();
}

        第一步:计算尾部左右两个坐标点位置。想要计算尾部两个坐标的位置,首先我们需要根据pnt1、和pnt2来计算两个点的长度,这样整体箭头的长度大致就确定了。然后根据细直箭头的尾部宽度的配置,在源码中可以看到设置的比例是0.15,具体是前面计算长度的0.15。最后计算获取第三点(起点到终点的连线上,以终点为轴,旋转angle后,距离终点distance的点)。

 var len = L.PlotUtils.getBaseLength(pnts);//pnt1和pnt2的距离的0.99次幂

        根据长度和设置的尾部宽度的系数可以得到尾部的宽度一个值,然后代入到计算第三个点的计算公式中,即可:

var tailLeft = L.PlotUtils.getThirdPoint(pnt2, pnt1, L.PlotConstants.HALF_PI, tailWidth, true);

        计算第三个点的坐标位置具体方法如下,这个方法在后续的过程中经常用到。

//获取第三点(起点到终点的连线上,以终点为轴,旋转angle后,距离终点distance的点)
L.PlotUtils.getThirdPoint = function (startPnt, endPnt, angle, distance, clockWise) {var azimuth = L.PlotUtils.getAzimuth(startPnt, endPnt);//获取终点相对于起点的方位角var alpha = clockWise ? azimuth + angle : azimuth - angle;var dx = distance * Math.cos(alpha);var dy = distance * Math.sin(alpha);return [endPnt[0] + dx, endPnt[1] + dy];
};

        下面结合图形来讲解tailLeft和tailRight的具体计算过程。对trailLeft这个点来说,就是pnt1沿着pnt2的方向逆时针旋转90度(\pi /2)的方向上,距离pnt1有trailWidth远的点。反方向上距离pnt2有trailWidth远的点就是trailRight。

        通过以上步骤即可获得尾部的两个点的坐标信息,然后我们依次来计算neck和head的两个点的位置信息。

        第二步:计算headLeft和headRight两个点。而head的两个坐标点的计算则反过来,以pnt2为起点按照逆时针和顺时针来进行坐标点的计算。偏转的角度为:Math.PI / 8.5,//头部角度。

        第三步:获取neckLeft和neckRight两个点的绘制与前两个点的绘制过程类似,这里不再进行赘述。主要步骤分两个,第一个是计算neckWidth,然后根据设置的neck的偏转角,这里取: 

neckAngle: Math.PI / 13,//颈部角度,大家可以根据实际情况来进行相应情况的设置。

        最后,根据计算获得的这7个点,连成一个Polygon面,然后叠加到地图上即可实现一个细直箭头。同理突击方向的箭头绘制也是一样的处理方法。

3、最终的成果

        为了展示细直箭头和突击方向的最终成果,我们结合天地图,使用Leaflet来进行一个两个结合的综合展示功能开发。动态绘制的代码如下:

// 直箭头
function addStraightArrow() {L.Plot.straightArrow([[28.17629, 112.923746],[28.188471, 112.948208]]).addTo(this.plotLayer);
}// 细直箭头
function addFineArrow() {L.Plot.fineArrow([[28.167286, 112.969236],[28.180224, 112.976618]]).addTo(this.plotLayer);L.Plot.fineArrow([[28.19248, 112.983398],[28.173415, 113.006058]]).addTo(this.plotLayer);
}// 突击方向
function addAssaultDirection() {L.Plot.assaultDirection([[28.180981, 112.901001],[28.200045, 112.937222]]).addTo(this.plotLayer);L.Plot.assaultDirection([[28.143903, 112.964344],[28.179165, 112.94117]]).addTo(this.plotLayer);L.Plot.assaultDirection([[28.211995, 112.984772],[28.202163, 112.962284]]).addTo(this.plotLayer);
}

        最终执行的效果如下图所示:

三、总结

        以上就是本文的主要内容,本文将重点讲解在Leaflet中如何进行细直箭头和突击方向的绘制,首先使用面向对象的方法对细直箭头和突击方向的属性和方法进行介绍,然后重点介绍在绘制细直箭头和突击方向对象的各个绘制点的计算过程,最后给出一个实例过程。行文仓促,难免有许多不足之处,如有不足,还请各位专家和博主在评论区中留下真知烁见,不才定当感激不尽。

        博文编写过程中,参考了下列内容(但本文做了更详细的介绍)在此表示感谢:

        1、基于Leaflet实现标绘——直箭头。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细整理!!html5常用标签

文章目录 前言一、HTML简介1.HTML文件结构2.各标签意义 二、HTML标签介绍1.标题标签2.段落标签3. 换行标签4.hr标签5. span标签6.div标签7.img标签8.超链接标签9.注释标签10.空格11.格式化标签12.sup上标和sub下标13. pre预格式化标签14.table 表格标签table 标签基础内容合并单…

在Java中使用GeoTools解析POI数据并存储到PostGIS实战

目录 前言 一、POI数据相关介绍 1、原始数据说明 2、空间数据库表设计 二、POI数据存储的设计与实现 1、对应的数据模型对象的设计 2、属性表数据和空间信息的读取 3、实际运行结果 三、总结 前言 POI点&#xff0c;全称为Point of Interest&#xff08;兴趣点&#xf…

MySQL基础篇 part1

为什么使用数据库和数据库基本概念 想在vscode用markdown了&#xff0c;为什么不直接拿pdf版本呢&#xff1f; DB:数据库(Database) 即存储数据的“仓库”&#xff0c;其本质是一个文件系统。它保存了一系列有组织的数据。 DBMS:数据库管理系统(Database Management System)…

YOLO11震撼发布!

非常高兴地向大家介绍 Ultralytics YOLO系列的新模型&#xff1a; YOLO11&#xff01; YOLO11 在以往 YOLO 模型基础上带来了一系列强大的功能和优化&#xff0c;使其速度更快、更准确、用途更广泛。主要改进包括 增强了特征提取功能&#xff0c;从而可以更精确地捕捉细节以更…

二维环境下的TDOA测距定位的MATLAB代码,带中文注释

TDOA测距定位程序介绍 概述 本MATLAB程序实现了基于时间差到达&#xff08;TDOA&#xff09;技术的二维测距定位&#xff0c;能够处理4个或任意数量&#xff08;大于3个&#xff09;的锚节点。在无线定位和导航系统中&#xff0c;TDOA是一种常用的定位方法&#xff0c;通过测量…

论文精读--Two-Stream Convolutional Networks for Action Recognition in Videos

对于单张图片&#xff0c;丢进卷积和全连接层直接得出分类结果就行 但对于视频&#xff0c;早期的一些工作把视频中的一些关键帧抽取出来&#xff0c;把一个个帧通过网络&#xff0c;最后把结果合并&#xff0c;或者把帧叠起来&#xff0c;一起丢进网络。在网络中进行early fu…

基于Springboot+Vue的基于协同过滤算法的个性化音乐推荐系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

【YOLO系列】YOLOv11正式发布!

Yolov11发布文档 代码链接 了解Ultralytics YOLO11的所有突破性功能&#xff0c;这是我们最新的人工智能模型&#xff0c;具有无与伦比的准确性和效率。 我们很高兴向大家介绍Ultralytics型号的下一次进化&#xff1a;YOLO11&#xff01;YOLO11建立在以前YOLO模型版本令人印象…

安装图片标识工具anylabeling

目录 下载压缩包 创建环境 安装opencv 安装第三方库 运行setup.py文件 安装过程可能会出现的错误&#xff1a; 错误1 错误2 安装完成 图标更换 之前提到的嵌入式开发】可编程4k蓝牙摄像头点击器还可以训练模型&#xff0c;使图像识别精度提高 现在讲解&#xff0c;如…

【人人保-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

TongESB7, TongGW, admin账号密码重置方式

停止控制台 修改系统库 identities 表 configuration字段中的password 重启manage

【C语言】指针详解(一)

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1.内存与地址2.指针变量与地址2.1 取地址操作符&2.2 指针变量2.3 指针类型2.4 解引用操作符2.5 指针变量的大小 3. 指针变量类型的意义3.1 指针的解引用 4. const修饰指针4.1 const修饰变量4.2 const修饰指针变量…

矿石运输船数据集、散货船数据集、普通货船数据集、集装箱船数据集、渔船数据集以及客船数据集

海船&#xff1a;用于船只检测的大规模精准标注数据集 我们很高兴地介绍一个新的大规模数据集——海船&#xff0c;该数据集专为训练和评估船只目标检测算法而设计。目前&#xff0c;这个数据集包含31,455张图像&#xff0c;并涵盖了六种常见的船只类型&#xff0c;包括矿石运…

如何使用ssm实现科技银行业务管理系统+vue

TOC ssm743科技银行业务管理系统vue 第一章 绪论 1.1 研究背景 在现在社会&#xff0c;对于信息处理方面&#xff0c;是有很高的要求的&#xff0c;因为信息的产生是无时无刻的&#xff0c;并且信息产生的数量是呈几何形式的增加&#xff0c;而增加的信息如何存储以及短时间…

网络通信——动态路由协议RIP

目录 一.动态路由协议分类 二.距离矢量路由协议 &#xff08;理解&#xff09; 三. 链路状态路由协议&#xff08;理解&#xff09; 四.RIP的工作原理 五.路由表的形成过程 六. RIP的度量值&#xff08;条数&#xff09;cost 七.RIP的版本&#xff08;v1和v2&#xff0…

springboot整合seata

一、准备 docker部署seata-server 1.5.2参考&#xff1a;docker安装各个组件的命令 二、springboot集成seata 2.1 引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>&…

数据清洗第1篇章 - 处理缺失值和重复值

数据清洗是数据分析过程中至关重要的一步&#xff0c;它确保数据的准确性、一致性和完整性。这不仅有助于提高分析结果的可靠性和有效性&#xff0c;还能为算法建模决策提供高质量的数据基础。在进行数据分析和建模的过程中&#xff0c;大量的时间花在数据准备上&#xff1a;加…

【Linux服务器】git和github交互使用

前言&#xff1a;有时候pycharm连接不上github&#xff0c;还是得命令行操作 目录 1. 准备git2. 配置github账户3. 上传项目3.1 创建本地仓库3.2 提交本地代码3.3 上传到github 4. 注意 1. 准备git 下载链接&#xff1a;官网 下载后直接运行安装&#xff0c;cmd输入git --vers…

Redis篇(缓存机制 - 多级缓存)(持续更新迭代)

目录 一、传统缓存的问题 二、JVM进程缓存 1. 导入案例 2. 初识Caffeine 3. 实现JVM进程缓存 3.1. 需求 3.2. 实现 三、Lua语法入门 1. 初识Lua 2. HelloWorld 3. 变量和循环 3.1. Lua的数据类型 3.2. 声明变量 3.3. 循环 4. 条件控制、函数 4.1. 函数 4.2. 条…

set和map结构的使用

个人主页&#xff1a;敲上瘾-CSDN博客 个人专栏&#xff1a;游戏、数据结构、c语言基础、c学习、算法 目录 一、序列式容器和关联式容器 二、set和multiset 1.insert 2.erase 3.find 4.count 三、map和mapmulti 1.pair 2.insert 3.find 4.operator[ ] 5.erase 6.lo…