private List <Vector2> ClipToBounds(Rect bounds) { var points = new List <Vector2>(); var n = Edges.Count; var i = 0; while (i < n && !Edges[i].Visible()) { i++; } if (i == n) { return(new List <Vector2>()); } var edge = Edges[i]; var orientation = EdgeOrientations[i]; points.Add(edge.ClippedEnds[orientation]); points.Add(edge.ClippedEnds[SideHelper.Other(orientation)]); for (var j = i + 1; j < n; j++) { edge = Edges[j]; if (!edge.Visible()) { continue; } Connect(points, j, bounds); } Connect(points, i, bounds, true); return(points); }
private void Connect(List <Vector2> points, int j, Rect bounds, bool closingUp = false) { var rightPoint = points[points.Count - 1]; var newEdge = Edges[j]; var newOrientation = EdgeOrientations[j]; var newPoint = newEdge.ClippedEnds[newOrientation]; if (!CloseEnough(rightPoint, newPoint)) { //todo: be sure this is ok to do but it seems more logical considering the last line if (Math.Abs(rightPoint.x - newPoint.x) > Epsilon && Math.Abs(rightPoint.y - newPoint.y) > Epsilon) { var rightCheck = BoundsCheck.Check(rightPoint, bounds); var newCheck = BoundsCheck.Check(newPoint, bounds); float px, py; if ((rightCheck & BoundsCheck.Right) != 0) { px = bounds.xMax; if ((newCheck & BoundsCheck.Bottom) != 0) { py = bounds.yMax; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Top) != 0) { py = bounds.yMin; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Left) != 0) { py = rightPoint.y - bounds.y + newPoint.y - bounds.y < bounds.height ? bounds.yMin : bounds.yMax; points.Add(new Vector2(px, py)); points.Add(new Vector2(bounds.xMin, py)); } } else if ((rightCheck & BoundsCheck.Left) != 0) { px = bounds.xMin; if ((newCheck & BoundsCheck.Bottom) != 0) { py = bounds.yMax; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Top) != 0) { py = bounds.yMin; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Right) != 0) { py = rightPoint.y - bounds.y + newPoint.y - bounds.y < bounds.height ? bounds.yMin : bounds.yMax; points.Add(new Vector2(px, py)); points.Add(new Vector2(bounds.xMax, py)); } } else if ((rightCheck & BoundsCheck.Top) != 0) { py = bounds.yMin; if ((newCheck & BoundsCheck.Right) != 0) { px = bounds.xMax; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Left) != 0) { px = bounds.xMin; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Bottom) != 0) { px = rightPoint.x - bounds.x + newPoint.x - bounds.x < bounds.width ? bounds.xMin : bounds.xMax; points.Add(new Vector2(px, py)); points.Add(new Vector2(px, bounds.yMax)); } } else if ((rightCheck & BoundsCheck.Bottom) != 0) { py = bounds.yMax; if ((newCheck & BoundsCheck.Right) != 0) { px = bounds.xMax; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Left) != 0) { px = bounds.xMin; points.Add(new Vector2(px, py)); } else if ((newCheck & BoundsCheck.Top) != 0) { px = rightPoint.x - bounds.x + newPoint.x - bounds.x < bounds.width ? bounds.xMin : bounds.xMax; points.Add(new Vector2(px, py)); points.Add(new Vector2(px, bounds.yMin)); } } } if (closingUp) { // newEdge's ends have already been added return; } points.Add(newPoint); } var newRightPoint = newEdge.ClippedEnds[SideHelper.Other(newOrientation)]; if (!CloseEnough(points [0], newRightPoint)) { points.Add(newRightPoint); } }
private static Site RightRegion(HalfEdge halfEdge, Site bottomMostSite) { var edge = halfEdge.Edge; return(edge == null ? bottomMostSite : edge.Site(SideHelper.Other((Side)halfEdge.LeftOrRight))); }
private void FortunesAlgorithm() { var newIntStar = Vector2.zero; var dataBounds = sites.GetSiteBounds(); var sqrtSiteCount = (int)(Mathf.Sqrt(sites.Count + 4)); var heap = new HalfEdgePriorityQueue(dataBounds.y, dataBounds.height, sqrtSiteCount); var edgeList = new EdgeList(dataBounds.x, dataBounds.width, sqrtSiteCount); var halfEdges = new List <HalfEdge>(); var vertices = new List <Vertex>(); var bottomMostSite = sites.Next(); var newSite = sites.Next(); for (;;) { if (heap.Empty() == false) { newIntStar = heap.Min(); } Site bottomSite; Vertex vertex; HalfEdge lbnd; HalfEdge rbnd; HalfEdge bisector; Edge edge; if (newSite != null && (heap.Empty() || CompareByYThenX(newSite, newIntStar) < 0)) { /* new site is smallest */ //trace("smallest: new site " + newSite); // Step 8: lbnd = edgeList.EdgeListLeftNeighbor(newSite.Coordinate); // the Halfedge just to the left of newSite //trace("lbnd: " + lbnd); rbnd = lbnd.EdgeListRightNeighbor; // the Halfedge just to the right //trace("rbnd: " + rbnd); bottomSite = RightRegion(lbnd, bottomMostSite); // this is the same as leftRegion(rbnd) // this Site determines the region containing the new site //trace("new Site is in region of existing site: " + bottomSite); // Step 9: edge = Edge.CreateBisectingEdge(bottomSite, newSite); //trace("new edge: " + edge); Edges.Add(edge); bisector = HalfEdge.Create(edge, Side.Left); halfEdges.Add(bisector); // inserting two Halfedges into edgeList constitutes Step 10: // insert bisector to the right of lbnd: edgeList.Insert(lbnd, bisector); // first half of Step 11: if ((vertex = Vertex.Intersect(lbnd, bisector)) != null) { vertices.Add(vertex); heap.Remove(lbnd); lbnd.Vertex = vertex; lbnd.YStar = vertex.Y + newSite.Distance(vertex); heap.Insert(lbnd); } lbnd = bisector; bisector = HalfEdge.Create(edge, Side.Right); halfEdges.Add(bisector); // second Halfedge for Step 10: // insert bisector to the right of lbnd: edgeList.Insert(lbnd, bisector); // second half of Step 11: if ((vertex = Vertex.Intersect(bisector, rbnd)) != null) { vertices.Add(vertex); bisector.Vertex = vertex; bisector.YStar = vertex.Y + newSite.Distance(vertex); heap.Insert(bisector); } newSite = sites.Next(); } else if (heap.Empty() == false) { /* intersection is smallest */ lbnd = heap.ExtractMin(); var llbnd = lbnd.EdgeListLeftNeighbor; rbnd = lbnd.EdgeListRightNeighbor; var rrbnd = rbnd.EdgeListRightNeighbor; bottomSite = LeftRegion(lbnd, bottomMostSite); var topSite = RightRegion(rbnd, bottomMostSite); // these three sites define a Delaunay triangle // (not actually using these for anything...) //_triangles.push(new Triangle(bottomSite, topSite, rightRegion(lbnd))); var v = lbnd.Vertex; v.SetIndex(); lbnd.Edge.SetVertex((Side)lbnd.LeftOrRight, v); rbnd.Edge.SetVertex((Side)rbnd.LeftOrRight, v); edgeList.Remove(lbnd); heap.Remove(rbnd); edgeList.Remove(rbnd); var leftRight = Side.Left; if (bottomSite.Y > topSite.Y) { var tempSite = bottomSite; bottomSite = topSite; topSite = tempSite; leftRight = Side.Right; } edge = Edge.CreateBisectingEdge(bottomSite, topSite); Edges.Add(edge); bisector = HalfEdge.Create(edge, leftRight); halfEdges.Add(bisector); edgeList.Insert(llbnd, bisector); edge.SetVertex(SideHelper.Other(leftRight), v); if ((vertex = Vertex.Intersect(llbnd, bisector)) != null) { vertices.Add(vertex); heap.Remove(llbnd); llbnd.Vertex = vertex; llbnd.YStar = vertex.Y + bottomSite.Distance(vertex); heap.Insert(llbnd); } if ((vertex = Vertex.Intersect(bisector, rrbnd)) != null) { vertices.Add(vertex); bisector.Vertex = vertex; bisector.YStar = vertex.Y + bottomSite.Distance(vertex); heap.Insert(bisector); } } else { break; } } // heap should be empty now heap.Dispose(); edgeList.Dispose(); foreach (var halfEdge in halfEdges) { halfEdge.ReallyDispose(); } halfEdges.Clear(); // we need the vertices to clip the edges foreach (var e in Edges) { e.ClipVertices(Bounds); } // but we don't actually ever use them again! foreach (var v in vertices) { v.Dispose(); } vertices.Clear(); }