Java 将自交路径2D拆分为多条非自交路径的算法?

Java 将自交路径2D拆分为多条非自交路径的算法?,java,algorithm,geometry,pathgeometry,Java,Algorithm,Geometry,Pathgeometry,我需要消除形状中的自相交。形状是由一组点构成的,因此该形状的所有线段都是直线。(仅直线,无曲线和圆弧) 以前,我试图从这些点创建Path2D,从中构造一个区域,然后使用其PathIterator创建了几个Path2D,它们不知何故是前一条路径的子路径,因此自连接消失了。但这对某些路径不起作用-自相交仍然存在 你们能给我指个地方吗?在那个里我可以找到好的算法来做类似的事情 编辑:我在任何地方都没有找到任何有用的东西,所以我编写了自己的算法。查看答案。如果区域不适合您,您可以尝试使用a将形状分解为一

我需要消除形状中的自相交。形状是由一组点构成的,因此该形状的所有线段都是直线。(仅直线,无曲线和圆弧)

以前,我试图从这些点创建Path2D,从中构造一个区域,然后使用其PathIterator创建了几个Path2D,它们不知何故是前一条路径的子路径,因此自连接消失了。但这对某些路径不起作用-自相交仍然存在

你们能给我指个地方吗?在那个里我可以找到好的算法来做类似的事情


编辑:我在任何地方都没有找到任何有用的东西,所以我编写了自己的算法。查看答案。

如果
区域
不适合您,您可以尝试使用a将
形状
分解为一组三角形,或者(使用
GL\u LINE\u LOOP
选项)只是边界边。

因此,由于我在web上找不到类似的东西,我编写了自己的算法

这可能是疯狂的无效,但它的工作速度足够快,我

下面是:

/**
 * Takes a polygon, defined by a list of lines, and splits it into several
 * paths on points of intersection. If non-self-intersected path is passed in,
 * the same path is returned.
 * @param path
 * @return
 */
public static List<List<Line2D>> splitPath(List<Line2D> lines) {
    List<List<Line2D>> splitted = new ArrayList<List<Line2D>>();
    // find intersections.
    loop1:
    for (Line2D l1 : lines) {
        for (Line2D l2 : lines) {
            if (l1 == l2) continue;
            Point2D intr;
            if ((intr = linesIntersect(l1, l2)) != null) {
                // creating two splitted subpaths
                int i1 = lines.indexOf(l1);
                int i2 = lines.indexOf(l2);

                List<Line2D> subpath1 = new ArrayList<Line2D>();
                subpath1.addAll(lines.subList(0, i1));
                subpath1.add(new Line2D.Double(l1.getP1(), intr));
                subpath1.add(new Line2D.Double(intr, l2.getP2()));
                subpath1.addAll(lines.subList(i2 + 1, lines.size()));
                splitted.addAll(splitPath(subpath1));

                List<Line2D> subpath2 = new ArrayList<Line2D>();
                subpath2.add(new Line2D.Double(intr, l1.getP2()));
                subpath2.addAll(lines.subList(i1 + 1, i2));
                subpath2.add(new Line2D.Double(l2.getP1(), intr));
                splitted.addAll(splitPath(subpath2));
                break loop1;
            }
        }
    }
    if (splitted.size() > 0) {
        return splitted;
    } else {
        return Collections.singletonList(lines);
    }
}

/**
 * Returns point of intersection of this line segments.
 * @param l1
 * @param l2
 * @return
 */
public static Point2D linesIntersect(Line2D l1, Line2D l2) {
    if (l1.getP1().equals(l2.getP2()) || l1.getP2().equals(l2.getP1())) return null;
    Point2D inter = lineIntersection(l1, l2);
    if (inter == null) return null;
    double infS = HEADER.infS;
    double x = inter.getX();
    if (((l1.getX1() > l1.getX2()) ? (x + infS > l1.getX2() && x - infS < l1.getX1()) : (x - infS < l1.getX2() && x + infS > l1.getX1())) &&
           ((l2.getX1() > l2.getX2()) ? (x + infS > l2.getX2() && x - infS < l2.getX1()) : (x - infS < l2.getX2() && x + infS > l2.getX1()))) {
        return inter;
    } else {
        return null;
    }
}

/**
 * Returns point of lines intersection, or null if they are parallel.
 * @param l1
 * @param l2
 * @return
 */
public static Point2D lineIntersection(Line2D l1, Line2D l2) {
    double a1 = l1.getY2() - l1.getY1();
    double b1 = l1.getX1() - l1.getX2();
    double c1 = a1*l1.getX1() + b1*l1.getY1();
    double a2 = l2.getY2() - l2.getY1();
    double b2 = l2.getX1() - l2.getX2();
    double c2 = a2*l2.getX1() + b2*l2.getY1();
    double det = a1*b2 - a2*b1;
    if (det != 0) {
        double x = (b2*c1 - b1*c2)/det;
        double y = (a1*c2 - a2*c1)/det;
        return new Point2D.Double(x, y);
    } else {
        // lines are parallel
        return null;
    }
}
/**
*获取由线列表定义的多边形,并将其拆分为多个
*交叉点上的路径。如果传入非自交路径,
*返回相同的路径。
*@param路径
*@返回
*/
公共静态列表拆分路径(列表行){
List SPLITED=新的ArrayList();
//找到交叉点。
循环1:
对于(Line2D l1:线){
对于(Line2D l2:线){
如果(l1==l2)继续;
点2D intr;
if((intr=linesIntersect(l1,l2))!=null){
//创建两个拆分的子路径
int i1=行。indexOf(l1);
int i2=行。indexOf(l2);
列表子路径1=新建ArrayList();
子路径1.addAll(行.子列表(0,i1));
子路径1.add(newline2d.Double(l1.getP1(),intr));
子路径1.add(newline2d.Double(intr,l2.getP2());
子路径1.addAll(lines.subList(i2+1,lines.size());
splitted.addAll(splitPath(subpath1));
列表子路径2=新建ArrayList();
子路径2.add(新的Line2D.Double(intr,l1.getP2());
子路径2.添加所有(行.子列表(i1+1,i2));
子路径2.add(newline2d.Double(l2.getP1(),intr));
splitted.addAll(splitPath(subpath2));
打破循环1;
}
}
}
如果(拆分的.size()>0){
返回分裂;
}否则{
返回集合。单音列表(行);
}
}
/**
*返回此线段的交点。
*@param l1
*@param l2
*@返回
*/
公共静态点2D linesIntersect(Line2D l1、Line2D l2){
if(l1.getP1().equals(l2.getP2())| l1.getP2().equals(l2.getP1())返回null;
点2D内部=线交点(l1,l2);
if(inter==null)返回null;
双infS=HEADER.infS;
double x=inter.getX();
如果((l1.getX1()>l1.getX2())?(x+infS>l1.getX2()&&x-infSl1.getX1())&&
((l2.getX1()>l2.getX2())?(x+infS>l2.getX2()&&x-infSl2.getX1()){
返回间隔;
}否则{
返回null;
}
}
/**
*返回线的交点,如果它们平行,则返回null。
*@param l1
*@param l2
*@返回
*/
公共静态点2D直线交点(Line2D l1、Line2D l2){
双a1=l1.getY2()-l1.getY1();
双b1=l1.getX1()-l1.getX2();
双c1=a1*l1.getX1()+b1*l1.getY1();
双a2=l2.getY2()-l2.getY1();
双b2=l2.getX1()-l2.getX2();
双c2=a2*l2.getX1()+b2*l2.getY1();
双det=a1*b2-a2*b1;
如果(det!=0){
双x=(b2*c1-b1*c2)/det;
双y=(a1*c2-a2*c1)/det;
返回新的点2d.Double(x,y);
}否则{
//线是平行的
返回null;
}
}

我为你的问题/答案添加了书签,以防我不得不自己实现类似的东西,但后来我发现这个项目有一个简单的实现方法。我从Python/Django调用GEOS,但整个过程都基于,所以我从这里开始,将下面的Python作为psuedo代码处理

基本上,如果一条线不是简单连接的,则并集操作会将其拆分为简单连接的部分(已解释),因此将该线与其第一个点并集可以满足我们的需要:

line  = LineString(list_of_lines_x_y_coordinates)
# union with first point splits into MultiLineString containing segments
segments = line.union(line[0]) 

单个三次Bézier可以自相交,因此在一般情况下,需要将Bézier细分为两个。试着寻找一个关于“Bézier曲线细分”或“de Casteljau算法”的好解释。@Peter Taylor-不,正如我所说,没有bezier曲线。只有行。我使用
区域成功地完成了这项工作,但从未见过您描述的问题。你能举一个例子,说明一条路径会产生一个有自相交的
区域吗?它有点大。但是等一下,我会把它寄到pastebin一个路径,和一个我用来分割它的方法。顺便问一下,你能用Area发布你的分割代码吗?也许我的程序有问题。@Rogach,我现在没有时间查找示例,但我简单地查看了您的代码,发现了一个可能的错误:忽略
SEG\u CLOSE
。当您获得该标志时,您应该关闭当前循环(如有必要,在末尾添加第一个点的副本)。这可能不是问题,因为
SEG_close
后面总是跟着
SEG_MOVETO
或在迭代结束时。是的,这可能是问题。但在这条道路上,“关闭”后面总是跟着“移动”。无论如何,我想我对分裂算法有个好主意。当我完成后,我会在这个问题中发布它。我也一直在研究这个问题-我怀疑你的算法不能处理二次问题