示例#1
0
 public Record(Voronoi v, bool clear = false)
 {
     this.eList  = v.vList;
     this.type   = 1;
     this.clear  = clear;
     this.enable = true;
 }
示例#2
0
        private void Fresh()
        {
            // 调整窗口大小
            Size = new Size(xSize + ControlPanel.Size.Width + Size.Width - ClientSize.Width, ySize + Size.Height - ClientSize.Height);

            // 刷新画板
            DrawingBroad.Image = new Bitmap(xSize, ySize);

            // 初始点集
            foreach (var point in pointList)
            {
                DrawPoint((float)point.X, (float)point.Y, Color.Blue);
            }

            Voronoi v = new Voronoi(pointList, xSize, ySize, precision);
            // 画维诺图
            var segments = v.QuerySegments();

            foreach (var seg in segments)
            {
                DrawLine(seg, Color.Black);
            }
            // 画三角网
            //foreach (var site in v.Sites)
            //{
            //	var face = v.QueryFace(site);
            //	foreach (var seg in face.Segments)
            //	{
            //		var edge = new Segment(seg.F1.Site, seg.F2.Site);
            //		DrawLine(edge, Color.Red);
            //	}
            //}
        }
示例#3
0
        /// <summary>
        /// 計算多個點的Voronoi Diagram
        /// </summary>
        /// <returns>Voronoi Diagram</returns>
        public Voronoi VoronoiMultiPoint(List <PointF> pList)
        {
            Voronoi v = new Voronoi();

            if (pList.Count == 1)
            {
                return(v);
            }
            else if (pList.Count == 2)
            {
                Voronoi twoVoronoi = VoronoiTwoPoint(pList);
                record.Add(new Record(twoVoronoi.vList, VORONOI));
                return(twoVoronoi);
            }
            else if (pList.Count == 3)
            {
                Voronoi threeVoronoi = VoronoiThreePoint(pList);
                record.Add(new Record(threeVoronoi.vList, VORONOI));
                return(threeVoronoi);
            }
            else if (pList.Count > 3)
            {
                List <PointF> pListL;
                List <PointF> pListR;
                MathEx.Divide(pList, out pListL, out pListR);
                v = Merge(VoronoiMultiPoint(pListL), VoronoiMultiPoint(pListR));
            }
            return(v);
        }
示例#4
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);
            }
        }
示例#5
0
        public Voronoi VoronoiThreePoint(PointF A, PointF B, PointF C)
        {
            Voronoi v = new Voronoi();
            PointF  triEx;
            PointF  mid;

            v.pList.Add(A);
            v.pList.Add(B);
            v.pList.Add(C);

            /* 三點共線 */
            if (MathEx.isCollinear(v.pList[0], v.pList[1], v.pList[2]))
            {
                /* 將點排序 */
                v.pList = MathEx.SortPointF(v.pList);

                /* 將邊無限延伸的做法 */
                mid = MathEx.GetMidPointF(v.pList[0], v.pList[1]);
                v.vList.Add(new Edge(mid.Add(MathEx.GetNormalVector(v.pList[0], v.pList[1]).Multi(600)), mid.Add(MathEx.GetNormalVector(v.pList[1], v.pList[0]).Multi(600)), v.pList[0], v.pList[1]));
                mid = MathEx.GetMidPointF(v.pList[1], v.pList[2]);
                v.vList.Add(new Edge(mid.Add(MathEx.GetNormalVector(v.pList[1], v.pList[2]).Multi(600)), mid.Add(MathEx.GetNormalVector(v.pList[2], v.pList[1]).Multi(600)), v.pList[1], v.pList[2]));

                /* 將邊畫到邊界的做法
                 * mid = MathEx.GetMidPointF(v.pList[0], v.pList[1]);
                 * v.vList.Add(new Edge(GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(v.pList[1], v.pList[0]))), GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(v.pList[0], v.pList[1])))));
                 * mid = MathEx.GetMidPointF(v.pList[1], v.pList[2]);
                 * v.vList.Add(new Edge(GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(v.pList[2], v.pList[1]))), GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(v.pList[1], v.pList[2])))));
                 */
            }
            else
            {
                /* 計算外心 */
                triEx = MathEx.GetTriangleExcenterPointF(A, B, C);

                /* 將點依逆時針方向排序 */
                v.pList = MathEx.SortVector(v.pList);

                for (int i = 0; i < v.pList.Count; i++)
                {
                    mid = MathEx.GetMidPointF(v.pList[i], v.pList[(i + 1) % 3]);

                    /* 將邊無限延伸的做法 */
                    v.vList.Add(new Edge(triEx, mid.Add(MathEx.GetNormalVector(v.pList[i], v.pList[(i + 1) % 3]).Multi(600)), v.pList[i], v.pList[(i + 1) % 3]));

                    /* 將邊畫到邊界的做法
                     * v.vList.Add(new Edge(triEx, GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(v.pList[i], v.pList[(i + 1) % 3])))));
                     */
                }
            }
            return(v);
        }
示例#6
0
        private void saveFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            saveFileDialog.Title  = "Save an Output File";
            //
            if (saveVertices.Count != 0)
            {
                this.dataNumber++;
                Voronoi       voronoi        = new Voronoi(saveVertices.Count);
                List <Vertex> sortedVertices = saveVertices.OrderBy(o => o.x).ToList();
                sortedVertices = voronoi.y_sorting(sortedVertices);
                for (int i = 0; i < sortedVertices.Count; i++)
                {
                    voronoi.setVertex(sortedVertices[i].x, sortedVertices[i].y);
                }
                this.voronoiList.Add(voronoi);
            }

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                System.IO.StreamWriter writer = new System.IO.StreamWriter(saveFileDialog.OpenFile());
                for (int j = 0; j < voronoiList[dataNumber].Num; j++)
                {
                    writer.WriteLine("P " + voronoiList[dataNumber].getVertex(j).x + " " + voronoiList[dataNumber].getVertex(j).y);
                }
                if (voronoiList[dataNumber].HPs.Count != 0)
                {
                    for (int j = 0; j < voronoiList[dataNumber].HPs.Count; j++)
                    {
                        if (voronoiList[dataNumber].HPs[j].is_line)
                        {
                            writer.WriteLine("E " + voronoiList[dataNumber].HPs[j].start_vertex.x + " " + voronoiList[dataNumber].HPs[j].start_vertex.y + " " + voronoiList[dataNumber].HPs[j].end_vertex.x + " " + voronoiList[dataNumber].HPs[j].end_vertex.y);
                        }
                        if (voronoiList[dataNumber].HPs[j].start_vertex.infinity && voronoiList[dataNumber].HPs[j].end_vertex.infinity)
                        {
                            continue;
                        }
                        writer.WriteLine("E " + voronoiList[dataNumber].HPs[j].start_vertex.x + " " + voronoiList[dataNumber].HPs[j].start_vertex.y + " " + voronoiList[dataNumber].HPs[j].end_vertex.x + " " + voronoiList[dataNumber].HPs[j].end_vertex.y);
                    }
                }
                writer.Dispose();
                writer.Close();
            }
            canvas.Clear(Color.White);
            saveVertices.Clear();
            voronoiList.Clear();
            Es.Clear();
            Ps.Clear();
        }
示例#7
0
        public Voronoi VoronoiTwoPoint(PointF A, PointF B)
        {
            PointF  mid = MathEx.GetMidPointF(A, B);
            Voronoi v   = new Voronoi();

            v.pList.Add(A);
            v.pList.Add(B);
            /* 將邊無限延伸的做法 */
            v.vList.Add(new Edge(mid.Add(MathEx.GetNormalVector(A, B).Multi(600)), mid.Add(MathEx.GetNormalVector(B, A).Multi(600)), A, B));

            /* 將邊畫到邊界的做法
             * v.vList.Add(new Edge(GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(A, B))), GetSidePointF(mid, mid.Add(MathEx.GetNormalVector(B, A)))));
             */
            return(v);
        }
示例#8
0
        public VoronoiDiagramForm()
        {
            InitializeComponent();
            pictBoxDaigram.AutoSize = true;
            diagramBitmap           = new Bitmap(512, 512);
            g = Graphics.FromImage(diagramBitmap);
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.Clear(Color.Transparent);
            pen = new Pen(Color.Black)
            {
                Width = 2
            };
            pictBoxDaigram.Image = diagramBitmap;

            voronoi = new Voronoi(0.1);
        }
示例#9
0
 public void BuildVoronoi()
 {
     vor = new Voronoi();
     vor.Generate(this.points);
 }
示例#10
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);
        }
示例#11
0
 /// <summary>
 /// 畫 Voronoi Diagram
 /// </summary>
 /// <param name="v">Voronoi 物件</param>
 /// <param name="color">畫筆顏色</param>
 public void DrawVoronoiDiagram(Voronoi v, Color color)
 {
     DrawVoronoiDiagram(v.vList, color);
 }
示例#12
0
        private void Step()
        {
            if (record.Count <= 0 || stepIndex > record.Count - 1)
            {
                /* 初始化 */
                v.pList.Clear();
                v.vList.Clear();
                record.Clear();
                stepIndex = 0;

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

                /* 畫 Voronoi Diagram */
                v = VoronoiMultiPoint(pList);
            }

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

            /* 隱藏特定紀錄 */
            if (record[stepIndex].type == VORONOI)
            {
                if (record[stepIndex].clear)
                {
                    record[stepIndex - 2].enable = false;
                    int count = 0;
                    for (int i = stepIndex - 1; i >= 0 && count < 2; i--)
                    {
                        if ((record[i].type == MERGE || record[i].type == VORONOI) && record[i].enable == true)
                        {
                            record[i].enable = false;
                            count++;
                        }
                    }
                }
            }
            else if (record[stepIndex].type == CONVEX_HULL)
            {
                if (record[stepIndex].clear)
                {
                    record[stepIndex - 1].enable = false;
                    record[stepIndex - 2].enable = false;
                }
            }
            else if (record[stepIndex].type == MERGE)
            {
                if (record[stepIndex].clear)
                {
                    record[stepIndex - 1].enable = false;
                    record[stepIndex - 2].enable = false;
                }
            }

            /* 畫紀錄 */
            for (int i = 0; i <= stepIndex; i++)
            {
                if (record[i].enable)
                {
                    DrawRecord(record[i]);
                }
                else
                {
                    continue;
                }
            }

            /* 重置步驟數 */
            if (stepIndex < record.Count)
            {
                stepIndex++;
            }
            else
            {
                stepIndex = 0;
            }
        }
示例#13
0
        private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.toolStripButton1.Enabled = false;
            canvas.Clear(Color.White);
            voronoiList.Clear();
            saveVertices.Clear();
            Ps.Clear();
            Es.Clear();
            this.dataNumber = -1;

            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter           = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            dialog.Title            = "選擇檔案";
            dialog.InitialDirectory = ".\\";
            if (dialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            is_open_file = true;
            int    index = 0;
            string line;

            //encoding.default避免中文亂碼
            System.IO.StreamReader file = new System.IO.StreamReader(dialog.FileName, Encoding.Default);
            while ((line = file.ReadLine()) != null)
            {
                index++;
                if (line.Contains('#'))
                {
                    continue;
                }
                else
                {
                    int      num   = 0;
                    string[] words = line.Split(' ');
                    Voronoi  voronoi;
                    if (words[0] == "0")
                    {
                        break;
                    }
                    else if (words[0] != "" && words.Length == 1 && words[0] != "P" && words[0] != "E")
                    {
                        num     = Int32.Parse(words[0]);
                        voronoi = new Voronoi(num);
                        for (int i = 0; i < num; i++)
                        {
                            line = file.ReadLine();
                            string[] points = line.Split();
                            voronoi.setVertex(Int32.Parse(points[0]), Int32.Parse(points[1]));
                        }
                        this.voronoiList.Add(voronoi);
                    }
                    else if (words[0] == "P")
                    {
                        Vertex tmp_v = new Vertex();
                        tmp_v.x = Int32.Parse(words[1]);
                        tmp_v.y = Int32.Parse(words[2]);
                        Ps.Add(tmp_v);
                    }
                    else if (words[0] == "E")
                    {
                        Edge tmp_edge = new Edge();
                        tmp_edge.start_vertex.x = Int32.Parse(words[1]);
                        tmp_edge.start_vertex.y = Int32.Parse(words[2]);
                        tmp_edge.end_vertex.x   = Int32.Parse(words[3]);
                        tmp_edge.end_vertex.y   = Int32.Parse(words[4]);
                        Es.Add(tmp_edge);
                    }
                }
            }
            this.dataNumber++;
            //自己點的檔案格式
            if (Ps.Count != 0)
            {
                Voronoi voronoi = new Voronoi(Ps.Count);
                for (int i = 0; i < Ps.Count; i++)
                {
                    voronoi.setVertex(Ps[i].x, Ps[i].y);
                    canvas.FillRectangle(brush, Ps[i].x, Ps[i].y, 2, 2);
                }
                voronoiList.Add(voronoi);
            }
            else
            {
                for (int i = 0; i < voronoiList[dataNumber].Num; i++)
                {
                    canvas.FillRectangle(brush, voronoiList[dataNumber].getVertex(i).x, voronoiList[dataNumber].getVertex(i).y, 2, 2);
                }
            }
            this.voronoiList[dataNumber].sort();
            //若有邊要畫
            if (Es.Count != 0)
            {
                for (int i = 0; i < Es.Count; i++)
                {
                    this.canvas.DrawLine(pen, Es[i].start_vertex.x, Es[i].start_vertex.y, Es[i].end_vertex.x, Es[i].end_vertex.y);
                }
            }
            //MessageBox.Show(index.ToString());
            this.toolStripStatusLabel1.Text = "Number " + (dataNumber + 1) + " of Data";
            if (voronoiList.Count > 1)
            {
                this.toolStripButton1.Enabled = true;
            }
            input_palette();
            this.toolStripButton2.Enabled = true;
            this.toolStripButton3.Enabled = true;
            this.pictureBox1.MouseClick  -= pictureBox1_MouseClick;
            file.Dispose();
            file.Close();
        }