master
parent
91d3fc4c97
commit
14d146a452
@ -0,0 +1,64 @@
|
||||
package de.wwwu.awolf.model.dao;
|
||||
|
||||
import de.wwwu.awolf.model.dao.Line.Segment;
|
||||
import de.wwwu.awolf.model.dao.Point;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by valen_000 on 14. 5. 2017.
|
||||
*/
|
||||
|
||||
public class Event {
|
||||
|
||||
private Point point;
|
||||
private ArrayList<Segment> segments;
|
||||
private double value;
|
||||
private int type;
|
||||
|
||||
public Event(Point p, Segment s, int type) {
|
||||
this.point = p;
|
||||
this.segments = new ArrayList<>(Arrays.asList(s));
|
||||
this.value = p.getX();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Event(Point p, ArrayList<Segment> s, int type) {
|
||||
this.point = p;
|
||||
this.segments = s;
|
||||
this.value = p.getX();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void add_point(Point p) {
|
||||
this.point = p;
|
||||
}
|
||||
|
||||
public Point get_point() {
|
||||
return this.point;
|
||||
}
|
||||
|
||||
public void add_segment(Segment s) {
|
||||
this.segments.add(s);
|
||||
}
|
||||
|
||||
public ArrayList<Segment> get_segments() {
|
||||
return this.segments;
|
||||
}
|
||||
|
||||
public void set_type(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int get_type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void set_value(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double get_value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|