/// <summary> /// Generate the voronoi diagram. /// </summary> /// <param name="points"></param> /// <param name="rect"></param> /// <param name="clipper"></param> public void GenerateDiagram(ref List <PointF> points, RectangleF rect, JCVClipper userClipper) { beachlineStart = new JCVHalfEdge(null, false); beachlineEnd = new JCVHalfEdge(null, false); clipper = userClipper; priorityQueue = new SortedSet <JCVHalfEdge>(); beachlineStart.right = beachlineEnd; beachlineEnd.left = beachlineStart; lastInserted = null; //maybe not needed; added for clarity edges = new List <JCVEdge>(); //create sites for each distinct point, sorted by min(y),min(x) sites = points.Distinct().Select((p, index) => new JCVSite(p, index)).OrderBy(s => s.Y).ThenBy(s => s.X).ToList(); bool noRect = (rect == default); if (noRect) { rect.X = sites.Min(s => s.X); rect.Y = sites.Min(s => s.Y); rect.Width = sites.Max(s => s.X) - rect.X; rect.Height = sites.Max(s => s.Y) - rect.Y; } //uses clipper to clip any points outside bounds. clipper.boundingBox = rect; sites = (List <JCVSite>)sites.Where(s => clipper.TestPoint(s.center)).ToList(); if (noRect) { // JCash used ceil and floor to adjust the bounding box to int coords- necessary? // see: jcv_rect_round(&tmp_rect); // Will add later if needed //pad bounding box by 10 in all directions clipper.boundingBox.Inflate(10, 10); rect = clipper.boundingBox; } this.Bounds = rect; int siteIndex = 1; //sites[0] is saved for initial bottom site int sCount = sites.Count; bool finished = false; while (!finished) { bool pqEmpty = (priorityQueue.Count == 0); bool before = true; if (!pqEmpty && siteIndex < sCount) { JCVHalfEdge he = priorityQueue.ElementAt(0); PointF p = new PointF(he.vertex.X, he.Y); before = IsPointBefore(sites[siteIndex].center, p); } if (siteIndex < sCount && (pqEmpty || before)) { SiteEvent(sites[siteIndex++]); } else if (!pqEmpty) { CircleEvent(); } else { finished = true; } } //end while for (JCVHalfEdge temphe = beachlineStart.right; temphe != beachlineEnd; temphe = temphe.right) { FinishLine(temphe.Edge); } FillGaps(); }
/// <summary> /// calls GenerateDiagram /// </summary> /// <param name="points"></param> /// <param name="rect"></param> /// <param name="clipper"></param> public JCVDiagram(ref List <PointF> points, RectangleF rect, JCVClipper clipper) { GenerateDiagram(ref points, rect, clipper); }