You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

intersections.ts 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { Bounds } from "types"
  2. import * as vec from "utils/vec"
  3. interface Intersection {
  4. didIntersect: boolean
  5. message: string
  6. points: number[][]
  7. }
  8. export function intersectCircleLine(
  9. c: number[],
  10. r: number,
  11. a1: number[],
  12. a2: number[]
  13. ): Intersection {
  14. const a =
  15. (a2[0] - a1[0]) * (a2[0] - a1[0]) + (a2[1] - a1[1]) * (a2[1] - a1[1])
  16. const b =
  17. 2 * ((a2[0] - a1[0]) * (a1[0] - c[0]) + (a2[1] - a1[1]) * (a1[1] - c[1]))
  18. const cc =
  19. c[0] * c[0] +
  20. c[1] * c[1] +
  21. a1[0] * a1[0] +
  22. a1[1] * a1[1] -
  23. 2 * (c[0] * a1[0] + c[1] * a1[1]) -
  24. r * r
  25. const deter = b * b - 4 * a * cc
  26. if (deter < 0) {
  27. return { didIntersect: false, message: "outside", points: [] }
  28. }
  29. if (deter === 0) {
  30. return { didIntersect: false, message: "tangent", points: [] }
  31. }
  32. var e = Math.sqrt(deter)
  33. var u1 = (-b + e) / (2 * a)
  34. var u2 = (-b - e) / (2 * a)
  35. if ((u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1)) {
  36. if ((u1 < 0 && u2 < 0) || (u1 > 1 && u2 > 1)) {
  37. return { didIntersect: false, message: "outside", points: [] }
  38. } else {
  39. return { didIntersect: false, message: "inside", points: [] }
  40. }
  41. }
  42. const result = { didIntersect: true, message: "intersection", points: [] }
  43. if (0 <= u1 && u1 <= 1) result.points.push(vec.lrp(a1, a2, u1))
  44. if (0 <= u2 && u2 <= 1) result.points.push(vec.lrp(a1, a2, u2))
  45. return result
  46. }
  47. export function intersectCircleRectangle(
  48. c: number[],
  49. r: number,
  50. point: number[],
  51. size: number[]
  52. ): Intersection[] {
  53. const tl = point
  54. const tr = vec.add(point, [size[0], 0])
  55. const br = vec.add(point, size)
  56. const bl = vec.add(point, [0, size[1]])
  57. const intersections: Intersection[] = []
  58. const topIntersection = intersectCircleLine(c, r, tl, tr)
  59. if (topIntersection.didIntersect) {
  60. intersections.push({ ...topIntersection, message: "top" })
  61. }
  62. const rightIntersection = intersectCircleLine(c, r, tr, br)
  63. if (rightIntersection.didIntersect) {
  64. intersections.push({ ...rightIntersection, message: "right" })
  65. }
  66. const bottomIntersection = intersectCircleLine(c, r, bl, br)
  67. if (bottomIntersection.didIntersect) {
  68. intersections.push({ ...bottomIntersection, message: "bottom" })
  69. }
  70. const leftIntersection = intersectCircleLine(c, r, tl, bl)
  71. if (leftIntersection.didIntersect) {
  72. intersections.push({ ...leftIntersection, message: "left" })
  73. }
  74. return intersections
  75. }
  76. export function intersectCircleBounds(
  77. c: number[],
  78. r: number,
  79. bounds: Bounds
  80. ): Intersection[] {
  81. const { minX, minY, width, height } = bounds
  82. const intersections = intersectCircleRectangle(
  83. c,
  84. r,
  85. [minX, minY],
  86. [width, height]
  87. )
  88. return intersections
  89. }