Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 获取由Voronoi线段形成的凸多边形集的最快方法_Java_Algorithm_Computational Geometry_Voronoi - Fatal编程技术网

Java 获取由Voronoi线段形成的凸多边形集的最快方法

Java 获取由Voronoi线段形成的凸多边形集的最快方法,java,algorithm,computational-geometry,voronoi,Java,Algorithm,Computational Geometry,Voronoi,我用Fortune的算法找到了一组点的Voronoi图。 我得到的是一个线段列表,但我需要知道哪些线段形成闭合多边形,并将它们放在一个对象中,由它们围绕的原点散列 找到这些的最快方法是什么?? 我应该从算法中保存一些关键信息吗?如果是,什么 这是我在C++中实现的java的Foxy算法的移植,它是C++实现的 Voronoi类{ //控制单元中心的点集 私人LinkedList临时秘书处; //定义单元划分位置的线段列表 私有链接列表输出; //尚未处理的场地,按X坐标的顺序排列 私人优先队列站

我用Fortune的算法找到了一组点的Voronoi图。 我得到的是一个线段列表,但我需要知道哪些线段形成闭合多边形,并将它们放在一个对象中,由它们围绕的原点散列

找到这些的最快方法是什么?? 我应该从算法中保存一些关键信息吗?如果是,什么

这是我在C++中实现的java的Foxy算法的移植,它是C++实现的

Voronoi类{
//控制单元中心的点集
私人LinkedList临时秘书处;
//定义单元划分位置的线段列表
私有链接列表输出;
//尚未处理的场地,按X坐标的顺序排列
私人优先队列站点;
//可能即将发生的cirlce事件,以X坐标的顺序排列
私有优先级队列事件;
//抛物线波阵面二元搜索树的根
私家弧根;
void runFortune(链接列表pts){
网站。清除();
事件。清除();
output.clear();
root=null;
p点;
ListIterator i=pts.ListIterator(0);
while(i.hasNext()){
提供(i.next());
}
//处理队列;选择x坐标较小的顶部元素。
而(sites.size()>0){
如果((events.size()>0)和(((CircleEvent)events.peek()).xpos)0){
processCircleEvent((CircleEvent)events.poll());
}
//清理悬垂的边缘。
finishEdges();
}
私有无效进程CircleEvent(CircleEvent事件){
if(event.valid){
//开始新的优势
边缘边缘Y=新边缘(事件p);
//从前面拆下相关的弧。
Arc parc=事件a;
如果(parc.prev!=null){
parc.prev.next=parc.next;
parc.prev.edge1=边缘;
}
如果(parc.next!=null){
parc.next.prev=parc.prev;
parc.next.edge0=边缘;
}
//完成此圆弧前后的边。
如果(parc.edge0!=null){
地块边缘0.饰面(事件p);
}
如果(parc.edge1!=null){
地块边缘1完工(事件p);
}
//重新检查p两侧的圆圈事件:
如果(parc.prev!=null){
checkCircleEvent(parc.prev,event.xpos);
}
如果(parc.next!=null){
checkCircleEvent(parc.next,event.xpos);
}
}
}
空心前镶件(点焦点){
if(root==null){
根=新弧(焦点);
返回;
}
弧parc=根;
while(parc!=null){
CircleResultPack rez=相交(焦点,parc);
如果(rez.有效){
//新抛物线与parc相交。如有必要,复制parc。
如果(parc.next!=null){
CircleResultPack rezz=相交(焦点,下一个地块);
如果(!rezz.valid){
弧bla=新弧(parc.focus);
bla.prev=parc;
bla.next=parc.next;
parc.next.prev=bla;
parc.next=bla;
}
}否则{
parc.next=新弧(parc.focus);
parc.next.prev=parc;
}
parc.next.edge1=parc.edge1;
//在parc和parc之间添加新圆弧。下一步。
电弧bla=新电弧(焦点);
bla.prev=parc;
bla.next=parc.next;
parc.next.prev=bla;
parc.next=bla;
parc=parc.next;//现在parc指向新圆弧。
//添加连接到parc端点的新半边。
parc.edge0=新边(重新定位中心);
parc.prev.edge1=parc.edge0;
parc.edge1=新边(重新定位中心);
parc.next.edge0=parc.edge1;
//检查新圆弧周围的新圆圈事件:
checkCircleEvent(parc,focus.x);
检查CircleEvent(parc.prev,focus.x);
选中CircleEvent(parc.next,focus.x);
返回;
}
//继续下一个弧
parc=parc.next;
}
//特殊情况:如果p从未与弧相交,则将其附加到列表中。
parc=根;
while(parc.next!=null){
parc=parc.next;//查找最后一个节点。
}
parc.next=新弧(焦点);
parc.next.prev=parc;
点开始=新点(0,(parc.next.focus.y+parc.focus.y)/2);
parc.next.edge0=新边(开始);
parc.edge1=parc.next.edge0;
}
无效检查循环通风(Arc parc,双XPO){
//使任何旧事件无效。
if((parc.event!=null)&&(parc.event.xpos!=xpos)){
parc.event.valid=false;
}
parc.event=null;
如果((parc.prev==null)| |(parc.next==null)){
返回;
}
CircleResultPack结果=圆形(parc.prev.focus、parc.focus、parc.next.focus);
if(result.valid&&result.rightmostX>xpos){
//创建新事件。
parc.event=新循环事件(result.rightmostX、result.center、parc);
活动报价(parc.event);
}
}
//通过a、b、c找到圆上最右边的点。
圆圈结果包圆圈(点a、点b、点c){
CircleResultPack结果=新CircleResultPack();
//检查bc是否是ab的“右转”。
如果((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y)>0){
result.valid=false;
返回结果;
}
//来自O'Rourke第2版第189页的算法。
双A=b.x-A.x;
双B=B.y-a.y;
双C=C.x-a.x;
双D=c.y-a.y;
双E=A*(A.x+b.x)+b*(A.y+b.y);
双F=C*(a.x+C.x)+D*(a.y+C.y);
双G=2*(A*(c.y-b.y)-b*(c.x-b.x));
如果(G==0){//点是共线的。
result.valid=false;
返回结果;
}
//圆的中心点。
点o=新点((D*E-B*F)/G,(A*F-C*E)/G);
class Voronoi {

// The set of points that control the centers of the cells
private LinkedList<Point> pts;
// A list of line segments that defines where the cells are divided
private LinkedList<Edge> output;
// The sites that have not yet been processed, in acending order of X coordinate
private PriorityQueue sites;
// Possible upcoming cirlce events in acending order of X coordinate
private PriorityQueue events;
// The root of the binary search tree of the parabolic wave front
private Arc root;

void runFortune(LinkedList pts) {

    sites.clear();
    events.clear();
    output.clear();
    root = null;

    Point p;
    ListIterator i = pts.listIterator(0);
    while (i.hasNext()) {
        sites.offer(i.next());
    }

    // Process the queues; select the top element with smaller x coordinate.
    while (sites.size() > 0) {
        if ((events.size() > 0) && ((((CircleEvent) events.peek()).xpos) <= (((Point) sites.peek()).x))) {
            processCircleEvent((CircleEvent) events.poll());
        } else {
            //process a site event by adding a curve to the parabolic front
            frontInsert((Point) sites.poll());
        }
    }

    // After all points are processed, do the remaining circle events.
    while (events.size() > 0) {
        processCircleEvent((CircleEvent) events.poll());
    }

    // Clean up dangling edges.
    finishEdges();

}

private void processCircleEvent(CircleEvent event) {
    if (event.valid) {
        //start a new edge
        Edge edgy = new Edge(event.p);

        // Remove the associated arc from the front.
        Arc parc = event.a;
        if (parc.prev != null) {
            parc.prev.next = parc.next;
            parc.prev.edge1 = edgy;
        }
        if (parc.next != null) {
            parc.next.prev = parc.prev;
            parc.next.edge0 = edgy;
        }

        // Finish the edges before and after this arc.
        if (parc.edge0 != null) {
            parc.edge0.finish(event.p);
        }
        if (parc.edge1 != null) {
            parc.edge1.finish(event.p);
        }

        // Recheck circle events on either side of p:
        if (parc.prev != null) {
            checkCircleEvent(parc.prev, event.xpos);
        }
        if (parc.next != null) {
            checkCircleEvent(parc.next, event.xpos);
        }

    }
}

void frontInsert(Point focus) {
    if (root == null) {
        root = new Arc(focus);
        return;
    }

    Arc parc = root;
    while (parc != null) {
        CircleResultPack rez = intersect(focus, parc);
        if (rez.valid) {
            // New parabola intersects parc.  If necessary, duplicate parc.

            if (parc.next != null) {
                CircleResultPack rezz = intersect(focus, parc.next);
                if (!rezz.valid){
                    Arc bla = new Arc(parc.focus);
                    bla.prev = parc;
                    bla.next = parc.next;
                    parc.next.prev = bla;
                    parc.next = bla;
                }
            } else {
                parc.next = new Arc(parc.focus);
                parc.next.prev = parc;
            }
            parc.next.edge1 = parc.edge1;

            // Add new arc between parc and parc.next.
            Arc bla = new Arc(focus);
            bla.prev = parc;
            bla.next = parc.next;
            parc.next.prev = bla;
            parc.next = bla;

            parc = parc.next; // Now parc points to the new arc.

            // Add new half-edges connected to parc's endpoints.
            parc.edge0 = new Edge(rez.center);
            parc.prev.edge1 = parc.edge0;
            parc.edge1 = new Edge(rez.center);
            parc.next.edge0 = parc.edge1;

            // Check for new circle events around the new arc:
            checkCircleEvent(parc, focus.x);
            checkCircleEvent(parc.prev, focus.x);
            checkCircleEvent(parc.next, focus.x);

            return;
        }

        //proceed to next arc
        parc = parc.next;
    }

    // Special case: If p never intersects an arc, append it to the list.
    parc = root;
    while (parc.next != null) {
        parc = parc.next; // Find the last node.
    }
    parc.next = new Arc(focus);
    parc.next.prev = parc;
    Point start = new Point(0, (parc.next.focus.y + parc.focus.y) / 2);
    parc.next.edge0 = new Edge(start);
    parc.edge1 = parc.next.edge0;

}

void checkCircleEvent(Arc parc, double xpos) {
    // Invalidate any old event.
    if ((parc.event != null) && (parc.event.xpos != xpos)) {
        parc.event.valid = false;
    }
    parc.event = null;

    if ((parc.prev == null) || (parc.next == null)) {
        return;
    }

    CircleResultPack result = circle(parc.prev.focus, parc.focus, parc.next.focus);
    if (result.valid && result.rightmostX > xpos) {
        // Create new event.
        parc.event = new CircleEvent(result.rightmostX, result.center, parc);
        events.offer(parc.event);
    }

}

// Find the rightmost point on the circle through a,b,c.
CircleResultPack circle(Point a, Point b, Point c) {
    CircleResultPack result = new CircleResultPack();

    // Check that bc is a "right turn" from ab.
    if ((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y) > 0) {
        result.valid = false;
        return result;
    }

    // Algorithm from O'Rourke 2ed p. 189.
    double A = b.x - a.x;
    double B = b.y - a.y;
    double C = c.x - a.x;
    double D = c.y - a.y;
    double E = A * (a.x + b.x) + B * (a.y + b.y);
    double F = C * (a.x + c.x) + D * (a.y + c.y);
    double G = 2 * (A * (c.y - b.y) - B * (c.x - b.x));

    if (G == 0) { // Points are co-linear.
        result.valid = false;
        return result;
    }

    // centerpoint of the circle.
    Point o = new Point((D * E - B * F) / G, (A * F - C * E) / G);
    result.center = o;

    // o.x plus radius equals max x coordinate.
    result.rightmostX = o.x + Math.sqrt(Math.pow(a.x - o.x, 2.0) + Math.pow(a.y - o.y, 2.0));

    result.valid = true;
    return result;
}

// Will a new parabola at point p intersect with arc i?
CircleResultPack intersect(Point p, Arc i) {
    CircleResultPack res = new CircleResultPack();
    res.valid = false;
    if (i.focus.x == p.x) {
        return res;
    }

    double a = 0.0;
    double b = 0.0;
    if (i.prev != null) // Get the intersection of i->prev, i.
    {
        a = intersection(i.prev.focus, i.focus, p.x).y;
    }
    if (i.next != null) // Get the intersection of i->next, i.
    {
        b = intersection(i.focus, i.next.focus, p.x).y;
    }

    if ((i.prev == null || a <= p.y) && (i.next == null || p.y <= b)) {
        res.center = new Point(0, p.y);

        // Plug it back into the parabola equation to get the x coordinate
        res.center.x = (i.focus.x * i.focus.x + (i.focus.y - res.center.y) * (i.focus.y - res.center.y) - p.x * p.x) / (2 * i.focus.x - 2 * p.x);

        res.valid = true;
        return res;
    }
    return res;
}

// Where do two parabolas intersect?
Point intersection(Point p0, Point p1, double l) {
    Point res = new Point(0, 0);
    Point p = p0;

    if (p0.x == p1.x) {
        res.y = (p0.y + p1.y) / 2;
    } else if (p1.x == l) {
        res.y = p1.y;
    } else if (p0.x == l) {
        res.y = p0.y;
        p = p1;
    } else {
        // Use the quadratic formula.
        double z0 = 2 * (p0.x - l);
        double z1 = 2 * (p1.x - l);

        double a = 1 / z0 - 1 / z1;
        double b = -2 * (p0.y / z0 - p1.y / z1);
        double c = (p0.y * p0.y + p0.x * p0.x - l * l) / z0 - (p1.y * p1.y + p1.x * p1.x - l * l) / z1;

        res.y = (-b - Math.sqrt((b * b - 4 * a * c))) / (2 * a);
    }
    // Plug back into one of the parabola equations.
    res.x = (p.x * p.x + (p.y - res.y) * (p.y - res.y) - l * l) / (2 * p.x - 2 * l);
    return res;
}

void finishEdges() {
    // Advance the sweep line so no parabolas can cross the bounding box.
    double l = gfx.width * 2 + gfx.height;

    // Extend each remaining segment to the new parabola intersections.
    Arc i = root;
    while (i != null) {
        if (i.edge1 != null) {
            i.edge1.finish(intersection(i.focus, i.next.focus, l * 2));
        }
        i = i.next;
    }
}

class Point implements Comparable<Point> {

    public double x, y;
    //public Point goal;

    public Point(double X, double Y) {
        x = X;
        y = Y;
    }

    public int compareTo(Point foo) {
        return ((Double) this.x).compareTo((Double) foo.x);
    }
}

class CircleEvent implements Comparable<CircleEvent> {

    public double xpos;
    public Point p;
    public Arc a;
    public boolean valid;

    public CircleEvent(double X, Point P, Arc A) {
        xpos = X;
        a = A;
        p = P;
        valid = true;
    }

    public int compareTo(CircleEvent foo) {
        return ((Double) this.xpos).compareTo((Double) foo.xpos);
    }
}

class Edge {

    public Point start, end;
    public boolean done;

    public Edge(Point p) {
        start = p;
        end = new Point(0, 0);
        done = false;
        output.add(this);
    }

    public void finish(Point p) {
        if (done) {
            return;
        }
        end = p;
        done = true;
    }
}

class Arc {
    //parabolic arc is the set of points eqadistant from a focus point and the beach line

    public Point focus;
    //these object exsit in a linked list
    public Arc next, prev;
    //
    public CircleEvent event;
    //
    public Edge edge0, edge1;

    public Arc(Point p) {
        focus = p;
        next = null;
        prev = null;
        event = null;
        edge0 = null;
        edge1 = null;
    }
}

class CircleResultPack {
    // stupid Java doesnt let me return multiple variables without doing this

    public boolean valid;
    public Point center;
    public double rightmostX;
}
}
LinkedList<Poly> polys;
//contains all polygons created by Voronoi edges

class Poly {
    //defines a single polygon
    public Point locus;
    public LinkedList<Points> verts;
}
for each vertex in Voronoi Diagram
    for each segment next to this point
       "walk around the perimeter" (just keep going counter-clockwise)
                     until you get back to the starting vertex