[英]Algorithm to split self-intersected Path2D into several not self-intersected paths?
我需要擺脫形狀中的自相交。 形狀由一組點構成,因此該形狀的所有線段都是線。 (只有直線,沒有曲線和圓弧)
以前,我嘗試從這些點創建 Path2D,從中構造一個區域,然后使用它的 PathIterator 我創建了幾個 Path2D,它們不知何故是先前路徑的子路徑,因此自相交消失了。 但這對某些路徑不起作用 - 自相交仍然存在。
所以你能指出我可以找到好的算法來做類似事情的地方嗎?
編輯:我在任何地方都沒有發現任何有用的東西,所以我編寫了自己的算法。 查看答案。
如果Area
不適合您,您可以嘗試使用GLUtessellator將您的Shape
分解為一組三角形,或者(使用GL_LINE_LOOP
選項)只是邊界邊緣。
所以,因為我在網上找不到這樣的東西,所以我寫了自己的算法。
它可能非常無效,但對我來說它的工作速度足夠快。
它是這樣的:
/**
* 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;
}
}
我為您的問題/答案添加了書簽,以防萬一我必須自己實現類似的東西,但后來我找到了GEOS項目,它有一個簡單的方法來實現這一點。 我正在從 Python/Django 調用 GEOS,但整個過程基於JTS(Java 拓撲套件),所以我將從那里開始並將以下 Python 視為偽代碼。
基本上,如果一條線不是簡單連接的,則 UNION 操作會將其拆分為簡單連接的部分( 在此處解釋),因此將線與其第一點聯合起來就可以滿足我們的需求:
line = LineString(list_of_lines_x_y_coordinates)
# union with first point splits into MultiLineString containing segments
segments = line.union(line[0])
我事先表示歉意。 (我尚無法評論。)這不是答案,而是@Rogach在“寶石”帖子上的問題。 我試圖編譯代碼,但陷入困境:double infS = HEADER.infS; 什么是HEADER?
另外,自您的第一篇文章發表以來,您有更好或更快速的算法嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.