package de.wwwu.awolf.model; import java.util.Objects; import org.apache.commons.math3.util.Precision; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 12.06.2017. */ 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 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) { 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); } /** * Konstruktor * * @param x1 x-Koordiante des Startpunkts * @param x2 x-Koordinate des Endpunkts * @param y1 y-Koordinate des Startpunkts * @param y2 y-Koordinate des Endpunkts */ public Line(double x1, double x2, double y1, 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); } 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; } /** * @return Steigung der Gerade */ public Double getM() { return m; } /** * @param m Steigung der Gerade */ public void setM(double m) { this.m = m; } /** * @return y-Achsenabschnitt der Gerade */ public Double getB() { return b; } /** * @param b y-Achsenabschnitt der Gerade */ public void setB(double b) { this.b = b; } /** * @return id der Gerade */ public String getId() { return id; } /** * @param id id der Gerade */ public void setId(String id) { 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 * * @param obj zu vergleichende Gerade * @return true falls die Geraden Gleich sind */ @Override public boolean equals(Object obj) { if (obj instanceof Line) { Line other = (Line) obj; return Precision.equals(other.getM(), this.getM(), EPSILON) && Precision .equals(other.getB(), this.getB(), EPSILON); } else { return super.equals(obj); } } @Override public int hashCode() { return Objects.hash(Precision.round(m, 5), Precision.round(b, 5)); } @Override public String toString() { return "Line m: " + this.getM() + ", b: " + this.getB(); } public Point intersect(Line line) { double x = (line.b - this.b) / (this.m - line.m); double y = this.m * x + this.b; 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) { return this.getB().compareTo(line.getB()); } else { return this.getM().compareTo(line.getM()); } } }