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> {
|
||||
|
||||
private static final double EPSILON = 0.00001;
|
||||
private static final double MIN = 9999d;
|
||||
private static final double MAX = -9999d;
|
||||
|
||||
|
||||
private double x1;
|
||||
private double x2;
|
||||
private double y1;
|
||||
private double y2;
|
||||
private Segment segment;
|
||||
private Double m;
|
||||
private Double b;
|
||||
|
||||
private Double x1;
|
||||
private Double x2;
|
||||
private Double y1;
|
||||
private Double y2;
|
||||
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param m Steigung
|
||||
* @param b y-Achsenabschnitt
|
||||
* @param id id
|
||||
*/
|
||||
public Line(double m, double b, String id) {
|
||||
public Line(Double m, Double b) {
|
||||
this.m = m;
|
||||
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) {
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
this.x2 = x2;
|
||||
|
||||
this.m = (y2 - y1) / (x2 - x1);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
|
@ -218,74 +122,6 @@ public class Line implements Comparable<Line> {
|
|||
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
|
||||
public int compareTo(Line line) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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 Set<Line> lines;
|
||||
private Double xMinimum;
|
||||
private Double xMaximum;
|
||||
private Double yMinimum;
|
||||
private Double yMaximum;
|
||||
private int size;
|
||||
|
||||
/**
|
||||
|
@ -29,11 +25,6 @@ public class LineModel {
|
|||
lines = new HashSet<>();
|
||||
size = 0;
|
||||
|
||||
xMinimum = Double.MAX_VALUE;
|
||||
xMaximum = Double.MIN_VALUE;
|
||||
yMinimum = Double.MAX_VALUE;
|
||||
yMaximum = Double.MIN_VALUE;
|
||||
|
||||
min = 0d;
|
||||
max = 0d;
|
||||
}
|
||||
|
@ -73,72 +64,6 @@ public class LineModel {
|
|||
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() {
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
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.Message;
|
||||
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.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||
|
@ -49,6 +50,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||
private Map<String, String> parameter;
|
||||
private Set<Point> intersections;
|
||||
|
||||
public LeastMedianOfSquaresEstimator() {
|
||||
parameter = new HashMap<>();
|
||||
|
@ -78,27 +80,21 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
start = System.currentTimeMillis();
|
||||
|
||||
//(2.) Let U <- (-inf, inf) be the initial active intervals...
|
||||
Comparator<Interval> comparator = (o1, o2) -> {
|
||||
if (o1.getDistance() < o2.getDistance()) {
|
||||
return -1;
|
||||
}
|
||||
if (o1.getDistance() > o2.getDistance()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
Comparator<Interval> comparator = Comparator.comparing(Interval::getDistance);
|
||||
|
||||
intervals = new PriorityQueue<>(comparator);
|
||||
intervals.add(new Interval(-10000, 10000));
|
||||
intervals.add(new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
|
||||
heightsigmaMin = Double.MAX_VALUE;
|
||||
|
||||
intersections = IntersectionComputer.getInstance().compute(setOfLines);
|
||||
|
||||
//(3.) Apply the following steps as long as the exists active intervals
|
||||
Interval interval;
|
||||
while (!this.intervals.isEmpty()) {
|
||||
interval = this.intervals.peek();
|
||||
if (interval.getActivity()) {
|
||||
//(a.) Select any active Interval and calc. the inversions
|
||||
int numberOfIntersections = countInversions(interval);
|
||||
long numberOfIntersections = countIntersections(interval);
|
||||
|
||||
//(b.) apply plane sweep
|
||||
if ((Double.parseDouble(parameter.get("Constant")) * n) >= numberOfIntersections) {
|
||||
|
@ -106,35 +102,27 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
} else {
|
||||
//(c.) otherwise....
|
||||
// get random intersections point...
|
||||
Collection<Point> tmpIntersections = IntersectionComputer
|
||||
.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper());
|
||||
boolean found = false;
|
||||
Collection<Point> tmpIntersections = intersections;
|
||||
for (Point tmpIntersection : tmpIntersections) {
|
||||
if (tmpIntersection.getX() > interval.getLower()
|
||||
&& tmpIntersection.getX() < interval.getUpper()) {
|
||||
intersectionsPoint = tmpIntersection.getX();
|
||||
found = true;
|
||||
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()) {
|
||||
this.intervals.add(subSlabU1);
|
||||
}
|
||||
if (subSlabU2.getActivity()) {
|
||||
this.intervals.add(subSlabU2);
|
||||
}
|
||||
splitActiveSlab(intersectionsPoint, interval);
|
||||
//(d.) this may update sigma min
|
||||
upperBound(intersectionsPoint);
|
||||
//(e.) for i={1,2}, call lower bound(Ui)
|
||||
lowerBound(subSlabU1);
|
||||
lowerBound(subSlabU2);
|
||||
|
||||
} else {
|
||||
this.intervals.poll();
|
||||
if (subSlabU1.getActivity()) {
|
||||
this.intervals.add(subSlabU1);
|
||||
}
|
||||
if (subSlabU2.getActivity()) {
|
||||
this.intervals.add(subSlabU2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -180,9 +168,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
* @param interval Intervall
|
||||
* @return Anzahl der Schnittpunkte
|
||||
*/
|
||||
public int countInversions(Interval interval) {
|
||||
return IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper()).size();
|
||||
public long countIntersections(Interval interval) {
|
||||
return this.intersections.stream().filter(point -> point.getX().compareTo(interval.getLower()) > 0 && point.getX().compareTo(interval.getUpper()) <= 0).count();
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,9 +184,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
|
||||
//initialisiere die x-Queue mit den 2D Punkten und sortiere nach x-Lexikographischer Ordnung
|
||||
List<Point> xQueue = new ArrayList<>();
|
||||
Collection<Point> points = IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper());
|
||||
for (Point point : points) {
|
||||
for (Point point : intersections) {
|
||||
if (point.getX() >= interval.getLower() && point.getX() < interval.getUpper()) {
|
||||
xQueue.add(point);
|
||||
}
|
||||
|
@ -216,8 +201,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
continue;
|
||||
} else if (currentBracelet[0] < heightOfBracelet) {
|
||||
heightOfBracelet = currentBracelet[0];
|
||||
bracelet = new Line(current.getX(), current.getX(), currentBracelet[1],
|
||||
currentBracelet[2]);
|
||||
bracelet = new Line(current.getX(), current.getX(), currentBracelet[1], currentBracelet[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,11 +242,9 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
if (height < heightsigmaMin) {
|
||||
heightsigmaMin = height;
|
||||
if (sigmaMin != null) {
|
||||
sigmaMin.setEndPoints(point, sortedLineSequence.get(i)
|
||||
, point, sortedLineSequence.get((i + kMinus) - 1));
|
||||
sigmaMin = new Line(point, sortedLineSequence.get(i), point, sortedLineSequence.get((i + kMinus) - 1));
|
||||
} else {
|
||||
sigmaMin = new Line(point, point, sortedLineSequence.get(i),
|
||||
sortedLineSequence.get((i + kMinus) - 1));
|
||||
sigmaMin = new Line(point, point, sortedLineSequence.get(i), sortedLineSequence.get((i + kMinus) - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,14 +279,16 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
uminList = getEjValues(pslab.getLower());
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Line level = new Line(pslab.getLower(), pslab.getUpper(), uminList.get(i),
|
||||
umaxList.get(i));
|
||||
Line level = new Line(pslab.getLower(), pslab.getUpper(), uminList.get(i), umaxList.get(i));
|
||||
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]++;
|
||||
}
|
||||
|
||||
if ((line.getY1() > level.getY1()) && (line.getY2() > level.getY2())) {
|
||||
if ((segment.first().getY() > levelSegment.first().getY()) && (segment.second().getY() > levelSegment.second().getY())) {
|
||||
strictlyGreater++;
|
||||
}
|
||||
}
|
||||
|
@ -373,10 +357,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
}
|
||||
if (intersections.size() >= kMinusValue) {
|
||||
Collections.sort(intersections);
|
||||
double height = Math
|
||||
.abs(intersections.get(0) - intersections.get(kMinusValue - 1));
|
||||
return new Double[]{height, intersections.get(0),
|
||||
intersections.get(kMinusValue - 1)};
|
||||
double height = Math.abs(intersections.get(0) - intersections.get(kMinusValue - 1));
|
||||
return new Double[]{height, intersections.get(0), intersections.get(kMinusValue - 1)};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -384,24 +366,17 @@ public class LeastMedianOfSquaresEstimator implements Algorithm {
|
|||
}
|
||||
|
||||
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) {
|
||||
double m = ((getSigmaMin().getX2() + getSigmaMin().getX1()) * 0.5);
|
||||
double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * -0.5;
|
||||
|
||||
slope = m;
|
||||
yInterception = b;
|
||||
|
||||
AlgorithmMessage data = new AlgorithmMessage();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(m, b));
|
||||
data.setLineData(new Line(slope, yInterception));
|
||||
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());
|
||||
|
|
|
@ -13,6 +13,7 @@ import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
|||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -39,9 +40,9 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
private Interval original;
|
||||
|
||||
//in der Literatur als L_i, C_i, und R_i bekannt
|
||||
private int countLeftSlab;
|
||||
private int countCenterSlab;
|
||||
private int countRightSlab;
|
||||
private long countLeftSlab;
|
||||
private long countCenterSlab;
|
||||
private long countRightSlab;
|
||||
|
||||
//in der Literatur als L_i, C_i, und R_i bekannt
|
||||
private Set<Point> intersectionsInLeftSlab;
|
||||
|
@ -49,7 +50,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
private Set<Point> intersectionsInRightSlab;
|
||||
|
||||
private double r;
|
||||
private int n;
|
||||
private long n;
|
||||
private double k;
|
||||
private double kLow;
|
||||
private double kHigh;
|
||||
|
@ -58,6 +59,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||
private Map<String, String> parameter;
|
||||
private Set<Point> intersections;
|
||||
|
||||
public RepeatedMedianEstimator() {
|
||||
parameter = new HashMap<>();
|
||||
|
@ -96,6 +98,8 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
double thetaLow = 0;
|
||||
double thetaHigh = 0;
|
||||
|
||||
intersections = IntersectionComputer.getInstance().compute(setOfLines);
|
||||
|
||||
while (countCenterSlab > 1) {
|
||||
n = countCenterSlab;
|
||||
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) {
|
||||
|
||||
List<Double> intersections = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
||||
original.getUpper());
|
||||
List<Double> left = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
||||
interval.getLower());
|
||||
List<Double> center = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(),
|
||||
interval.getUpper());
|
||||
//interval is the current interval
|
||||
Set<Point> intersections = IntersectionComputer.getInstance().compute(lines);
|
||||
long leftSize = intersections.stream().filter(p -> p.getX() <= interval.getLower()).count();
|
||||
long centerSize = intersections.stream().filter(p -> p.getX() >= interval.getLower() && p.getX() < interval.getUpper()).count();
|
||||
|
||||
double ki = Math.ceil((n - 1) * 0.5) - left.size();
|
||||
double i = (Math.ceil((Math.sqrt(n) * ki) / center.size()));
|
||||
double ki = Math.ceil((n - 1) * 0.5) - leftSize;
|
||||
double i = (Math.ceil((Math.sqrt(n) * ki) / centerSize));
|
||||
int accessIndex;
|
||||
if (i < 0) {
|
||||
accessIndex = 0;
|
||||
|
@ -183,8 +182,8 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
} else {
|
||||
accessIndex = (int) i;
|
||||
}
|
||||
|
||||
return FastElementSelector.randomizedSelect(intersections, accessIndex);
|
||||
LinkedList<Point> points = new LinkedList<>(intersections);
|
||||
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'].
|
||||
*/
|
||||
public void countNumberOfIntersectionsAbscissas(final double lower, final double upper) {
|
||||
IntersectionComputer instance = IntersectionComputer.getInstance();
|
||||
|
||||
intersectionsInLeftSlab = new HashSet<>(
|
||||
instance.compute(setOfLines, interval.getLower(), lower));
|
||||
intersectionsInCenterSlab = new HashSet<>(instance.compute(setOfLines, lower, upper));
|
||||
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();
|
||||
countLeftSlab = intersections.stream().filter(point -> point.getX().compareTo(lower) < 0).count();
|
||||
countCenterSlab = intersections.stream().filter(point -> point.getX().compareTo(lower) >= 0 && point.getX().compareTo(upper) < 0).count();
|
||||
countRightSlab = intersections.stream().filter(point -> point.getX().compareTo(upper) >= 0).count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,7 +234,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
}
|
||||
|
||||
private Line pepareResult(final double thetaLow, final double thetaHigh) {
|
||||
slope = thetaLow;
|
||||
slope = thetaLow * -1;
|
||||
List<Double> potentialYInterceptions = new ArrayList<>();
|
||||
setOfLines.forEach(line -> {
|
||||
potentialYInterceptions.add(line.getB() - (slope * line.getM()));
|
||||
|
@ -268,7 +257,7 @@ public class RepeatedMedianEstimator implements Algorithm {
|
|||
/**
|
||||
* @return Anzahl der Geraden
|
||||
*/
|
||||
public Integer getN() {
|
||||
public Long getN() {
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,14 @@ import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
|||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Flow;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
|
@ -30,12 +32,11 @@ import java.util.concurrent.Flow;
|
|||
*/
|
||||
public class TheilSenEstimator implements Algorithm {
|
||||
|
||||
|
||||
private static final Algorithm.Type type = Type.TS;
|
||||
|
||||
private List<Line> setOfLines;
|
||||
private double r;
|
||||
private double N;
|
||||
private double intervalSize;
|
||||
private int k;
|
||||
//Intervall und die temporaeren Grenzen
|
||||
private Interval interval;
|
||||
|
@ -45,6 +46,7 @@ public class TheilSenEstimator implements Algorithm {
|
|||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmMessage> subscriber;
|
||||
private Map<String, String> parameter;
|
||||
private List<Point> intersections;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -53,62 +55,53 @@ public class TheilSenEstimator implements Algorithm {
|
|||
*/
|
||||
public Line call() {
|
||||
|
||||
int n = this.setOfLines.size();
|
||||
this.N = BinomialCoeffizient.run(n, 2);
|
||||
int numberOfLines = this.setOfLines.size();
|
||||
this.intervalSize = BinomialCoeffizient.run(numberOfLines, 2);
|
||||
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
|
||||
this.k = (int) (N / 2);
|
||||
this.k = (int) (intervalSize / 2);
|
||||
|
||||
double POSITIV_INF = 9999.0;
|
||||
double NEGATIV_INF = -9999.0;
|
||||
interval = new Interval(NEGATIV_INF, POSITIV_INF);
|
||||
interval = new Interval(Double.MIN_VALUE, Double.MAX_VALUE);
|
||||
//damit eine initiale Ordnung herscht
|
||||
//Collections.sort(intervalIntersections);
|
||||
|
||||
r = n;
|
||||
List<Point> intervalIntersections = new LinkedList<>(IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper()));
|
||||
r = numberOfLines;
|
||||
intersections = new LinkedList<>(IntersectionComputer.getInstance().compute(setOfLines));
|
||||
while (true) {
|
||||
double EPSILON = 0.00001;
|
||||
if (this.N <= n
|
||||
|| (Math.abs(interval.getUpper() - interval.getLower())) < EPSILON) {
|
||||
if (this.intervalSize <= numberOfLines || (Math.abs(interval.getUpper() - interval.getLower())) < EPSILON) {
|
||||
break;
|
||||
} else {
|
||||
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
|
||||
int numberOfIntersections = getIntervalSize(NEGATIV_INF,
|
||||
interval.getLower());
|
||||
int numberOfIntersections = getIntervalSize(Double.MIN_VALUE, interval.getLower());
|
||||
|
||||
//Randomized Interpolating Search
|
||||
//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 jB = (int) Math.min(r, Math.floor(j + (1.5 * Math.sqrt(r))));
|
||||
|
||||
|
||||
/* Suche nach einem passenderen und kleineren Intervall
|
||||
Schleife terminiert wenn die das k-te Elemnet zwischen aVariant und bVariant liegt und
|
||||
das Intrvall weniger als 11*N / sqrt(r) Elemente besitzt */
|
||||
List<Point> sampledIntersections = new LinkedList<>();
|
||||
do {
|
||||
//zufällige Stichprobe
|
||||
List<Point> sampledIntersections = RandomSampler
|
||||
.run(intervalIntersections, r);
|
||||
Collections.shuffle(intersections);
|
||||
for(int i=0; i < r; i++) {
|
||||
sampledIntersections.add(intersections.get(i % intersections.size()));
|
||||
}
|
||||
|
||||
aVariant = FastElementSelector
|
||||
.randomizedSelect(getIntersectionAbscissas(sampledIntersections),
|
||||
jA);
|
||||
bVariant = FastElementSelector
|
||||
.randomizedSelect(getIntersectionAbscissas(sampledIntersections),
|
||||
jB);
|
||||
} while (!checkCondition(NEGATIV_INF));
|
||||
aVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jA);
|
||||
bVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jB);
|
||||
} while (!checkCondition(sampledIntersections));
|
||||
|
||||
interval.setLower(aVariant);
|
||||
interval.setUpper(bVariant);
|
||||
intervalIntersections = getOpenIntervalElements(interval.getLower(),
|
||||
interval.getUpper());
|
||||
N = getIntervalSize(interval.getLower(), interval.getUpper());
|
||||
intersections = getOpenIntervalElements(interval.getLower(), interval.getUpper());
|
||||
intervalSize = getIntervalSize(interval.getLower(), interval.getUpper());
|
||||
}
|
||||
}
|
||||
|
||||
return pepareResult();
|
||||
return prepareResults();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,19 +132,13 @@ public class TheilSenEstimator implements Algorithm {
|
|||
*
|
||||
* @return Boolscher Wert ob die Bedingung erfüllt ist
|
||||
*/
|
||||
private Boolean checkCondition(final double lowerBound) {
|
||||
//Double kthElement = FastElementSelector.randomizedSelect(xCoordinates, k);
|
||||
//Boolean cond1 = (kthElement > aVariant) && (kthElement <= bVariant);
|
||||
private Boolean checkCondition(List<Point> sampledIntersections) {
|
||||
Point kthElement = FastElementSelector.randomizedSelect(sampledIntersections, k);
|
||||
Boolean cond1 = (kthElement.getX() > aVariant) && (kthElement.getX() <= bVariant);
|
||||
|
||||
int lowerCount = getIntervalSize(lowerBound, aVariant);
|
||||
int higherCount = getIntervalSize(lowerBound, bVariant);
|
||||
int count = getIntervalSize(aVariant, bVariant);
|
||||
|
||||
Boolean conda = k > lowerCount;
|
||||
Boolean condb = k <= higherCount;
|
||||
|
||||
Boolean cond1 = conda && condb;
|
||||
|
||||
Boolean cond2 = (higherCount - lowerCount) <= ((11 * N) / Math.sqrt(r));
|
||||
Boolean cond2 = count <= ((11 * intervalSize) / Math.sqrt(r));
|
||||
|
||||
return (cond1 && cond2) || (aVariant == bVariant);
|
||||
}
|
||||
|
@ -166,7 +153,10 @@ public class TheilSenEstimator implements Algorithm {
|
|||
* @return Anzahl der Schnittpunkte im Interval [a,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
|
||||
*/
|
||||
public List<Point> getOpenIntervalElements(double a, double b) {
|
||||
Collection<Point> intersections = IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, a, b);
|
||||
return new ArrayList<>(intersections);
|
||||
return intersections.stream().filter(point -> point.getX().compareTo(a) >= 0 && point.getX() < 0).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Line pepareResult() {
|
||||
double m, x;
|
||||
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
|
||||
private Line prepareResults() {
|
||||
List<Point> intervalElements = getOpenIntervalElements(interval.getLower(), interval.getUpper());
|
||||
double pseudoIndex = getIntervalSize(-9999.0, interval.getLower()) * 1.0;
|
||||
m = FastElementSelector.randomizedSelect(resultAbscissas, k - pseudoIndex);
|
||||
|
||||
Set<Double> unique = new LinkedHashSet<>(yCoords);
|
||||
yCoords.clear();
|
||||
yCoords.addAll(unique);
|
||||
b = FastElementSelector.randomizedSelect(yCoords, yCoords.size() * 0.5) * -1;
|
||||
slope = m;
|
||||
double m = FastElementSelector.randomizedSelect(intervalElements, k - pseudoIndex).getX();
|
||||
double b = FastElementSelector.randomizedSelect(intervalElements, intervalElements.size() * 0.5).getY() * -1;
|
||||
slope = m * -1;
|
||||
yInterception = b;
|
||||
|
||||
if (this.subscriber != null) {
|
||||
AlgorithmMessage data = new AlgorithmMessage();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(m, b));
|
||||
data.setLineData(new Line(slope, yInterception));
|
||||
this.subscriber.onNext(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ public class NaiveLeastMedianOfSquaresEstimator implements Algorithm {
|
|||
* @return Steigung
|
||||
*/
|
||||
public Double getSlope() {
|
||||
return m * -1;
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -163,7 +163,7 @@ public class NaiveRepeatedMedianEstimator implements Algorithm {
|
|||
* @return Steigung
|
||||
*/
|
||||
public double getSlope() {
|
||||
return medianX * -1;
|
||||
return medianX;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -114,7 +114,7 @@ public class NaiveTheilSenEstimator implements Algorithm {
|
|||
* @return Steigung
|
||||
*/
|
||||
public double getSlope() {
|
||||
return slope * -1;
|
||||
return slope;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,10 @@ public class CloudDatasetGenerator implements Callable<Set<Line>> {
|
|||
double signal = m * i + b;
|
||||
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 + "");
|
||||
lines.add(line);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ public class DatasetGenerator {
|
|||
while (size < n) {
|
||||
double y = random.nextGaussian();
|
||||
double signal = m * y + b;
|
||||
signal *= -1;
|
||||
|
||||
if (!points.containsKey(y)) {
|
||||
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()) {
|
||||
Line line = new Line(d.getKey(), d.getValue());
|
||||
line.setId(idx + "");
|
||||
Line line = new Line(min, max, d.getKey() * min + d.getValue(), d.getKey() * max + d.getValue());
|
||||
line.setId(idx++ + "");
|
||||
lines.add(line);
|
||||
idx++;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -20,7 +21,7 @@ public class FastElementSelector {
|
|||
* @param i Rang des gewünschten Elements
|
||||
* @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 end = a.size() - 1;
|
||||
|
@ -57,7 +58,7 @@ public class FastElementSelector {
|
|||
* @param end Index des letzten Elements
|
||||
* @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;
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
|
@ -80,11 +81,11 @@ public class FastElementSelector {
|
|||
* @param end Index des letzten Elements
|
||||
* @return Pivotelement
|
||||
*/
|
||||
private static int partition(List<Double> a, int start, int end) {
|
||||
Double x = a.get(end);
|
||||
private static <Object extends Comparable<Object>> int partition(List<? extends Object> a, int start, int end) {
|
||||
Object x = a.get(end);
|
||||
int i = start - 1;
|
||||
for (int j = start; j <= end - 1; j++) {
|
||||
if (a.get(j) <= x) {
|
||||
if (a.get(j).compareTo(x) < 0) {
|
||||
i++;
|
||||
Collections.swap(a, i, j);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
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.Point;
|
||||
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
|
||||
* einer passenden Größe auf vier Threads ausgelagert.
|
||||
*
|
||||
* @param lower untere Schranke
|
||||
* @param higher obere Schranke
|
||||
* @return Liste der Schnittpunkte
|
||||
*/
|
||||
public Set<Point> compute(final Collection<Line> lines, final double lower,
|
||||
final double higher) {
|
||||
|
||||
final Set<Line> fullInput = new HashSet<>(lines);
|
||||
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;
|
||||
}
|
||||
public Set<Point> compute(final Collection<Line> lines) {
|
||||
BentleyOttmann bentleyOttmann = new BentleyOttmann(lines);
|
||||
bentleyOttmann.find_intersections();
|
||||
return bentleyOttmann.get_intersections();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
lineSerie.getData().clear();
|
||||
Double x1 = pLine.calculateX1(model.getMin());
|
||||
Double y1 = pLine.calculateY1(model.getMin());
|
||||
Double x2 = pLine.calculateX2(model.getMax());
|
||||
Double y2 = pLine.calculateY2(model.getMax());
|
||||
Double x1 = model.getMin();
|
||||
Double y1 = model.getMin() * pLine.getM() + pLine.getB();
|
||||
Double x2 = model.getMax();
|
||||
Double y2 = model.getMax() * pLine.getM() + pLine.getB();
|
||||
|
||||
lineSerie.getData().add(new XYChart.Data<>(x1, y1));
|
||||
lineSerie.getData().add(new XYChart.Data<>(x2, y2));
|
||||
|
|
Loading…
Reference in New Issue