algorithms-for-computing-li.../src/main/java/de/wwwu/awolf/presenter/util/BentleyOttmann.java

193 lines
6.5 KiB
Java

package de.wwwu.awolf.presenter.util;
import de.wwwu.awolf.model.dao.Interval;
import de.wwwu.awolf.model.dao.Line;
import de.wwwu.awolf.model.dao.Line.Segment;
import de.wwwu.awolf.model.dao.Point;
import de.wwwu.awolf.model.dao.Event;
import java.util.*;
/**
* source code:
* https://github.com/valenpe7/bentley-ottmann
* Created by valen_000 on 14. 5. 2017.
*/
public class BentleyOttmann {
private Queue<Event> Q;
private NavigableSet<Segment> T;
private Set<Point> X;
private Collection<Line> lines;
BentleyOttmann(Collection<Line> lines) {
this.Q = new PriorityQueue<>(new event_comparator());
this.T = new TreeSet<>(new segment_comparator());
this.X = new HashSet<>();
this.lines = lines;
lines.forEach(line -> {
Segment segment = line.getSegment();
this.Q.add(new Event(segment.first(), segment, 0));
this.Q.add(new Event(segment.second(), segment, 1));
});
}
public void find_intersections() {
while(!this.Q.isEmpty()) {
Event e = this.Q.poll();
double L = e.get_value();
switch(e.get_type()) {
case 0:
for(Segment s : e.get_segments()) {
this.recalculate(L);
this.T.add(s);
if(this.T.lower(s) != null) {
Segment r = this.T.lower(s);
this.report_intersection(r, s, L);
}
if(this.T.higher(s) != null) {
Segment t = this.T.higher(s);
this.report_intersection(t, s, L);
}
if(this.T.lower(s) != null && this.T.higher(s) != null) {
Segment r = this.T.lower(s);
Segment t = this.T.higher(s);
this.remove_future(r, t);
}
}
break;
case 1:
for(Segment s : e.get_segments()) {
if(this.T.lower(s) != null && this.T.higher(s) != null) {
Segment r = this.T.lower(s);
Segment t = this.T.higher(s);
this.report_intersection(r, t, L);
}
this.T.remove(s);
}
break;
case 2:
Segment s_1 = e.get_segments().get(0);
Segment s_2 = e.get_segments().get(1);
this.swap(s_1, s_2);
if(s_1.get_value() < s_2.get_value()) {
if(this.T.higher(s_1) != null) {
Segment t = this.T.higher(s_1);
this.report_intersection(t, s_1, L);
this.remove_future(t, s_2);
}
if(this.T.lower(s_2) != null) {
Segment r = this.T.lower(s_2);
this.report_intersection(r, s_2, L);
this.remove_future(r, s_1);
}
} else {
if(this.T.higher(s_2) != null) {
Segment t = this.T.higher(s_2);
this.report_intersection(t, s_2, L);
this.remove_future(t, s_1);
}
if(this.T.lower(s_1) != null) {
Segment r = this.T.lower(s_1);
this.report_intersection(r, s_1, L);
this.remove_future(r, s_2);
}
}
this.X.add(e.get_point());
break;
}
}
}
private boolean report_intersection(Segment s_1, Segment s_2, double L) {
double x1 = s_1.first().getX();
double y1 = s_1.first().getY();
double x2 = s_1.second().getX();
double y2 = s_1.second().getY();
double x3 = s_2.first().getX();
double y3 = s_2.first().getY();
double x4 = s_2.second().getX();
double y4 = s_2.second().getY();
double r = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3);
if(r != 0) {
double t = ((x3 - x1) * (y4 - y3) - (y3 - y1) * (x4 - x3)) / r;
double u = ((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) / r;
if(t >= 0 && t <= 1 && u >= 0 && u <= 1) {
double x_c = x1 + t * (x2 - x1);
double y_c = y1 + t * (y2 - y1);
if(x_c > L) {
this.Q.add(new Event(new Point(x_c, y_c), new ArrayList<>(Arrays.asList(s_1, s_2)), 2));
return true;
}
}
}
return false;
}
private boolean remove_future(Segment s_1, Segment s_2) {
for(Event e : this.Q) {
if(e.get_type() == 2) {
if((e.get_segments().get(0) == s_1 && e.get_segments().get(1) == s_2) || (e.get_segments().get(0) == s_2 && e.get_segments().get(1) == s_1)) {
this.Q.remove(e);
return true;
}
}
}
return false;
}
private void swap(Segment s_1, Segment s_2) {
this.T.remove(s_1);
this.T.remove(s_2);
double value = s_1.get_value();
s_1.set_value(s_2.get_value());
s_2.set_value(value);
this.T.add(s_1);
this.T.add(s_2);
}
private void recalculate(double L) {
Iterator<Segment> iter = this.T.iterator();
while(iter.hasNext()) {
iter.next().calculate_value(L);
}
}
public void print_intersections() {
for(Point p : this.X) {
Logging.logInfo("Intersection: (" + p.getX() + ", " + p.getY() + ")");
}
}
public Set<Point> get_intersections() {
print_intersections();
return this.X;
}
private class event_comparator implements Comparator<Event> {
@Override
public int compare(Event e_1, Event e_2) {
if(e_1.get_value() > e_2.get_value()) {
return 1;
}
if(e_1.get_value() < e_2.get_value()) {
return -1;
}
return 0;
}
}
private class segment_comparator implements Comparator<Segment> {
@Override
public int compare(Segment s_1, Segment s_2) {
if(s_1.get_value() < s_2.get_value()) {
return 1;
}
if(s_1.get_value() > s_2.get_value()) {
return -1;
}
return 0;
}
}
}