Example #1
0
        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;
        }
Example #2
0
        // ---------------------------------------------------------------------------
        // 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;
        }
Example #3
0
        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;
        }
Example #4
0
        // 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;
        }