leaflet学习笔记-贝塞尔曲线绘制(八)

news2024/11/23 21:23:39

前言

两点之间的连线是很常见的,但是都是直直的一条线段,为了使连线更加平滑,我们可以使用曲线进行连线,本功能考虑使用贝塞尔曲线进行连线绘制,最后将线段的两端节点连接,返回一个polygon。

贝塞尔简介

给定不同的点 P0 和 P1,线性贝塞尔曲线只是这两点之间的一条线。

相当于线性插值。

Turf.bezierSpline()简介

接受一条线,通过应用贝塞尔样条算法返回一个弯曲的版本

官方例子

var line = turf.lineString([
  [-76.091308, 18.427501],
  [-76.695556, 18.729501],
  [-76.552734, 19.40443],
  [-74.61914, 19.134789],
  [-73.652343, 20.07657],
  [-73.157958, 20.210656]
]);

var curved = turf.bezierSpline(line);

参数说明

line:input LineString

options:{

resolution:点之间的时间(毫秒)

sharpness:衡量样条路径应该有多弯曲的一个度量

}

具体可以查看官方的bezierSpline函数

UseBezierSpline.js完整代码

import { onBeforeUnmount, reactive, ref } from 'vue'
import * as turf from '@turf/turf'

/**
 * @Description 接受一条线,通过应用贝塞尔样条算法返回一个弯曲的版本(贝塞尔曲线)
 * @param mainMap 地图对象
 * @param drawComplete 完成绘制的回调函数
 * @Param bezierOptions
 * @Param bezierOptions.resolution 点之间的时间(毫秒)
 * @Param bezierOptions.sharpness 衡量样条路径应该有多弯曲的一个度量
 * @param drawLayer 绘制图形的layer
 * @Author ZhangJun
 * @Date  2024-01-11 09:55:12
 * @return void
 **/
export default function useBezierSpline(mainMap, drawComplete = null, bezierOptions = {}, drawLayer = undefined) {
  //默认的贝塞尔配置参数合并
  let bezierOptions_config = reactive({
    resolution: 1000,
    sharpness: 0.85,
    ...bezierOptions,
  })

  //绘制事件状态
  let status = ref('start')

  // 记录当前状态是否可以拖动绘制
  let isDragging = true

  //拖动绘制的坐标
  let drawPath = []

  //拖动绘制的线
  let drawLine = reactive(null)

  //鼠标正在移动的点
  let movePoint

  //最终绘制的polygon,最终返回的就是它的轮廓坐标
  let polygon_draw = reactive(null)

  //鼠标提示
  let mouseEventPopup = new L.popup({ className: 'customPopup', closeButton: false })

  if (mainMap) {
    //关闭的时候一定要销毁
    onBeforeUnmount(() => {
      closeDraw()
      mainMap?.removeLayer(drawLayer)
    })

    if (!drawLayer) {
      drawLayer = L.featureGroup([])
      drawLayer.addTo(mainMap)
    }

    //初始化事件
    let initEvents = () => {
      isDragging = false

      //按下鼠标确定需要添加的节点(暂停中)
      mainMap.on('mousedown', (e) => {
        isDragging = false
        let { lat, lng } = e.latlng
        drawPath = [...drawPath, [lng, lat]]

        //如果才开始点击第一次,就创建一个polyline,后面需要动态需改它的path
        if (drawPath?.length === 1) {
          status.value = 'start'
          //添加绘制line
          drawLine = L.polyline(drawPath, { color: 'red' }).addTo(mainMap)
        }
      })

      //松开鼠标开始拖动绘制(开始绘制)
      mainMap.on('mouseup', (e) => {
        isDragging = true
      })

      //鼠标移动绘制(绘制中)
      mainMap.on('mousemove', (e) => {
        if (isDragging) {
          let { lat, lng } = e.latlng
          movePoint = [lng, lat]
          //动态生成贝塞尔曲线的feature
          let splineFeature = generationBezierSpline(drawPath, movePoint)
          if (splineFeature) {
            let tempCoords = turf.getCoords(turf.flip(splineFeature))
            //将生成的贝塞尔曲线的坐标传给polyline,在地图上刷新渲染
            drawLine?.setLatLngs(tempCoords)
          }
        }
        mouseEventPopup?.setLatLng(e.latlng)?.setContent('右键结束绘制')

        //如果还没有添加就直接先添加一下
        if (!mainMap.hasLayer(mouseEventPopup)) {
          //打开方向的popup
          mouseEventPopup?.openOn(mainMap)
        }
      })

      //右键结束(结束绘制)
      mainMap.on('contextmenu', (e) => {
        let coords = turf.getCoords(turf.flip(drawLine.toGeoJSON()))
        //生成polygon
        polygon_draw = L.polygon(coords, { color: 'green' })

        clearDrawLayer()
        addLayersToDrawLayer([polygon_draw])
        //移除曲线
        mainMap?.removeLayer(drawLine)

        status.value = 'end'
        //绘制完成的回调
        if (typeof drawComplete === 'function') {
          let result = getResult(polygon_draw)
          drawComplete(result)
        }
      })

    }

    //移除事件
    let removeEvents = () => {
      //按下鼠标
      mainMap?.off('mousedown')
      //抬起鼠标
      mainMap?.off('mouseup')
      //拖拽事件
      mainMap?.off('mousemove')
      //右键事件
      mainMap?.off('contextmenu')
    }

    //开始绘制
    let startDraw = () => {
      //禁止拖动地图
      mainMap?.dragging?.disable()
      //初始化事件
      initEvents()
    }

    //清除原来绘制的内容
    let clearDrawLayer = () => {
      drawPath = []
      drawLayer?.clearLayers()
    }

    //添加要素到drawLayer
    let addLayersToDrawLayer = (features = []) => {
      features?.forEach(feature => {
        drawLayer.addLayer(feature)
      })
    }

    /**
     * @Description 生成曲线
     * @Param originalPath 已经确定的点坐标集合
     * @Param lastPoint 最后一个坐标点,一般为移动的点坐标
     * @Author ZhangJun
     * @Date  2024-01-11 10:36:11
     * @return void
     **/
    let generationBezierSpline = (originalPath = drawPath, lastPoint = movePoint) => {
      if (originalPath?.length > 0) {
        //加入最后一个点
        let line = turf.lineString([...originalPath, lastPoint], bezierOptions_config)
        return turf.bezierSpline(line)
      }

      return null
    }

    //关闭绘制功能
    let closeDraw = () => {
      //清空绘制的几何
      clearDrawLayer()
      //一定要移除事件,否则事件之间会有干扰
      removeEvents()

      //移除popup
      mainMap?.closePopup(mouseEventPopup)

      //激活拖拽功能
      mainMap?.dragging?.enable()
    }

    //获取最终的polygon的轮廓坐标
    let getResult = (feature = polygon_draw) => {
      if (feature) {
        //获取输入 feature 并将它们的所有坐标从 [x, y] 翻转为 [y, x]。
        let featureCollection = turf.flip(feature.toGeoJSON())
        return turf.getCoords(featureCollection)
      }
      return []
    }

    return { status, getResult, closeDraw, drawLayer, bezierOptions_config, startDraw }
  }

  return {}
}

UseBezierSpline.js使用

if (wizMap?.map) {
  let { startDraw, closeDraw, status: temp, getResult } = useBezierSpline(wizMap?.map)
  getCoords = getResult
  //当前绘制状态(是否完成绘制)
  status.value = temp

  onMounted(() => {
    //需要这种处理,不然会有异常
    nextTick(() => {
      startDraw()
    })
  })
}

效果

贝塞尔曲线


本文为学习笔记,仅供参考

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LangChain学习之旅】—(4) 模型I/O:输入提示、调用模型、解析输出

【LangChain学习之旅】—(4) 模型I/O:输入提示、调用模型、解析输出 Model I/OLangChain 中提示模板的构建语言模型为什么选择langchain输出解析总结 Reference:LangChain 实战课 Model I/O 我们可以把对模型的使用过程拆解成三块…

分布式引擎Elasticsearch本地部署并结合内网穿透远程访问

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

怎么看待存在争议的低代码?

一、低代码直接效果怎么样? 以体验过的JNPF平台为例,JNPF低代码开发的过程就是可以通过拖拉拽的方式去完成软件开发,复杂功能可以通过二次开发来解决,提升开发效率,降低开发成本。 给大家举个例子,以我们熟…

ORACLE RAC DG文件路径错乱解决办法

最近接手了一个客户的RAC-RAC dg环境的维护,登录上去之后发现dg延迟了8天,由于主库的空间非常紧张,归档日志早就删除了,所以准备使用rman基于scn点的备份恢复的方案恢复dg同步 在备份完成之后,使用新的控制文件进行数据恢复的时候报错datafile 43 not found: 检查了一下发现当…

SpringBoot请求参数加密、响应参数解密

SpringBoot请求参数加密、响应参数解密 1.说明 在项目开发工程中,有的项目可能对参数安全要求比较高,在整个http数据传输的过程中都需要对请求参数、响应参数进行加密,也就是说整个请求响应的过程都是加密处理的,不在浏览器上暴…

[linux]编译一个ko文件并运行

一、需求 有一段代码需要在运行时加载注入内核中&#xff0c;当用户层需要访问时可以提供内核态环境去运行。 二、c代码构建 // #include <errno.h> // #include <string.h> // #include <stdio.h> // #include <fcntl.h> // #include <stdlib.h…

全新小白菜QQ云端机器人登录系统源码 /去除解密授权学习版源码

源码介绍&#xff1a; 全新小白菜QQ云端机器人登录系统源码&#xff0c;是一款经过全面解密的授权学习版源码。 这款源码已解除了授权版的限制&#xff0c;然而许多人可能对其用途并不了解。实际上&#xff0c;该源码主要面向群机器人爱好者设计。它是一个基于挂机宝机器人框…

基于3D Gaussian Splatting与NeRF实现三维重建(使用IPhone创建数据集)

基于Spectacular AI与NeRF实现三维重建-使用IPhone创建数据集 前言项目简介创建数据集扫描处理数据集 解析数据集Python环境 Windows ffmpeg 环境搭建数据集处理安装Nerfstudio需要CUDA环境 依次安装依赖pip install nerfstudio Nerfstudio实现效果开始训练参数配置实时训练浏览…

吐血整理,自动化测试框架总结,一篇从0到1策底打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、什么是框架 定…

目标检测开源数据集——道路坑洼

一、危害 对车辆的影响&#xff1a;道路坑洼会导致车辆行驶不稳&#xff0c;增加车辆的颠簸&#xff0c;不仅影响乘坐舒适度&#xff0c;还可能对车辆的悬挂系统、轮胎等造成损害。长期在坑洼路面上行驶&#xff0c;车辆的减震系统、悬挂系统等关键部件容易受损&#xff0c;进…

(超详细)2-YOLOV5改进-添加SimAM注意力机制

1、在yolov5/models下面新建一个SimAM.py文件&#xff0c;在里面放入下面的代码 代码如下&#xff1a; import torch import torch.nn as nnclass SimAM(torch.nn.Module):def __init__(self, e_lambda1e-4):super(SimAM, self).__init__()self.activaton nn.Sigmoid()self…

中国电子学会2022年12月份青少年软件编程Scratch图形化等级考试试卷二级真题(含答案)

1.运行下列哪段程序&#xff0c;可以让狗狗走到木屋门口&#xff1f;&#xff08;C&#xff09;(2分) A. B. C. D. 答案解析&#xff1a;小窝在狗狗前方90度方向&#xff0c;我们使用程序让狗狗向前移动即可&#xff0c;移动距离不会超过舞台的宽度&#xff08;480&#xf…

git init 执行后发生了什么?

首先在磁盘中创建一个新目录 Git&#xff0c;进入该目录后执行 git init 初始化。这个时候目录下会创建一个隐藏目录 ./git&#xff0c;这个./git 目录叫做 Git 版本库或者仓库 $ git init Initialized empty Git repository in D:/Git/.git/在讲解.git 目录内容前&#xff0c…

Xcode15 升级问题记录

这里写自定义目录标题 新版本Xcode15升级问题1&#xff1a;rsync error: some files could not be transferred (code 23) at ...参考 新版本Xcode15升级 下载地址&#xff1a;https://developer.apple.com/download/all/ 我目前使用的版本是Xcode15.2 我新创建了一个项目&…

《JVM由浅入深学习【七】 2024-01-11》JVM由简入深学习提升分享

亲爱的读者们&#xff0c;欢迎来到本篇博客&#xff0c;这是JVM第七次分享&#xff0c;下面是七个JVM常用常面的分享&#xff0c;请笑纳 目录 1. 几个与JVM 内存相关的核心参数2.如何计算一个对象的大小3.堆为什么要分为新生代和老年代4.JVM堆的年轻代为什么要有两个 Survivor…

分布式限流和本地限流那些事?

分布式限流和本地限流的目的是一样的&#xff0c;当然我建议技术人在自己的服务中优先考虑本地限流&#xff0c;那样对于自己的API的影响会小一点。 限流这种技术&#xff0c;在没有触发限流的阈值的时候&#xff0c;是不会有什么大的问题的&#xff0c;当时一旦触发阈值&…

全网独家:基于openEuler-22.03-LTS-SP4底包构建opengauss 2.1.0 rpm包安装的单机轻量版数据库容器

本文基于openEuler-22.03-LTS-SP4底包,使用rpm安装方式构建opengauss 2.1.0 单机轻量版数据库容器。 一、openEuler-22.03-LTS-SP4底包 1、下载镜像 下载链接 sha256:ffe6c97428d6e684519dd670c18d6681861bdc17719b0387c6e11a65e37a771f openEuler-docker.x86_64.tar.xz …

景联文科技:以高质量数据赋能文生图大模型

1月5日&#xff0c;在智求共赢・中国AIGC产业应用峰会暨无界AI生态合作伙伴大会上&#xff0c;中国AIGC产业联盟联合无界AI发布了《中国AIGC文生图产业白皮书2023》&#xff0c;从AIGC文生图发展历程、主流工具、产业实践以及规模预测等多个维度&#xff0c;全面揭示了中国AIGC…

electron+vue编辑Office Word?

Electron 桌面应用是基于 Chromium 内核的&#xff0c;而谷歌Chrome取消了对PPAPI插件支持后&#xff0c;在线Office方案纷纷失效&#xff0c;只能更换国产浏览器在低版本浏览器苟延残喘&#xff0c;不能用于electronvue项目。 经过小编不断的寻找&#xff0c;终于找到一款至今…

vue3的福音框架arco.design

前言&#xff1a; 在vue2于2023年底正式宣布不在维护&#xff0c;vue3使用越来越频繁的时刻&#xff0c;我们实现项目的辅助框架也越来越多。element, iview, antd 等经典框架继续风靡一时&#xff0c;不过也有很多好的框架&#xff0c;功能也强大&#xff0c;比如我们今天说的…