C# Bentley-Ottmann算法的实现

C# Bentley-Ottmann算法的实现,c#,algorithm,computational-geometry,C#,Algorithm,Computational Geometry,我在C#中正确实现Bentley Ottmann算法时遇到一些问题。我正试图根据伪代码实现它。我已经在下面发布了我的主要代码。假设我的BST和PriorityQueue类实现正确,您认为代码有任何问题吗 没有错误,但并不是所有的交点都被找到,只有一些。我猜代码的else部分有错误(当当前事件是交点时)。我不确定通过交换BST中两个段的位置来交换伪代码意味着什么。我这样做好吗?因为最终,两者在BST中并没有真正交换。我也不能仅仅改变它们的位置,因为这可能会破坏BST的属性 另外,我假设分段在BST

我在C#中正确实现Bentley Ottmann算法时遇到一些问题。我正试图根据伪代码实现它。我已经在下面发布了我的主要代码。假设我的
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,则相反。(画一幅画。)

这可能很有启发性