added Bentley-Ottman Plane Sweep algorithm for intersection computation. Adjusted the algorithms.
This commit is contained in:
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,52 +13,18 @@ import org.apache.commons.math3.util.Precision;
|
||||||
public class Line implements Comparable<Line> {
|
public class Line implements Comparable<Line> {
|
||||||
|
|
||||||
private static final double EPSILON = 0.00001;
|
private static final double EPSILON = 0.00001;
|
||||||
private static final double MIN = 9999d;
|
private double x1;
|
||||||
private static final double MAX = -9999d;
|
private double x2;
|
||||||
|
private double y1;
|
||||||
|
private double y2;
|
||||||
|
private Segment segment;
|
||||||
private Double m;
|
private Double m;
|
||||||
private Double b;
|
private Double b;
|
||||||
|
|
||||||
private Double x1;
|
|
||||||
private Double x2;
|
|
||||||
private Double y1;
|
|
||||||
private Double y2;
|
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
/**
|
public Line(Double m, Double b) {
|
||||||
* Konstruktor
|
|
||||||
*
|
|
||||||
* @param m Steigung
|
|
||||||
* @param b y-Achsenabschnitt
|
|
||||||
* @param id id
|
|
||||||
*/
|
|
||||||
public Line(double m, double b, String id) {
|
|
||||||
this.m = m;
|
this.m = m;
|
||||||
this.b = b;
|
this.b = b;
|
||||||
|
|
||||||
this.x1 = MAX;
|
|
||||||
this.y1 = (MAX * m) + b;
|
|
||||||
this.x2 = MIN * 0.5;
|
|
||||||
this.y2 = ((MIN * 0.5) * m) + b;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Konstruktor
|
|
||||||
*
|
|
||||||
* @param m Steigung
|
|
||||||
* @param b y-Achsenabschnitt
|
|
||||||
*/
|
|
||||||
public Line(double m, double b) {
|
|
||||||
this.m = m;
|
|
||||||
this.b = b;
|
|
||||||
|
|
||||||
this.x1 = calculateX1(MAX);
|
|
||||||
this.y1 = calculateY1(MAX);
|
|
||||||
this.x2 = calculateX2(MIN * 0.5);
|
|
||||||
this.y2 = calculateY2(MIN * 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,29 +37,12 @@ public class Line implements Comparable<Line> {
|
||||||
*/
|
*/
|
||||||
public Line(double x1, double x2, double y1, double y2) {
|
public Line(double x1, double x2, double y1, double y2) {
|
||||||
this.x1 = x1;
|
this.x1 = x1;
|
||||||
this.x2 = x2;
|
|
||||||
this.y1 = y1;
|
this.y1 = y1;
|
||||||
this.y2 = y2;
|
this.y2 = y2;
|
||||||
|
this.x2 = x2;
|
||||||
|
|
||||||
this.m = (y2 - y1) / (x2 - x1);
|
this.m = (y2 - y1) / (x2 - x1);
|
||||||
this.b = y2 - (x2 * m);
|
this.b = y2 - (x2 * m);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double calculateX1(Double min) {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double calculateY1(Double min) {
|
|
||||||
return (min * (m * -1)) + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double calculateX2(Double max) {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double calculateY2(Double max) {
|
|
||||||
return (max * (m * -1)) + b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,51 +87,6 @@ public class Line implements Comparable<Line> {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return x-Koordiante des Startpunkts
|
|
||||||
*/
|
|
||||||
public Double getX1() {
|
|
||||||
return x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return x-Koordiante des Endpunkts
|
|
||||||
*/
|
|
||||||
public Double getX2() {
|
|
||||||
return x2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return y-Koordiante des Startpunkts
|
|
||||||
*/
|
|
||||||
public Double getY1() {
|
|
||||||
return y1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return y-Koordiante des Endpunkts
|
|
||||||
*/
|
|
||||||
public Double getY2() {
|
|
||||||
return y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setzt die Koordianten des Segments. Aus dem Segment wird eine Gerade berechnet.
|
|
||||||
*
|
|
||||||
* @param x1 x-Koordiante des Startpunkts
|
|
||||||
* @param y1 y-Koordiante des Endpunkts
|
|
||||||
* @param x2 x-Koordinate des Startpunkts
|
|
||||||
* @param y2 y-Koordinte des Endpunkts
|
|
||||||
*/
|
|
||||||
public void setEndPoints(double x1, double y1, double x2, double y2) {
|
|
||||||
this.x1 = x1;
|
|
||||||
this.x2 = x2;
|
|
||||||
this.y1 = y1;
|
|
||||||
this.y2 = y2;
|
|
||||||
this.m = (y2 - y1) / (x2 - x1);
|
|
||||||
this.b = y2 - (x2 * m);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vergleich einzelner Geradern
|
* Vergleich einzelner Geradern
|
||||||
*
|
*
|
||||||
|
@ -218,74 +122,6 @@ public class Line implements Comparable<Line> {
|
||||||
return new Point(x, y);
|
return new Point(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given three colinear points p, q, r, the function checks if
|
|
||||||
// point q lies on line segment 'pr'
|
|
||||||
public boolean onSegment(Point p, Point q, Point r) {
|
|
||||||
return q.getX() <= Math.max(p.getX(), r.getX()) && q.getX() >= Math
|
|
||||||
.min(p.getX(), r.getX()) &&
|
|
||||||
q.getY() <= Math.max(p.getY(), r.getY()) && q.getY() >= Math
|
|
||||||
.min(p.getY(), r.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
// To find orientation of ordered triplet (p, q, r).
|
|
||||||
// The function returns following values
|
|
||||||
// 0 --> p, q and r are colinear
|
|
||||||
// 1 --> Clockwise
|
|
||||||
// 2 --> Counterclockwise
|
|
||||||
public int orientation(Point p, Point q, Point r) {
|
|
||||||
// See https://www.geeksforgeeks.org/orientation-3-ordered-points/
|
|
||||||
// for details of below formula.
|
|
||||||
double val = (q.getY() - p.getY()) * (r.getX() - q.getX()) -
|
|
||||||
(q.getX() - p.getX()) * (r.getY() - q.getY());
|
|
||||||
|
|
||||||
if (val == 0) {
|
|
||||||
return 0; // colinear
|
|
||||||
}
|
|
||||||
|
|
||||||
return (val > 0) ? 1 : 2; // clock or counterclock wise
|
|
||||||
}
|
|
||||||
|
|
||||||
// The main function that returns true if line segment 'p1q1'
|
|
||||||
// and 'p2q2' intersect.
|
|
||||||
// Line A: y = mx + b -->
|
|
||||||
public boolean doIntersect(Line line, double lower, double upper) {
|
|
||||||
//this
|
|
||||||
Point p1 = new Point(calculateX1(lower), calculateY1(lower));
|
|
||||||
Point q1 = new Point(calculateX2(upper), calculateY2(upper));
|
|
||||||
Point p2 = new Point(line.calculateX1(lower), line.calculateY1(lower));
|
|
||||||
Point q2 = new Point(line.calculateX2(upper), line.calculateY2(upper));
|
|
||||||
// Find the four orientations needed for general and
|
|
||||||
// special cases
|
|
||||||
int o1 = orientation(p1, q1, p2);
|
|
||||||
int o2 = orientation(p1, q1, q2);
|
|
||||||
int o3 = orientation(p2, q2, p1);
|
|
||||||
int o4 = orientation(p2, q2, q1);
|
|
||||||
|
|
||||||
// General case
|
|
||||||
if (o1 != o2 && o3 != o4) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special Cases
|
|
||||||
// p1, q1 and p2 are colinear and p2 lies on segment p1q1
|
|
||||||
if (o1 == 0 && onSegment(p1, p2, q1)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// p1, q1 and q2 are colinear and q2 lies on segment p1q1
|
|
||||||
if (o2 == 0 && onSegment(p1, q2, q1)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2, q2 and p1 are colinear and p1 lies on segment p2q2
|
|
||||||
if (o3 == 0 && onSegment(p2, p1, q2)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2, q2 and q1 are colinear and q1 lies on segment p2q2
|
|
||||||
return o4 == 0 && onSegment(p2, q1, q2);// Doesn't fall in any of the above cases
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Line line) {
|
public int compareTo(Line line) {
|
||||||
if (Precision.compareTo(this.getM(), line.getM(), EPSILON) == 0) {
|
if (Precision.compareTo(this.getM(), line.getM(), EPSILON) == 0) {
|
||||||
|
@ -294,4 +130,89 @@ public class Line implements Comparable<Line> {
|
||||||
return this.getM().compareTo(line.getM());
|
return this.getM().compareTo(line.getM());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Segment getSegment(Interval interval) {
|
||||||
|
double xLow = interval.getLower();
|
||||||
|
double yLow = Double.NEGATIVE_INFINITY;
|
||||||
|
double xHigh = interval.getUpper();
|
||||||
|
double yHigh = Double.POSITIVE_INFINITY;
|
||||||
|
|
||||||
|
if (interval.getLower() > Double.MIN_VALUE && !Double.isNaN((interval.getLower() * m + b)) && !Double.isInfinite(interval.getLower() * m + b)) {
|
||||||
|
yLow = interval.getLower() * m + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interval.getUpper() < Double.MAX_VALUE && !Double.isNaN(interval.getUpper() * m + b) && !Double.isInfinite(interval.getUpper() * m + b) ) {
|
||||||
|
yHigh = interval.getUpper() * m + b;
|
||||||
|
}
|
||||||
|
this.segment = new Segment(new Point(xLow, yLow), new Point(xHigh, yHigh));
|
||||||
|
|
||||||
|
return this.segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Segment getSegment() {
|
||||||
|
this.segment = new Segment(new Point(x1, y1), new Point(x2, y2));
|
||||||
|
return this.segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX1() {
|
||||||
|
return x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX2() {
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY1() {
|
||||||
|
return y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY2() {
|
||||||
|
return y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Segment {
|
||||||
|
|
||||||
|
private Point p_1;
|
||||||
|
private Point p_2;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
Segment(Point p_1, Point p_2) {
|
||||||
|
this.p_1 = p_1;
|
||||||
|
this.p_2 = p_2;
|
||||||
|
this.calculate_value(this.first().getX());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point first() {
|
||||||
|
if(p_1.getX() <= p_2.getX()) {
|
||||||
|
return p_1;
|
||||||
|
} else {
|
||||||
|
return p_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point second() {
|
||||||
|
if(p_1.getX() <= p_2.getX()) {
|
||||||
|
return p_2;
|
||||||
|
} else {
|
||||||
|
return p_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculate_value(double value) {
|
||||||
|
double x1 = this.first().getX();
|
||||||
|
double x2 = this.second().getX();
|
||||||
|
double y1 = this.first().getY();
|
||||||
|
double y2 = this.second().getY();
|
||||||
|
this.value = y1 + (((y2 - y1) / (x2 - x1)) * (value - x1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_value(double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double get_value() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@ public class LineModel {
|
||||||
private Double min;
|
private Double min;
|
||||||
|
|
||||||
private Set<Line> lines;
|
private Set<Line> lines;
|
||||||
private Double xMinimum;
|
|
||||||
private Double xMaximum;
|
|
||||||
private Double yMinimum;
|
|
||||||
private Double yMaximum;
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,11 +25,6 @@ public class LineModel {
|
||||||
lines = new HashSet<>();
|
lines = new HashSet<>();
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
xMinimum = Double.MAX_VALUE;
|
|
||||||
xMaximum = Double.MIN_VALUE;
|
|
||||||
yMinimum = Double.MAX_VALUE;
|
|
||||||
yMaximum = Double.MIN_VALUE;
|
|
||||||
|
|
||||||
min = 0d;
|
min = 0d;
|
||||||
max = 0d;
|
max = 0d;
|
||||||
}
|
}
|
||||||
|
@ -73,72 +64,6 @@ public class LineModel {
|
||||||
this.size = lines.size();
|
this.size = lines.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Minimale x-Koordiante
|
|
||||||
*/
|
|
||||||
public Double getxMinimum() {
|
|
||||||
return xMinimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param xMinimum Minimale x-Koordiante
|
|
||||||
*/
|
|
||||||
public void setxMinimum(Double xMinimum) {
|
|
||||||
this.xMinimum = xMinimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Maximale x-Koordiante
|
|
||||||
*/
|
|
||||||
public Double getxMaximum() {
|
|
||||||
return xMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param xMaximum Maximale x-Koordiante
|
|
||||||
*/
|
|
||||||
public void setxMaximum(Double xMaximum) {
|
|
||||||
this.xMaximum = xMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Minimale y-Koordiante
|
|
||||||
*/
|
|
||||||
public Double getyMinimum() {
|
|
||||||
return yMinimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param yMinimum Minimale y-Koordiante
|
|
||||||
*/
|
|
||||||
public void setyMinimum(Double yMinimum) {
|
|
||||||
this.yMinimum = yMinimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Maximale y-Koordiante
|
|
||||||
*/
|
|
||||||
public Double getyMaximum() {
|
|
||||||
return yMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param yMaximum Maximale y-Koordiante
|
|
||||||
*/
|
|
||||||
public void setyMaximum(Double yMaximum) {
|
|
||||||
this.yMaximum = yMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setzt die minimalen, maximalen x- und y-Koordinaten
|
|
||||||
*/
|
|
||||||
public void resetRanges() {
|
|
||||||
xMinimum = Double.MAX_VALUE;
|
|
||||||
xMaximum = Double.MIN_VALUE;
|
|
||||||
yMinimum = Double.MAX_VALUE;
|
|
||||||
yMaximum = Double.MIN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package de.wwwu.awolf.presenter.algorithms.advanced;
|
package de.wwwu.awolf.presenter.algorithms.advanced;
|
||||||
|
|
||||||
import de.wwwu.awolf.model.dao.Interval;
|
|
||||||
import de.wwwu.awolf.model.dao.Line;
|
|
||||||
import de.wwwu.awolf.model.dao.Point;
|
|
||||||
import de.wwwu.awolf.model.communication.AlgorithmMessage;
|
import de.wwwu.awolf.model.communication.AlgorithmMessage;
|
||||||
import de.wwwu.awolf.model.communication.Message;
|
import de.wwwu.awolf.model.communication.Message;
|
||||||
import de.wwwu.awolf.model.communication.SubscriberType;
|
import de.wwwu.awolf.model.communication.SubscriberType;
|
||||||
|
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.presenter.AbstractPresenter;
|
import de.wwwu.awolf.presenter.AbstractPresenter;
|
||||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||||
import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||||
|
@ -49,6 +50,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
private double yInterception;
|
private double yInterception;
|
||||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||||
private Map<String, String> parameter;
|
private Map<String, String> parameter;
|
||||||
|
private Set<Point> intersections;
|
||||||
|
|
||||||
public LeastMedianOfSquaresEstimator() {
|
public LeastMedianOfSquaresEstimator() {
|
||||||
parameter = new HashMap<>();
|
parameter = new HashMap<>();
|
||||||
|
@ -78,27 +80,21 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
|
|
||||||
//(2.) Let U <- (-inf, inf) be the initial active intervals...
|
//(2.) Let U <- (-inf, inf) be the initial active intervals...
|
||||||
Comparator<Interval> comparator = (o1, o2) -> {
|
Comparator<Interval> comparator = Comparator.comparing(Interval::getDistance);
|
||||||
if (o1.getDistance() < o2.getDistance()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (o1.getDistance() > o2.getDistance()) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
intervals = new PriorityQueue<>(comparator);
|
intervals = new PriorityQueue<>(comparator);
|
||||||
intervals.add(new Interval(-10000, 10000));
|
intervals.add(new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
|
||||||
heightsigmaMin = Double.MAX_VALUE;
|
heightsigmaMin = Double.MAX_VALUE;
|
||||||
|
|
||||||
|
intersections = IntersectionComputer.getInstance().compute(setOfLines);
|
||||||
|
|
||||||
//(3.) Apply the following steps as long as the exists active intervals
|
//(3.) Apply the following steps as long as the exists active intervals
|
||||||
Interval interval;
|
Interval interval;
|
||||||
while (!this.intervals.isEmpty()) {
|
while (!this.intervals.isEmpty()) {
|
||||||
interval = this.intervals.peek();
|
interval = this.intervals.peek();
|
||||||
if (interval.getActivity()) {
|
if (interval.getActivity()) {
|
||||||
//(a.) Select any active Interval and calc. the inversions
|
//(a.) Select any active Interval and calc. the inversions
|
||||||
int numberOfIntersections = countInversions(interval);
|
long numberOfIntersections = countIntersections(interval);
|
||||||
|
|
||||||
//(b.) apply plane sweep
|
//(b.) apply plane sweep
|
||||||
if ((Double.parseDouble(parameter.get("Constant")) * n) >= numberOfIntersections) {
|
if ((Double.parseDouble(parameter.get("Constant")) * n) >= numberOfIntersections) {
|
||||||
|
@ -106,35 +102,27 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
} else {
|
} else {
|
||||||
//(c.) otherwise....
|
//(c.) otherwise....
|
||||||
// get random intersections point...
|
// get random intersections point...
|
||||||
Collection<Point> tmpIntersections = IntersectionComputer
|
Collection<Point> tmpIntersections = intersections;
|
||||||
.getInstance()
|
|
||||||
.compute(setOfLines, interval.getLower(), interval.getUpper());
|
|
||||||
boolean found = false;
|
|
||||||
for (Point tmpIntersection : tmpIntersections) {
|
for (Point tmpIntersection : tmpIntersections) {
|
||||||
if (tmpIntersection.getX() > interval.getLower()
|
if (tmpIntersection.getX() > interval.getLower()
|
||||||
&& tmpIntersection.getX() < interval.getUpper()) {
|
&& tmpIntersection.getX() < interval.getUpper()) {
|
||||||
intersectionsPoint = tmpIntersection.getX();
|
intersectionsPoint = tmpIntersection.getX();
|
||||||
found = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found) {
|
|
||||||
splitActiveSlab(intersectionsPoint, interval);
|
|
||||||
//(d.) this may update sigma min
|
|
||||||
upperBound(intersectionsPoint);
|
|
||||||
//(e.) for i={1,2}, call lower bound(Ui)
|
|
||||||
lowerBound(subSlabU1);
|
|
||||||
lowerBound(subSlabU2);
|
|
||||||
|
|
||||||
if (subSlabU1.getActivity()) {
|
splitActiveSlab(intersectionsPoint, interval);
|
||||||
this.intervals.add(subSlabU1);
|
//(d.) this may update sigma min
|
||||||
}
|
upperBound(intersectionsPoint);
|
||||||
if (subSlabU2.getActivity()) {
|
//(e.) for i={1,2}, call lower bound(Ui)
|
||||||
this.intervals.add(subSlabU2);
|
lowerBound(subSlabU1);
|
||||||
}
|
lowerBound(subSlabU2);
|
||||||
|
|
||||||
} else {
|
if (subSlabU1.getActivity()) {
|
||||||
this.intervals.poll();
|
this.intervals.add(subSlabU1);
|
||||||
|
}
|
||||||
|
if (subSlabU2.getActivity()) {
|
||||||
|
this.intervals.add(subSlabU2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -180,9 +168,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
* @param interval Intervall
|
* @param interval Intervall
|
||||||
* @return Anzahl der Schnittpunkte
|
* @return Anzahl der Schnittpunkte
|
||||||
*/
|
*/
|
||||||
public int countInversions(Interval interval) {
|
public long countIntersections(Interval interval) {
|
||||||
return IntersectionComputer.getInstance()
|
return this.intersections.stream().filter(point -> point.getX().compareTo(interval.getLower()) > 0 && point.getX().compareTo(interval.getUpper()) <= 0).count();
|
||||||
.compute(setOfLines, interval.getLower(), interval.getUpper()).size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,9 +184,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
|
|
||||||
//initialisiere die x-Queue mit den 2D Punkten und sortiere nach x-Lexikographischer Ordnung
|
//initialisiere die x-Queue mit den 2D Punkten und sortiere nach x-Lexikographischer Ordnung
|
||||||
List<Point> xQueue = new ArrayList<>();
|
List<Point> xQueue = new ArrayList<>();
|
||||||
Collection<Point> points = IntersectionComputer.getInstance()
|
for (Point point : intersections) {
|
||||||
.compute(setOfLines, interval.getLower(), interval.getUpper());
|
|
||||||
for (Point point : points) {
|
|
||||||
if (point.getX() >= interval.getLower() && point.getX() < interval.getUpper()) {
|
if (point.getX() >= interval.getLower() && point.getX() < interval.getUpper()) {
|
||||||
xQueue.add(point);
|
xQueue.add(point);
|
||||||
}
|
}
|
||||||
|
@ -216,8 +201,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
continue;
|
continue;
|
||||||
} else if (currentBracelet[0] < heightOfBracelet) {
|
} else if (currentBracelet[0] < heightOfBracelet) {
|
||||||
heightOfBracelet = currentBracelet[0];
|
heightOfBracelet = currentBracelet[0];
|
||||||
bracelet = new Line(current.getX(), current.getX(), currentBracelet[1],
|
bracelet = new Line(current.getX(), current.getX(), currentBracelet[1], currentBracelet[2]);
|
||||||
currentBracelet[2]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,11 +242,9 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
if (height < heightsigmaMin) {
|
if (height < heightsigmaMin) {
|
||||||
heightsigmaMin = height;
|
heightsigmaMin = height;
|
||||||
if (sigmaMin != null) {
|
if (sigmaMin != null) {
|
||||||
sigmaMin.setEndPoints(point, sortedLineSequence.get(i)
|
sigmaMin = new Line(point, sortedLineSequence.get(i), point, sortedLineSequence.get((i + kMinus) - 1));
|
||||||
, point, sortedLineSequence.get((i + kMinus) - 1));
|
|
||||||
} else {
|
} else {
|
||||||
sigmaMin = new Line(point, point, sortedLineSequence.get(i),
|
sigmaMin = new Line(point, point, sortedLineSequence.get(i), sortedLineSequence.get((i + kMinus) - 1));
|
||||||
sortedLineSequence.get((i + kMinus) - 1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,14 +279,16 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
uminList = getEjValues(pslab.getLower());
|
uminList = getEjValues(pslab.getLower());
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
Line level = new Line(pslab.getLower(), pslab.getUpper(), uminList.get(i),
|
Line level = new Line(pslab.getLower(), pslab.getUpper(), uminList.get(i), umaxList.get(i));
|
||||||
umaxList.get(i));
|
|
||||||
for (Line line : lines) {
|
for (Line line : lines) {
|
||||||
if ((line.getY1() < level.getY1()) && (line.getY2() < level.getY2())) {
|
Segment segment = line.getSegment(pslab);
|
||||||
|
Segment levelSegment = level.getSegment(pslab);
|
||||||
|
|
||||||
|
if ((segment.first().getY() < levelSegment.first().getY()) && (segment.second().getY() < levelSegment.second().getY())) {
|
||||||
alpha[i]++;
|
alpha[i]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((line.getY1() > level.getY1()) && (line.getY2() > level.getY2())) {
|
if ((segment.first().getY() > levelSegment.first().getY()) && (segment.second().getY() > levelSegment.second().getY())) {
|
||||||
strictlyGreater++;
|
strictlyGreater++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,10 +357,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
}
|
}
|
||||||
if (intersections.size() >= kMinusValue) {
|
if (intersections.size() >= kMinusValue) {
|
||||||
Collections.sort(intersections);
|
Collections.sort(intersections);
|
||||||
double height = Math
|
double height = Math.abs(intersections.get(0) - intersections.get(kMinusValue - 1));
|
||||||
.abs(intersections.get(0) - intersections.get(kMinusValue - 1));
|
return new Double[]{height, intersections.get(0), intersections.get(kMinusValue - 1)};
|
||||||
return new Double[]{height, intersections.get(0),
|
|
||||||
intersections.get(kMinusValue - 1)};
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -384,24 +366,17 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Line pepareResult() {
|
private Line pepareResult() {
|
||||||
|
double m = (getSigmaMin().getX1() + getSigmaMin().getX2()) * 0.5;
|
||||||
|
double b = (getSigmaMin().getY1() + getSigmaMin().getY2() ) * 0.5;
|
||||||
|
slope = m * -1;
|
||||||
|
yInterception = b;
|
||||||
|
|
||||||
if (this.subscriber != null) {
|
if (this.subscriber != null) {
|
||||||
double m = ((getSigmaMin().getX2() + getSigmaMin().getX1()) * 0.5);
|
|
||||||
double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * -0.5;
|
|
||||||
|
|
||||||
slope = m;
|
|
||||||
yInterception = b;
|
|
||||||
|
|
||||||
AlgorithmMessage data = new AlgorithmMessage();
|
AlgorithmMessage data = new AlgorithmMessage();
|
||||||
data.setAlgorithmType(getType());
|
data.setAlgorithmType(getType());
|
||||||
data.setType(SubscriberType.ALGORITHM);
|
data.setType(SubscriberType.ALGORITHM);
|
||||||
data.setLineData(new Line(m, b));
|
data.setLineData(new Line(slope, yInterception));
|
||||||
this.subscriber.onNext(data);
|
this.subscriber.onNext(data);
|
||||||
} else {
|
|
||||||
double m = (getSigmaMin().getX2() + getSigmaMin().getX1()) * 0.5;
|
|
||||||
double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * -0.5;
|
|
||||||
|
|
||||||
slope = m;
|
|
||||||
yInterception = b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Line(getSlope(), getYInterception());
|
return new Line(getSlope(), getYInterception());
|
||||||
|
|
|
@ -13,6 +13,7 @@ import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||||
import de.wwwu.awolf.presenter.util.Logging;
|
import de.wwwu.awolf.presenter.util.Logging;
|
||||||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -39,9 +40,9 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
private Interval original;
|
private Interval original;
|
||||||
|
|
||||||
//in der Literatur als L_i, C_i, und R_i bekannt
|
//in der Literatur als L_i, C_i, und R_i bekannt
|
||||||
private int countLeftSlab;
|
private long countLeftSlab;
|
||||||
private int countCenterSlab;
|
private long countCenterSlab;
|
||||||
private int countRightSlab;
|
private long countRightSlab;
|
||||||
|
|
||||||
//in der Literatur als L_i, C_i, und R_i bekannt
|
//in der Literatur als L_i, C_i, und R_i bekannt
|
||||||
private Set<Point> intersectionsInLeftSlab;
|
private Set<Point> intersectionsInLeftSlab;
|
||||||
|
@ -49,7 +50,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
private Set<Point> intersectionsInRightSlab;
|
private Set<Point> intersectionsInRightSlab;
|
||||||
|
|
||||||
private double r;
|
private double r;
|
||||||
private int n;
|
private long n;
|
||||||
private double k;
|
private double k;
|
||||||
private double kLow;
|
private double kLow;
|
||||||
private double kHigh;
|
private double kHigh;
|
||||||
|
@ -58,6 +59,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
private double yInterception;
|
private double yInterception;
|
||||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||||
private Map<String, String> parameter;
|
private Map<String, String> parameter;
|
||||||
|
private Set<Point> intersections;
|
||||||
|
|
||||||
public RepeatedMedianEstimator() {
|
public RepeatedMedianEstimator() {
|
||||||
parameter = new HashMap<>();
|
parameter = new HashMap<>();
|
||||||
|
@ -96,6 +98,8 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
double thetaLow = 0;
|
double thetaLow = 0;
|
||||||
double thetaHigh = 0;
|
double thetaHigh = 0;
|
||||||
|
|
||||||
|
intersections = IntersectionComputer.getInstance().compute(setOfLines);
|
||||||
|
|
||||||
while (countCenterSlab > 1) {
|
while (countCenterSlab > 1) {
|
||||||
n = countCenterSlab;
|
n = countCenterSlab;
|
||||||
r = Math.ceil(Math.pow(n, Double.parseDouble(parameter.get("Beta"))));
|
r = Math.ceil(Math.pow(n, Double.parseDouble(parameter.get("Beta"))));
|
||||||
|
@ -163,18 +167,13 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
*/
|
*/
|
||||||
public Double estimateMedianIntersectionAbscissas(List<Line> lines, Line sampledLine) {
|
public Double estimateMedianIntersectionAbscissas(List<Line> lines, Line sampledLine) {
|
||||||
|
|
||||||
List<Double> intersections = IntersectionComputer.getInstance()
|
//interval is the current interval
|
||||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
Set<Point> intersections = IntersectionComputer.getInstance().compute(lines);
|
||||||
original.getUpper());
|
long leftSize = intersections.stream().filter(p -> p.getX() <= interval.getLower()).count();
|
||||||
List<Double> left = IntersectionComputer.getInstance()
|
long centerSize = intersections.stream().filter(p -> p.getX() >= interval.getLower() && p.getX() < interval.getUpper()).count();
|
||||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
|
||||||
interval.getLower());
|
|
||||||
List<Double> center = IntersectionComputer.getInstance()
|
|
||||||
.calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(),
|
|
||||||
interval.getUpper());
|
|
||||||
|
|
||||||
double ki = Math.ceil((n - 1) * 0.5) - left.size();
|
double ki = Math.ceil((n - 1) * 0.5) - leftSize;
|
||||||
double i = (Math.ceil((Math.sqrt(n) * ki) / center.size()));
|
double i = (Math.ceil((Math.sqrt(n) * ki) / centerSize));
|
||||||
int accessIndex;
|
int accessIndex;
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
accessIndex = 0;
|
accessIndex = 0;
|
||||||
|
@ -183,8 +182,8 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
} else {
|
} else {
|
||||||
accessIndex = (int) i;
|
accessIndex = (int) i;
|
||||||
}
|
}
|
||||||
|
LinkedList<Point> points = new LinkedList<>(intersections);
|
||||||
return FastElementSelector.randomizedSelect(intersections, accessIndex);
|
return FastElementSelector.randomizedSelect(points, accessIndex).getX();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,20 +201,10 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
* Berechnet die Anzahl der Schnittpunkte pro Bereich. Insgesammt gibt es drei Bereiche: Im Intervall => (a,b], vor dem Intervall => (a', a], hinter dem Intervall => (b, b'].
|
* Berechnet die Anzahl der Schnittpunkte pro Bereich. Insgesammt gibt es drei Bereiche: Im Intervall => (a,b], vor dem Intervall => (a', a], hinter dem Intervall => (b, b'].
|
||||||
*/
|
*/
|
||||||
public void countNumberOfIntersectionsAbscissas(final double lower, final double upper) {
|
public void countNumberOfIntersectionsAbscissas(final double lower, final double upper) {
|
||||||
IntersectionComputer instance = IntersectionComputer.getInstance();
|
|
||||||
|
|
||||||
intersectionsInLeftSlab = new HashSet<>(
|
countLeftSlab = intersections.stream().filter(point -> point.getX().compareTo(lower) < 0).count();
|
||||||
instance.compute(setOfLines, interval.getLower(), lower));
|
countCenterSlab = intersections.stream().filter(point -> point.getX().compareTo(lower) >= 0 && point.getX().compareTo(upper) < 0).count();
|
||||||
intersectionsInCenterSlab = new HashSet<>(instance.compute(setOfLines, lower, upper));
|
countRightSlab = intersections.stream().filter(point -> point.getX().compareTo(upper) >= 0).count();
|
||||||
intersectionsInRightSlab = new HashSet<>(
|
|
||||||
instance.compute(setOfLines, upper, interval.getUpper()));
|
|
||||||
|
|
||||||
int tmp = new HashSet<>(
|
|
||||||
instance.compute(setOfLines, interval.getLower(), interval.getUpper()))
|
|
||||||
.size();
|
|
||||||
countLeftSlab = intersectionsInLeftSlab.size();
|
|
||||||
countCenterSlab = intersectionsInCenterSlab.size();
|
|
||||||
countRightSlab = intersectionsInRightSlab.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,7 +234,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Line pepareResult(final double thetaLow, final double thetaHigh) {
|
private Line pepareResult(final double thetaLow, final double thetaHigh) {
|
||||||
slope = thetaLow;
|
slope = thetaLow * -1;
|
||||||
List<Double> potentialYInterceptions = new ArrayList<>();
|
List<Double> potentialYInterceptions = new ArrayList<>();
|
||||||
setOfLines.forEach(line -> {
|
setOfLines.forEach(line -> {
|
||||||
potentialYInterceptions.add(line.getB() - (slope * line.getM()));
|
potentialYInterceptions.add(line.getB() - (slope * line.getM()));
|
||||||
|
@ -268,7 +257,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
||||||
/**
|
/**
|
||||||
* @return Anzahl der Geraden
|
* @return Anzahl der Geraden
|
||||||
*/
|
*/
|
||||||
public Integer getN() {
|
public Long getN() {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,14 @@ import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Flow;
|
import java.util.concurrent.Flow;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||||
|
@ -30,12 +32,11 @@ import java.util.concurrent.Flow;
|
||||||
*/
|
*/
|
||||||
public class TheilSenEstimator implements Algorithm {
|
public class TheilSenEstimator implements Algorithm {
|
||||||
|
|
||||||
|
|
||||||
private static final Algorithm.Type type = Type.TS;
|
private static final Algorithm.Type type = Type.TS;
|
||||||
|
|
||||||
private List<Line> setOfLines;
|
private List<Line> setOfLines;
|
||||||
private double r;
|
private double r;
|
||||||
private double N;
|
private double intervalSize;
|
||||||
private int k;
|
private int k;
|
||||||
//Intervall und die temporaeren Grenzen
|
//Intervall und die temporaeren Grenzen
|
||||||
private Interval interval;
|
private Interval interval;
|
||||||
|
@ -45,6 +46,7 @@ public class TheilSenEstimator implements Algorithm {
|
||||||
private double yInterception;
|
private double yInterception;
|
||||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||||
private Map<String, String> parameter;
|
private Map<String, String> parameter;
|
||||||
|
private List<Point> intersections;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,62 +55,53 @@ public class TheilSenEstimator implements Algorithm {
|
||||||
*/
|
*/
|
||||||
public Line call() {
|
public Line call() {
|
||||||
|
|
||||||
int n = this.setOfLines.size();
|
int numberOfLines = this.setOfLines.size();
|
||||||
this.N = BinomialCoeffizient.run(n, 2);
|
this.intervalSize = BinomialCoeffizient.run(numberOfLines, 2);
|
||||||
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
|
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
|
||||||
this.k = (int) (N / 2);
|
this.k = (int) (intervalSize / 2);
|
||||||
|
|
||||||
double POSITIV_INF = 9999.0;
|
interval = new Interval(Double.MIN_VALUE, Double.MAX_VALUE);
|
||||||
double NEGATIV_INF = -9999.0;
|
|
||||||
interval = new Interval(NEGATIV_INF, POSITIV_INF);
|
|
||||||
//damit eine initiale Ordnung herscht
|
//damit eine initiale Ordnung herscht
|
||||||
//Collections.sort(intervalIntersections);
|
|
||||||
|
|
||||||
r = n;
|
r = numberOfLines;
|
||||||
List<Point> intervalIntersections = new LinkedList<>(IntersectionComputer.getInstance()
|
intersections = new LinkedList<>(IntersectionComputer.getInstance().compute(setOfLines));
|
||||||
.compute(setOfLines, interval.getLower(), interval.getUpper()));
|
|
||||||
while (true) {
|
while (true) {
|
||||||
double EPSILON = 0.00001;
|
double EPSILON = 0.00001;
|
||||||
if (this.N <= n
|
if (this.intervalSize <= numberOfLines || (Math.abs(interval.getUpper() - interval.getLower())) < EPSILON) {
|
||||||
|| (Math.abs(interval.getUpper() - interval.getLower())) < EPSILON) {
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
|
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
|
||||||
int numberOfIntersections = getIntervalSize(NEGATIV_INF,
|
int numberOfIntersections = getIntervalSize(Double.MIN_VALUE, interval.getLower());
|
||||||
interval.getLower());
|
|
||||||
|
|
||||||
//Randomized Interpolating Search
|
//Randomized Interpolating Search
|
||||||
//Hilfsvariablen (siehe original Paper)
|
//Hilfsvariablen (siehe original Paper)
|
||||||
double j = (r / N) * (double) (k - numberOfIntersections);
|
double j = (r / intervalSize) * (double) (k - numberOfIntersections);
|
||||||
int jA = (int) Math.max(1, Math.floor(j - (1.5 * Math.sqrt(r))));
|
int jA = (int) Math.max(1, Math.floor(j - (1.5 * Math.sqrt(r))));
|
||||||
int jB = (int) Math.min(r, Math.floor(j + (1.5 * Math.sqrt(r))));
|
int jB = (int) Math.min(r, Math.floor(j + (1.5 * Math.sqrt(r))));
|
||||||
|
|
||||||
|
|
||||||
/* Suche nach einem passenderen und kleineren Intervall
|
/* Suche nach einem passenderen und kleineren Intervall
|
||||||
Schleife terminiert wenn die das k-te Elemnet zwischen aVariant und bVariant liegt und
|
Schleife terminiert wenn die das k-te Elemnet zwischen aVariant und bVariant liegt und
|
||||||
das Intrvall weniger als 11*N / sqrt(r) Elemente besitzt */
|
das Intrvall weniger als 11*N / sqrt(r) Elemente besitzt */
|
||||||
|
List<Point> sampledIntersections = new LinkedList<>();
|
||||||
do {
|
do {
|
||||||
//zufällige Stichprobe
|
//zufällige Stichprobe
|
||||||
List<Point> sampledIntersections = RandomSampler
|
Collections.shuffle(intersections);
|
||||||
.run(intervalIntersections, r);
|
for(int i=0; i < r; i++) {
|
||||||
|
sampledIntersections.add(intersections.get(i % intersections.size()));
|
||||||
|
}
|
||||||
|
|
||||||
aVariant = FastElementSelector
|
aVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jA);
|
||||||
.randomizedSelect(getIntersectionAbscissas(sampledIntersections),
|
bVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jB);
|
||||||
jA);
|
} while (!checkCondition(sampledIntersections));
|
||||||
bVariant = FastElementSelector
|
|
||||||
.randomizedSelect(getIntersectionAbscissas(sampledIntersections),
|
|
||||||
jB);
|
|
||||||
} while (!checkCondition(NEGATIV_INF));
|
|
||||||
|
|
||||||
interval.setLower(aVariant);
|
interval.setLower(aVariant);
|
||||||
interval.setUpper(bVariant);
|
interval.setUpper(bVariant);
|
||||||
intervalIntersections = getOpenIntervalElements(interval.getLower(),
|
intersections = getOpenIntervalElements(interval.getLower(), interval.getUpper());
|
||||||
interval.getUpper());
|
intervalSize = getIntervalSize(interval.getLower(), interval.getUpper());
|
||||||
N = getIntervalSize(interval.getLower(), interval.getUpper());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pepareResult();
|
return prepareResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,19 +132,13 @@ public class TheilSenEstimator implements Algorithm {
|
||||||
*
|
*
|
||||||
* @return Boolscher Wert ob die Bedingung erfüllt ist
|
* @return Boolscher Wert ob die Bedingung erfüllt ist
|
||||||
*/
|
*/
|
||||||
private Boolean checkCondition(final double lowerBound) {
|
private Boolean checkCondition(List<Point> sampledIntersections) {
|
||||||
//Double kthElement = FastElementSelector.randomizedSelect(xCoordinates, k);
|
Point kthElement = FastElementSelector.randomizedSelect(sampledIntersections, k);
|
||||||
//Boolean cond1 = (kthElement > aVariant) && (kthElement <= bVariant);
|
Boolean cond1 = (kthElement.getX() > aVariant) && (kthElement.getX() <= bVariant);
|
||||||
|
|
||||||
int lowerCount = getIntervalSize(lowerBound, aVariant);
|
int count = getIntervalSize(aVariant, bVariant);
|
||||||
int higherCount = getIntervalSize(lowerBound, bVariant);
|
|
||||||
|
|
||||||
Boolean conda = k > lowerCount;
|
Boolean cond2 = count <= ((11 * intervalSize) / Math.sqrt(r));
|
||||||
Boolean condb = k <= higherCount;
|
|
||||||
|
|
||||||
Boolean cond1 = conda && condb;
|
|
||||||
|
|
||||||
Boolean cond2 = (higherCount - lowerCount) <= ((11 * N) / Math.sqrt(r));
|
|
||||||
|
|
||||||
return (cond1 && cond2) || (aVariant == bVariant);
|
return (cond1 && cond2) || (aVariant == bVariant);
|
||||||
}
|
}
|
||||||
|
@ -166,7 +153,10 @@ public class TheilSenEstimator implements Algorithm {
|
||||||
* @return Anzahl der Schnittpunkte im Interval [a,b)
|
* @return Anzahl der Schnittpunkte im Interval [a,b)
|
||||||
*/
|
*/
|
||||||
public int getIntervalSize(double a, double b) {
|
public int getIntervalSize(double a, double b) {
|
||||||
return getOpenIntervalElements(a, b).size();
|
if (a == b)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return getOpenIntervalElements(a, b).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,45 +169,22 @@ public class TheilSenEstimator implements Algorithm {
|
||||||
* @return Liste der Schnittpunkte die im Interval (a,b) vertreten sind
|
* @return Liste der Schnittpunkte die im Interval (a,b) vertreten sind
|
||||||
*/
|
*/
|
||||||
public List<Point> getOpenIntervalElements(double a, double b) {
|
public List<Point> getOpenIntervalElements(double a, double b) {
|
||||||
Collection<Point> intersections = IntersectionComputer.getInstance()
|
return intersections.stream().filter(point -> point.getX().compareTo(a) >= 0 && point.getX() < 0).collect(Collectors.toList());
|
||||||
.compute(setOfLines, a, b);
|
|
||||||
return new ArrayList<>(intersections);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Line pepareResult() {
|
private Line prepareResults() {
|
||||||
double m, x;
|
List<Point> intervalElements = getOpenIntervalElements(interval.getLower(), interval.getUpper());
|
||||||
double b, y;
|
|
||||||
|
|
||||||
List<Point> resultSt = getOpenIntervalElements(interval.getLower(),
|
|
||||||
interval.getUpper());
|
|
||||||
List<Double> resultAbscissas = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Point p : resultSt) {
|
|
||||||
resultAbscissas.add(p.getX());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Double> yCoords = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Point p : getOpenIntervalElements(interval.getLower(), interval.getUpper())) {
|
|
||||||
yCoords.add(p.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
double pseudoIndex = getIntervalSize(-9999.0, interval.getLower()) * 1.0;
|
double pseudoIndex = getIntervalSize(-9999.0, interval.getLower()) * 1.0;
|
||||||
m = FastElementSelector.randomizedSelect(resultAbscissas, k - pseudoIndex);
|
double m = FastElementSelector.randomizedSelect(intervalElements, k - pseudoIndex).getX();
|
||||||
|
double b = FastElementSelector.randomizedSelect(intervalElements, intervalElements.size() * 0.5).getY() * -1;
|
||||||
Set<Double> unique = new LinkedHashSet<>(yCoords);
|
slope = m * -1;
|
||||||
yCoords.clear();
|
|
||||||
yCoords.addAll(unique);
|
|
||||||
b = FastElementSelector.randomizedSelect(yCoords, yCoords.size() * 0.5) * -1;
|
|
||||||
slope = m;
|
|
||||||
yInterception = b;
|
yInterception = b;
|
||||||
|
|
||||||
if (this.subscriber != null) {
|
if (this.subscriber != null) {
|
||||||
AlgorithmMessage data = new AlgorithmMessage();
|
AlgorithmMessage data = new AlgorithmMessage();
|
||||||
data.setAlgorithmType(getType());
|
data.setAlgorithmType(getType());
|
||||||
data.setType(SubscriberType.ALGORITHM);
|
data.setType(SubscriberType.ALGORITHM);
|
||||||
data.setLineData(new Line(m, b));
|
data.setLineData(new Line(slope, yInterception));
|
||||||
this.subscriber.onNext(data);
|
this.subscriber.onNext(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ public class NaiveLeastMedianOfSquaresEstimator implements Algorithm {
|
||||||
* @return Steigung
|
* @return Steigung
|
||||||
*/
|
*/
|
||||||
public Double getSlope() {
|
public Double getSlope() {
|
||||||
return m * -1;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -163,7 +163,7 @@ public class NaiveRepeatedMedianEstimator implements Algorithm {
|
||||||
* @return Steigung
|
* @return Steigung
|
||||||
*/
|
*/
|
||||||
public double getSlope() {
|
public double getSlope() {
|
||||||
return medianX * -1;
|
return medianX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class NaiveTheilSenEstimator implements Algorithm {
|
||||||
* @return Steigung
|
* @return Steigung
|
||||||
*/
|
*/
|
||||||
public double getSlope() {
|
public double getSlope() {
|
||||||
return slope * -1;
|
return slope;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -37,7 +37,10 @@ public class CloudDatasetGenerator implements Callable<Set<Line>> {
|
||||||
double signal = m * i + b;
|
double signal = m * i + b;
|
||||||
signal *= -1;
|
signal *= -1;
|
||||||
|
|
||||||
Line line = new Line(i, signal - y);
|
double min = -10000d;
|
||||||
|
double max = 10000d;
|
||||||
|
|
||||||
|
Line line = new Line(min, max, i * min + signal - y, i * max + signal - y);
|
||||||
line.setId(i - 1 + "");
|
line.setId(i - 1 + "");
|
||||||
lines.add(line);
|
lines.add(line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ public class DatasetGenerator {
|
||||||
while (size < n) {
|
while (size < n) {
|
||||||
double y = random.nextGaussian();
|
double y = random.nextGaussian();
|
||||||
double signal = m * y + b;
|
double signal = m * y + b;
|
||||||
signal *= -1;
|
|
||||||
|
|
||||||
if (!points.containsKey(y)) {
|
if (!points.containsKey(y)) {
|
||||||
points.put(y, signal);
|
points.put(y, signal);
|
||||||
|
@ -52,12 +51,14 @@ public class DatasetGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = lines.size();
|
double min = -10000d;
|
||||||
|
double max = 10000d;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
for (Map.Entry<Double, Double> d : points.entrySet()) {
|
for (Map.Entry<Double, Double> d : points.entrySet()) {
|
||||||
Line line = new Line(d.getKey(), d.getValue());
|
Line line = new Line(min, max, d.getKey() * min + d.getValue(), d.getKey() * max + d.getValue());
|
||||||
line.setId(idx + "");
|
line.setId(idx++ + "");
|
||||||
lines.add(line);
|
lines.add(line);
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package de.wwwu.awolf.presenter.util.Comparators;
|
|
||||||
|
|
||||||
import de.wwwu.awolf.model.dao.Line;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
|
||||||
*
|
|
||||||
* @Author: Armin Wolf
|
|
||||||
* @Email: a_wolf28@uni-muenster.de
|
|
||||||
* @Date: 19.06.2017.
|
|
||||||
*/
|
|
||||||
public class YOrderLineComparatorBegin implements Comparator<Line> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Line o1, Line o2) {
|
|
||||||
return o1.getY1().compareTo(o2.getY1());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package de.wwwu.awolf.presenter.util.Comparators;
|
|
||||||
|
|
||||||
import de.wwwu.awolf.model.dao.Line;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
|
||||||
*
|
|
||||||
* @Author: Armin Wolf
|
|
||||||
* @Email: a_wolf28@uni-muenster.de
|
|
||||||
* @Date: 19.06.2017.
|
|
||||||
*/
|
|
||||||
public class YOrderLineComparatorEnd implements Comparator<Line> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Line o1, Line o2) {
|
|
||||||
return o1.getY2().compareTo(o2.getY2());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package de.wwwu.awolf.presenter.util;
|
package de.wwwu.awolf.presenter.util;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ public class FastElementSelector {
|
||||||
* @param i Rang des gewünschten Elements
|
* @param i Rang des gewünschten Elements
|
||||||
* @return das Element
|
* @return das Element
|
||||||
*/
|
*/
|
||||||
public static Double randomizedSelect(List<Double> a, double i) {
|
public static <Object extends Comparable<Object>> Object randomizedSelect(List<? extends Object> a, double i) {
|
||||||
|
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = a.size() - 1;
|
int end = a.size() - 1;
|
||||||
|
@ -57,7 +58,7 @@ public class FastElementSelector {
|
||||||
* @param end Index des letzten Elements
|
* @param end Index des letzten Elements
|
||||||
* @return Pivotelement
|
* @return Pivotelement
|
||||||
*/
|
*/
|
||||||
private static int randomizedPartition(List<Double> a, int start, int end) {
|
private static <Object extends Comparable<Object>> int randomizedPartition(List<? extends Object> a, int start, int end) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
SecureRandom random = new SecureRandom();
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
@ -80,11 +81,11 @@ public class FastElementSelector {
|
||||||
* @param end Index des letzten Elements
|
* @param end Index des letzten Elements
|
||||||
* @return Pivotelement
|
* @return Pivotelement
|
||||||
*/
|
*/
|
||||||
private static int partition(List<Double> a, int start, int end) {
|
private static <Object extends Comparable<Object>> int partition(List<? extends Object> a, int start, int end) {
|
||||||
Double x = a.get(end);
|
Object x = a.get(end);
|
||||||
int i = start - 1;
|
int i = start - 1;
|
||||||
for (int j = start; j <= end - 1; j++) {
|
for (int j = start; j <= end - 1; j++) {
|
||||||
if (a.get(j) <= x) {
|
if (a.get(j).compareTo(x) < 0) {
|
||||||
i++;
|
i++;
|
||||||
Collections.swap(a, i, j);
|
Collections.swap(a, i, j);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package de.wwwu.awolf.presenter.util;
|
package de.wwwu.awolf.presenter.util;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import de.wwwu.awolf.model.dao.Interval;
|
||||||
import de.wwwu.awolf.model.dao.Line;
|
import de.wwwu.awolf.model.dao.Line;
|
||||||
import de.wwwu.awolf.model.dao.Point;
|
import de.wwwu.awolf.model.dao.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -46,128 +47,11 @@ public class IntersectionComputer {
|
||||||
* Berechnet zu einer gegebenen Menge von dualen Geraden die Schnittpunkte. Dafür wird ein modifizierter Merge-Sort Algorithmus verwendett. Um die Performance zu steigern wird die Berechnung ab
|
* Berechnet zu einer gegebenen Menge von dualen Geraden die Schnittpunkte. Dafür wird ein modifizierter Merge-Sort Algorithmus verwendett. Um die Performance zu steigern wird die Berechnung ab
|
||||||
* einer passenden Größe auf vier Threads ausgelagert.
|
* einer passenden Größe auf vier Threads ausgelagert.
|
||||||
*
|
*
|
||||||
* @param lower untere Schranke
|
|
||||||
* @param higher obere Schranke
|
|
||||||
* @return Liste der Schnittpunkte
|
* @return Liste der Schnittpunkte
|
||||||
*/
|
*/
|
||||||
public Set<Point> compute(final Collection<Line> lines, final double lower,
|
public Set<Point> compute(final Collection<Line> lines) {
|
||||||
final double higher) {
|
BentleyOttmann bentleyOttmann = new BentleyOttmann(lines);
|
||||||
|
bentleyOttmann.find_intersections();
|
||||||
final Set<Line> fullInput = new HashSet<>(lines);
|
return bentleyOttmann.get_intersections();
|
||||||
final Set<Line> copyInput = new HashSet<>(lines);
|
|
||||||
|
|
||||||
if (lower == higher) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
} else {
|
|
||||||
Logging.logDebug(
|
|
||||||
"Open ForkJoinPool: lines: " + lines.size() + " I(" + lower + ", " + higher
|
|
||||||
+ "]");
|
|
||||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
|
||||||
RecursiveComputationTask recursiveComputationTask = new RecursiveComputationTask(
|
|
||||||
fullInput,
|
|
||||||
copyInput, lower, higher);
|
|
||||||
pool.execute(recursiveComputationTask);
|
|
||||||
Set<Point> join = recursiveComputationTask.join();
|
|
||||||
return join;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Berechnet die Schnittpunkte zwischen einer gegebenen Gerade und einer Menge an Geraden.
|
|
||||||
*
|
|
||||||
* @param set Menge an Geraden
|
|
||||||
* @param sampledLine eine spezielle Gerade
|
|
||||||
* @return Liste mit x Koordinaten der Schnittpunkte
|
|
||||||
*/
|
|
||||||
public List<Double> calculateIntersectionAbscissas(Collection<Line> set, Line sampledLine,
|
|
||||||
double lower, double upper) {
|
|
||||||
List<Line> lines = new LinkedList<>(set);
|
|
||||||
Set<Double> intersections = new HashSet<>();
|
|
||||||
|
|
||||||
for (Line line : lines) {
|
|
||||||
if (line != sampledLine) {
|
|
||||||
if (sampledLine.doIntersect(line, lower, upper)) {
|
|
||||||
intersections.add(sampledLine.intersect(line).getX());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>(intersections);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RecursiveComputationTask extends RecursiveTask<Set<Point>> {
|
|
||||||
|
|
||||||
private static final int THRESHOLD = 200;
|
|
||||||
|
|
||||||
private final Set<Line> lines;
|
|
||||||
private final Set<Line> fullList;
|
|
||||||
private final double lower;
|
|
||||||
private final double upper;
|
|
||||||
|
|
||||||
public RecursiveComputationTask(final Set<Line> fullList, final Set<Line> lines,
|
|
||||||
final double lower, final double upper) {
|
|
||||||
this.lines = lines;
|
|
||||||
this.fullList = fullList;
|
|
||||||
this.lower = lower;
|
|
||||||
this.upper = upper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Set<Point> compute() {
|
|
||||||
if (this.lines.isEmpty()) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
} else if (this.lines.size() > THRESHOLD) {
|
|
||||||
return ForkJoinTask.invokeAll(createSubTask()).stream()
|
|
||||||
.map(ForkJoinTask::join)
|
|
||||||
.flatMap(Collection::stream).collect(Collectors.toSet());
|
|
||||||
} else {
|
|
||||||
return work(this.fullList, this.lines, this.lower, this.upper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<RecursiveComputationTask> createSubTask() {
|
|
||||||
List<RecursiveComputationTask> dividedTasks = new ArrayList<>();
|
|
||||||
|
|
||||||
long midpoint = Math.round(this.lines.size() * 0.5);
|
|
||||||
|
|
||||||
Set<Line> firstSubSet = new HashSet<>();
|
|
||||||
Set<Line> secondSubSet = new HashSet<>();
|
|
||||||
AtomicInteger count = new AtomicInteger();
|
|
||||||
this.lines.forEach(next -> {
|
|
||||||
int index = count.getAndIncrement();
|
|
||||||
if (index < midpoint) {
|
|
||||||
firstSubSet.add(next);
|
|
||||||
} else {
|
|
||||||
secondSubSet.add(next);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dividedTasks
|
|
||||||
.add(new RecursiveComputationTask(this.fullList, firstSubSet, this.lower,
|
|
||||||
this.upper));
|
|
||||||
dividedTasks
|
|
||||||
.add(new RecursiveComputationTask(this.fullList, secondSubSet, this.lower,
|
|
||||||
this.upper));
|
|
||||||
return dividedTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Point> work(Set<Line> fullList, Set<Line> lines, double lower,
|
|
||||||
double higher) {
|
|
||||||
Set<Point> points = new HashSet<>();
|
|
||||||
List<List<Line>> lists = Lists
|
|
||||||
.cartesianProduct(new ArrayList<>(fullList), new ArrayList<>(lines));
|
|
||||||
lists.forEach(entry -> {
|
|
||||||
if (entry.get(0).doIntersect(entry.get(1), lower, upper)) {
|
|
||||||
Point intersect = entry.get(0).intersect(entry.get(1));
|
|
||||||
if (intersect.getX() > lower && intersect.getX() <= higher) {
|
|
||||||
points.add(intersect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return new HashSet<>(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,10 +95,10 @@ public class AlgorithmTabController {
|
||||||
|
|
||||||
if (pLine != null) {
|
if (pLine != null) {
|
||||||
lineSerie.getData().clear();
|
lineSerie.getData().clear();
|
||||||
Double x1 = pLine.calculateX1(model.getMin());
|
Double x1 = model.getMin();
|
||||||
Double y1 = pLine.calculateY1(model.getMin());
|
Double y1 = model.getMin() * pLine.getM() + pLine.getB();
|
||||||
Double x2 = pLine.calculateX2(model.getMax());
|
Double x2 = model.getMax();
|
||||||
Double y2 = pLine.calculateY2(model.getMax());
|
Double y2 = model.getMax() * pLine.getM() + pLine.getB();
|
||||||
|
|
||||||
lineSerie.getData().add(new XYChart.Data<>(x1, y1));
|
lineSerie.getData().add(new XYChart.Data<>(x1, y1));
|
||||||
lineSerie.getData().add(new XYChart.Data<>(x2, y2));
|
lineSerie.getData().add(new XYChart.Data<>(x2, y2));
|
||||||
|
|
Loading…
Reference in New Issue