// create a new site where the HalfEdges intersect private Site Intersect(HalfEdge firstHalfEdge, HalfEdge secondHalfEdge) { Edge edge; HalfEdge halfEdge; bool isRightOfSite; // vertex Edge firstEdge = firstHalfEdge.Edge; Edge secondEdge = secondHalfEdge.Edge; if (firstEdge == null || secondEdge == null) { return null; } // if the two edges bisect the same parent, return null if (firstEdge.Region[1] == secondEdge.Region[1]) { return null; } double distance = (firstEdge.A * secondEdge.B) - (firstEdge.B * secondEdge.A); if (-1.0e-10 < distance && distance < 1.0e-10) { return null; } double intersectionPointX = ((firstEdge.C * secondEdge.B) - (secondEdge.C * firstEdge.B)) / distance; double intersectionPointY = ((secondEdge.C * firstEdge.A) - (firstEdge.C * secondEdge.A)) / distance; if ((firstEdge.Region[1].Coordinates.Y < secondEdge.Region[1].Coordinates.Y) || (firstEdge.Region[1].Coordinates.Y == secondEdge.Region[1].Coordinates.Y && firstEdge.Region[1].Coordinates.X < secondEdge.Region[1].Coordinates.X)) { halfEdge = firstHalfEdge; edge = firstEdge; } else { halfEdge = secondHalfEdge; edge = secondEdge; } isRightOfSite = intersectionPointX >= edge.Region[1].Coordinates.X; if ((isRightOfSite && halfEdge.ELpm == LEdge) || (!isRightOfSite && halfEdge.ELpm == REdge)) { return null; } // create a new site at the point of intersection - this is a new vector; event waiting to happen Site intersectionSite = new Site(); intersectionSite.Coordinates.X = intersectionPointX; intersectionSite.Coordinates.Y = intersectionPointY; return intersectionSite; }
private bool VoronoiBoundaries() { Site bottom, top, temp, point; Site vertex; Point newIntersectionStart = null; int index; HalfEdge leftBoundary, rightBoundary, aboveHalfEdgeLeftBoundary, lowestHalfEdgeRightBoundary, bisector; Edge bisectionEdge; this.InitPriorityQueue(); this.InitEdgeList(); this.bottomSite = this.GoToNextSite(); Site newSite = this.GoToNextSite(); while (true) { if (!this.IsPriorityQueueEmpty()) { newIntersectionStart = this.ExtractMinPointFromPriorityQueue(); } /// if the lowest site has a smaller y value than the lowest vector intersection, process the site; ///otherwise process the vector intersection if (newSite != null && (this.IsPriorityQueueEmpty() || newSite.Coordinates.Y < newIntersectionStart.Y || (newSite.Coordinates.Y == newIntersectionStart.Y && newSite.Coordinates.X < newIntersectionStart.X))) { /// new site is smallest -this is a site event; /// get the first half edge to the left of the new site leftBoundary = this.FindLeftBoundary(newSite.Coordinates); // get the first HalfEdge to the RIGHT of the new site rightBoundary = this.RightHalfEdge(leftBoundary); // if this halfedge has no edge,bot =bottom site (whatever that // is) bottom = this.GetRightRegion(leftBoundary); // create a new edge that bisects bisectionEdge = this.BisectEdge(bottom, newSite); // create a new HalfEdge, setting its ELpm field to 0 bisector = this.CreateHalfEdge(bisectionEdge, LEdge); // insert this new bisector edge between the left and right // vectors in a linked list this.InsertHalfEdge(leftBoundary, bisector); // if the new bisector intersects with the left edge, // remove the left edge's vertex, and put in the new one if ((point = this.Intersect(leftBoundary, bisector)) != null) { this.DeleteHalfEdgeFromPriorityQueue(leftBoundary); double distance = this.CalculateDistance(point, newSite); this.InsertHalfEdgeInPriorityQueue(leftBoundary, point, distance); } leftBoundary = bisector; // create a new HalfEdge, setting its ELpm field to 1 bisector = this.CreateHalfEdge(bisectionEdge, REdge); // insert the new HE to the right of the original bisector // earlier in the IF stmt this.InsertHalfEdge(leftBoundary, bisector); // if this new bisector intersects with the new HalfEdge if ((point = this.Intersect(bisector, rightBoundary)) != null) { // push the HE into the ordered linked list of vertices double distance = this.CalculateDistance(point, newSite); this.InsertHalfEdgeInPriorityQueue(bisector, point, distance); } newSite = this.GoToNextSite(); } else if (!this.IsPriorityQueueEmpty()) { /// intersection is smallest - this is a vector event; pop the HalfEdge with the lowest vector /// off the ordered list of vectors leftBoundary = this.ExtractMinHalfEdgeFromPriorityQueue(); // get the HalfEdge to the left of the above HE aboveHalfEdgeLeftBoundary = this.LeftHalfEdge(leftBoundary); // get the HalfEdge to the right of the above HE rightBoundary = this.RightHalfEdge(leftBoundary); // get the HalfEdge to the right of the HE to the right of the // lowest HE lowestHalfEdgeRightBoundary = this.RightHalfEdge(rightBoundary); // get the Site to the left of the left HE which it bisects bottom = this.GetLeftRegion(leftBoundary); // get the Site to the right of the right HE which it bisects top = this.GetRightRegion(rightBoundary); // get the vertex that caused this event vertex = leftBoundary.Vertex; // set the vertex number this.CreateVertex(vertex); // set the endpoint of the left HalfEdge to be this vector this.SetEndPoint(leftBoundary.Edge, leftBoundary.ELpm, vertex); // set the endpoint of the right HalfEdge to be this vector this.SetEndPoint(rightBoundary.Edge, rightBoundary.ELpm, vertex); // mark the lowest HE for deletion this.DeleteHalfEdge(leftBoundary); // remove all vertex events to do with the right HE this.DeleteHalfEdgeFromPriorityQueue(rightBoundary); // mark the right HE for deletion this.DeleteHalfEdge(rightBoundary); index = LEdge; /// if the site to the left of the event is higher than the site /// to the right of it, then swap them and set the index variable to 1 if (bottom.Coordinates.Y > top.Coordinates.Y) { temp = bottom; bottom = top; top = temp; index = REdge; } /// create an Edge (or line) that is between the two Sites. This creates the formula of /// the line, and assigns a line number to it bisectionEdge = this.BisectEdge(bottom, top); // create a HE from the edge and make it point to that edge with its ELedge field bisector = this.CreateHalfEdge(bisectionEdge, index); // insert the new bisector to the right of the left HE this.InsertHalfEdge(aboveHalfEdgeLeftBoundary, bisector); /// Set one endpoint to the new edge to be the vector point 'v'; If the site to the left of this /// bisector is higher than the right site, then this endpoint is put in position 0; /// otherwise - in position 1 this.SetEndPoint(bisectionEdge, REdge - index, vertex); /// if left half edge and the new bisector intersect, then delete /// the left half edge, and reinsert it if ((point = this.Intersect(aboveHalfEdgeLeftBoundary, bisector)) != null) { double distance = this.CalculateDistance(point, bottom); this.DeleteHalfEdgeFromPriorityQueue(aboveHalfEdgeLeftBoundary); this.InsertHalfEdgeInPriorityQueue(aboveHalfEdgeLeftBoundary, point, distance); } // if right half edge and the new bisector intersect, then reinsert it if ((point = this.Intersect(bisector, lowestHalfEdgeRightBoundary)) != null) { double distance = this.CalculateDistance(point, bottom); this.InsertHalfEdgeInPriorityQueue(bisector, point, distance); } } else { break; } } for (leftBoundary = this.RightHalfEdge(this.edgeListLeftEnd); leftBoundary != this.edgeListRightEnd; leftBoundary = this.RightHalfEdge(leftBoundary)) { bisectionEdge = leftBoundary.Edge; this.ClipLine(bisectionEdge); } return true; }
private void SetEndPoint(Edge edge, int index, Site site) { edge.EdgePoints[index] = site; if (edge.EdgePoints[REdge - index] == null) { return; } this.ClipLine(edge); }
private double CalculateDistance(Site firstSite, Site secondSite) { double dX = firstSite.Coordinates.X - secondSite.Coordinates.X; double dY = firstSite.Coordinates.Y - secondSite.Coordinates.Y; return Math.Sqrt((dX * dX) + (dY * dY)); }
private void PushGraphEdge(Site leftSite, Site rightSite, double x1, double y1, double x2, double y2) { GraphEdge newEdge = new GraphEdge(); this.graphEdgesList.Add(newEdge); newEdge.X1 = x1; newEdge.Y1 = y1; newEdge.X2 = x2; newEdge.Y2 = y2; newEdge.FirstSiteIndex = leftSite.SiteIndex; newEdge.SecondSiteIndex = rightSite.SiteIndex; }
// push the HalfEdge into the ordered linked list of vertices private void InsertHalfEdgeInPriorityQueue(HalfEdge halfEdge, Site site, double offset) { HalfEdge nextHalfEdge; halfEdge.Vertex = site; halfEdge.YStart = (double)(site.Coordinates.Y + offset); HalfEdge lastHalfEdge = this.priorityQueueHash[this.GetPriorityQueueBucket(halfEdge)]; while ((nextHalfEdge = lastHalfEdge.NextPriorityQueueMember) != null && (halfEdge.YStart > nextHalfEdge.YStart || (halfEdge.YStart == nextHalfEdge.YStart && site.Coordinates.X > nextHalfEdge.Vertex.Coordinates.X))) { lastHalfEdge = nextHalfEdge; } halfEdge.NextPriorityQueueMember = lastHalfEdge.NextPriorityQueueMember; lastHalfEdge.NextPriorityQueueMember = halfEdge; this.priorityQueueMembersCount++; }
private void CreateVertex(Site vertex) { vertex.SiteIndex = this.verticesCount; this.verticesCount++; }
private Edge BisectEdge(Site firstSite, Site secondSite) { double dX = 0.0d; double dY = 0.0d; double adX = 0.0d; double adY = 0.0d; Edge newEdge = new Edge(); newEdge.Region[0] = firstSite; newEdge.Region[1] = secondSite; newEdge.EdgePoints[0] = null; newEdge.EdgePoints[1] = null; dX = secondSite.Coordinates.X - firstSite.Coordinates.X; dY = secondSite.Coordinates.Y - firstSite.Coordinates.Y; adX = dX > 0 ? dX : -dX; adY = dY > 0 ? dY : -dY; newEdge.C = (double)((firstSite.Coordinates.X * dX) + (firstSite.Coordinates.Y * dY) + (((dX * dX) + (dY * dY)) * 0.5)); if (adX > adY) { newEdge.A = 1.0; newEdge.B = dY / dX; newEdge.C /= dX; } else { newEdge.A = dX / dY; newEdge.B = 1.0; newEdge.C /= dY; } newEdge.EdgeN = this.edgesCount; this.edgesCount++; return newEdge; }
private void SortSites(Site[] sites) { List<Site> sitesList = new List<Site>(sites.Length); for (int i = 0; i < sites.Length; i++) { sitesList.Add(sites[i]); } sitesList.Sort(new SiteSorter()); // Copy back into the array for (int i = 0; i < sites.Length; i++) { sites[i] = sitesList[i]; } }