/// <summary> /// This method can also be called to clear the object of any of its data from a previous run. You do this when you /// want to create some blue noise. For instance with the Lloyd Relaxation iterations. /// </summary> /// <created>Dennis Steinmeijer</created> /// <date>2013-07-20</date> public void Reset() { this.SiteList.Clear(); this.Sites.Clear(); this.Cells.Clear(); this.FirstCircle = null; this.Edges.Clear(); this.BeachLines = new RBTree(); this.Circles = new RBTree(); this.BeachJunkyard.Clear(); this.CircleJunkyard.Clear(); this.EdgeVertices.Clear(); }
/// <summary> /// Checks to see if a circle event is available in the junkyard and uses it, /// or makes a new one and returns it. /// </summary> private Circle GetCircle() { Circle objCircle = null; // Check to see whether the stack is empty. if (this.CircleJunkyard.Count > 0) { // Try to retrieve a circle vent from the junkyard. objCircle = this.CircleJunkyard.Pop(); } // If we don't find a circle event in the junkyard we'll make a new one. if (objCircle == null) { objCircle = new Circle(); } // And give it back! return objCircle; }
/// <summary> /// Attach a circle event. /// </summary> private void AttachCircle(Beach objArc) { // This is a node in the RBTree which points to a beachsection. Beach objArcLeft = objArc.Previous as Beach; Beach objArcRight = objArc.Next as Beach; if (objArcLeft == null || objArcRight == null) { return; } // Does that ever happen? Point objSiteLeft = objArcLeft.Site; Point objSite = objArc.Site; Point objSiteRight = objArcRight.Site; // If site of left beachsection is same as site of right beachsection, there can't be convergence. if (objSiteLeft == objSiteRight) { return; } // Find the circumscribed circle for the three sites associated // with the beachsection triplet. // rhill 2011-05-26: It is more efficient to calculate in-place // rather than getting the resulting circumscribed circle from an // object returned by calling Voronoi.circumcircle() // http://mathforum.org/library/drmath/view/55002.html // Except that I bring the origin at cSite to simplify calculations. // The bottom-most part of the circumcircle is our Fortune 'circle // event', and its center is a vertex potentially part of the final // Voronoi diagram. double bx = objSite.x; double by = objSite.y; double ax = objSiteLeft.x - bx; double ay = objSiteLeft.y - by; double cx = objSiteRight.x - bx; double cy = objSiteRight.y - by; // If points l->c->r are clockwise, then center beach section does not // collapse, hence it can't end up as a vertex (we reuse 'd' here, which // sign is reverse of the orientation, hence we reverse the test. // http://en.wikipedia.org/wiki/Curve_orientation#Orientation_of_a_simple_polygon // rhill 2011-05-21: Nasty finite precision error which caused circumcircle() to // return infinites: 1e-12 seems to fix the problem. double d = 2 * (ax * cy - ay * cx); if (d >= -2e-12) { return; } double ha = ax * ax + ay * ay; double hc = cx * cx + cy * cy; double x = (cy * ha - ay * hc) / d; double y = (ax * hc - cx * ha) / d; double ycenter = y + by; // Important: ybottom should always be under or at sweep, so no need // to waste CPU cycles by checking // Recycle circle event object if possible. Circle objCircle = this.GetCircle(); objCircle.Arc = objArc; objCircle.Site = objSite; objCircle.x = x + bx; objCircle.y = ycenter + Math.Sqrt(x * x + y * y); // y bottom objCircle.ycenter = ycenter; objArc.Circle = objCircle; // find insertion point in RB-tree: circle events are ordered from // smallest to largest Circle objNodePrevious = null; Circle objNode = this.Circles.Root as Circle; while (objNode != null) { if (objCircle.y < objNode.y || (objCircle.y == objNode.y && objCircle.x <= objNode.x)) { if (objNode.Left != null) { objNode = objNode.Left as Circle; } else { objNodePrevious = objNode.Previous as Circle; break; } } else { if (objNode.Right != null) { objNode = objNode.Right as Circle; } else { objNodePrevious = objNode; break; } } } this.Circles.InsertSuccessor(objNodePrevious, objCircle); if (objNodePrevious == null) { this.FirstCircle = objCircle; } }
/// <summary> /// Detach a circle event. /// </summary> private void DetachCircleEvent(Beach objArc) { Circle objCircle = objArc.Circle; if (objCircle == null) { return; } if (objCircle.Previous == null) { this.FirstCircle = objCircle.Next as Circle; } // Remove from RBTree. this.Circles.RemoveNode(objCircle); this.CircleJunkyard.Push(objCircle); objArc.Circle = null; }