package de.wwwu.awolf.presenter.util; import com.google.common.collect.Lists; import de.wwwu.awolf.model.Line; import de.wwwu.awolf.model.Point; import java.util.*; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; import java.util.stream.Collectors; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 18.09.2017. */ public class IntersectionComputer { private static IntersectionComputer instance; /** * Konstruktor */ private IntersectionComputer() { } public static IntersectionComputer getInstance() { if (instance == null) { instance = new IntersectionComputer(); Logging.logInfo("Created instance of IntersectionComputer"); } return instance; } /** * 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 Collection compute(final List lines, final double lower, final double higher) { if (lower == higher) { return Collections.emptyList(); } else { Logging.logDebug("Open ForkJoinPool: lines: " + lines.size() + " I(" + lower + ", " + higher + "]"); ForkJoinPool pool = ForkJoinPool.commonPool(); RecursiveComputationTask recursiveComputationTask = new RecursiveComputationTask(lines, lines, lower, higher); pool.execute(recursiveComputationTask); return recursiveComputationTask.join(); } } /** * Berechnet die Schnittpunkte zwischen einer gegebenen Gerade und einer Menge an Geraden. * * @param set Menge an Geraden * @param sampledLine eine spezielle Gerade * @return Liste mit x Koordinaten der Schnittpunkte */ public List calculateIntersectionAbscissas(List 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 = 20; private final List lines; private final List fullList; private final double lower; private final double upper; public RecursiveComputationTask(final List fullList, final List lines, final double lower, final double upper) { this.lines = lines; this.fullList = fullList; this.lower = lower; this.upper = upper; } @Override protected Collection compute() { if (this.lines.isEmpty()) { return Collections.emptyList(); } else if (this.lines.size() > THRESHOLD) { Logging.logDebug("Bigger than threshold, split into subtask."); return ForkJoinTask.invokeAll(createSubTask()).stream().map(ForkJoinTask::join).flatMap(Collection::stream).collect(Collectors.toList()); } else { return work(this.fullList, this.lines, this.lower, this.upper); } } private Collection createSubTask() { List dividedTasks = new ArrayList<>(); dividedTasks.add(new RecursiveComputationTask(this.fullList, this.lines.subList(0, this.lines.size() / 2), this.lower, this.upper)); dividedTasks.add(new RecursiveComputationTask(this.fullList, this.lines.subList(this.lines.size() / 2, this.lines.size()), this.lower, this.upper)); return dividedTasks; } private Collection work(List fullList, List 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); } } }