package de.wwwu.awolf.presenter.util; import de.wwwu.awolf.model.Interval; import de.wwwu.awolf.model.Line; import de.wwwu.awolf.model.Point; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 18.09.2017. */ public class IntersectionComputer { private List lines; private Set intersections; private Double xMinimum; private Double xMaximum; private Double yMinimum; private Double yMaximum; private Thread[] worker; /** * Konstruktor * * @param lines Liste der Geraden */ public IntersectionComputer(List lines) { this.lines = lines; this.worker = new Thread[4]; this.intersections = new TreeSet<>(); xMinimum = Double.MAX_VALUE; xMaximum = Double.MIN_VALUE; yMinimum = Double.MAX_VALUE; yMaximum = Double.MIN_VALUE; } /** * 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 ArrayList compute(final double lower, final double higher) { if (lines.size() > 16) { worker[0] = new Thread(() -> { work(lines.subList(0, (lines.size() / 4)), lower, higher); }); worker[0].start(); worker[1] = new Thread(() -> { work(lines.subList((lines.size() / 4) + 1, (lines.size() / 2)), lower, higher); }); worker[1].start(); worker[2] = new Thread(() -> { work(lines.subList((lines.size() / 2) + 1, 3 * (lines.size() / 4)), lower, higher); }); worker[2].start(); worker[3] = new Thread(() -> { work(lines.subList(3 * (lines.size() / 4) + 1, (lines.size())), lower, higher); }); worker[3].start(); for (Thread t : worker) { try { t.join(); } catch (InterruptedException e) { Logging.logError(e.getMessage(), e); Thread.currentThread().interrupt(); } } } else { work(lines, lower, higher); } return new ArrayList<>(intersections); } /** * 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. * * @return Liste der Schnittpunkte */ public ArrayList compute() { return compute(-99999, 99999); } private void work(List lines, double lower, double higher) { IntersectionCounter counter = new IntersectionCounter(); int count = counter.run(lines, new Interval(lower, higher)); ArrayList points = counter.calculateIntersectionAbscissas(); for (Point p : points) { if (!isFound(p)) { addIntersection(p); setRanges(p); } } } /** * Synchronisierter Zugriff auf die Liste der Geraden * * @return Liste der Geraden */ public synchronized List getLines() { return lines; } /** * Synchronisierter hinzufügen eines Schnittpunkts * * @param p Schnittpunkt */ public synchronized void addIntersection(Point p) { this.intersections.add(p); } /** * Synchronisiertes abfragen ob ein Schnittpunkt bereits gefunden wurde. * * @param p Schnittpunkt * @return true, falls der Schnittpunkt p bereits gefunden wurde */ public synchronized boolean isFound(Point p) { return intersections.contains(p); } /** * Zu einem Punkt werden die minimalen, maximalen x- und y-Koordinaten überprüft und ggf. * neu gesetzt * * @param point Schnittpunkt */ public void setRanges(Point point) { xMaximum = (point.getX() > xMaximum) ? point.getX() : xMaximum; xMinimum = (point.getX() < xMinimum) ? point.getX() : xMinimum; yMaximum = (point.getY() > yMaximum) ? point.getY() : yMaximum; yMinimum = (point.getY() < yMinimum) ? point.getY() : yMinimum; } /** * Synchronisierter Zugriff auf die minimale x-Koordiante * * @return minimale x-Koordiante */ public synchronized Double getxMinimum() { return xMinimum; } /** * Synchronisierter Zugriff auf die maximale x-Koordinate * * @return maximale x-Koordinate */ public synchronized Double getxMaximum() { return xMaximum; } /** * Synchronisierter Zugriff auf die minimale y-Koordinate * * @return minimale y-Koordinate */ public synchronized Double getyMinimum() { return yMinimum; } /** * Synchronisierter Zugriff auf die maximale y-Koordinate * * @return maximale y-Koordinate */ public synchronized Double getyMaximum() { return yMaximum; } }