public QueueItem(CircleEvent ce) { CircleEvent = ce; X = ce.Site.X; Y = ce.Site.Y; Type = 1; IsVoided = false; }
private string GetReallyShortString() { var nodeShort = "(x=" + X + ", y=" + Y + "), color=" + (Color == 0 ? "Red" : "Black") + ", details: "; var siteStr = (Site == null) ? "null" : Site.ToString(); var beachStr = (BeachSection == null) ? "null" : BeachSection.ToString(); var ceStr = (CircleEvent == null) ? "null" : CircleEvent.ToString(); return(nodeShort + "[site=" + siteStr + ", beach=" + beachStr + ", circleEvent=" + ceStr + "]"); }
public string GetFullString(int level, bool doNotFollow = false) { String str = ""; for (int i = 0; i < 3 * level; i++) { str = str + " "; } var nodeShort = "(x=" + X + ", y=" + Y + "), color=" + (Color == 0 ? "Red" : "Black") + ", details: "; var siteStr = (Site == null) ? "null" : Site.ToString(); var beachStr = (BeachSection == null) ? "null" : BeachSection.ToString(); var ceStr = (CircleEvent == null) ? "null" : CircleEvent.ToString(); return(str + nodeShort + "[site=" + siteStr + ", beach=" + beachStr + ", circleEvent=" + ceStr + "]\n" + str + ("(" + level + ") ") + "LEFT: " + NodeString(Left, level + 1, doNotFollow) + "\n" + str + ("(" + level + ") ") + "RIGHT: " + NodeString(Right, level + 1, doNotFollow) + "\n" + str + ("(" + level + ") ") + "PREVIOUS: " + NodeString(Previous, level, true) + "\n" + str + ("(" + level + ") ") + "NEXT: " + NodeString(Next, level, true) + "\n"); }
public void DetachCircleEvent(TreeNode arc) { //var circleEvent = arc.circleEvent; //if (circleEvent) //{ // if (!circleEvent.rbPrevious) // { // this.firstCircleEvent = circleEvent.rbNext; // } // this.circleEvents.rbRemoveNode(circleEvent); // remove from RB-tree // this.circleEventJunkyard.push(circleEvent); // arc.circleEvent = null; //} //var circleEvent = n.AsCircleEvent(); //var circleEvent = n.BeachSection.Site; var circleEvent = arc.CircleEvent; if (circleEvent != null) { if (arc.CircleEventNode.Previous == null) { firstCircleEvent = arc.Next.CircleEvent; //firstCircleEventNode = n.Next; //if(firstCircleEvent.CircleEvent == null) //{ // Console.WriteLine("ERROR2"); //} } CircleEvents.RemoveNode(arc.CircleEventNode); CircleEvents.Dump("circleEvents, detachCircleEvent remove", circleEventCounter++); arc.CircleEvent = null; arc.CircleEventNode = null; } }
public void AttachCircleEvent(TreeNode n) { // start // var lArc = arc.rbPrevious, //rArc = arc.rbNext; // if (!lArc || !rArc) { return; } // does that ever happen? // var lSite = lArc.site, // cSite = arc.site, // rSite = rArc.site; var lArc = n.Previous; var rArc = n.Next; if (lArc == null || rArc == null) { Console.WriteLine("SHOULD NOT HAPPEN"); return; } var lSite = lArc.BeachSection.Site; var cSite = n.BeachSection.Site; var rSite = rArc.BeachSection.Site; // if (lSite === rSite) { return; } if (lSite.X == rSite.X && lSite.Y == rSite.Y) { return; } // var bx = cSite.x, // by = cSite.y, // ax = lSite.x - bx, // ay = lSite.y - by, // cx = rSite.x - bx, // cy = rSite.y - by; var bx = cSite.X; var by = cSite.Y; var ax = lSite.X - bx; var ay = lSite.Y - by; var cx = rSite.X - bx; var cy = rSite.Y - by; // var d = 2 * (ax * cy - ay * cx); // if (d >= -2e-12) { return; } var d = 2 * (ax * cy - ay * cx); if (d >= -2e-12) { return; } // var ha = ax * ax + ay * ay, // hc = cx * cx + cy * cy, // x = (cy * ha - ay * hc) / d, // y = (ax * hc - cx * ha) / d, // ycenter = y + by; var ha = ax * ax + ay * ay; var hc = cx * cx + cy * cy; var x = (cy * ha - ay * hc) / d; var y = (ax * hc - cx * ha) / d; var ycenter = y + by; // var circleEvent = this.circleEventJunkyard.pop(); // if (!circleEvent) // { // circleEvent = new this.CircleEvent(); // } var circleEvent = new CircleEvent(); // circleEvent.arc = arc; // circleEvent.site = cSite; // circleEvent.x = x + bx; // circleEvent.y = ycenter + this.sqrt(x * x + y * y); // y bottom // circleEvent.ycenter = ycenter; // arc.circleEvent = circleEvent; circleEvent.Arc = n; circleEvent.Site = cSite; circleEvent.X = x + bx; circleEvent.Y = ycenter + Math.Sqrt(x * x + y * y); circleEvent.CenterY = ycenter; n.CircleEvent = circleEvent; //n.X = circleEvent.X; // probably remove //n.Y = circleEvent.Y; // probably remove TreeNode predecessor = null; TreeNode node = CircleEvents.root; // var predecessor = null, // node = this.circleEvents.root; // while (node) // { // if (circleEvent.y < node.y || (circleEvent.y === node.y && circleEvent.x <= node.x)) // { // if (node.rbLeft) // { // node = node.rbLeft; // } // else // { // predecessor = node.rbPrevious; // break; // } // } // else // { // if (node.rbRight) // { // node = node.rbRight; // } // else // { // predecessor = node; // break; // } // } // } while (node != null) { if (circleEvent.Y < node.Y || (circleEvent.Y == node.Y && circleEvent.X <= node.X)) { if (node.Left != null) { node = node.Left; } else { predecessor = node.Previous; break; } } else { if (node.Right != null) { node = node.Right; } else { predecessor = node; break; } } } // this.circleEvents.rbInsertSuccessor(predecessor, circleEvent); // if (!predecessor) // { // this.firstCircleEvent = circleEvent; // } var circleNode = new TreeNode { BeachSection = n.BeachSection, CircleEvent = circleEvent, X = circleEvent.X, Y = circleEvent.Y }; CircleEvents.InsertSuccessor(predecessor, circleNode); n.CircleEventNode = circleNode; //dumpTree(this.circleEvents, "circleEvents, attachCircleEvent insert", circleEventCounter); CircleEvents.Dump("circleEvents, attachCircleEvent insert", circleEventCounter++); if (predecessor == null) { //firstCircleEvent = circleNode; //firstCircleEventNode = circleNode; //firstCircleEvent = circleEvent; firstCircleEvent = circleNode.CircleEvent; //if(circleNode.CircleEvent == null) //{ // Console.WriteLine("ERROR"); //} } // end }
public void RemoveBeachSection(CircleEvent circle) //TreeNode beachSectionNode) //BeachSection b, TreeNode beachSectionNode) { //var circle = beachsection.circleEvent, // x = circle.x, // y = circle.ycenter, // vertex = this.createVertex(x, y), // previous = beachsection.rbPrevious, // next = beachsection.rbNext, // disappearingTransitions = [beachsection], // abs_fn = Math.abs; //var circle = b.CircleEvent.CircleEvent; //var circle = beachSectionNode.CircleEvent; var beachSectionNode = circle.Arc; var x = circle.X; var y = circle.CenterY; var vertex = CreateVertex(x, y); var previous = beachSectionNode.Previous; var next = beachSectionNode.Next; //var disappearingTransitions = new List<BeachSection>(); var disappearingTransitions = new List <TreeNode>(); disappearingTransitions.Add(beachSectionNode); //this.detachBeachsection(beachsection); DetachBeachSection(beachSectionNode); //var lArc = previous; //while (lArc.circleEvent && abs_fn(x - lArc.circleEvent.x) < 1e-9 && abs_fn(y - lArc.circleEvent.ycenter) < 1e-9) //{ // previous = lArc.rbPrevious; // disappearingTransitions.unshift(lArc); // this.detachBeachsection(lArc); // mark for reuse // lArc = previous; //} //disappearingTransitions.unshift(lArc); //this.detachCircleEvent(lArc); var lArc = previous; while (lArc.CircleEvent != null && Math.Abs(x - lArc.CircleEvent.X) < epsilon && Math.Abs(y - lArc.CircleEvent.CenterY) < epsilon) { previous = lArc.Previous; disappearingTransitions.Insert(0, lArc); //DetachBeachSection(lArc.BeachSection, lArc); DetachBeachSection(lArc); lArc = previous; } disappearingTransitions.Insert(0, lArc); DetachCircleEvent(lArc); //// look right //var rArc = next; //while (rArc.circleEvent && abs_fn(x - rArc.circleEvent.x) < 1e-9 && abs_fn(y - rArc.circleEvent.ycenter) < 1e-9) //{ // next = rArc.rbNext; // disappearingTransitions.push(rArc); // this.detachBeachsection(rArc); // mark for reuse // rArc = next; //} //disappearingTransitions.push(rArc); //this.detachCircleEvent(rArc); var rArc = next; while (rArc.CircleEvent != null && Math.Abs(x - rArc.CircleEvent.X) < epsilon && Math.Abs(y - rArc.CircleEvent.CenterY) < epsilon) { next = rArc.Next; disappearingTransitions.Add(rArc); //DetachBeachSection(rArc.BeachSection, rArc); DetachBeachSection(rArc); rArc = next; } disappearingTransitions.Add(rArc); DetachCircleEvent(rArc); //var nArcs = disappearingTransitions.length, // iArc; //for (iArc = 1; iArc < nArcs; iArc++) //{ // rArc = disappearingTransitions[iArc]; // lArc = disappearingTransitions[iArc - 1]; // this.setEdgeStartpoint(rArc.edge, lArc.site, rArc.site, vertex); //} var nArcs = disappearingTransitions.Count; int iArc; for (iArc = 1; iArc < nArcs; iArc++) { rArc = disappearingTransitions[iArc]; lArc = disappearingTransitions[iArc - 1]; rArc.BeachSection.Edge.SetStartPoint(lArc.BeachSection.Site, rArc.BeachSection.Site, vertex); } //lArc = disappearingTransitions[0]; //rArc = disappearingTransitions[nArcs - 1]; //rArc.edge = this.createEdge(lArc.site, rArc.site, undefined, vertex); lArc = disappearingTransitions[0]; rArc = disappearingTransitions[nArcs - 1]; rArc.BeachSection.Edge = CreateEdge(lArc.BeachSection.Site, rArc.BeachSection.Site, null, vertex); //this.a--ttachCircleEvent(lArc); //this.a--ttachCircleEvent(rArc); AttachCircleEvent(lArc); AttachCircleEvent(rArc); }
public void Compute(List <Site> input) { //this.reset(); Reset(); //// any diagram data available for recycling? //// I do that here so that this is included in execution time //if (this.toRecycle) //{ // this.vertexJunkyard = this.vertexJunkyard.concat(this.toRecycle.vertices); // this.edgeJunkyard = this.edgeJunkyard.concat(this.toRecycle.edges); // this.cellJunkyard = this.cellJunkyard.concat(this.toRecycle.cells); // this.toRecycle = null; //} //// Initialize site event queue //var siteEvents = sites.slice(0); //siteEvents.sort(function(a, b){ // var r = b.y - a.y; // if (r) { return r; } // return b.x - a.x; //}); Sites = new List <Site>(); Console.WriteLine("+++ INITIALIZING WITH " + input.Count + " SITES"); for (int i = 0; i < input.Count; i++) { var s = Input[i]; Sites.Add(s); } Sites.Sort(); //// process queue //var site = siteEvents.pop(), // siteid = 0, // xsitex, // to avoid duplicate sites // xsitey, // cells = this.cells, // circle; var site = PopSite(); double xsitex = -1, xsitey = -1; CircleEvent circle = null; //// main loop //for (; ; ) //{ // // we need to figure whether we handle a site or circle event // // for this we find out if there is a site event and it is // // 'earlier' than the circle event // circle = this.firstCircleEvent; for (; ;) { circle = firstCircleEvent; //circle = firstCircleEvent == null ? null : firstCircleEvent.Arc; if (site != null && (circle == null || site.Y < circle.Y || (site.Y == circle.Y && site.X < circle.X) ) ) { if (site.X != xsitex || site.Y != xsitey) { //GetCell(site.Id) = CreateCell(site); Cells.Add(site.Id, CreateCell(site)); AddBeachSection(site); xsitex = site.X; xsitey = site.Y; } site = PopSite(); } else if (circle != null) { //RemoveBeachSection(circle.BeachSection, circle); //RemoveBeachSection(circle.CircleEvent.Arc); RemoveBeachSection(circle); } else { break; } } // // add beach section // if (site && (!circle || site.y < circle.y || (site.y === circle.y && site.x < circle.x))) // { // // only if site is not a duplicate // if (site.x !== xsitex || site.y !== xsitey) // { // // first create cell for new site // cells[siteid] = this.createCell(site); // site.voronoiId = siteid++; // // then create a beachsection for that site // this.addBeachsection(site); // // remember last site coords to detect duplicate // xsitey = site.y; // xsitex = site.x; // } // site = siteEvents.pop(); // } // // remove beach section // else if (circle) // { // this.removeBeachsection(circle.arc); // } // // all done, quit // else // { // break; // } //} }
public void RemoveArc(CircleEvent e) { // var x = event.center.x; // var y = event.center.y; // var sweep = event.y; // var deletionPoint = this.findDeletionPoint(x, sweep); // // there could be more than one empty arc at the deletion point, this // // happens when more than two edges are linked by the same vertex, // // so we will collect all those edges by looking up both sides of // // the deletion point var x = e.CenterX; var y = e.CenterY; var sw = e.Y; int deletionPoint = FindDeletionPoint(x, sw); // // look left // var iLeft = deletionPoint; // while (iLeft-1 > 0 && this.equalWithEpsilon(x, this.leftBreakPoint(iLeft-1, sweep)) ) { // iLeft--; // } int iLeft = deletionPoint; while (iLeft - 1 > 0 && equals(x, GetLeftBreakPoint(iLeft - 1, sw))) { iLeft--; } //// look right /// //var iRight = deletionPoint; // while (iRight+1 < this.arcs.length && this.equalWithEpsilon(x,this.rightBreakPoint(iRight+1, sweep)) ) { // iRight++; //} int iRight = deletionPoint; while (iRight + 1 < Arcs.Count && equals(x, GetRightBreakPoint(iRight + 1, sw))) { iRight++; } //// walk through all the collapsed beach sections and set the start point //// of their left edge //var lArc, rArc; // for (var iArc=iLeft; iArc<=iRight+1; iArc++) { // lArc = this.arcs[iArc - 1]; // rArc = this.arcs[iArc]; // this.setEdgeStartpoint(rArc.edge, lArc.site, rArc.site, new this.Vertex(x, y)); //} BeachSection lArc, rArc; for (int iArc = iLeft; iArc <= iRight + 1; iArc++) { lArc = Arcs[iArc - 1]; rArc = Arcs[iArc]; rArc.Edge.SetStartPoint(lArc.Site, rArc.Site, new Vertex(x, y)); } // // void circle events of collapsed beach sections and adjacent beach sections // this.voidCircleEvents(iLeft-1,iRight+1); VoidCircleEvents(iLeft - 1, iRight + 1); // // removed collapsed beach sections from beachline // this.arcs.splice(iLeft,iRight-iLeft+1); Arcs.RemoveRange(iLeft, iRight - iLeft + 1); //// create new edge as we have a new transition between //// two beach sections which were previously not adjacent //lArc = this.arcs [iLeft-1]; //rArc = this.arcs [iLeft]; lArc = Arcs[iLeft - 1]; rArc = Arcs[iLeft]; //rArc.edge = this.createEdge(lArc.site,rArc.site,undefined,new this.Vertex(x, y)); rArc.Edge = CreateEdge(lArc.Site, rArc.Site, null, new Vertex(x, y)); // // create circle events if any for beach sections left in the beachline // // adjacent to collapsed sections // this.addCircleEvents(iLeft-1,sweep); // this.addCircleEvents(iLeft,sweep); AddCircleEvents(iLeft - 1, sw); AddCircleEvents(iLeft, sw); }
public QueueItem QueuePushCircle(CircleEvent item) { var o = new QueueItem(item); //var q = this.circEvents; //var r = q.length; //if (r) //{ // var l = 0; // var i, c; // while (l < r) // { // i = (l + r) >> 1; // c = o.y - q[i].y; // if (!c) { c = o.x - q[i].x; } // if (c > 0) { r = i; } // else { l = i + 1; } // } // q.splice(l, 0, o); //} //else //{ // q.push(o); //} var q = CircleEvents; var r = q.Count; if (r > 0) { int l = 0; int i; double c; while (l < r) { i = (l + r) / 2; c = o.Y - q[i].Y; if (c == 0) { c = o.X - q[i].X; } if (c > 0) { r = i; } else { l = i + 1; } } q.Insert(l, o); } else { q.Add(o); } return(o); }
public void AddCircleEvents(int iArc, double sw) { // addCircleEvents: function(iArc, sweep) { // if (iArc <= 0 || iArc >= this.arcs.length - 1) { return; } if (iArc <= 0 || iArc >= Arcs.Count - 1) { return; } // var arc = this.arcs[iArc]; // var lSite = this.arcs[iArc - 1].site; // var cSite = this.arcs[iArc].site; // var rSite = this.arcs[iArc + 1].site; var arc = Arcs[iArc]; var lSite = Arcs[iArc - 1].Site; var cSite = Arcs[iArc].Site; var rSite = Arcs[iArc + 1].Site; // // if any two sites are repeated in the same beach section triplet, // // there can't be convergence // if (lSite.id == rSite.id || lSite.id == cSite.id || cSite.id == rSite.id) { return; } if (lSite.Id == rSite.Id || lSite.Id == cSite.Id || cSite.Id == rSite.Id) { return; } // // if points l->c->r are clockwise, then center beach section does not // // converge, hence it can't end up as a vertex // if ((lSite.y - cSite.y) * (rSite.x - cSite.x) <= (lSite.x - cSite.x) * (rSite.y - cSite.y)) { return; } if ((lSite.Y - cSite.Y) * (rSite.X - cSite.X) <= (lSite.X - cSite.X) * (rSite.Y - cSite.Y)) { return; } // // find circumscribed circle // var circle = this.circumcircle(lSite, cSite, rSite); var circle = CalculateCircle(lSite, cSite, rSite); // // not valid if the bottom-most point of the circumcircle // // is above the sweep line // // TODO: And what if it is on the sweep line, should it be discarded if it is // // *before* the last processed x value? Need to think about this. // var ybottom = circle.y + circle.radius; var ybottom = circle.Y + circle.Radius; // if (!this.greaterThanOrEqualWithEpsilon(ybottom, sweep)) { return; } if (!gte(ybottom, sw)) { return; } // var circEvent ={ // type: this.CIRCLE_EVENT, // site: cSite, // x: circle.x, // y: ybottom, // center: { x: circle.x, y: circle.y} // }; // arc.circleEvent = circEvent; // this.queuePushCircle(circEvent); //}, var ce = new CircleEvent { Site = cSite, X = circle.X, Y = ybottom, CenterX = circle.X, CenterY = circle.Y }; arc.CircleEvent = QueuePushCircle(ce); }