我在Processing中编写了一个程序,用于实现线段交叉问题的Bentley-Ottmann算法。
程序返回一组点,但没有找到所有的交点。有谁能告诉我,我做错了什么?
我想我遵循了算法所需的所有步骤。我研究了“计算几何 - 算法和应用”,以及一个名为“计算一组线段中的交叉点:Bentley-Ottmann算法”的文章,来自Michiel Smid。
虽然,我没有考虑垂直线的限制,与三个线段的交叉等。大多数时候要求得到满足,但结果仍然不是预期的。
这是一个例子
这是我的代码
import java.util.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
Algorithm algorithm = new Algorithm();
List<Line2D> initialList = new ArrayList<Line2D>();
List<Double> xStructure = new ArrayList<Double>();
Set<Point2D> intersections = new HashSet<Point2D>();
void setup() {
size(640, 480);
initialList = algorithm.createListOfRandomLines(5);
long start = System.currentTimeMillis();
intersections = algorithm.runBentleyOttmann(initialList);
long stop = System.currentTimeMillis() - start;
System.out.println(String.format("Execution Time: %f sec", (float)TimeUnit.MILLISECONDS.toSeconds(stop)));
}
void draw() {
background(255);
strokeWeight(1);
stroke(0);
for(Line2D l : initialList)
line((float)l.getX1(), (float)l.getY1(), (float)l.getX2(), (float)l.getY2());
strokeWeight(5);
stroke(255,0,0);
for(Point2D p : intersections)
point((float)p.getX(), (float)p.getY());
}
class Algorithm {
TreeMap<Double, List<Line2D>> xStructure;
Double slPosition;
List<Line2D> slStatus; // Y-structure
Set<Point2D> intersectionPoints;
public Algorithm() {
intersectionPoints = new HashSet<Point2D>();
slPosition = Double.MIN_VALUE;
slStatus = new ArrayList<Line2D>();
xStructure = new TreeMap<Double, List<Line2D>>();
}
public Set<Point2D> runBentleyOttmann(List<Line2D> list) {
//System.out.println("DEBUG INFO: runBentleyOttmann got input a list of " + list.size() + " line segments.");
xStructure = createMapOfSortedEndpointsAndCorespondingLineSegment(list);
//System.out.println("DEBUG INFO: runBentleyOttmann x-structure now contains the " + xStructure.size() + " endpoints.");
//System.out.println("DEBUG INTO: runBentleyOttmann sweep line is at position " + slPosition);
//System.out.println("DEBUG INFO: runBentleyOttmann begins while loop");
while (!xStructure.isEmpty()) {
Map.Entry<Double, List<Line2D>> entry = xStructure.pollFirstEntry();
Double min = entry.getKey();
slPosition = min;
List<Line2D> lines = entry.getValue();
//System.out.println("-----DEBUG INFO: runBentleyOttmann let min be the minimum element of x-structure " + min);
//System.out.println("-----DEBUG INFO: runBentleyOttmann delete min from the x-structure");
//System.out.println("-----DEBUG INFO: runBentleyOttmann checks endpoint type");
if (checkEndpointType(lines) == EndpointType.LEFT) {
//System.out.println("----------DEBUG INFO: Endpoint Type LEFT");
handleLeftEndpoint(lines);
}
else if (checkEndpointType(lines) == EndpointType.RIGHT) {
//System.out.println("----------DEBUG INFO: Endpoint Type RIGHT");
handleRightEndpoint(lines);
}
else if (checkEndpointType(lines) == EndpointType.INTERSECTION) {
//System.out.println("----------DEBUG INFO: Endpoint Type INTERSECTION");
handleIntersectionEndpoint(lines);
}
}
//System.out.println("DEBUG INFO: runBentleyOttmann ends while loop");
return intersectionPoints;
}
public void handleIntersectionEndpoint(List<Line2D> lines) {
Line2D l1 = slStatus.get(slStatus.indexOf(lines.get(0)));
Line2D l2 = slStatus.get(slStatus.indexOf(lines.get(1)));
if (slStatus.indexOf(l1) > slStatus.indexOf(l2)) {
Line2D ltemp = slStatus.get(slStatus.indexOf(lines.get(0)));
l1 = l2;
l2 = ltemp;
}
Line2D prev;
Line2D next;
if (slStatus.indexOf(l1) > 0) {
prev = getAboveLine(l1);
if (prev != null)
if (l2.intersectsLine(prev)) {
Point2D ip = findIntersectionPoint(l2, prev);
if (ip.getX() > slPosition) {
intersectionPoints.add(findIntersectionPoint(l2, prev));
List<Line2D> tempList = new ArrayList<Line2D>();
tempList.add(l2);
tempList.add(prev);
xStructure.put(ip.getX(), tempList);
}
}
}
if (slStatus.indexOf(l2) < slStatus.size()-1) {
next = getBelowLine(l2);
if (next != null)
if (l1.intersectsLine(next)) {
Point2D ip = findIntersectionPoint(l1, next);
if (ip.getX() > slPosition) {
intersectionPoints.add(findIntersectionPoint(l1, next));
List<Line2D> tempList = new ArrayList<Line2D>();
tempList.add(l1);
tempList.add(next);
xStructure.put(ip.getX(), tempList);
}
}
}
System.out.println(slStatus.indexOf(l1) + " " + slStatus.indexOf(l2));
}
public void handleLeftEndpoint(List<Line2D> lines) {
//System.out.println("HANDLE LEFT ENDPOINT started");
slStatus.add(lines.get(0));
//System.out.println("Line [X1=" + lines.get(0).getX1() + ", Y1=" + lines.get(0).getY1() + ", X2=" + lines.get(0).getX2() + ", Y2=" + lines.get(0).getY2() + "] added to Y-Structure.");
Collections.sort(slStatus, new YComparator());
//System.out.println("Y-Structure is sorted by Y endpoint");
Line2D above = getAboveLine(lines.get(0));
if (above != null)
if (lines.get(0).intersectsLine(above)) {
Point2D ip = findIntersectionPoint(lines.get(0), above);
if (ip.getX() > slPosition) {
intersectionPoints.add(findIntersectionPoint(lines.get(0), above));
List<Line2D> tempList = new ArrayList<Line2D>();
tempList.add(lines.get(0));
tempList.add(above);
xStructure.put(ip.getX(), tempList);
}
}
Line2D below = getBelowLine(lines.get(0));
if (below != null)
if (lines.get(0).intersectsLine(below)) {
Point2D ip = findIntersectionPoint(lines.get(0), below);
if (ip.getX() > slPosition) {
intersectionPoints.add(findIntersectionPoint(lines.get(0), below));
List<Line2D> tempList = new ArrayList<Line2D>();
tempList.add(lines.get(0));
tempList.add(below);
xStructure.put(ip.getX(), tempList);
}
}
//System.out.println("HANDLE LEFT ENDPOINT finished");
}
public void handleRightEndpoint(List<Line2D> lines) {
//System.out.println("HANDLE RIGHT ENDPOINT started");
Line2D above = getAboveLine(lines.get(0));
Line2D below = getBelowLine(lines.get(0));
if (above != null && below != null)
if (above.intersectsLine(below)){
Point2D ip = findIntersectionPoint(lines.get(0), below);
if (ip.getX() > slPosition)
intersectionPoints.add(findIntersectionPoint(lines.get(0), below));
}
slStatus.remove(lines.get(0));
//System.out.println("Line [X1=" + lines.get(0).getX1() + ", Y1=" + lines.get(0).getY1() + ", X2=" + lines.get(0).getX2() + ", Y2=" + lines.get(0).getY2() + "] deleted from Y-Structure.");
}
public Line2D getAboveLine(Line2D line) {
if (slStatus.indexOf(line) > 0) {
Line2D a = slStatus.get(slStatus.indexOf(line)-1);
//System.out.println("getAboveLine returns line [X1=" + a.getX1() + ", Y1=" + a.getY1() + ", X2=" + a.getX2() + ", Y2=" + a.getY2() + "]");
return a;
}
//System.out.println("getAboveLine returns no line");
return null;
}
public Line2D getBelowLine(Line2D line) {
if (slStatus.indexOf(line) < slStatus.size()-1) {
Line2D b = slStatus.get(slStatus.indexOf(line)+1);
//System.out.println("getBelowLine returns line [X1=" + b.getX1() + ", Y1=" + b.getY1() + ", X2=" + b.getX2() + ", Y2=" + b.getY2() + "]");
//System.out.println("getAboveLine returns no line");
return b;
}
return null;
}
public EndpointType checkEndpointType(List<Line2D> lines) {
if (lines.size() == 2)
return EndpointType.INTERSECTION;
if (slStatus.contains(lines.get(0)))
return EndpointType.RIGHT;
if (!slStatus.contains(lines.get(0)))
return EndpointType.LEFT;
return null;
}
public List<Line2D> sortEndpointsByXCoordinate(List<Line2D> inputList) {
List<Line2D> returnList = new ArrayList(inputList);
Collections.sort(returnList, new XComparator());
return returnList;
}
public TreeMap<Double, List<Line2D>> createMapOfSortedEndpointsAndCorespondingLineSegment(List<Line2D> inputList) {
TreeMap returnTreeMap = new TreeMap<Double, Line2D>();
for (Line2D l : inputList) {
List<Line2D> tempList = new ArrayList<Line2D>();
tempList.add(l);
returnTreeMap.put(l.getX1(), tempList);
returnTreeMap.put(l.getX2(), tempList);
}
return returnTreeMap;
}
public List<Double> createListOfSortedEndpoints(List<Line2D> inputList) {
List<Double> returnList = new ArrayList<Double>();
for (Line2D l : inputList) {
returnList.add(l.getBounds().getX());
returnList.add(l.getBounds().getY());
}
Collections.sort(returnList);
//System.out.println("DEBUG INFO: createListOfSortedEndpoints returns " + returnList.size() + " endpoints");
return returnList;
}
public List<Line2D> createListOfRandomLines(int size) {
Set<Line2D> hashset = new HashSet<Line2D>();
Random random = new Random();
while (hashset.size() != size) {
Line2D line = new Line2D.Double();
line.setLine(random.nextInt(width-1)+1, random.nextInt(height-1)+1, random.nextInt(width-1)+1, random.nextInt(height-1)+1);
hashset.add(line);
}
List<Line2D> returnList = new ArrayList(hashset);
return returnList;
}
public Point2D findIntersectionPoint(Line2D l1, Line2D l2) {
Double p0_x = l1.getX1();
Double p0_y = l1.getY1();
Double p1_x = l1.getX2();
Double p1_y = l1.getY2();
Double p2_x = l2.getX1();
Double p2_y = l2.getY1();
Double p3_x = l2.getX2();
Double p3_y = l2.getY2();
Double s1_x = p1_x - p0_x;
Double s1_y = p1_y - p0_y;
Double s2_x = p3_x - p2_x;
Double s2_y = p3_y - p2_y;
Double s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
Double i_x, i_y;
i_x = p0_x + (t * s1_x);
i_y = p0_y + (t * s1_y);
Point2D p = new Point2D.Double(i_x, i_y);
return p;
}
}
class XComparator implements Comparator<Line2D>{
public int compare(Line2D l1, Line2D l2){
return new Double(l1.getBounds().getX()).compareTo(l2.getBounds().getX());
}
}
class YComparator implements Comparator<Line2D>{
public int compare(Line2D l1, Line2D l2){
return new Double(l1.getBounds().getY()).compareTo(l2.getBounds().getY());
}
}
enum EndpointType {
LEFT, RIGHT, INTERSECTION
};
答案 0 :(得分:0)
我建议考虑以下Java实现:https://github.com/stanislav-antonov/bentley-ottmann
它非常干净和简约,但是仍然可以处理所有主要的边缘情况。