private void Fortunes()
        {
            Site nSite;
            Site bottomSite;
            Site topSite;
            Site tSite;

            Vertex v1;
            Vertex v2;

            Point newIntStar = null;

            Orientation lr;
            HalfEdge    lBnd;
            HalfEdge    rBnd;
            HalfEdge    llBnd;
            HalfEdge    rrBnd;
            HalfEdge    bisector;

            Edge e;

            Rectangle dataBounds = sites.GetSitesBounds();

            int sqrtNSites             = (int)Math.Sqrt(sites.GetLength() + 4);
            HalfEdgePriorityQueue heap = new HalfEdgePriorityQueue(dataBounds.y, dataBounds.height, sqrtNSites);
            EdgeList        edgeList   = new EdgeList(dataBounds.x, dataBounds.width, sqrtNSites);
            List <HalfEdge> halfEdges  = new List <HalfEdge>();
            List <Vertex>   vertices   = new List <Vertex>();

            Site lowestSite = this.sites.Next();

            nSite = sites.Next();

            for (;;)
            {
                if (heap.Empty() == false)
                {
                    newIntStar = heap.Min();
                }

                if (nSite != null && (heap.Empty() || CompareByYThenX(nSite, newIntStar) < 0))
                {
                    lBnd       = edgeList.EdgeListLeftNeighbor(nSite.coord);
                    rBnd       = lBnd.edgeListRightNeighbor;
                    bottomSite = RightRegion(lBnd, lowestSite);
                    e          = Edge.CreateBisectingEdge(bottomSite, nSite);
                    this.edges.Add(e);

                    bisector = HalfEdge.Create(e, Orientation.LEFT);
                    halfEdges.Add(bisector);
                    //Console.WriteLine(lBnd.edgeListLeftNeighbor);
                    //Console.WriteLine(lBnd.edgeListRightNeighbor);
                    edgeList.Insert(lBnd, bisector);

                    if ((v2 = Vertex.Intersect(lBnd, bisector)) != null)
                    {
                        vertices.Add(v2);
                        heap.Remove(lBnd);
                        lBnd.v     = v2;
                        lBnd.yStar = v2.GetCoord().y + nSite.Dist(v2);
                        heap.Insert(lBnd);
                    }

                    lBnd     = bisector;
                    bisector = HalfEdge.Create(e, Orientation.RIGHT);
                    halfEdges.Add(bisector);
                    edgeList.Insert(lBnd, bisector);

                    if ((v2 = Vertex.Intersect(bisector, rBnd)) != null)
                    {
                        vertices.Add(v2);
                        bisector.v     = v2;
                        bisector.yStar = v2.GetCoord().y + nSite.Dist(v2);
                        heap.Insert(bisector);
                    }

                    nSite = this.sites.Next();
                }
                else if (heap.Empty() == false)
                {
                    lBnd  = heap.ExtractMin();
                    llBnd = lBnd.edgeListLeftNeighbor;
                    rBnd  = lBnd.edgeListRightNeighbor;
                    rrBnd = rBnd.edgeListRightNeighbor;

                    bottomSite = LeftRegion(lBnd, lowestSite);
                    topSite    = RightRegion(rBnd, lowestSite);

                    v1 = lBnd.v;
                    v1.SetIndex();
                    lBnd.e.SetVertex(lBnd.orientation, v1);
                    rBnd.e.SetVertex(rBnd.orientation, v1);
                    edgeList.Remove(lBnd);
                    heap.Remove(rBnd);
                    edgeList.Remove(rBnd);
                    lr = Orientation.LEFT;

                    if (bottomSite.coord.y > topSite.coord.y)
                    {
                        tSite      = bottomSite;
                        bottomSite = topSite;
                        topSite    = tSite;
                        lr         = Orientation.RIGHT;
                    }

                    e = Edge.CreateBisectingEdge(bottomSite, topSite);
                    this.edges.Add(e);
                    bisector = HalfEdge.Create(e, lr);
                    halfEdges.Add(bisector);
                    edgeList.Insert(llBnd, bisector);
                    e.SetVertex(Orientation.Other(lr), v1);

                    if ((v2 = Vertex.Intersect(llBnd, bisector)) != null)
                    {
                        vertices.Add(v2);
                        heap.Remove(llBnd);
                        llBnd.v     = v2;
                        llBnd.yStar = v2.GetCoord().y + bottomSite.Dist(v2);
                        heap.Insert(llBnd);
                    }

                    if ((v2 = Vertex.Intersect(bisector, rrBnd)) != null)
                    {
                        vertices.Add(v2);
                        bisector.v     = v2;
                        bisector.yStar = v2.GetCoord().y + bottomSite.Dist(v2);
                        heap.Insert(bisector);
                    }
                }
                else
                {
                    break;
                }
            }

            heap.Dispose();
            edgeList.Dispose();

            foreach (HalfEdge hE in halfEdges)
            {
                hE.Kill();
            }

            halfEdges.Clear();

            foreach (Edge tE in this.edges)
            {
                tE.ClipVertices(bounds);
            }

            foreach (Vertex v0 in vertices)
            {
                v0.Dispose();
            }

            vertices.Clear();
        }