Пример #1
0
        // 检查是否可能发生圆事件,arc 为新增的弧
        private void FixCircleEvent(ArcData arc)
        {
            if (arc == null || arc.Prev == null || arc.Next == null)
            {
                // 凑不齐三个焦点
                return;
            }

            if (arc.CircleEvent != null)
            {
                arc.CircleEvent.Deleted = true;
                arc.CircleEvent         = null;
            }

            Point a = arc.Prev.A;
            Point b = arc.A;
            Point c = arc.Next.A;

            Point center;               // 圆心
            Point bottom;               // 圆最低点

            // 一般来说,三点肯定可以算出一个圆,除非三点共线
            if (GenerateCircle(a, b, c, out center, out bottom))
            {
                // 并不是所有圆都作数,因为后期一个焦点并不只对应一段弧,可能被分割成好几段
                // 只有当两个交点重合时,才当作是圆事件

                // 这里可以去树里面找出两个交点的结点
                // 也可以直接创建个新的直接算
                var temp01 = new IntersectionData(a, b);
                var temp02 = new IntersectionData(b, c);

                // 重合是在扫描线扫到圆最低点时才发生,所以这里传的参数应该是最低点坐标
                var l = temp01.CalcIntersection(bottom.Y);
                var r = temp02.CalcIntersection(bottom.Y);

                // 判断l、r 两点是否重合,这里应该是造成较大误差的地方,可以想办法改进判断方法
                if (EqualTo(l, r))
                {
                    // 产生一个圆事件,加入优先队列
                    arc.CircleEvent = new CircleEvent(center, bottom, arc);
                    priorityQueue.Push(arc.CircleEvent);
                }
            }
        }
Пример #2
0
        private void Finish()
        {
            // 找出一条扫描线,保证抛物线交点一定在边框外
            var y = XSize + YSize;

            // 先找到双向链表头
            var curr = tree.FindMin();

            // 遍历双向链表
            while (curr != null)
            {
                if (curr.Next != null)
                {
                    var intersection = new IntersectionData(curr.A, curr.Next.A);
                    if (curr.S1 != null)
                    {
                        FinishSegment(curr.S1, intersection.CalcIntersection(y));
                    }
                }
                curr = curr.Next;
            }
        }
Пример #3
0
        private void ProcSiteEvent(SiteEvent e)
        {
            if (tree.Empty())
            {
                // 树为空时,直接添加成第一个结点
                IData data = new ArcData(e.QueryPoint(), null, false);
                tree.AddFirstArc(data);
            }
            else
            {
                // 先找出站点正上方的弧
                ArcData oldArc = tree.GetAboveArc(e.QueryPoint());

                // 正上方的弧将被拆成两段,所以肯定会破坏其的圆事件
                if (oldArc.CircleEvent != null)
                {
                    oldArc.CircleEvent.Deleted = true;
                    oldArc.CircleEvent         = null;
                }

                //if (oldArc.A.Y == e.QueryPoint().Y) {
                //	// 可以选择不要这个分支,直接统一走下面那个
                //	// 这样的话,计算交点的方法需要做特殊处理

                //	// 如果正上方弧的 y 坐标和新站点的 y 坐标一致
                //	// 则是一条弧分裂成两条弧,将原先的弧删掉,新增一个内部结点和两个叶子结点
                //	var intersection = new IntersectionData(oldArc.A, e.QueryPoint(), oldArc.Fa, oldArc.IsLeft(), tree);
                //	var arc01 = new ArcData(oldArc.A, intersection, true);
                //	var arc02 = new ArcData(e.QueryPoint(), intersection, false);

                //	// 维护双向链表
                //	arc01.Prev = oldArc.Prev;
                //	arc02.Prev = arc01;
                //	if (oldArc.Next != null) {
                //		oldArc.Next.Prev = arc02;
                //	}

                //	if (oldArc.Prev != null) {
                //		oldArc.Prev.Next = arc01;
                //	}
                //	arc01.Next = arc02;
                //	arc02.Next = oldArc.Next;

                //	arc01.S0 = oldArc.S0;

                //	// 交点目前坐标,用于创建维诺图边
                //	var p = intersection.CalcIntersection(e.QueryPoint().Y);

                //	// 交点计算
                //	var seg = new Segment(p, QueryFace(e.QueryPoint()), QueryFace(oldArc.A));
                //	arc01.S1 = seg;
                //	arc02.S0 = seg;

                //	FixCircleEvent(arc01);
                //} else {

                // 正常情况下,正上方的弧会被新增弧分割成两段
                // 将原先的弧删掉,新增两个内部结点和三个叶子结点
                var intersection01 = new IntersectionData(oldArc.A, e.QueryPoint(), oldArc.Fa, oldArc.IsLeft(), tree);
                var intersection02 = new IntersectionData(e.QueryPoint(), oldArc.A, intersection01, false, tree);
                var arc01          = new ArcData(oldArc.A, intersection01, true);
                var arc02          = new ArcData(e.QueryPoint(), intersection02, true);
                var arc03          = new ArcData(oldArc.A, intersection02, false);

                // 维护双向链表
                arc01.Prev = oldArc.Prev;
                arc02.Prev = arc01;
                arc03.Prev = arc02;
                if (oldArc.Next != null)
                {
                    oldArc.Next.Prev = arc03;
                }

                if (oldArc.Prev != null)
                {
                    oldArc.Prev.Next = arc01;
                }
                arc01.Next = arc02;
                arc02.Next = arc03;
                arc03.Next = oldArc.Next;

                // 原弧分裂出来的两段弧分别继承S0、S1
                arc01.S0 = oldArc.S0;
                arc03.S1 = oldArc.S1;

                // 交点目前坐标,用于创建维诺图边
                // 目前两个交点应该是重叠的,由这两个点勾勒出同一条维诺图边
                var p = intersection01.CalcIntersection(e.QueryPoint().Y);

                var seg = new Segment(p, QueryFace(e.QueryPoint()), QueryFace(oldArc.A));
                arc01.S1 = seg;
                arc02.S0 = seg;

                seg      = new Segment(p, QueryFace(e.QueryPoint()), QueryFace(oldArc.A));
                arc02.S1 = seg;
                arc03.S0 = seg;

                FixCircleEvent(arc01);
                FixCircleEvent(arc03);
                //	}
            }
        }