Java 将自交路径2D拆分为多条非自交路径的算法?
我需要消除形状中的自相交。形状是由一组点构成的,因此该形状的所有线段都是直线。(仅直线,无曲线和圆弧) 以前,我试图从这些点创建Path2D,从中构造一个区域,然后使用其PathIterator创建了几个Path2D,它们不知何故是前一条路径的子路径,因此自连接消失了。但这对某些路径不起作用-自相交仍然存在 你们能给我指个地方吗?在那个里我可以找到好的算法来做类似的事情Java 将自交路径2D拆分为多条非自交路径的算法?,java,algorithm,geometry,pathgeometry,Java,Algorithm,Geometry,Pathgeometry,我需要消除形状中的自相交。形状是由一组点构成的,因此该形状的所有线段都是直线。(仅直线,无曲线和圆弧) 以前,我试图从这些点创建Path2D,从中构造一个区域,然后使用其PathIterator创建了几个Path2D,它们不知何故是前一条路径的子路径,因此自连接消失了。但这对某些路径不起作用-自相交仍然存在 你们能给我指个地方吗?在那个里我可以找到好的算法来做类似的事情 编辑:我在任何地方都没有找到任何有用的东西,所以我编写了自己的算法。查看答案。如果区域不适合您,您可以尝试使用a将形状分解为一
编辑:我在任何地方都没有找到任何有用的东西,所以我编写了自己的算法。查看答案。如果
区域
不适合您,您可以尝试使用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
或在迭代结束时。是的,这可能是问题。但在这条道路上,“关闭”后面总是跟着“移动”。无论如何,我想我对分裂算法有个好主意。当我完成后,我会在这个问题中发布它。我也一直在研究这个问题-我怀疑你的算法不能处理二次问题