给定一个简单多边形,多边形按照顺时针或者逆时针的数许排列

内部等距离缩小或者外部放大的多边形,实际上是由距离一系列平行已知多边形的边,并且距离为L的线段所构成的。

外围的是原多边形,内侧是新的多边形

算法构造

多边形的相邻两条边,L1和L2,交于Pi点

做平行于L1和L2,平行线间距是L的,并且位于多边形内部的两条边,交于Qi

我们要计算出Qi的坐标

如图,

PiQi向量,显然是等于平行四边形的两个相邻边的向量v1和v2的和的

而v1和v2向量的方向,就是组成多边形的边的方向,可以用顶点差来表示

v1和v2向量的长度是相同的,等于平行线间距L与两个线段夹角的sin值的除法。

即: Qi = Pi + (v1 + v2)

Qi = Pi + L / sinθ * ( Normalize(v2) + Normalize(v1))

Sin θ = |v1 × v2 | /|v1|/|v2|

计算步骤:

⑴、获取多边形顶点数组PList;

⑵、计算DPList[Vi+1-Vi];

⑶、单位化NormalizeDPList,得到NDP[DPi];(用同一个数组存储)

⑷、Sinα = Dp(i+1) X DP(i);

⑸、Qi = Pi + d/sinα (NDPi+1-NDPi)

⑹、这样一次性可以把所有顶点计算完。

注意,交换Qi表达式当中NDPi+1-NDPi的顺序就可以得到外部多边形顶点数组。

用Swift实现的代码如下,在playground可直接运行

import Foundation

class Point2D  {

var x:Double =0

var y:Double =0

init(_ x:Double,_ y:Double){self.x=x;self.y=y}

init( point:Point2D){x=point.x;y=point.y}

}

//func += (inout left:Point2D, right:Point2D )     { left.x+=right.x;left.y += right.y;}

func +  (left:Point2D, right:Point2D)->Point2D   {return Point2D(left.x+right.x, left.y+right.y)}

func -  (left:Point2D, right:Point2D)->Point2D   {return Point2D(left.x-right.x, left.y-right.y)}

func *  (left:Point2D, right:Point2D)->Double    {return left.x*right.x + left.y*right.y}

func *  (left:Point2D, value:Double )->Point2D   {return Point2D(left.x*value, left.y*value)}

// 自定义的向量差乘运算符号,

infix operator ** {}

func ** (left:Point2D, right:Point2D)->Double {return left.x*right.y - left.y*right.x}

var pList   = [Point2D]()  // 原始顶点坐标, 在initPList函数当中初始化赋值

var dpList  = [Point2D]() // 边向量dpList[i+1]- dpLIst[i] 在 initDPList函数当中计算后赋值

var ndpList = [Point2D]() // 单位化的边向量, 在initNDPList函数当中计算后肤质,实际使用的时候,完全可以用dpList来保存他们

var newList = [Point2D]()  // 新的折线顶点,在compute函数当中,赋值

// 初始化顶点队列

func initPList(){

pList  = [ Point2D(0,0),

Point2D(0,100),

Point2D(100,100),

Point2D(50,50),

Point2D(100,0),

]

}

// 初始化dpList  两顶点间向量差

func initDPList()->Void{

print("计算dpList")

var index  : Int

for index=0; index<pList.count; ++index{

dpList.append(pList[index==pList.count-1 ? 0: index+1]-pList[index]);

print("dpList[\(index)]=(\(dpList[index].x),\(dpList[index].y))")

}

}

// 初始化ndpList,单位化两顶点向量差

func initNDPList()->Void{

print("开始计算ndpList")

var index=0;

for ; index<dpList.count; ++index {

ndpList.append(dpList[index] * ( 1.0 /sqrt(dpList[index]*dpList[index])));

print("ndpList[\(index)]=(\(ndpList[index].x),\(ndpList[index].y))")

}

}

// 计算新顶点, 注意参数为负是向内收缩, 为正是向外扩张

func computeLine(dist:Double)->Void{

print("开始计算新顶点")

var index = 0

let count = pList.count;

for ; index<count; ++index {

var point:Point2D

let startIndex = index==0 ? count-1 : index-1

let endIndex   = index

let sina =ndpList[startIndex] **ndpList[endIndex]

let length = dist / sina

let vector =ndpList[endIndex] -ndpList[startIndex]

point = pList[index] + vector*length

newList.append(point);

print("newList[\(index)] = (\(point.x),\(point.y))")

}

}

// 整个算法的调用顺序

func run()->Void {

initPList();

initDPList()

initNDPList()

computeLine(-5)  // 负数为内缩, 正数为外扩。 需要注意算法本身并没有检测内缩多少后折线会自相交,那不是本代码的示范意图

}

run()

折线平行线的计算方法相关推荐

  1. 根据折线经纬度获取的折线平行线

    /** * @Title: main * @Description: TODO(经纬度根据获取折线的平行线) * @param list 平行线 * @param angle (公里数)距离真实线范围 ...

  2. 折线多边形的原位放大

    文章目录 需要生成的效果 折线多边形的原位缩放两种办法 6.10 多边形放大.缩小及移动 P309 c#实现 缺点 分析 向量缩放办法 算法剖析 算法步骤 c#代码 Revit API 方法 需要生成 ...

  3. 一种基于分段线性插值的Gamma校正硬件实现

    一种基于分段线性插值的Gamma校正硬件实现 以下gamma校正内容摘自<视频信号预处理IP的硬件实现和软件验证>电子科技大学 徐琦 GAMMA 曲线校正(Gamma Correction ...

  4. 基于折线生成平行线的C#算法实现

    经过几天的研究,基于C#实现了一根折线生成平行线,解决了出现折点时的坐标变化.可应用于地图开发中的路段展现,也可以应用于管线设计应用. 下面是代码片段,如需要进一步沟通请加Q59135929 publ ...

  5. 用g.raphael.js高速绘制饼图、柱状图、点状图、折线图(下)

    首先,这里有个g.raphael.js的范例文章,可以直接看,我就不转载了: http://www.cnblogs.com/lhb25/archive/2013/01/09/gRaphael-java ...

  6. 百度地图 使用两条平行线表示路线

    根据他人的程序修改的,原文是如何利用百度地图JSAPI画带箭头的线? 在此,使用两条平行线表示路线. 1.坐标计算: 2.代码如下: <%@ page language="java&q ...

  7. swift:打造你自己的折线图

    看到苹果Health里的折线图了吗.我们就是要打造一个这样的折线图.没看过的请看下图. 我们的主题在于折线图本身.其他的包括步数.日平均值等描述类的内容这里就不涉及了. 首先观察,这个图种包含些什么组 ...

  8. 两直线平行交叉相乘_人教版初中数学七年级下册 平行线判定2公开课优质课课件教案视频...

    平 行 线 的 判 定 一.教材分析 1.主要内容及其地位 本节的主要内容是平行线的判定公理及两个判定定理,由分析画平行线的过程得知,画平行线实际上就是画相等的同位角,由此得到平行线的判定公理--&q ...

  9. GIS中墨卡托与WGS 84的瓦片编号计算方法

    GIS中墨卡托与WGS 84的瓦片编号计算方法   在GIS中计算瓦片的编号,墨卡托与WGS 84的计算方法与瓦片行列号是不一样的,为什么会有这样的差异呢?主要是因为我们的墨卡托是投影坐标系,WGS ...

最新文章

  1. 知名网站的 404 页面长啥样?
  2. Nature调查:6%中国科研人年薪超50万元!
  3. python语法书籍推荐_python语法的书
  4. elment-ui文件上传详解
  5. 即将到截止日期,Frontiers期刊向您邀稿啦!脑机接口领域
  6. Python--面向对象之组合
  7. BGP——路由通告+IBGP水平分割机制+RR路由反射器(讲解+配置命令)
  8. ORM框架SQLAlchemy使用学习
  9. list大数据转换对象_EXCEL比分列强大百倍的数据转换功能
  10. 深度学习框架中的魔鬼:探究人工智能系统中的安全问题
  11. 规范规约是最左规约吗_Java开发者必须要知道的MySQL规范
  12. 如何在 Mac 上修改鼠标指针颜色?
  13. Office文档修复介绍之:laola文件格式介绍
  14. MFC 通用对话框之颜色对话框
  15. cm-14.1 Android系统定制(二):内置系统应用
  16. centos7下升级GLIBC2.31
  17. python excel计算_怎么用python导入excel计算方差
  18. 前端网络——get和post的区别
  19. Nginx 无法重启报错 Starting nginx
  20. Windows快捷键集

热门文章

  1. 通信机房,到底长什么样?
  2. 职教云python题和答案_智慧职教云课堂APPPython程序设计题目及答案
  3. Java中String字符串:空字符串、存放空的字符串、null的区别
  4. 《当程序员的那些狗日日子》(四)喘过气来了
  5. 关于Sass与Compass的一些笔记
  6. Arcgis怎么将标注变成分子分母形式
  7. Python计算机视觉——第四章 照相机模型与增强现实
  8. 一个最简单的C#管道(NamePipe)全双工通信实例
  9. 垃圾收集器的内存回收机制
  10. [转]创业时如有500万元,我早完了