【问题标题】:Implementing the Bentley-Ottmann algorithm实现 Bentley-Ottmann 算法
【发布时间】:2010-12-20 14:01:38
【问题描述】:

我在 C# 中正确实现 Bentley-Ottmann 算法时遇到了一些问题。我正在尝试根据伪代码here 来实现它。我在下面发布了我的主要代码。假设我的BSTPriorityQueue 类实现正确,你发现代码有什么问题吗?

没有错误,但不是所有的交点都找到了,只有一些。我的猜测是代码的else 部分存在错误(当当前事件是交叉点时)。我不确定通过交换 BST 中两个段的位置伪代码意味着什么。我的做法好吗?因为最后,两者在 BST 中并没有真正交换。我也不能只改变他们的位置,因为这可能会破坏 BST 属性。

另外,我是否正确地假设段在 BST 中按其左端点的 Y 坐标排序?

我注意到的另一个我似乎无法追踪的错误是,有时(0, 0) 会进入eventList(0, 0)Geometry.Intersects 输出,以防没有交集,但在这种情况下,if 条件应该阻止它被添加。我不知道它是如何进入的。如果我在添加一个点后打印eventList 的内容,(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);
            }
        }
    }
}

【问题讨论】:

    标签: c# algorithm computational-geometry


    【解决方案1】:

    如果不知道其他类究竟做了什么,我真的无法理解你的代码,但我可以回答你的一些其他问题。

    段在 BST 中按它们与扫描线相交的 Y 坐标排序。因此,当我们遇到左端点时,我们使用进入线段左端点的 y 坐标将线段添加到树中(将其与另一线段与扫描线相交的 Y 坐标进行比较)。当我们遇到一个正确的端点时,我们会从树中删除该段。当我们遇到一个交点时,那么这两条线段的交点与扫描线的交点顺序会切换,所以我们在树中交换这两条线段。例如考虑两个段

     A = {(-1,1),(1,-1)} and
     B = {(-1,-1),(1,1)}
    

    当扫描线的X坐标小于0时,线段A与扫描线的交点大于线段B与扫描线的交点。如果扫描线大于 0,则相反。 (画个图。)

    画一个简单的例子可能很有启发性,并逐步跟踪正在发生的事情,为每个事件绘制扫描线并在事件之间的列中标记段,然后跟踪 BST 并验证BST 与其有效区域中的段保持相同的顺序。 (如果这不是很清楚,我很抱歉。)

    注意:这假设您的线段处于“一般位置”,即没有线段是垂直的,在给定点相交的线段不超过两个等。处理不在一般位置的线段在@987654321 中进行了概述@

    【讨论】:

      猜你喜欢
      • 2011-12-28
      • 1970-01-01
      • 2012-10-25
      • 2012-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多