Algorithm 在基于DCEL/半边的图形中动态添加边?
我试图实现一个矢量图形“绘图”系统,本质上,用户可以在屏幕上画线,并与相交线创建的区域交互。我正在努力确定/评估这些区域是什么 我尝试了几种不同的解决方案,主要是保留一个边列表并运行BFS以找到最短的周期,但这带来了无数问题,BFS会以非法方式进行快捷操作,而孔和退化边导致的问题超出了我的计算范围,因此我转向DCEL,半边系统 我已经阅读了关于这个话题的所有文章,包括两篇经常被引用的文章:和。然而,这两种方法似乎都不能解决我在向图形动态添加边时遇到的问题 假设我从这一条边开始 半边在一个循环中相互连接,全局无边界“外表面”连接到其中一条半边。轻松,明白了 然后添加另一条边,附加到中心顶点: 新的半边工作正常,我们更新流入v1下一个指针的边,使其成为唯一可用的其他边,而不是它们的孪生边。再说一次,这对我来说很有意义 让我非常困惑的是,当我们将第三条边添加到中心顶点时,这里发生了什么: 我知道这就是它应该看起来的样子和链接,但我对如何通过编程实现这一点感到困惑,因为我不确定如何确定边(4,1)是指向边(1,2)还是指向边(1,3)(类似地,对于边应该指向什么(1,4)) 当你看这张图片时,答案似乎很明显,但当你试图以一种稳健、严密的算法方式将其合理化时,我的大脑会融化,我无法理解它。我正在读的教科书(计算几何,马克·德伯格等人,第35页)只是说 “[测试边的位置]应按边的循环顺序 围绕顶点v” hilvi.org文章中给出的用于查找要链接的传出边和传入边的算法似乎根本不起作用,因为它将取顶点1,并跟随其传出边的孪生边,直到找到一条“自由”边,在本例中,该边是(2,1),这是错误的。(除非我理解不正确,否则我可能对整个问题的理解都是错误的。)Algorithm 在基于DCEL/半边的图形中动态添加边?,algorithm,graphics,graph-theory,Algorithm,Graphics,Graph Theory,我试图实现一个矢量图形“绘图”系统,本质上,用户可以在屏幕上画线,并与相交线创建的区域交互。我正在努力确定/评估这些区域是什么 我尝试了几种不同的解决方案,主要是保留一个边列表并运行BFS以找到最短的周期,但这带来了无数问题,BFS会以非法方式进行快捷操作,而孔和退化边导致的问题超出了我的计算范围,因此我转向DCEL,半边系统 我已经阅读了关于这个话题的所有文章,包括两篇经常被引用的文章:和。然而,这两种方法似乎都不能解决我在向图形动态添加边时遇到的问题 假设我从这一条边开始 半边在一个循环中相
所以我完全被难住了。我现在唯一的想法是为每个半边创建某种标题属性,在这里我测量了边创建的角度,并以这种方式选择边,也许这是对的,但这似乎与半边结构所支持的相反,至少在我阅读的文章中,似乎没有提到类似的内容。任何帮助都将不胜感激。这个问题我已经讨论了一个多星期了,似乎无法解决。是的,所以我花了很多时间思考这个问题,说实话,我有点惊讶我找不到这个问题的直接答案。因此,如果将来有人遇到类似的问题,想要从头开始填充半边图,这里有一个可行的解决方案。我没有博客,所以我在这里写 我不知道这是否是最好的答案,但它在线性时间内工作,对我来说似乎很简单 我将处理与传统DCEL略有不同的以下对象/类:
class Vertex {
x;
y;
edges = []; //A list of all Half Edges with their origin at this vertex.
//Technically speaking this could be calculated as needed,
and you could just keep a single outgoing edge, but I'm not
in crucial need of space in my application so I'm just
using an array of all of them.
}
class HalfEdge {
origin; //The Vertex which this half-edge emanates from
twin; // The half-edge pair to this half-edge
face; // The region/face this half-edge is incident to
next; // The half-edge that this half-edge points to
prev; // The half-edge that points to this half-edge
angle; //The number of degrees this hedge is CW from the segment (0, 0) -> (inf, 0)
}
class Face {
outer_edge; //An arbitrary half-edge on the outer boundary defining this face.
inner_edges = []; //A collection of arbitrary half-edges, each defining
//A hole in the face.
global; //A boolean describing if the face is the global face or not.
//This could also be done by having a single "global face" Face instance.
//This is simply how I did it.
}
用于在(x,y)处初始化顶点:
setAngle(){
const dx = this.destination().x - this.origin.x;
const dy = this.destination().y - this.origin.y;
const l = Math.sqrt(dx * dx + dy * dy);
if (dy > 0) {
this.angle = toDeg(Math.acos(dx / l));
} else {
this.angle = toDeg(Math.PI * 2 - Math.acos(dx / l));
}
function toDeg(rads) {
return 180 * rads / Math.PI;
}
}
index-1
(如果index=0
,我们返回边缘[edges.length-1]
)。以edge的孪生兄弟为例,这就成了我们在上面的hivli文章中描述的AInBOut=AIn.next
AIn.next=hedgeAB
,同样地,hedgeAB.prev=AIn
,然后hedgeBA.next=AOut
,AOut.prev=hedgeBA
。对hedgeBA也执行步骤3-5,但在顶点B上运行CCW搜索除外