多边形扩展和收缩(凸多边形和凹多边形)

article/2025/9/18 10:22:16

目录

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

背景介绍:

如下图所示,黑色是原多边形,红色是扩展的多边形,蓝色是收缩的多边形。这是最终的效果。
在这里插入图片描述
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
}

http://chatgpt.dhexx.cn/article/y1shEVar.shtml

相关文章

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

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

判断多边形是凹多边形还是凸多边形,以及求凹点

转载&#xff1a;计算机几何 - 如何判断一个多边形是凸多边形还是凹多边形_刘建宁的博客-CSDN博客_凹多边形和凸多边形的区别 重点&#xff1a; 1.凸多边形指的是多边形的每个内角小于180度。 2.凹多边形指的是至少有一个内角大于180度。 判断多边形性质 多边形内角和等于(n…

凸多边形最优三角

前言&#xff1a;大三下算法课&#xff0c;自己看的凸多边形最优三角&#xff0c;最后上台讲解&#xff0c;和子涵苗子等一起的一段时间 1.相关概念 • 凸多边形&#xff1a;一个简单多边形及其内部构成一个闭凸集时&#xff0c;则 称该简单多边形为一个凸多边形。 • 边&#…

动态规划DP——凸多边形最优三角剖分

1.问题分析 我们可以把披萨饼看作是一个凸多边形&#xff0c;凸多边形是指多边形的任意两点的连线均落在多边形的内部或边界上。 &#xff08;1&#xff09;什么是凸多边形&#xff1f; 如下图所示&#xff0c;是一个凸多边形 如下图所示&#xff0c;不是一个凸多边&#xff0c…

凸多边形、凹多边形、凸包算法

凸多边形&#xff1a; &#xff08;Convex Polygon&#xff09;可以有以下三种定义&#xff1a; 1、没有任何一个内角是优角&#xff08;Reflexive Angle&#xff09;的多边形。 2、如果把一个多边形的所有边中&#xff0c;有一条边向两方无限延长成为一直线时&#xff0c;其他…

搜狗浏览器屏蔽广告插件_“云法庭”里“云勘验” 法院开审搜狗浏览器插件屏蔽优酷视频广告案...

在第20个世界知识产权日到来之际&#xff0c;北京海淀法院通过“北京法院云法庭”公开开庭审理原告优酷信息技术(北京)有限公司(下称优酷公司)与被告北京搜狗科技发展有限公司、被告北京搜狗信息服务有限公司(下合称搜狗公司)涉搜狗浏览器插件屏蔽优酷视频广告不正当竞争纠纷案…

搜狗浏览器屏蔽广告插件_“云法庭”里“云勘验”,海淀法院开庭审理搜狗浏览器插件屏蔽优酷视频广告不正当竞争纠纷案...

来源&#xff1a; 北京海淀法院 特别提示&#xff1a;凡本号注明“来源”或“转自”的作品均转载自媒体&#xff0c;版权归原作者及原出处所有。所分享内容为作者个人观点&#xff0c;仅供读者学习参考&#xff0c;不代表本号观点。 在第20个世界知识产权日到来之际&#xff0…

搜狗浏览器屏蔽广告插件_“云法庭”里“云勘验”法院开审搜狗浏览器插件屏蔽优酷视频广告案...

在第20个世界知识产权日到来之际&#xff0c;北京海淀法院通过“北京法院云法庭”公开开庭审理原告优酷信息技术(北京)有限公司(下称优酷公司)与被告北京搜狗科技发展有限公司、被告北京搜狗信息服务有限公司(下合称搜狗公司)涉搜狗浏览器插件屏蔽优酷视频广告不正当竞争纠纷案…

【视频广告位叫法】

例如&#xff1a;爱奇艺&#xff0c;优酷&#xff0c;腾讯视频&#xff0c;前贴&#xff0c;中插&#xff0c;暂停贴&#xff0c;后贴广告位&#xff01;

优酷 DSP 广告投放系统架构实践

作者 | 鸿雁 阿里文娱技术专家 导读&#xff1a;随着 RTB 网络在线展现广告交易模式的兴起&#xff0c;各大公司都纷纷搭建自己的 DSP ( Demand-Side Platform ) 广告投放系统进行获客。优酷在近几年也搭建 DSP 系统&#xff0c;并且在持续迭代。在这一过程中&#xff0c;经历…

优酷视频在网站里播放

工具/原料 准备一组代码&#xff1a; <embed srchttp://static.youku.com/v1.0.0149/v/swf/loader.swf?VideoIDS视频ID&winTypeadshow&isAutoPlaytrue quality"high" width"580" height"435" align"middle" allowScriptA…

网页引用优酷视频并添加封面自动播放

引用优酷视频可以减轻公司的服务器压力&#xff0c;而且和自己上传保存视频相比会方便轻松许多&#xff0c;不过相对的需要忍受广告。 首先你需要在优酷里找到你要引用的视频&#xff0c;或者自己上传。然后打开会有一个分享按钮&#xff1a; 以我使用的第二个为例&#xff0…

html上传优酷视频,如何将视频发布到自己的企业网站上?

郑州做网站是为了更好的宣传企业&#xff0c;如果网站要想有视频的表现形式&#xff0c;那就得花点心思去考虑了。一般情况下&#xff0c;要想把视频放到网站上&#xff0c;无外乎就两种方式&#xff1a;第一、直接把视频上传到网站目录&#xff0c;然后在合适的位置调用。由于…

php视频系统源码,基于ThinkPHP框架仿优酷视频源码带数据,后台功能强大

源码介绍 最新高仿优酷视频网源码带数据&#xff0c;后台功能齐全强大&#xff0c;而且是基于thinkphph内核开发&#xff0c;很不错&#xff0c;虽然是旧版模板&#xff0c;但是也值得学习&#xff0c;尤其是正在学习ThinkPHP框架的人拿来学习&#xff0c;相信你需要&#xff0…

鸿蒙os去广告,隐藏福利?华为鸿蒙OS新惊喜:优酷视频流转播放可免广告

近日&#xff0c;华为鸿蒙OS 2.0开发者公测版推送正式开启&#xff0c;包括华为Mate X2、Mate 40系列等机型均可先行尝鲜。 根据目前已知信息来看&#xff0c;华为手机从6月初开始将可升级鸿蒙系统。 随着参与开发者公测的用户逐渐增多&#xff0c;网上出现大量鸿蒙OS的测试体验…

优酷视频整段代理php,thinkphp仿优酷带数据源码|php仿优酷视频源码带后台功能强大...

本项目是仿优酷官网&#xff0c;优酷官网是一个集多种知识面为一体的网站&#xff0c;能全面的锻炼我们的技能,所以我们决定仿优酷网。 本项目后台主要实现了&#xff1a;用户管理、分类管理、视频管理、评论管理、权限管理、轮播管理、网站配置和广告管理以及登录退出等模块。…

android加载优酷视频播放器,使用android优酷视频云一些问题

最近项目迭代需要添加视频播放功能&#xff0c;由于若干原因就选择了优酷视频&#xff0c;本来挺简单的一个功能在做的时候居然碰到了若干意想不到的问题&#xff0c;果然还是优酷视频提供的demo最稳定啊&#xff0c;啥问题木有~~o(>_ 好了&#xff0c;闲话不多说&#xff0…

html调用优酷视频播放,优酷网视频播放器站外调用详解

优酷网视频播放器站外调用详解 蓝叶 网站设计 2011-03-21 14201 5评论 自从蓝叶准备做视频盒&#xff0c;就一直在研究各个视频站播放器调用代码&#xff0c;只要搞明白了 代码我都共享出来了&#xff0c;这次说说优酷网播放器的站外调用方法。优酷网默认获取的 站…

mac os x 设置终端快捷键

大家都知道在linux下可以用ctraltt组合快捷来打开终端&#xff0c;那么在OS X上可以吗&#xff1f;答案是肯定的&#xff0c;其实OS X上很多功能都可以通过Apple自家的Automator.app创建&#xff0c;且使用此方法可以为任何程序创建快捷键。 废话少说&#xff0c;下面给大家演…

Mac - 当前位置打开终端

1、点击屏幕顶部的“Finder”弹出下拉菜单。 2、点击“服务”菜单项弹出子菜单&#xff0c;点击子菜单中的“服务偏好设置” 3、点击弹出的服务偏好设置窗口中的“服务”并勾选“新建位于文件夹位置的终端窗口”&#xff1b;点击该项还可以为该操作设置快捷键。 4、关闭设置窗口…