public Edge CreateEdge(Point lSite, Point rSite, Point va, Point vb) { Edge edge = new Edge(lSite, rSite); this.edges.Add(edge); if (va) { edge.SetStartPoint(lSite, rSite, va); } if (vb) { edge.SetEndPoint(lSite, rSite, vb); } this.cells[lSite.id].halfEdges.Add(new HalfEdge(edge, lSite, rSite)); this.cells[rSite.id].halfEdges.Add(new HalfEdge(edge, rSite, lSite)); return edge; }
// --------------------------------------------------------------------------- // Diagram completion methods // connect dangling edges (not if a cursory test tells us // it is not going to be visible. // return value: // false: the dangling va couldn't be connected // true: the dangling va could be connected public bool ConnectEdge(Edge edge, Bounds bbox) { // skip if end point already connected Point vb = edge.vb; if (!!vb) { return true; } // make local copy for performance purpose Point va = edge.va; float xl = bbox.min.x; float xr = bbox.max.x; float yt = bbox.min.z; float yb = bbox.max.z; Point lSite = edge.lSite; Point rSite = edge.rSite; float lx = lSite.x; float ly = lSite.y; float rx = rSite.x; float ry = rSite.y; float fx = (lx + rx) / 2; float fy = (ly + ry) / 2; float fm = float.NaN; float fb = 0.0f; // if we reach here, this means cells which use this edge will need // to be closed, whether because the edge was removed, or because it // was connected to the bounding box. this.cells[lSite.id].closeMe = true; this.cells[rSite.id].closeMe = true; // get the line equation of the bisector if line is not vertical if (ry != ly) { fm = (lx - rx) / (ry - ly); fb = fy - fm * fx; } // remember, direction of line (relative to left site): // upward: left.x < right.x // downward: left.x > right.x // horizontal: left.x == right.x // upward: left.x < right.x // rightward: left.y < right.y // leftward: left.y > right.y // vertical: left.y == right.y // depending on the direction, find the best side of the // bounding box to use to determine a reasonable start point // rhill 2013-12-02: // While at it, since we have the values which define the line, // clip the end of va if it is outside the bbox. // https://github.com/gorhill/Javascript-Voronoi/issues/15 // TODO: Do all the clipping here rather than rely on Liang-Barsky // which does not do well sometimes due to loss of arithmetic // precision. The code here doesn't degrade if one of the vertex is // at a huge distance. // special case: vertical line if (float.IsNaN(fm)) { // doesn't intersect with viewport if (fx < xl || fx >= xr) { return false; } // downward if (lx > rx) { if (!va || va.y < yt) { //Debug.Log(yt); va = new Point(fx, yt); } else if (va.y >= yb) { //Debug.Log(yb); return false; } vb = new Point(fx, yb); } // upward else { if (!va || va.y > yb) { //Debug.Log(yb); va = new Point(fx, yb); } else if (va.y < yt) { //Debug.Log(yt); return false; } vb = new Point(fx, yt); } } // closer to vertical than horizontal, connect start point to the // top or bottom side of the bounding box else if (fm < -1 || fm > 1) { // downward if (lx > rx) { if (!va || va.y < yt) { //Debug.Log(va.y + " yt: " + yt); va = new Point((yt - fb) / fm, yt); } else if (va.y >= yb) { //Debug.Log(va.y + " yb: " + yb); return false; } vb = new Point((yb - fb) / fm, yb); } // upward else { if (!va || va.y > yb) { //Debug.Log(va.y + " yb: " + yb); va = new Point((yb - fb) / fm, yb); } else if (va.y < yt) { //Debug.Log(va.y + " yt: " + yt); return false; } vb = new Point((yt - fb) / fm, yt); } } // closer to horizontal than vertical, connect start point to the // left or right side of the bounding box else { // rightward if (ly < ry) { if (!va || va.x < xl) { //Debug.Log(va.x + " xl: " + xl); va = new Point(xl, fm * xl + fb); } else if (va.x >= xr) { //Debug.Log(va.x + " xr: " + xr); return false; } vb = new Point(xr, fm * xr + fb); } // leftward else { if (!va || va.x > xr) { //Debug.Log(va.x + " xr: " + xr); va = new Point(xr, fm * xr + fb); } else if (va.x < xl) { //Debug.Log(va.x + " xl: " + xl); return false; } vb = new Point(xl, fm * xl + fb); } } edge.va = va; edge.vb = vb; return true; }
public Edge CreateBorderEdge(Point lSite, Point va, Point vb) { Edge edge = new Edge(lSite, null); edge.va = va; edge.vb = vb; this.edges.Add(edge); return edge; }
// line-clipping code taken from: // Liang-Barsky function by Daniel White // http://www.skytopia.com/project/articles/compsci/clipping.html // Thanks! // A bit modified to minimize code paths public bool ClipEdge(Edge edge, Bounds bbox) { float ax = edge.va.x; float ay = edge.va.y; float bx = edge.vb != null ? edge.vb.x : float.NaN; float by = edge.vb != null ? edge.vb.y : float.NaN; float t0 = 0; float t1 = 1; float dx = bx - ax; float dy = by - ay; // left float q = ax - bbox.min.x; if (dx == 0 && q < 0) { return false; } float r = -q / dx; if (dx < 0) { if (r < t0) { return false; } if (r < t1) { t1 = r; } } else if (dx > 0) { if (r > t1) { return false; } if (r > t0) { t0 = r; } } // right q = bbox.max.x - ax; if (dx == 0 && q < 0) { return false; } r = q / dx; if (dx < 0) { if (r > t1) { return false; } if (r > t0) { t0 = r; } } else if (dx > 0) { if (r < t0) { return false; } if (r < t1) { t1 = r; } } // top q = ay - bbox.min.z; if (dy == 0 && q < 0) { return false; } r = -q / dy; if (dy < 0) { if (r < t0) { return false; } if (r < t1) { t1 = r; } } else if (dy > 0) { if (r > t1) { return false; } if (r > t0) { t0 = r; } } // bottom q = bbox.max.z - ay; if (dy == 0 && q < 0) { return false; } r = q / dy; if (dy < 0) { if (r > t1) { return false; } if (r > t0) { t0 = r; } } else if (dy > 0) { if (r < t0) { return false; } if (r < t1) { t1 = r; } } // if we reach this point, Voronoi edge is within bbox // if t0 > 0, va needs to change // rhill 2011-06-03: we need to create a new vertex rather // than modifying the existing one, since the existing // one is likely shared with at least another edge if (t0 > 0) { edge.va = new Point(ax + t0 * dx, ay + t0 * dy); } // if t1 < 1, vb needs to change // rhill 2011-06-03: we need to create a new vertex rather // than modifying the existing one, since the existing // one is likely shared with at least another edge if (t1 < 1) { edge.vb = new Point(ax + t1 * dx, ay + t1 * dy); } // va and/or vb were clipped, thus we will need to close // cells which use this edge. if (t0 > 0 || t1 < 1) { this.cells[edge.lSite.id].closeMe = true; this.cells[edge.rSite.id].closeMe = true; } return true; }