Exemple #1
0
        private void Run()
        {
            if (pList.Count > 0)
            {
                /* 初始化 */
                v.pList.Clear();
                v.vList.Clear();
                record.Clear();
                stepIndex = 0;
                ClearPaint();

                /* 初始畫布建置 */
                ClearPaint();
                foreach (PointF i in pList)
                {
                    DrawPointF(i, Color.DarkRed);
                }

                /* 排序點 */
                pList = MathEx.SortPointF(pList);

                /* 畫 Convex Hull */
                DrawConvexHull(MathEx.GetConvexHull(pList));

                /* 畫 Voronoi Diagram */
                v = VoronoiMultiPoint(pList);
                DrawVoronoiDiagram(v.vList, Color.DarkGreen);
            }
        }
Exemple #2
0
        /// <summary>
        /// 取得上下切線
        /// </summary>
        /// <param name="pListL">左半部的點集合</param>
        /// <param name="pListR">左半部的點集合</param>
        /// <returns>上下切線</returns>
        public List <Edge> GetTangent(List <PointF> pListL, List <PointF> pListR)
        {
            List <Edge>   tangent = new List <Edge>();
            List <PointF> pList   = new List <PointF>();
            List <PointF> chList;

            pList.AddRange(pListL);
            pList.AddRange(pListR);
            pList  = MathEx.SortPointF(pList);
            chList = MathEx.GetConvexHull(pList);

            for (int i = 0; i < chList.Count; i++)
            {
                if ((pListL.Contains(chList[i]) && pListR.Contains(chList[(i + 1) % chList.Count])) || (pListR.Contains(chList[i]) && pListL.Contains(chList[(i + 1) % chList.Count])))
                {
                    tangent.Add(new Edge(chList[i], chList[(i + 1) % chList.Count]));
                }
            }

            record.Add(new Record(chList, tangent, CONVEX_HULL, true));
            return(tangent);
        }
Exemple #3
0
        /// <summary>
        /// 合併左右半部的 Voronoi Diagram
        /// </summary>
        /// <param name="vL">左半部的 Voronoi Diagram</param>
        /// <param name="vR">右半部的 Voronoi Diagram</param>
        /// <returns>合併的 Voronoi Diagram</returns>
        public Voronoi Merge(Voronoi vL, Voronoi vR)
        {
            Voronoi v = new Voronoi();

            try
            {
                /* 找上切線和下切線 */
                List <PointF> chL = MathEx.GetConvexHull(vL.pList);
                record.Add(new Record(chL, CONVEX_HULL));
                List <PointF> chR = MathEx.GetConvexHull(vR.pList);
                record.Add(new Record(chR, CONVEX_HULL));
                List <Edge> tangent = GetTangent(chL, chR);

                #region 找 Hyper Plane
                List <Edge> hpList = new List <Edge>();    // Hyper Plane
                PointF?     p;                             // 暫存 Hyper Plane 與 Voronoi 的交點
                PointF?     nearPoint     = null;          // Hyper Plane 與 Voronoi 最先碰到的交點
                PointF?     lastNearPoint = null;          // 上一個 nearPoint
                Edge        scan;                          // 掃描線段
                Edge        candidate  = new Edge();       // 碰到的線段
                Edge        last       = new Edge();       // 上一個碰到的線段
                Edge        hyperPlane = new Edge();       // 當前的 Hyper Plane
                List <int>  eliminate  = new List <int>(); // 需要消線的索引
                List <int>  delete     = new List <int>(); // 需要刪線的索引

                foreach (PointF i in vL.pList)
                {
                    v.pList.Add(new PointF(i.X, i.Y));
                }
                foreach (PointF i in vR.pList)
                {
                    v.pList.Add(new PointF(i.X, i.Y));
                }
                foreach (Edge i in vL.vList)
                {
                    v.vList.Add(new Edge(i.A, i.B, i.a, i.b));
                }
                foreach (Edge i in vR.vList)
                {
                    v.vList.Add(new Edge(i.A, i.B, i.a, i.b));
                }

                /* 掃描線從上切線進入 */
                scan          = new Edge(tangent[0].A, tangent[0].B);
                lastNearPoint = scan.GetBisector().A;
                while (!scan.Equals(tangent[1]))
                {
                    hyperPlane = scan.GetBisector();

                    /* 找最先碰到的線的交點 */
                    nearPoint = null;
                    for (int i = 0; i < v.vList.Count; i++)
                    {
                        if (last != null && last.Equals(v.vList[i]))
                        {
                            continue;
                        }
                        /* 找交點且 Hyper Plane 不能回頭 */
                        if ((p = MathEx.GetIntersection(hyperPlane, v.vList[i])) != null && Math.Round(Convert.ToDouble(((PointF)lastNearPoint).Y)) >= ((PointF)p).Y)
                        {
                            /* 找到第一個交點 */
                            if (nearPoint == null)
                            {
                                nearPoint = p;
                                candidate = v.vList[i];
                                continue;
                            }
                            if (MathEx.GetDistance(hyperPlane.A, (PointF)p) < MathEx.GetDistance(hyperPlane.A, (PointF)nearPoint))
                            {
                                nearPoint = p;
                                candidate = v.vList[i];
                            }
                        }
                    }

                    /* 從上一段 Hyper Plane 接著畫 */
                    if (lastNearPoint != null)
                    {
                        hyperPlane.A = (PointF)lastNearPoint;
                    }
                    hpList.Add(new Edge(hyperPlane.A, (PointF)nearPoint, scan.A, scan.B));

                    eliminate.Add(v.vList.IndexOf(candidate));
                    last          = candidate;
                    lastNearPoint = nearPoint;

                    /* 尋找下一條掃描線 */
                    if (scan.A.Equals(candidate.a))
                    {
                        scan.A = candidate.b;
                    }
                    else if (scan.A.Equals(candidate.b))
                    {
                        scan.A = candidate.a;
                    }
                    else if (scan.B.Equals(candidate.a))
                    {
                        scan.B = candidate.b;
                    }
                    else if (scan.B.Equals(candidate.b))
                    {
                        scan.B = candidate.a;
                    }
                }
                /* 上切線等於下切線:共線 */
                if (tangent[0].Equals(tangent[1]))
                {
                    hpList.Add(new Edge(tangent[0].GetBisector().A, tangent[0].GetBisector().B, scan.A, scan.B));
                }
                else
                {
                    hpList.Add(new Edge((PointF)nearPoint, tangent[1].GetBisector().A, scan.A, scan.B));
                }

                record.Add(new Record(hpList, HYPER_LINE));
                #endregion

                #region 消線
                for (int i = 0; i < eliminate.Count; i++)
                {
                    if (MathEx.Cross(hpList[i].A, hpList[i].B, hpList[i + 1].B) >= 0)
                    {
                        if (MathEx.Cross(hpList[i].A, hpList[i].B, v.vList[eliminate[i]].A) > 0)
                        {
                            /* 消除延伸線 */
                            foreach (Edge j in v.vList)
                            {
                                if (j.A.Equals(v.vList[eliminate[i]].A) && !j.B.Equals(v.vList[eliminate[i]].B))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.A, j.B) > 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                                else if (j.B.Equals(v.vList[eliminate[i]].A) && !j.A.Equals(v.vList[eliminate[i]].B))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.B, j.A) > 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                            }
                            v.vList[eliminate[i]].A = hpList[i].B;
                        }
                        else
                        {
                            /* 消除延伸線 */
                            foreach (Edge j in v.vList)
                            {
                                if (j.A.Equals(v.vList[eliminate[i]].B) && !j.B.Equals(v.vList[eliminate[i]].A))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.A, j.B) > 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                                else if (j.B.Equals(v.vList[eliminate[i]].B) && !j.A.Equals(v.vList[eliminate[i]].A))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.B, j.A) > 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                            }
                            v.vList[eliminate[i]].B = hpList[i].B;
                        }
                    }
                    else if (MathEx.Cross(hpList[i].A, hpList[i].B, hpList[i + 1].B) < 0)
                    {
                        if (MathEx.Cross(hpList[i].A, hpList[i].B, v.vList[eliminate[i]].A) < 0)
                        {
                            /* 消除延伸線 */
                            foreach (Edge j in v.vList)
                            {
                                if (j.A.Equals(v.vList[eliminate[i]].A) && !j.B.Equals(v.vList[eliminate[i]].B))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.A, j.B) < 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                                else if (j.B.Equals(v.vList[eliminate[i]].A) && !j.A.Equals(v.vList[eliminate[i]].B))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.B, j.A) < 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                            }
                            v.vList[eliminate[i]].A = hpList[i].B;
                        }
                        else
                        {
                            /* 消除延伸線 */
                            foreach (Edge j in v.vList)
                            {
                                if (j.A.Equals(v.vList[eliminate[i]].B) && !j.B.Equals(v.vList[eliminate[i]].A))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.A, j.B) < 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                                else if (j.B.Equals(v.vList[eliminate[i]].B) && !j.A.Equals(v.vList[eliminate[i]].A))
                                {
                                    if (MathEx.Cross(hpList[i].B, j.B, j.A) < 0)
                                    {
                                        delete.Add(v.vList.IndexOf(j));
                                    }
                                }
                            }
                            v.vList[eliminate[i]].B = hpList[i].B;
                        }
                    }
                }
                /* 刪除延伸線 */
                delete = delete.OrderByDescending(X => X).Distinct().ToList();
                foreach (int i in delete)
                {
                    v.vList.RemoveAt(i);
                }

                record.Add(new Record(v.vList, VORONOI, true));
                #endregion

                foreach (Edge i in hpList)
                {
                    v.vList.Add(new Edge(i.A, i.B, i.a, i.b));
                }
                record.Add(new Record(v.vList, MERGE, true));
            }
            catch (Exception e)
            {
                //MessageBox.Show("Coming Soon...", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            return(v);
        }