您当前位置:www.4675.com > www.8364.com >
www.8364.com

而像codeproject 或Wikipedia 上的源码可读性太差(不

2019-11-26

  我们需要一条扫描线和一条海岸线,这两条线都跟着法式的运转,通过整个平面。扫描线是一条曲线,我们能够假定它是程度的,正在平面上从上到下地挪动。正在算法运转期间,扫描线上方的初始点曾经被纳入Voronoi图,而扫描线下方的点暂未考虑。海滩线不是一条曲线,而是一条复杂的多段曲线,彩天下app,位于扫描线的上方,它将曾经确定的区域和未确定的区域朋分开,即不管后续还有几多个点,海岸线上方的维诺图都曾经是确定的了。对于扫描线上方的初始点,我们能够定义距离该点和扫描线等距的点的曲线(即以该点为核心,以扫描线为准线的抛物线),海岸线就是这些抛物线并集的鸿沟。跟着扫描线的推进,海岸线中相邻抛物线交点(订交的点)将勾勒出维诺图的边。海岸线也跟着扫描线的推进而推进,一直连结其上的点到核心的距离和到扫描线的距离相等。

  2、若何生成维诺图的,有个gif 图能够帮帮理解,两头那段英文的算法描述写得很好,读下来大致就有了生成维诺图的思(英文欠好的能够百度翻译一下)。下面还附了个伪代码,不外这伪代码我是完全看不懂了,百度翻译也不管用了。文章末尾还附加了几个算法源码,不外不保举阅读,代码可读性太差了,归正我是啃不下来,后面会保举一个写得比力清晰的源码。

  下面先保举几篇我看过写得比力好的进修材料,能够用于参考。(吐槽:这几篇是我从海量博客中筛选出来的,网上能搜出一堆相关博客,可实正有内容的却没有几篇)

  理论上,两种图形能够互相。1、生成维诺图后,毗连有公共边的初始点集,便可形成德洛内三角。2、生成德洛内三角后,针对每一个三角形边,生成垂曲等分线,并将垂曲等分线的端点设置为三角形边所正在外接圆的圆心即可(内部三角形边的垂曲等分线为线段,鸿沟三角形边的垂曲等分线为射线)。

  1、扫描线:扫描线 一曲扫描到 y = maxY,扫描完成后,维诺图也将生成完毕。(上图的黑色线、海岸线

  2、我们需要快速获取某点正上方的抛物线,所以引入排序二叉树,排序二叉树每一个叶子结点代表一段抛物线,每一个内部结点代表相邻抛物线的交点,排序根据就是交点的 x 坐标,从而能够用logn 的时间,快速获取某点正上方的抛物线。(排序二叉树可能会退化成链表,实正利用的时候能够考虑能否能够替代成均衡二叉树)

  维诺图的方针是找出所有坐点对应区域的边,而边是跟着扫描线挪动,由相邻抛物线交点勾勒出来的,所以我们把边记正在弧上,一条弧摆布各有一个交点,所以我们每条弧记两条边S0、S1。当发生坐点事务时,先找到其正上方的弧,然后这条弧两头部门将被新的抛物线代替,即由一段弧变成两个交点Inter1、Inter2 和 三段弧Arc1、Arc2、Arc3,此中Arc2 是新增的弧,Arc1、Arc3 是原弧出来的,所以Arc1 的S0 承继自原弧的S0,Arc3 的S1 承继自原弧的S1,Arc1 的S1 取 Arc2 的S0 将指向按照左交点建立的一条新边,Arc2 的S1 和Arc3 的S0 将指向按照左交点建立的一条新边。当发生圆事务时,弧Arc 消逝,所以 Arc 的S0、S1 将完成构制,即S0、S1 的起点设置正在圆事务的圆心,而 Arc 消逝后,其前置弧和后置弧订交正在一路,所以前置弧的S1 和后置弧的S0 将指向按照圆心建立的一条新边。当所有事务处置完毕后,我们需要假设一条扫描线,使残剩的所有相邻弧交点位于维诺图鸿沟外,计较此时这些交点的,完成残剩的维诺图边。

  1、若何生成Delaunay三角网的博客。这篇文章是地比力细,比力全,比力容易理解的,不外同样有良多坑,阅读时不要脱漏了博客评论区,那里指出了良多坑点。最坑的一点,即便你解除万难,写出了和做者一模一样的代码,仍然有良多BUG,好比点数少的环境下有可能没有任何生成,好比最一生成的德洛内三角不是凸包等。当然,文章确实好,值得一看,用来理解德洛内三角是很有帮帮的。

  维诺图(Voronoi Diagram),简单来说,是一种平面区域的划分体例。假设平面上有 n 个点:P1 ~ Pn,那么对应维诺图则划分成 n 个区域:S1 ~ Sn,而且 Si 内所有点到 Pi 的距离小于等于到其他肆意点的距离。维诺图还经常和德洛内三角(Delaunay 三角网)扯上关系,德洛内三角是一系列相连不堆叠的三角形调集,特点有两个:1、肆意三角形的外接圆不包含面内其他三角形极点,2、相邻两个三角形形成的凸四边形,互换对角线,六个内角的最小角不会增大。如下图,实线形成德洛内三角,虚线形成维诺图,德洛内三角每一个三角形的极点即是维诺图的初始点集。

  所以,该算法的沉点即是若何处置坐点事务和圆事务。起首看坐点事务,当扫描线 做扫描线 距离相等,当扫描线 时,将生成一条以 P4 为核心,扫描线为准线的抛物线 对应的海岸线订交于两点,这两点会跟着扫描线的挪动而分手,现实上,这两点将勾勒出统一条维诺图边(能够确定该边上点到 P4 和 P2 距离相等)。P4 抛物线 抛物线 抛物线朋分成两段抛物线 下方没有新的坐点,跟着扫描线 对应抛物线将越变越宽,可能会将原先 S1、S2 挤兑没,即 S1 可能由一段抛物线 抛物线 抛物线 的交点沉合,这便发生了一个圆事务,即缩小成的那一点到 P1、P2、P4 距离相等。当然法式不成能做到一点一点的挪动扫描线,所以生成圆事务,是正在碰到 P4 的一霎时决定的,即碰到 P4 时,判断 P1、P2、P4 能否共圆。接着我们来看圆事务,当发生了圆事务后,就申明有某一段抛物线缩小成一个点,所以我们就需要将该段抛物线删除,并生成曾经确定下来的维诺图边。

  该算法利用了排序二叉树来海岸线,利用优先队列来可能惹起海岸线变化的事务。这些事务包罗新增抛物线到海岸线(扫描过一个初始点,称之为坐点事务)和从海岸线中删除某一条抛物线(这条抛物线缩小成一个点时,即海岸线中相邻的三个抛物线核心生成的圆取扫描线相切,称之为圆事务)。每一个事务能够用发生该事务时的扫描线 y 坐标来确定优先级。然后,我们要做的就是频频从优先队列中取出事务,进行处置,可能会影响到海岸线布局,可能会新增圆事务。

  3、若何生成维诺图的博客,内容比力少,不外比力清晰,附加的伪代码也比力容易理解,有了大致思后按照这篇博客来完美代码。

  4、供给源码的博客,其他良多博客都只是简单引见方式,而像codeproject 或Wikipedia 上的源码可读性太差(不是我吐槽,是实的太差,完全看不懂),而这篇博客供给的代码很适合用来进修,定义清晰了然,虽然代码效率达不到logn,但这仅仅是存放海岸线的数据布局差别,其余内容取平面扫描法分歧,能够参照该源码去解读保举的第三篇博客。不外该源码也有些BUG,有一些特殊环境会前往不准确的维诺图。

  3、我们需要快速查抄相邻的三段抛物线对应核心能否共圆,所以引入双向链表,用于办理排序二叉树的叶子结点,即每个叶子结点记实上一片叶子和下一片叶子指针。