Line data Source code
1 : import '../../extensions.dart'; 2 : import 'line.dart'; 3 : 4 : /// A [LineSegment] represent a segment of an infinitely long line, it is the 5 : /// segment between the [from] and [to] vectors (inclusive). 6 : class LineSegment { 7 : final Vector2 from; 8 : final Vector2 to; 9 : 10 7 : LineSegment(this.from, this.to); 11 : 12 : /// Returns an empty list if there are no intersections between the segments 13 : /// If the segments are concurrent, the intersecting point is returned as a 14 : /// list with a single point 15 3 : List<Vector2> intersections(LineSegment otherSegment) { 16 9 : final result = toLine().intersections(otherSegment.toLine()); 17 3 : if (result.isNotEmpty) { 18 : // The lines are not parallel 19 3 : final intersection = result.first; 20 3 : if (containsPoint(intersection) && 21 3 : otherSegment.containsPoint(intersection)) { 22 : // The intersection point is on both line segments 23 : return result; 24 : } 25 : } else { 26 : // In here we know that the lines are parallel 27 3 : final overlaps = ({ 28 9 : from: otherSegment.containsPoint(from), 29 9 : to: otherSegment.containsPoint(to), 30 9 : otherSegment.from: containsPoint(otherSegment.from), 31 9 : otherSegment.to: containsPoint(otherSegment.to), 32 6 : }..removeWhere((_key, onSegment) => !onSegment)) 33 3 : .keys 34 3 : .toSet(); 35 3 : if (overlaps.isNotEmpty) { 36 1 : return [ 37 1 : overlaps.fold<Vector2>( 38 1 : Vector2.zero(), 39 2 : (sum, point) => sum + point, 40 1 : ) / 41 2 : overlaps.length.toDouble(), 42 : ]; 43 : } 44 : } 45 3 : return []; 46 : } 47 : 48 3 : bool containsPoint(Vector2 point, {double epsilon = 0.000001}) { 49 9 : final delta = to - from; 50 : final crossProduct = 51 39 : (point.y - from.y) * delta.x - (point.x - from.x) * delta.y; 52 : 53 : // compare versus epsilon for floating point values 54 6 : if (crossProduct.abs() > epsilon) { 55 : return false; 56 : } 57 : 58 : final dotProduct = 59 39 : (point.x - from.x) * delta.x + (point.y - from.y) * delta.y; 60 3 : if (dotProduct < 0) { 61 : return false; 62 : } 63 : 64 9 : final squaredLength = from.distanceToSquared(to); 65 3 : if (dotProduct > squaredLength) { 66 : return false; 67 : } 68 : 69 : return true; 70 : } 71 : 72 1 : bool pointsAt(Line line) { 73 2 : final result = toLine().intersections(line); 74 1 : if (result.isNotEmpty) { 75 3 : final delta = to - from; 76 1 : final intersection = result.first; 77 2 : final intersectionDelta = intersection - to; 78 : // Whether the two points [from] and [through] forms a ray that points on 79 : // the line represented by this object 80 5 : if (delta.x.sign == intersectionDelta.x.sign && 81 5 : delta.y.sign == intersectionDelta.y.sign) { 82 : return true; 83 : } 84 : } 85 : return false; 86 : } 87 : 88 12 : Line toLine() => Line.fromPoints(from, to); 89 : 90 0 : @override 91 : String toString() { 92 0 : return '[$from, $to]'; 93 : } 94 : }