private void fortunesAlgorithm()
    {
        Site newSite, bottomSite, topSite, tempSite;
        Vertex v, vertex;
        Vector2 newintstar;
        LR leftRight;
        Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
        Edge edge;

        Rect dataBounds = _sites.getSitesBounds();

        int sqrt_nsites = (int)(Mathf.Sqrt(_sites.length + 4));
        HalfedgePriorityQueue heap = new HalfedgePriorityQueue(dataBounds.y, dataBounds.height, sqrt_nsites);
        EdgeList edgeList = new EdgeList(dataBounds.x, dataBounds.width, sqrt_nsites);
        List<Halfedge> halfEdges = new List<Halfedge> ();
        List<Vertex> vertices = new List<Vertex>();

        Site bottomMostSite = _sites.next();
        newSite = _sites.next();

        for (;;)
        {
            if (heap.empty() == false)
            {
                newintstar = heap.min();
            }

            if (newSite != null
                &&  (heap.empty() || compareByYThenX(newSite, newintstar) < 0))
            {
                /* new site is smallest */
                //trace("smallest: new site " + newSite);

                // Step 8:
                lbnd = edgeList.edgelistLeftNeighbor(newSite.Coord);	// the Halfedge just to the left of newSite
                //trace("lbnd: " + lbnd);
                rbnd = lbnd.edgeListRightNeighbor;		// the Halfedge just to the right
                //trace("rbnd: " + rbnd);
                bottomSite = rightRegion(lbnd,bottomMostSite);		// this is the same as leftRegion(rbnd)
                // this Site determines the region containing the new site
                //trace("new Site is in region of existing site: " + bottomSite);

                // Step 9:
                edge = Edge.createBisectingEdge(bottomSite, newSite);
                //trace("new edge: " + edge);
                _edges.Add(edge);

                bisector = Halfedge.create(edge, LR.LEFT);
                halfEdges.Add(bisector);
                // inserting two Halfedges into edgeList constitutes Step 10:
                // insert bisector to the right of lbnd:
                edgeList.insert(lbnd, bisector);

                // first half of Step 11:
                if ((vertex = Vertex.intersect(lbnd, bisector)) != null)
                {
                    vertices.Add(vertex);
                    heap.remove(lbnd);
                    lbnd.vertex = vertex;
                    lbnd.ystar = vertex.y + newSite.dist(vertex);
                    heap.insert(lbnd);
                }

                lbnd = bisector;
                bisector = Halfedge.create(edge, LR.RIGHT);
                halfEdges.Add(bisector);
                // second Halfedge for Step 10:
                // insert bisector to the right of lbnd:
                edgeList.insert(lbnd, bisector);

                // second half of Step 11:
                if ((vertex = Vertex.intersect(bisector, rbnd)) != null)
                {
                    vertices.Add(vertex);
                    bisector.vertex = vertex;
                    bisector.ystar = vertex.y + newSite.dist(vertex);
                    heap.insert(bisector);
                }

                newSite = _sites.next();
            }
            else if (heap.empty() == false)
            {
                /* intersection is smallest */
                lbnd = heap.extractMin();
                llbnd = lbnd.edgeListLeftNeighbor;
                rbnd = lbnd.edgeListRightNeighbor;
                rrbnd = rbnd.edgeListRightNeighbor;
                bottomSite = leftRegion(lbnd,bottomMostSite);
                topSite = rightRegion(rbnd,bottomMostSite);
                // these three sites define a Delaunay triangle
                // (not actually using these for anything...)
                //_triangles.push(new Triangle(bottomSite, topSite, rightRegion(lbnd)));

                v = lbnd.vertex;
                v.setIndex();
                lbnd.edge.setVertex(lbnd.leftRight, v);
                rbnd.edge.setVertex(rbnd.leftRight, v);
                edgeList.remove(lbnd);
                heap.remove(rbnd);
                edgeList.remove(rbnd);
                leftRight = LR.LEFT;
                if (bottomSite.y > topSite.y)
                {
                    tempSite = bottomSite; bottomSite = topSite; topSite = tempSite; leftRight = LR.RIGHT;
                }
                edge = Edge.createBisectingEdge(bottomSite, topSite);
                _edges.Add(edge);
                bisector = Halfedge.create(edge, leftRight);
                halfEdges.Add(bisector);
                edgeList.insert(llbnd, bisector);
                edge.setVertex(LR.other(leftRight), v);
                if ((vertex = Vertex.intersect(llbnd, bisector)) != null)
                {
                    vertices.Add(vertex);
                    heap.remove(llbnd);
                    llbnd.vertex = vertex;
                    llbnd.ystar = vertex.y + bottomSite.dist(vertex);
                    heap.insert(llbnd);
                }
                if ((vertex = Vertex.intersect(bisector, rrbnd)) != null)
                {
                    vertices.Add(vertex);
                    bisector.vertex = vertex;
                    bisector.ystar = vertex.y + bottomSite.dist(vertex);
                    heap.insert(bisector);
                }
            }
            else
            {
                break;
            }
        }

        // heap should be empty now
        heap.dispose();
        edgeList.dispose();

        //		foreach (Halfedge halfEdge in halfEdges)
        //		{
        //			halfEdge.reallyDispose();
        //		}
        halfEdges.Clear();// = 0;

        // we need the vertices to clip the edges
        foreach (Edge edge1 in _edges)
        {
            edge1.clipVertices(_plotBounds);
        }
        // but we don't actually ever use them again!
        //		foreach (vertex in vertices)
        //		{
        //			vertex.dispose();
        //		}
        vertices.Clear();// = 0;
    }