C# Bentley-Ottmann算法的实现
我在C#中正确实现Bentley Ottmann算法时遇到一些问题。我正试图根据伪代码实现它。我已经在下面发布了我的主要代码。假设我的C# Bentley-Ottmann算法的实现,c#,algorithm,computational-geometry,C#,Algorithm,Computational Geometry,我在C#中正确实现Bentley Ottmann算法时遇到一些问题。我正试图根据伪代码实现它。我已经在下面发布了我的主要代码。假设我的BST和PriorityQueue类实现正确,您认为代码有任何问题吗 没有错误,但并不是所有的交点都被找到,只有一些。我猜代码的else部分有错误(当当前事件是交点时)。我不确定通过交换BST中两个段的位置来交换伪代码意味着什么。我这样做好吗?因为最终,两者在BST中并没有真正交换。我也不能仅仅改变它们的位置,因为这可能会破坏BST的属性 另外,我假设分段在BST
BST
和PriorityQueue
类实现正确,您认为代码有任何问题吗
没有错误,但并不是所有的交点都被找到,只有一些。我猜代码的else
部分有错误(当当前事件是交点时)。我不确定通过交换BST中两个段的位置来交换伪代码意味着什么。我这样做好吗?因为最终,两者在BST中并没有真正交换。我也不能仅仅改变它们的位置,因为这可能会破坏BST的属性
另外,我假设分段在BST中按其左端的Y
-坐标排序是否正确
我注意到的另一个似乎无法追踪的错误是,有时点(0,0)
进入事件列表(0,0)
由几何体输出。如果没有交点,则相交
,但在这种情况下,if
条件应阻止其添加。我不知道它是怎么进来的。如果在添加点后打印事件列表的内容,(0,0)
将永远不会显示。如果在提取并弹出元素后打印内容,有时会显示(0,0)
。这可能与Pop()
方法打乱引用有关,还是肯定是我的PriorityQueue
实现中的问题
如果需要,我还可以展示BST和优先级队列的实现
static class BentleyOttman
{
private static void AddIntersectionEvent(PriorityQueue eventList, Segment segEv, Segment segA, SegPoint i)
{
i.IntersectingSegments = new Tuple<Segment, Segment>(segEv, segA);
i.Type = SegmentPointType.IntersectionPoint;
eventList.Add(i);
}
public static void Solve(Panel surface, TextBox debug)
{
debug.Clear();
var segList = Generator.SegList;
PriorityQueue eventList = new PriorityQueue();
foreach (Segment s in segList)
{
eventList.Add(new SegPoint(s.A, s, SegmentPointType.LeftEndpoint));
eventList.Add(new SegPoint(s.B, s, SegmentPointType.RightEndpoint));
}
BST sweepLine = new BST();
while (!eventList.Empty)
{
SegPoint ev = eventList.Top();
eventList.Pop();
if (ev.Type == SegmentPointType.LeftEndpoint)
{
Segment segEv = ev.Segment;
sweepLine.Insert(segEv);
Segment segA = sweepLine.InorderPre(segEv);
Segment segB = sweepLine.InorderSuc(segEv);
SegPoint i = new SegPoint();
if (segA != null && Geometry.Intersects(segEv, segA, out i.Point))
{
AddIntersectionEvent(eventList, segA, segEv, i);
}
if (segB != null && Geometry.Intersects(segEv, segB, out i.Point))
{
AddIntersectionEvent(eventList, segEv, segB, i);
}
}
else if (ev.Type == SegmentPointType.RightEndpoint)
{
Segment segEv = ev.Segment;
Segment segA = sweepLine.InorderPre(segEv);
Segment segB = sweepLine.InorderSuc(segEv);
sweepLine.Remove(segEv);
SegPoint i = new SegPoint();
if (segA != null && segB != null && Geometry.Intersects(segA, segB, out i.Point))
{
AddIntersectionEvent(eventList, segA, segB, i);
}
}
else
{
Generator.DrawPoint(ev.Point, surface, Brushes.Red);
Segment seg1 = ev.IntersectingSegments.Item1;
Segment seg2 = ev.IntersectingSegments.Item2;
sweepLine.Remove(seg1);
sweepLine.Remove(seg2);
Segment t = new Segment(seg1);
seg1 = new Segment(seg2);
seg2 = new Segment(t);
sweepLine.Insert(seg1);
sweepLine.Insert(seg2);
Segment segA = sweepLine.InorderPre(seg2);
Segment segB = sweepLine.InorderSuc(seg1);
SegPoint i = new SegPoint();
if (segA != null && Geometry.Intersects(seg2, segA, out i.Point))
AddIntersectionEvent(eventList, segA, seg2, i);
if (segB != null && Geometry.Intersects(seg1, segB, out i.Point))
AddIntersectionEvent(eventList, seg1, segB, i);
}
}
}
}
静态类BentleyOttman
{
专用静态无效AddIntersectionEvent(优先级队列事件列表、段segEv、段segA、段i)
{
i、 IntersectingSegments=新元组(segEv,segA);
i、 类型=分段点类型。相交点;
事件列表。添加(i);
}
公共静态无效解决(面板表面、文本框调试)
{
debug.Clear();
var segList=Generator.segList;
PriorityQueue eventList=新建PriorityQueue();
foreach(segList中的段s)
{
添加(新的SegPoint(s.A,s,SegmentPointType.LeftEndpoint));
添加(新的SegPoint(s.B,s,SegmentPointType.RightEndpoint));
}
BST扫描线=新的BST();
而(!eventList.Empty)
{
SegPoint ev=eventList.Top();
eventList.Pop();
if(ev.Type==SegmentPointType.LeftEndpoint)
{
分段segEv=ev.分段;
扫描线插入(segEv);
段segA=扫掠线INORDERPE(segEv);
段segB=扫掠线。顺序UC(segEv);
SegPoint=新SegPoint();
if(segA!=null&&Geometry.Intersects(segEv,segA,out i.Point))
{
AddIntersectionEvent(事件列表、segA、segEv、i);
}
if(segB!=null&&Geometry.Intersects(segEv,segB,out i.Point))
{
AddIntersectionEvent(事件列表、segEv、segB、i);
}
}
else if(ev.Type==SegmentPointType.RightEndpoint)
{
分段segEv=ev.分段;
段segA=扫掠线INORDERPE(segEv);
段segB=扫掠线。顺序UC(segEv);
扫掠线。移除(segEv);
SegPoint=新SegPoint();
如果(segA!=null&&segB!=null&&Geometry.Intersects(segA、segB、out i.Point))
{
AddIntersectionEvent(事件列表、segA、segB、i);
}
}
其他的
{
发电机.牵引点(电动点,表面,电刷.红色);
段seg1=ev.IntersectingSegments.Item1;
段seg2=ev.IntersectingSegments.Item2;
扫掠线。移除(seg1);
扫掠线。移除(seg2);
t段=新段(seg1);
seg1=新段(seg2);
seg2=新段(t);
扫描线插入(seg1);
扫描线插入(seg2);
段segA=扫描线。顺序排列(seg2);
segB段=扫掠线。按顺序排列(seg1);
SegPoint=新SegPoint();
if(segA!=空和几何体相交(seg2、segA、out i.Point))
AddIntersectionEvent(事件列表、segA、seg2、i);
if(segB!=null&&Geometry.Intersects(seg1,segB,out i.Point))
AddIntersectionEvent(事件列表、seg1、segB、i);
}
}
}
}
如果不了解其他类的具体功能,我真的无法理解您的代码,但我可以回答您的其他一些问题
线段在BST中按其与扫描线相交的Y坐标排序。因此,当遇到左端点时,我们使用输入线段左端点的y坐标将线段添加到树中(将其与另一个线段与扫掠线交点的y坐标进行比较)。当我们遇到右端点时,我们将从树中删除该段。当我们遇到交集时,两个线段的交集顺序将与扫描线切换,因此我们交换树中的两个线段。例如,考虑这两个部分
A = {(-1,1),(1,-1)} and
B = {(-1,-1),(1,1)}
当扫描线的X坐标小于0时,线段A与扫描线的交点大于线段B与扫描线的交点。如果扫描线大于0,则相反。(画一幅画。)
这可能很有启发性