diff --git a/src/main/java/de/wwwu/awolf/model/dao/Event.java b/src/main/java/de/wwwu/awolf/model/dao/Event.java new file mode 100644 index 0000000..3fb230e --- /dev/null +++ b/src/main/java/de/wwwu/awolf/model/dao/Event.java @@ -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 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 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 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; + } + +} diff --git a/src/main/java/de/wwwu/awolf/model/dao/Line.java b/src/main/java/de/wwwu/awolf/model/dao/Line.java index e612dd1..03891ec 100644 --- a/src/main/java/de/wwwu/awolf/model/dao/Line.java +++ b/src/main/java/de/wwwu/awolf/model/dao/Line.java @@ -13,52 +13,18 @@ import org.apache.commons.math3.util.Precision; public class Line implements Comparable { 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 { */ 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 { 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 { 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 { 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; + } + + } } diff --git a/src/main/java/de/wwwu/awolf/model/dao/LineModel.java b/src/main/java/de/wwwu/awolf/model/dao/LineModel.java index 5b3dff6..1fecead 100644 --- a/src/main/java/de/wwwu/awolf/model/dao/LineModel.java +++ b/src/main/java/de/wwwu/awolf/model/dao/LineModel.java @@ -16,10 +16,6 @@ public class LineModel { private Double min; private Set 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; } diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/LeastMedianOfSquaresEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/LeastMedianOfSquaresEstimator.java index 5b6fcad..9cf94f2 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/LeastMedianOfSquaresEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/LeastMedianOfSquaresEstimator.java @@ -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 subscriber; private Map parameter; + private Set 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 comparator = (o1, o2) -> { - if (o1.getDistance() < o2.getDistance()) { - return -1; - } - if (o1.getDistance() > o2.getDistance()) { - return 1; - } else { - return 0; - } - }; + Comparator 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 tmpIntersections = IntersectionComputer - .getInstance() - .compute(setOfLines, interval.getLower(), interval.getUpper()); - boolean found = false; + Collection 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 xQueue = new ArrayList<>(); - Collection 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()); diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/RepeatedMedianEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/RepeatedMedianEstimator.java index 1d3c553..b1c7378 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/RepeatedMedianEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/RepeatedMedianEstimator.java @@ -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 intersectionsInLeftSlab; @@ -49,7 +50,7 @@ public class RepeatedMedianEstimator implements Algorithm { private Set 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 subscriber; private Map parameter; + private Set 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 lines, Line sampledLine) { - List intersections = IntersectionComputer.getInstance() - .calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), - original.getUpper()); - List left = IntersectionComputer.getInstance() - .calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), - interval.getLower()); - List center = IntersectionComputer.getInstance() - .calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(), - interval.getUpper()); + //interval is the current interval + Set 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 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 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; } diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/TheilSenEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/TheilSenEstimator.java index 2af54e7..1886999 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/TheilSenEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/advanced/TheilSenEstimator.java @@ -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 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 subscriber; private Map parameter; + private List 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 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 sampledIntersections = new LinkedList<>(); do { //zufällige Stichprobe - List 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 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 getOpenIntervalElements(double a, double b) { - Collection 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 resultSt = getOpenIntervalElements(interval.getLower(), - interval.getUpper()); - List resultAbscissas = new ArrayList<>(); - - for (Point p : resultSt) { - resultAbscissas.add(p.getX()); - } - - List yCoords = new ArrayList<>(); - - for (Point p : getOpenIntervalElements(interval.getLower(), interval.getUpper())) { - yCoords.add(p.getY()); - } - - //TODO + private Line prepareResults() { + List intervalElements = getOpenIntervalElements(interval.getLower(), interval.getUpper()); double pseudoIndex = getIntervalSize(-9999.0, interval.getLower()) * 1.0; - m = FastElementSelector.randomizedSelect(resultAbscissas, k - pseudoIndex); - - Set 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); } diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveLeastMedianOfSquaresEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveLeastMedianOfSquaresEstimator.java index 62d86a6..2cd93c7 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveLeastMedianOfSquaresEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveLeastMedianOfSquaresEstimator.java @@ -139,7 +139,7 @@ public class NaiveLeastMedianOfSquaresEstimator implements Algorithm { * @return Steigung */ public Double getSlope() { - return m * -1; + return m; } @Override diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveRepeatedMedianEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveRepeatedMedianEstimator.java index fcb551b..ce3e0e6 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveRepeatedMedianEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveRepeatedMedianEstimator.java @@ -163,7 +163,7 @@ public class NaiveRepeatedMedianEstimator implements Algorithm { * @return Steigung */ public double getSlope() { - return medianX * -1; + return medianX; } /** diff --git a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveTheilSenEstimator.java b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveTheilSenEstimator.java index 011c22f..ef73692 100644 --- a/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveTheilSenEstimator.java +++ b/src/main/java/de/wwwu/awolf/presenter/algorithms/naive/NaiveTheilSenEstimator.java @@ -114,7 +114,7 @@ public class NaiveTheilSenEstimator implements Algorithm { * @return Steigung */ public double getSlope() { - return slope * -1; + return slope; } /** diff --git a/src/main/java/de/wwwu/awolf/presenter/data/generator/CloudDatasetGenerator.java b/src/main/java/de/wwwu/awolf/presenter/data/generator/CloudDatasetGenerator.java index 56786c4..bf6c061 100644 --- a/src/main/java/de/wwwu/awolf/presenter/data/generator/CloudDatasetGenerator.java +++ b/src/main/java/de/wwwu/awolf/presenter/data/generator/CloudDatasetGenerator.java @@ -37,7 +37,10 @@ public class CloudDatasetGenerator implements Callable> { 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); } diff --git a/src/main/java/de/wwwu/awolf/presenter/data/generator/DatasetGenerator.java b/src/main/java/de/wwwu/awolf/presenter/data/generator/DatasetGenerator.java index acfe325..be0be45 100644 --- a/src/main/java/de/wwwu/awolf/presenter/data/generator/DatasetGenerator.java +++ b/src/main/java/de/wwwu/awolf/presenter/data/generator/DatasetGenerator.java @@ -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 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; diff --git a/src/main/java/de/wwwu/awolf/presenter/util/BentleyOttmann.java b/src/main/java/de/wwwu/awolf/presenter/util/BentleyOttmann.java new file mode 100644 index 0000000..d3b447f --- /dev/null +++ b/src/main/java/de/wwwu/awolf/presenter/util/BentleyOttmann.java @@ -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 Q; + private NavigableSet T; + private Set X; + private Collection lines; + + BentleyOttmann(Collection 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 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 get_intersections() { + print_intersections(); + return this.X; + } + + private class event_comparator implements Comparator { + @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 { + @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; + } + } +} \ No newline at end of file diff --git a/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorBegin.java b/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorBegin.java deleted file mode 100644 index 469280d..0000000 --- a/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorBegin.java +++ /dev/null @@ -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 { - - @Override - public int compare(Line o1, Line o2) { - return o1.getY1().compareTo(o2.getY1()); - } -} \ No newline at end of file diff --git a/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorEnd.java b/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorEnd.java deleted file mode 100644 index b50414f..0000000 --- a/src/main/java/de/wwwu/awolf/presenter/util/Comparators/YOrderLineComparatorEnd.java +++ /dev/null @@ -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 { - - @Override - public int compare(Line o1, Line o2) { - return o1.getY2().compareTo(o2.getY2()); - } -} diff --git a/src/main/java/de/wwwu/awolf/presenter/util/FastElementSelector.java b/src/main/java/de/wwwu/awolf/presenter/util/FastElementSelector.java index 0110aeb..36e5aef 100644 --- a/src/main/java/de/wwwu/awolf/presenter/util/FastElementSelector.java +++ b/src/main/java/de/wwwu/awolf/presenter/util/FastElementSelector.java @@ -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 a, double i) { + public static > Object randomizedSelect(List 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 a, int start, int end) { + private static > int randomizedPartition(List 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 a, int start, int end) { - Double x = a.get(end); + private static > int partition(List 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); } diff --git a/src/main/java/de/wwwu/awolf/presenter/util/IntersectionComputer.java b/src/main/java/de/wwwu/awolf/presenter/util/IntersectionComputer.java index 94f9e5e..ae2cfcd 100644 --- a/src/main/java/de/wwwu/awolf/presenter/util/IntersectionComputer.java +++ b/src/main/java/de/wwwu/awolf/presenter/util/IntersectionComputer.java @@ -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 compute(final Collection lines, final double lower, - final double higher) { - - final Set fullInput = new HashSet<>(lines); - final Set 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 join = recursiveComputationTask.join(); - return join; - } + public Set compute(final Collection 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 calculateIntersectionAbscissas(Collection set, Line sampledLine, - double lower, double upper) { - List lines = new LinkedList<>(set); - Set 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> { - - private static final int THRESHOLD = 200; - - private final Set lines; - private final Set fullList; - private final double lower; - private final double upper; - - public RecursiveComputationTask(final Set fullList, final Set lines, - final double lower, final double upper) { - this.lines = lines; - this.fullList = fullList; - this.lower = lower; - this.upper = upper; - } - - @Override - protected Set 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 createSubTask() { - List dividedTasks = new ArrayList<>(); - - long midpoint = Math.round(this.lines.size() * 0.5); - - Set firstSubSet = new HashSet<>(); - Set 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 work(Set fullList, Set lines, double lower, - double higher) { - Set points = new HashSet<>(); - List> 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); - } - - - } - } diff --git a/src/main/java/de/wwwu/awolf/view/controller/AlgorithmTabController.java b/src/main/java/de/wwwu/awolf/view/controller/AlgorithmTabController.java index c7e8a27..f2250bf 100644 --- a/src/main/java/de/wwwu/awolf/view/controller/AlgorithmTabController.java +++ b/src/main/java/de/wwwu/awolf/view/controller/AlgorithmTabController.java @@ -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));