예제 #1
0
        /// <summary>
        ///     Determines if the Point is to the right of the HalfEdge.
        /// </summary>
        /// <param name="el">edge</param>
        /// <param name="p">point</param>
        /// <returns>1 if p is to the right of HalfEdge</returns>
        private static bool IsRightOf(HalfEdge el, Point2D p)
        {
            bool above;
            var  e           = el.Edge;
            var  topsite     = e.Reg[1];
            var  rightOfSite = p.X > topsite.X;

            if (rightOfSite && (el.Midpoint == 0))
            {
                return(true);
            }
            if (!rightOfSite && (el.Midpoint == 1))
            {
                return(false);
            }
            if (DoubleComparison.IsEqual(e.A, 1.0))
            {
                var dyp  = p.Y - topsite.Y;
                var dxp  = p.X - topsite.X;
                var fast = false;
                if ((!rightOfSite && (e.B < 0.0)) || (rightOfSite && (e.B >= 0.0)))
                {
                    above = dyp >= e.B * dxp;
                    fast  = above;
                }
                else
                {
                    above = p.X + p.Y * e.B > e.C;
                    if (e.B < 0.0)
                    {
                        above = !above;
                    }
                    if (!above)
                    {
                        fast = true;
                    }
                }
                if (fast)
                {
                    return(el.Midpoint == 0 ? above : !above);
                }
                var dxs = topsite.X - e.Reg[0].X;
                above = e.B * (dxp * dxp - dyp * dyp) < dxs * dyp * (1.0 + 2.0 * dxp / dxs + e.B * e.B);
                if (e.B < 0.0)
                {
                    above = !above;
                }
            }
            else
            {
                var yl = e.C - e.A * p.X;
                var t1 = p.Y - yl;
                var t2 = p.X - topsite.X;
                var t3 = yl - topsite.Y;
                above = t1 * t1 > t2 * t2 + t3 * t3;
            }
            return(el.Midpoint == 0 ? above : !above);
        }
예제 #2
0
        // push the HalfEdge into the ordered linked list of vertices
        internal void PQinsert(HalfEdge he, Point2D v, double offset)
        {
            HalfEdge next;

            he.Vertex = v;
            he.YStar  = v.Y + offset;
            var last = _hash[0];

            _min = 0;
            while (((next = last.NextSite) != null) && ((he.YStar > next.YStar) || (DoubleComparison.IsEqual(he.YStar, next.YStar) && (v.X > next.Vertex.X))))
            {
                last = next;
            }

            he.NextSite   = last.NextSite;
            last.NextSite = he;
            _count++;
        }
예제 #3
0
        /// <summary>
        ///     Creates a new site where the HalfEdges intersect.
        /// </summary>
        /// <param name="el1">HalfEdge to intersect</param>
        /// <param name="el2">HalfEdge to intersect</param>
        /// <returns>new site/point at intersection</returns>
        private static Point2D Intersect(HalfEdge el1, HalfEdge el2)
        {
            Edge     e;
            HalfEdge el;

            var e1 = el1.Edge;
            var e2 = el2.Edge;

            if ((e1 == null) || (e2 == null) || (e1.Reg[1] == e2.Reg[1]))
            {
                return(null);
            }

            var d = e1.A * e2.B - e1.B * e2.A;

            //This checks for the value being basically zero
            if ((-0.0000000001 < d) && (d < 0.0000000001))
            {
                return(null);
            }

            var xint = (e1.C * e2.B - e2.C * e1.B) / d;
            var yint = (e2.C * e1.A - e1.C * e2.A) / d;

            if ((e1.Reg[1].Y < e2.Reg[1].Y) || (DoubleComparison.IsEqual(e1.Reg[1].Y, e2.Reg[1].Y) &&
                                                (e1.Reg[1].X < e2.Reg[1].X)))
            {
                el = el1;
                e  = e1;
            }
            else
            {
                el = el2;
                e  = e2;
            }

            return(((xint >= e.Reg[1].X) && (el.Midpoint == 0)) || ((xint < e.Reg[1].X) && (el.Midpoint == 1)) ? null : new Point2D(xint, yint));
        }
예제 #4
0
        /// <summary>
        ///     Starts fortune's algorithm.
        /// </summary>
        private void Voronoi()
        {
            Point2D  newintstar = null;
            HalfEdge leftBound;

            var queue = new PriorityQueue(NumSites);

            _bottomsite = NextSite();
            var list    = new EdgeList(NumSites);
            var newsite = NextSite();

            while (true)
            {
                Point2D  bot;
                Point2D  p;
                HalfEdge rbnd;
                HalfEdge bisector;
                Edge     e;

                if (!queue.IsEmpty())
                {
                    newintstar = queue.Min();
                }

                //if the lowest site has a smaller y value than the lowest vector intersection, process the site
                //otherwise process the vector intersection
                if ((newsite != null) && (queue.IsEmpty() || (newintstar == null) || (newsite.Y < newintstar.Y) || (DoubleComparison.IsEqual(newsite.Y, newintstar.Y) && (newsite.X < newintstar.X))))
                {                                                     /* new site is smallest - this is a site event*/
                    leftBound = list.LeftBound(newsite);              //get the first HalfEdge to the LEFT of the new site
                    rbnd      = leftBound.Right;                      //get the first HalfEdge to the RIGHT of the new site
                    bot       = Rightreg(leftBound);                  //if this HalfEdge has no edge, , bot = bottom site (whatever that is)
                    e         = Bisect(bot, newsite);                 //create a new edge that bisects
                    bisector  = new HalfEdge(e, 0);                   //create a new HalfEdge, setting its elPm field to 0
                    EdgeList.ElInsert(leftBound, bisector);           //insert this new bisector edge between the left and right vectors in a linked list

                    if ((p = Intersect(leftBound, bisector)) != null) //if the new bisector intersects with the left edge, remove the left edge's vertex, and put in the new one
                    {
                        queue.PQinsert(queue.Delete(leftBound), p, p.Distance(newsite));
                    }

                    leftBound = bisector;
                    bisector  = new HalfEdge(e, 1);                       //create a new HalfEdge, setting its elPm field to 1
                    EdgeList.ElInsert(leftBound, bisector);               //insert the new HE to the right of the original bisector earlier in the IF stmt

                    if ((p = Intersect(bisector, rbnd)) != null)          //if this new bisector intersects with the
                    {
                        queue.PQinsert(bisector, p, p.Distance(newsite)); //push the HE into the ordered linked list of vertices
                    }
                    newsite = NextSite();
                }
                else if (!queue.IsEmpty())
                {                                   /* intersection is smallest - this is a vector event */
                    leftBound = queue.ExtractMin(); //pop the HalfEdge with the lowest vector off the ordered list of vectors
                    var llbnd = leftBound.Left;
                    rbnd = leftBound.Right;         //get the HalfEdge to the right of the above HE
                    var rrbnd = rbnd.Right;
                    bot = Leftreg(leftBound);       //get the Site to the left of the left HE which it bisects
                    var top = Rightreg(rbnd);

                    var leftBoundVertex = leftBound.Vertex;
                    Endpoint(leftBound.Edge, leftBound.Midpoint, leftBoundVertex); //set the endpoint of the left HalfEdge to be this vector
                    Endpoint(rbnd.Edge, rbnd.Midpoint, leftBoundVertex);           //set the endpoint of the right HalfEdge to be this vector
                    list.Delete(leftBound);                                        //mark the lowest HE for deletion - can't delete yet because there might be pointers to it in Hash Map
                    queue.Delete(rbnd);                                            //remove all vertex events to do with the  right HE
                    list.Delete(rbnd);                                             //mark the right HE for deletion - can't delete yet because there might be pointers to it in Hash Map
                    var pm = 0;

                    if (bot.Y > top.Y)
                    { //if the site to the left of the event is higher than the Site to the right of it, then swap them and set the 'pm' variable to 1
                        var temp = bot;
                        bot = top;
                        top = temp;
                        pm  = 1;
                    }

                    e        = Bisect(bot, top);          //Create Edge between the two Sites
                    bisector = new HalfEdge(e, pm);       //Create a HE from the Edge 'e', and make it point to that edge with its elEdge field
                    EdgeList.ElInsert(llbnd, bisector);   //Insert the new bisector to the right of the left HE
                    Endpoint(e, 1 - pm, leftBoundVertex); //Set one endpoint to the new edge to be the vector point 'v'

                    //If left HE and the new bisector don't intersect, then delete the left HE, and reinsert
                    if ((p = Intersect(llbnd, bisector)) != null)
                    {
                        queue.PQinsert(queue.Delete(llbnd), p, p.Distance(bot));
                    }

                    //If right HE and the new bisector don't intersect, then reinsert it
                    if ((p = Intersect(bisector, rrbnd)) != null)
                    {
                        queue.PQinsert(bisector, p, p.Distance(bot));
                    }
                }
                else
                {
                    break;
                }
            }

            for (leftBound = list.LeftEnd.Right; leftBound != list.RightEnd; leftBound = leftBound.Right)
            {
                ClipLine(leftBound.Edge);
            }
        }
예제 #5
0
        private void ClipLine(Edge e)
        {
            double x1;
            double x2;
            double y1;
            double y2;

            //if the distance between the two points this line was created from is less than
            //the square root of 2, then ignore it
            if (e.Reg[0].Distance(e.Reg[1]) < 1.41421356)
            {
                return;
            }

            var s1 = DoubleComparison.IsEqual(e.A, 1.0) && (e.B >= 0.0) ? e.EndPoints[1] : e.EndPoints[0];
            var s2 = DoubleComparison.IsEqual(e.A, 1.0) && (e.B >= 0.0) ? e.EndPoints[0] : e.EndPoints[1];

            if (DoubleComparison.IsEqual(e.A, 1.0))
            {
                y1 = (s1 != null) && (s1.Y > 1) ? s1.Y : 1;
                y1 = y1 > ImageHeight ? ImageHeight : y1;
                x1 = e.C - e.B * y1;
                y2 = (s2 != null) && (s2.Y < ImageHeight) ? s2.Y : ImageHeight;
                y2 = y2 < 1 ? 1 : y2;
                x2 = e.C - e.B * y2;

                if (((x1 > ImageWidth) && (x2 > ImageWidth)) || ((x1 < 1) && (x2 < 1)))
                {
                    return;
                }

                x1 = x1 > ImageWidth ? ImageWidth : x1;
                x1 = x1 < 1 ? 1 : x1;
                y1 = (x1 > ImageWidth) || (x1 < 1) ? (e.C - x1) / e.B : y1;
                x2 = x2 > ImageWidth ? ImageWidth : x2;
                x2 = x2 < 1 ? 1 : x2;
                y2 = (x2 > ImageWidth) || (x2 < 1) ? (e.C - x2) / e.B : y2;
            }
            else
            {
                x1 = (s1 != null) && (s1.X > 1) ? s1.X : 1;
                x1 = x1 > ImageWidth ? ImageWidth : x1;
                y1 = e.C - e.A * x1;
                x2 = (s2 != null) && (s2.X < ImageWidth) ? s2.X : ImageWidth;
                x2 = x2 < 1 ? 1 : x2;
                y2 = e.C - e.A * x2;

                if (((y1 > ImageHeight) & (y2 > ImageHeight)) | ((y1 < 1) & (y2 < 1)))
                {
                    return;
                }

                y1 = y1 > ImageHeight ? ImageHeight : y1;
                y1 = y1 < 1 ? 1 : y1;
                x1 = (y1 > ImageHeight) || (y1 < 1) ? (e.C - y1) / e.A : x1;
                y2 = y2 > ImageHeight ? ImageHeight : y2;
                y2 = y2 < 1 ? 1 : y2;
                x2 = (y2 > ImageHeight) || (y2 < 1) ? (e.C - y2) / e.A : x2;
            }

            PushGraphEdge(x1, y1, x2, y2);
        }