目录

  • 背景介绍:
  • 知识积累:
  • 思路点拨:
  • 代码区域:

背景介绍:

如下图所示,黑色是原多边形,红色是扩展的多边形,蓝色是收缩的多边形。这是最终的效果。

PS:楼主使用的是ES6的语法,地图是高德地图API

知识积累:

使用的是高中所学的向量的知识和三角公式知识。
对于向量:

  • 设二维向量:a = (a1, a2); b = (b1, b2);
  • 设三维向量:OA = (x1, y1, z1); OB = (x2, y2, z2);
  1. 向量点乘积:a · b = a1 * b1 + a2 * b2 = |a| |b| cos<a, b>
  2. 向量单位化:a 单位化后的 na = (a1 / Math.sqrt(a1 * a1 + a2 * a2), a1 / Math.sqrt(a1 * a1 + a2 * a2))
  3. 向量叉乘积:
    二维: a X b = (a1 * b2) - (a2 * b1)
    三维:OA X OB = (y1 * z2 - y2 * z1, x2 * z1 - x1 * z2, x1 * y2 - x2 * y1)
  4. 半角公式:

思路点拨:

  1. 用一个数组paths表示要操作的多边形。其中paths的格式为:[[117.14589,36.659714],[117.145278,36.658952],[117.14626,36.658505],[117.147017,36.659628]]
  2. 需要将paths的经纬度换成像素坐标。原因:如果使用经纬度和要扩展(收缩)大小做对比会有单位不统一的问题。解决方案:使用map.lnglatToPixel将经纬度换成像素坐标;使用map.pixelToLngLat将像素坐标转换成经纬度坐标。
  3. 如上图所示,PP1 = (x1 - x, y1 - y); PP2 = (x2 - x, y2 - y); 令vx1 = x1 - x;vy1 = y1 - y;vx2 = x2 - x;vy2 = y2 - y;则 PP1 = (vx1, vy1); PP2 = (vx2, vy2);
  4. PP1PP2 单位化后,就得到了v1 = (vx1 / n1, vy1 / n1) 和 v2 = (vx2 / n2, vy2 / n2)。其中n1 = norm(vx1, vy1);n2 = norm(vx2, vy2)
  5. PQ = v1 + v2 = (vx1 / n1 + vx2 / n2, vy1 / n1 + vy2 / n2)。设 vx = vx1 / n1 + vx2 / n2;vy = vy1 / n1 + vy2 / n2,则PQ = (vx, vy)。还需要对PQ做单位化,则PQ = (vx / n, vy / n),其中n = norm(vx, vy)。
  6. 根据向量点乘积的含义,可以得到cos<v1, v2> = (vx1 * vx2 + vy1 * vy2) / (n1 * n2);
  7. |PQ| = L / sin(<v1, v2> / 2) 经化简可得 L / Math.sqrt(1 - (v1x * v2x + v1y * v2y) / 2)
  8. 根据上述所说,就可以得到完整的PQ,现在加上P点坐标,就可以得到Q点坐标。
  9. 处理完成后,记得将像素坐标转成经纬度坐标。
  10. 在处理凹多边形时,需要使用叉乘积。用来判断是两向量的夹角是凹角还是凸角。
    若叉乘积 < 0,向量夹角为 凹角;若叉乘为OP1 X OP2,则 P1 - O - P2 为顺时针。
    若叉乘积 > 0,向量夹角为 凸角;若叉乘为OP1 X OP2,则 P1 - O - P2 为逆时针。
    若叉乘积 = 0,向量夹角为 平角;若叉乘为OP1 X OP2,则 P1 - O - P2 在一条直线上。
    因此在计算PQ 方向的时候,若为凸角, PQ = PP1 + PP2;若为凸角,PQ = P1P + P2P。无论是凸角还是凹角,|PQ| 是 恒定不变的,都为:|PQ| = L / Math.sqrt(1 - (v1x * v2x + v1y * v2y) / 2)

代码区域:

废话不多说,下面是完整代码(ES6),地图使用的是高德地图

/*** 计算多边形的外延* 算法详情可移步:https://blog.csdn.net/sun_and_breeze/article/details/107517088 去看* @param {*} map 高德地图map对象* @param {*} zoom 地图缩放比例* @param {*} scale 地图比例尺. 高德地图可以通过map.getScale()来获取。含义:表示当前屏幕距离一米代表实际距离多少米* @param {*} paths 多边形顶点数组。PS:下面代码中是按照多边形顶点逆时针排列的顺序进行处理的,如果你的顶点数组是顺时针,那么是用reverse方法倒过来即可。* @param {*} extra 外延大小。为正: 向外扩; 为负: 向内缩* @return 扩展或缩小后的多边形顶点数组*/
export const calcPolygonExtra = (map, zoom, scale, paths, extra) => {if (!zoom) returnconst norm = (x, y) => Math.sqrt((x * x) + (y * y))const len = paths.length// 获取实际1m对应像素是多少const extraPixel = (extra / scale) * getDPI() * 1000let polygon = []for (let i = 0; i < len; i++) {const point = map.lnglatToPixel(paths[i], zoom) // P 点const point1 = map.lnglatToPixel(paths[i === 0 ? len - 1 : i - 1], zoom) // P1 点const point2 = map.lnglatToPixel(paths[i === len - 1 ? 0 : i + 1], zoom) // P2 点// 向量PP1const vectorX1 = point1.x - point.x // 向量PP1 横坐标const vectorY1 = point1.y - point.y // 向量PP1 纵坐标const n1 = norm(vectorX1, vectorY1) // 向量的平方根 为了对向量PP1做单位化let vectorUnitX1 = vectorX1 / n1 // 向量单位化 横坐标let vectorUnitY1 = vectorY1 / n1 // 向量单位化 纵坐标// 向量PP2const vectorX2 = point2.x - point.x // 向量PP2 横坐标const vectorY2 = point2.y - point.y // 向量PP2 纵坐标const n2 = norm(vectorX2, vectorY2) // 向量的平方根 为了对向量PP1做单位化let vectorUnitX2 = vectorX2 / n2 // 向量单位化 横坐标let vectorUnitY2 = vectorY2 / n2 // 向量单位化 纵坐标// PQ距离const vectorLen = -extraPixel / Math.sqrt((1 - ((vectorUnitX1 * vectorUnitX2) + (vectorUnitY1 * vectorUnitY2))) / 2)// 根据向量的叉乘积来判断角是凹角还是凸角if (((vectorX1 * vectorY2) + (-1 * vectorY1 * vectorX2)) < 0) {vectorUnitX2 *= -1vectorUnitY2 *= -1vectorUnitX1 *= -1vectorUnitY1 *= -1}// PQ的方向const vectorX = vectorUnitX1 + vectorUnitX2const vectorY = vectorUnitY1 + vectorUnitY2const n = vectorLen / norm(vectorX, vectorY)const vectorUnitX = vectorX * nconst vectorUnitY = vectorY * nconst polygonX = vectorUnitX + point.xconst polygonY = vectorUnitY + point.yconst polygonLngLat = map.pixelToLngLat(new window.AMap.Pixel(polygonX, polygonY), zoom)polygon[i] = [polygonLngLat.getLng(), polygonLngLat.getLat()]}return polygon
}/*** 获取屏幕DPI的算法。屏幕每一毫米对应多少像素。*/
const getDPI = () => {let dpiif (window.screen.deviceXDPI !== undefined) {dpi = window.screen.deviceXDPI// arrDPI[1] = window.screen.deviceYDPI} else {let tmpNode = document.createElement('DIV')tmpNode.style.cssText = 'width:1mm;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden'document.body.appendChild(tmpNode)dpi = parseInt(tmpNode.offsetWidth, 0)// arrDPI[1] = parseInt(tmpNode.offsetHeight, 0)tmpNode.parentNode.removeChild(tmpNode)}return dpi
}

多边形扩展和收缩(凸多边形和凹多边形)相关推荐

  1. 判断一个多边形是凸多边形还是凹多边形

    题目: 判断一个多边形是凸多边形还是凹多边形 输入: 输入包含多组测试数据,每组数据占2行,首先一行是一个整数n,表示多边形顶点的个数,然后一行是2×n个整数,表示逆时针顺序的n个顶点的坐标(xi,y ...

  2. 什么是凸多边形和凹多边形

    GIS有时需要用算法判断线段是否在多边形内: 最基本的出发点如下, 线段在多边形内的一个必要条件是线段的两个端点都在多边形内,但由于多边形可能为凹,所以这不能成为判断的充分条件: 就是说, 如果线段的 ...

  3. OpenShift 4 - Knative教程 (4) 自动扩展和收缩

    <OpenShift 4.x HOL教程汇总> 说明:本文已经在OpenShift 4.10环境中验证 文章目录 自动扩展和收缩功能说明 配置自动扩展收缩 配置扩展收缩上下限 自动扩展和收 ...

  4. 多边形分割成若干凸多边形(NavMesh的初步形成)

    多边形分割成若干凸多边形(NavMesh的初步形成) 由于发毕设论文会利用到相关内容,所以暂时将文章下掉了,会6月份重新上传.尽情谅解.

  5. 顶角判别法识别多边形的凸凹性,并将凹多边形近似处理为凸多边形

    顶角判别法:    该算法首先在顶点数据集中找J坐标值最大的点,若J坐标值最大的点不止一个,则在J坐标值最大的这些点中找,坐标值最大的点,这样找出的顶 点一定显凸性;然后,以该凸顶点为支点顺时针方向旋 ...

  6. java计算一个多边形的重心_2D凸多边形碰撞检测算法(二) - GJK(上)

    2D凸多边形碰撞检测算法(二) - GJK(上) 原理 在 Narrow Phase 精细碰撞检测中,除了 SAT ,另外一个就是 GJK(Gilbert–Johnson–Keerthi)算法.它足够 ...

  7. 多边形向内收缩指定距离的实现

    import math import numpy as np def calc_cos_angle(a,b): #计算两个向量的夹角余弦inner_ab=a[0]*b[0]+a[1]*b[1]abs_ ...

  8. LISP多边形形心计算公式_凸多边形形心坐标计算方法

    顶点 序号 三角形 面积 100 X Y 6839102 X Y 1 4524 2016 2 4587 2084 Xa Ya Xb Yb Xc Yc 3 4645 2156 1 2 3 4524 20 ...

  9. 图形/多段线内缩外扩思路

    图形/多段线内缩外扩思路 前言 我在网上找了很多关于多边形内缩外扩的资料,也测试了一些算法库,如Clipper,boost::geometry::buffer,其实都可以得到不错的结果. Clippe ...

  10. canvas 判断哪个元素被点击_监听 Canvas 内部元素点击事件的三种方法

    canvas内部元素不能像DOM元素一样方便的添加交互事件监听,因为canvas内不存在"元素"这个概念,他们仅仅是canvas绘制出来的图形.这对于交互开发来说是一个必经障碍,想 ...

最新文章

  1. 高速串行总线系列(5)总线的各种基础问题
  2. Unity2D游戏开发基础教程1.2项目、资源和场景
  3. python基本数据类型包括哪些_python入门3——基本数据类型
  4. Winform开发之ADO.NET对象Connection、Command、DataReader、DataAdapter、DataSet和DataTable简介...
  5. cnsl是什么意思_VS2010下创建静态链接库和动态链接库
  6. python的重点和难点_python知识点汇总-Go语言中文社区
  7. Android用ImageView显示本地和网上的图片
  8. python3.5安装tensorflow_如何为Python 3.5安装OpenCV,Tensorflow和机器学习框架运行对象检测应用程序...
  9. 2021-09-08推荐系统 简述DeepFM模型
  10. 虚拟机装xp 架设服务器,VMware安装虚拟机系统ghost xp sp3步骤图解
  11. iOS 如何找到或生成 .dSYM 文件
  12. 百度网盘机器人软件工具自动发货管理文件好友群补发文件资料 (可用于拼多多淘宝闲鱼虚拟店商品自动发货)
  13. 更换ip地址后虚拟机无法联网,连接失败
  14. srs linux开机启动,SRS之安装与使用
  15. 三种求最短路算法基本描述及实现(C++)
  16. 也谈“为什么中国的程序员总被称为码农?”
  17. 自定义maven archetype,上传到nexus,并使用nexus远程的archetype创建项目
  18. 大众mpv_大众mpv商务车7座车型 大众mpv都有哪些?
  19. 第五届声学、振动、噪声控制国际研讨会(CAVNC 2022)
  20. 打印机打印列队中打印状态为错误的解决方式之一

热门文章

  1. 【lssvm分类】基于粒子群算法优化最小二乘支持向量机lssvm实现数据分类matlab代码
  2. 基于遗传算法的柔性车间调度优化(Matlab代码实现)
  3. CCA算法 matlab,典型相关分析(CCA)附算法应用及程序
  4. 【Python】根据经纬度计算距离
  5. 【精】Photoshop抠图全方位攻略
  6. 菜鸟驿站是什么快递_菜鸟驿站是什么快递
  7. 基于fpga的256M SDRAM控制器 【内含256m sdram仿真模型】
  8. MySQL命令执行sql文件的两种方法
  9. 职高计算机专业c语言_重庆市职业高中计算机专业C语言试题
  10. 【STM32F429的DSP教程】第1章 初学数字信号处理准备工作