package de.wwwu.awolf.presenter.util; import de.wwwu.awolf.model.Interval; import de.wwwu.awolf.model.Line; import de.wwwu.awolf.model.Pair; import de.wwwu.awolf.model.Point; import de.wwwu.awolf.presenter.util.Comparators.YOrderLineComparatorBegin; import de.wwwu.awolf.presenter.util.Comparators.YOrderLineComparatorEnd; import java.util.*; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 18.06.2017. */ public class IntersectionCounter { private HashMap dictionaryTO; private HashMap dictionaryBACK; private ArrayList substituted; private ArrayList inversions; private List set; //indexieren der Punkte damit die schnittpunkte berechnet werden können private HashMap secondaryDictionaryTO; private HashMap secondaryDictionaryBACK; private ArrayList umin; /** * Berechnet die Inversionen zwischen zwei Listen mit Integer Werten. Diese Methode dient als * Wrapper Methode. Die Logik steht in der countInversions Funktion. * * @param a Liste * @param b Liste * @return Anzahl an Inversionen */ public int run(List a, List b) { dictionaryTO = new HashMap<>(); dictionaryBACK = new HashMap<>(); substituted = new ArrayList<>(); inversions = new ArrayList<>(); ArrayList temp = new ArrayList<>(); temp.addAll(a); for (int i = 0; i < a.size(); i++) { dictionaryTO.put(a.get(i), i + 1); dictionaryBACK.put(i + 1, a.get(i)); } for (int j = 0; j < b.size(); j++) { substituted.add(dictionaryTO.get(b.get(j))); } int ret = countInversions(substituted, 0, substituted.size() - 1, temp); return ret; } /** * Wrapper Methode um herauszufinden wieviele Inversionen zwischen den Schnittpunkten der Werte * in der Liste und den Endpunkten des Intervalls entstehen. * * @param set Liste mit Werten (m,b) um Schnittpunkte zu berechnen * @param interval Interval * @return Anzahl an Inversionen */ public int run(List set, Interval interval) { ArrayList listA = new ArrayList<>(); ArrayList listB = new ArrayList<>(); prepareData(set, interval, listA, listB); return run(listA, listB); } /** * Methode die, die Daten für die Funktion run vorbereitet. Es werden die Schnittpunkte * bzgl. der unteren und oberen Grenze des Intervals und den Werten der Liste (m,b) berechnet. Diese * Werte haben die selbe x Koordinate aber verschiedene y Koordinaten. * * @param set Liste mit Werten m,b * @param interval Interval * @param listA Schnittpunkte bzgl. unteren Grenze * @param listB Schnittpunkte bzgl. oberen Grenze */ private void prepareData(List set, Interval interval, ArrayList listA, ArrayList listB) { secondaryDictionaryTO = new HashMap<>(); secondaryDictionaryBACK = new HashMap<>(); this.set = set; umin = new ArrayList<>(); Line tmpLine; for (Line p : set) { //vertauscht das Point standardmäßig die x lexikografische Ordnung betrachtet tmpLine = new Line(p.getM(), p.getM(), interval.getLower() * p.getM() + p.getB(), interval.getUpper() * p.getM() + p.getB()); //wird benötigt um späer die Schnittpunkte ermitteln zu können tmpLine.setB(p.getB()); tmpLine.setM(p.getM()); umin.add(tmpLine); } for (int i = 0; i < umin.size(); i++) { secondaryDictionaryTO.put(umin.get(i), i); secondaryDictionaryBACK.put(i, this.set.get(i)); } Collections.sort(umin, new YOrderLineComparatorBegin()); for (Line q : umin) { listA.add(secondaryDictionaryTO.get(q)); } Collections.sort(umin, new YOrderLineComparatorEnd()); for (Line q : umin) { listB.add(secondaryDictionaryTO.get(q)); } } /** * Angepasster Merge-Sort Algorithmus. * Die Funktion bekommt neben den standard Parametern zusätzlich eine Liste mit Elementen * die als Groundtruth dienen. * * @param a Eingabefeld mit den Elementen die überprüft werden sollen. * @param start Startpunkt des Eingabefeldes. * @param end Endpunkt des Eingabefeldes. * @param aux Temporäres Array das beim Mergen eine Kopie des original Arrays ist. * @return Anzahl der inversionen zwischen a und aux. */ public int countInversions(List a, int start, int end, List aux) { if (start >= end) { return 0; } int invCount = 0; int mid = start + (end - start) / 2; int invCountLeft = countInversions(a, start, mid, aux); // divide and conquer int invCountRight = countInversions(a, mid + 1, end, aux); // divide and conquer invCount += (invCountLeft + invCountRight); for (int i = start; i <= end; i++) { aux.set(i, a.get(i)); } int left = start; int right = mid + 1; int index = start; //hier beginnt das merging //iteriere über die Teillisten while (left <= mid && right <= end) { //wenn die linke Teilliste das kleinere Element besitzt kopiere //das Element in das neue Array if (aux.get(left) < aux.get(right)) { a.set(index++, aux.get(left++)); } else { //merke die inversionspaare for (int i = left; i <= mid; i++) { // Logging.logInfo(aux.get(i)+" -- "+ aux.get(right)); inversions.add(new Pair(aux.get(i), aux.get(right))); } a.set(index++, aux.get(right++)); invCount += mid - left + 1; // number of inversions for aux[right] } } while (left <= mid) { a.set(index++, aux.get(left++)); } // no need to copy over remaining aux[right++] because they are already inside a return invCount; } /** * Diese Methode liefert nur nach dem Ausführen der run Funktion Sinnvolle Werte. */ public ArrayList calculateIntersectionAbscissas() { ArrayList result = new ArrayList<>(); ArrayList points = new ArrayList<>(); for (int i = 0; i < inversions.size(); i++) { result.add(new Pair(dictionaryBACK.get(inversions.get(i).getP1()), dictionaryBACK.get(inversions.get(i).getP2()))); } for (Pair p : result) { Line line = secondaryDictionaryBACK.get(p.getP1()); Line sampledLine = secondaryDictionaryBACK.get(p.getP2()); if (!line.equals(sampledLine)) { double intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM()); double yintercept = sampledLine.getM() * intersection + sampledLine.getB(); Point point = new Point(intersection, yintercept); points.add(point); } } return points; } /** * 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) { List lines = new LinkedList<>(set); List intersections = new ArrayList<>(); double intersection; for (Line line : lines) { if (line != sampledLine) { intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM()); intersections.add(intersection); } } return intersections; } }