using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bbiwarg.Utility { public enum LineSide { onLine = 0, above = 1, below = 2 } class Line2D { private Vector2D p1; private Vector2D p2; private Vector2D direction; private float length; private int numCombinedLines; public Vector2D P1 { get { return p1; } private set { p1 = value; } } public Vector2D P2 { get { return p2; } private set { p2 = value; } } public Vector2D Direction { get { return direction; } private set { direction = value; } } public float Length { get { return length; } private set { length = value; } } public int NumCombinedLines { get { return numCombinedLines; } private set { numCombinedLines = value; } } public Line2D(Vector2D p1, Vector2D p2) { setPoints(p1, p2); NumCombinedLines = 1; } public Line2D(List lines) { //list all points List points = new List(); List directions = new List(); NumCombinedLines = 0; foreach (Line2D line in lines) { points.Add(line.P1); points.Add(line.P2); directions.Add(line.Direction); NumCombinedLines += line.NumCombinedLines; } //find two points with max-distance Vector2D a = points[0]; Vector2D b = points[0]; float length = 0; foreach (Vector2D p in points) { float distanceToA = p.getDistanceTo(a); float distanceToB = p.getDistanceTo(b); if (distanceToA > length && distanceToA >= distanceToB) { b = p; length = distanceToA; } else if (distanceToB > length && distanceToB > distanceToA) { a = p; length = distanceToA; } } //project a and b on mean-line Vector2D meanPoint = Vector2D.mean(points); Vector2D meanDirection = Vector2D.mean(directions); Line2D meanLine = new Line2D(meanPoint, meanPoint + meanDirection); Vector2D meanA = meanLine.projectToLine(a); Vector2D meanB = meanLine.projectToLine(b); setPoints(meanA, meanB); } private void setPoints(Vector2D p1, Vector2D p2) { //endpoints P1 = p1; P2 = p2; //direction direction = (P1-P2).normalize(); //length Length = P1.getDistanceTo(P2); } public float getAngleBetween(Line2D line) { float angle = direction.getAngleBetween(line.Direction); return Math.Min(angle, 180-angle); } public float getParallelDistanceTo(Line2D line) { if (onSide(line.P1) != onSide(line.P2)) return 0; Vector2D a1 = projectToLine(line.P1); Vector2D a2 = projectToLine(line.P2); float distanceA1 = a1.getDistanceTo(line.P1); float distanceA2 = a2.getDistanceTo(line.P2); return Math.Min(distanceA1, distanceA2); } public float getVerticalDistanceTo(Line2D line) { Vector2D a1 = projectToLine(line.P1); Vector2D a2 = projectToLine(line.P2); if (P1.isInBox(a1, a2) || P2.isInBox(a1, a2)) return 0; float distanceP1A1 = P1.getDistanceTo(a1); float distanceP1A2 = P1.getDistanceTo(a2); float distanceP2A1 = p2.getDistanceTo(a1); float distanceP2A2 = p2.getDistanceTo(a2); return Math.Min(Math.Min(distanceP1A1, distanceP1A2), Math.Min(distanceP2A1, distanceP2A2)); } public LineSide onSide(Vector2D point) { float yPerX = direction.Y / direction.X; float xDiff = point.X - P1.X; float newY = P1.Y + yPerX * xDiff; if (newY < point.Y) return LineSide.above; else if (newY > point.Y) return LineSide.below; else return LineSide.onLine; } public Vector2D projectToLine(Vector2D point) { float px = point.X, py = point.Y, dx = Direction.X, dy = Direction.Y, ox = P1.X, oy = P1.Y; float diffx = px - ox; float diffy = py - oy; float diff_d = (diffx * dx + diffy * dy); float d_d = (dx * dx + dy * dy); float q = diff_d / d_d; float newX = ox + q * dx; float newY = oy + q * dy; return new Vector2D(newX, newY); } public override string ToString() { return (int)P1.X + "|" + (int)P1.Y + " --- " + (int)P2.X + "|" + (int)P2.Y; } } }