bbox.ts 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { Bounds } from "./excalidraw/element/bounds";
  2. import { Point } from "./excalidraw/types";
  3. export type LineSegment = [Point, Point];
  4. export function getBBox(line: LineSegment): Bounds {
  5. return [
  6. Math.min(line[0][0], line[1][0]),
  7. Math.min(line[0][1], line[1][1]),
  8. Math.max(line[0][0], line[1][0]),
  9. Math.max(line[0][1], line[1][1]),
  10. ];
  11. }
  12. export function crossProduct(a: Point, b: Point) {
  13. return a[0] * b[1] - b[0] * a[1];
  14. }
  15. export function doBBoxesIntersect(a: Bounds, b: Bounds) {
  16. return a[0] <= b[2] && a[2] >= b[0] && a[1] <= b[3] && a[3] >= b[1];
  17. }
  18. export function translate(a: Point, b: Point): Point {
  19. return [a[0] - b[0], a[1] - b[1]];
  20. }
  21. const EPSILON = 0.000001;
  22. export function isPointOnLine(l: LineSegment, p: Point) {
  23. const p1 = translate(l[1], l[0]);
  24. const p2 = translate(p, l[0]);
  25. const r = crossProduct(p1, p2);
  26. return Math.abs(r) < EPSILON;
  27. }
  28. export function isPointRightOfLine(l: LineSegment, p: Point) {
  29. const p1 = translate(l[1], l[0]);
  30. const p2 = translate(p, l[0]);
  31. return crossProduct(p1, p2) < 0;
  32. }
  33. export function isLineSegmentTouchingOrCrossingLine(
  34. a: LineSegment,
  35. b: LineSegment,
  36. ) {
  37. return (
  38. isPointOnLine(a, b[0]) ||
  39. isPointOnLine(a, b[1]) ||
  40. (isPointRightOfLine(a, b[0])
  41. ? !isPointRightOfLine(a, b[1])
  42. : isPointRightOfLine(a, b[1]))
  43. );
  44. }
  45. // https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/
  46. export function doLineSegmentsIntersect(a: LineSegment, b: LineSegment) {
  47. return (
  48. doBBoxesIntersect(getBBox(a), getBBox(b)) &&
  49. isLineSegmentTouchingOrCrossingLine(a, b) &&
  50. isLineSegmentTouchingOrCrossingLine(b, a)
  51. );
  52. }