geometry.test.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import {
  2. pointFrom,
  3. lineSegment,
  4. polygon,
  5. pointOnLineSegment,
  6. pointOnPolygon,
  7. polygonIncludesPoint,
  8. segmentsIntersectAt,
  9. } from "@excalidraw/math";
  10. import type {
  11. GlobalPoint,
  12. LineSegment,
  13. Polygon,
  14. Radians,
  15. } from "@excalidraw/math";
  16. import { pointInEllipse, pointOnEllipse, type Ellipse } from "../src/shape";
  17. describe("point and line", () => {
  18. // const l: Line<GlobalPoint> = line(point(1, 0), point(1, 2));
  19. // it("point on left or right of line", () => {
  20. // expect(pointLeftofLine(point(0, 1), l)).toBe(true);
  21. // expect(pointLeftofLine(point(1, 1), l)).toBe(false);
  22. // expect(pointLeftofLine(point(2, 1), l)).toBe(false);
  23. // expect(pointRightofLine(point(0, 1), l)).toBe(false);
  24. // expect(pointRightofLine(point(1, 1), l)).toBe(false);
  25. // expect(pointRightofLine(point(2, 1), l)).toBe(true);
  26. // });
  27. const s: LineSegment<GlobalPoint> = lineSegment(
  28. pointFrom(1, 0),
  29. pointFrom(1, 2),
  30. );
  31. it("point on the line", () => {
  32. expect(pointOnLineSegment(pointFrom(0, 1), s)).toBe(false);
  33. expect(pointOnLineSegment(pointFrom(1, 1), s, 0)).toBe(true);
  34. expect(pointOnLineSegment(pointFrom(2, 1), s)).toBe(false);
  35. });
  36. });
  37. describe("point and polygon", () => {
  38. const poly: Polygon<GlobalPoint> = polygon(
  39. pointFrom(10, 10),
  40. pointFrom(50, 10),
  41. pointFrom(50, 50),
  42. pointFrom(10, 50),
  43. );
  44. it("point on polygon", () => {
  45. expect(pointOnPolygon(pointFrom(30, 10), poly)).toBe(true);
  46. expect(pointOnPolygon(pointFrom(50, 30), poly)).toBe(true);
  47. expect(pointOnPolygon(pointFrom(30, 50), poly)).toBe(true);
  48. expect(pointOnPolygon(pointFrom(10, 30), poly)).toBe(true);
  49. expect(pointOnPolygon(pointFrom(30, 30), poly)).toBe(false);
  50. expect(pointOnPolygon(pointFrom(30, 70), poly)).toBe(false);
  51. });
  52. it("point in polygon", () => {
  53. const poly: Polygon<GlobalPoint> = polygon(
  54. pointFrom(0, 0),
  55. pointFrom(2, 0),
  56. pointFrom(2, 2),
  57. pointFrom(0, 2),
  58. );
  59. expect(polygonIncludesPoint(pointFrom(1, 1), poly)).toBe(true);
  60. expect(polygonIncludesPoint(pointFrom(3, 3), poly)).toBe(false);
  61. });
  62. });
  63. describe("point and ellipse", () => {
  64. const ellipse: Ellipse<GlobalPoint> = {
  65. center: pointFrom(0, 0),
  66. angle: 0 as Radians,
  67. halfWidth: 2,
  68. halfHeight: 1,
  69. };
  70. it("point on ellipse", () => {
  71. [
  72. pointFrom(0, 1),
  73. pointFrom(0, -1),
  74. pointFrom(2, 0),
  75. pointFrom(-2, 0),
  76. ].forEach((p) => {
  77. expect(pointOnEllipse(p, ellipse)).toBe(true);
  78. });
  79. expect(pointOnEllipse(pointFrom(-1.4, 0.7), ellipse, 0.1)).toBe(true);
  80. expect(pointOnEllipse(pointFrom(-1.4, 0.71), ellipse, 0.01)).toBe(true);
  81. expect(pointOnEllipse(pointFrom(1.4, 0.7), ellipse, 0.1)).toBe(true);
  82. expect(pointOnEllipse(pointFrom(1.4, 0.71), ellipse, 0.01)).toBe(true);
  83. expect(pointOnEllipse(pointFrom(1, -0.86), ellipse, 0.1)).toBe(true);
  84. expect(pointOnEllipse(pointFrom(1, -0.86), ellipse, 0.01)).toBe(true);
  85. expect(pointOnEllipse(pointFrom(-1, -0.86), ellipse, 0.1)).toBe(true);
  86. expect(pointOnEllipse(pointFrom(-1, -0.86), ellipse, 0.01)).toBe(true);
  87. expect(pointOnEllipse(pointFrom(-1, 0.8), ellipse)).toBe(false);
  88. expect(pointOnEllipse(pointFrom(1, -0.8), ellipse)).toBe(false);
  89. });
  90. it("point in ellipse", () => {
  91. [
  92. pointFrom(0, 1),
  93. pointFrom(0, -1),
  94. pointFrom(2, 0),
  95. pointFrom(-2, 0),
  96. ].forEach((p) => {
  97. expect(pointInEllipse(p, ellipse)).toBe(true);
  98. });
  99. expect(pointInEllipse(pointFrom(-1, 0.8), ellipse)).toBe(true);
  100. expect(pointInEllipse(pointFrom(1, -0.8), ellipse)).toBe(true);
  101. expect(pointInEllipse(pointFrom(-1, 1), ellipse)).toBe(false);
  102. expect(pointInEllipse(pointFrom(-1.4, 0.8), ellipse)).toBe(false);
  103. });
  104. });
  105. describe("line and line", () => {
  106. const lineA: LineSegment<GlobalPoint> = lineSegment(
  107. pointFrom(1, 4),
  108. pointFrom(3, 4),
  109. );
  110. const lineB: LineSegment<GlobalPoint> = lineSegment(
  111. pointFrom(2, 1),
  112. pointFrom(2, 7),
  113. );
  114. const lineC: LineSegment<GlobalPoint> = lineSegment(
  115. pointFrom(1, 8),
  116. pointFrom(3, 8),
  117. );
  118. const lineD: LineSegment<GlobalPoint> = lineSegment(
  119. pointFrom(1, 8),
  120. pointFrom(3, 8),
  121. );
  122. const lineE: LineSegment<GlobalPoint> = lineSegment(
  123. pointFrom(1, 9),
  124. pointFrom(3, 9),
  125. );
  126. const lineF: LineSegment<GlobalPoint> = lineSegment(
  127. pointFrom(1, 2),
  128. pointFrom(3, 4),
  129. );
  130. const lineG: LineSegment<GlobalPoint> = lineSegment(
  131. pointFrom(0, 1),
  132. pointFrom(2, 3),
  133. );
  134. it("intersection", () => {
  135. expect(segmentsIntersectAt(lineA, lineB)).toEqual([2, 4]);
  136. expect(segmentsIntersectAt(lineA, lineC)).toBe(null);
  137. expect(segmentsIntersectAt(lineB, lineC)).toBe(null);
  138. expect(segmentsIntersectAt(lineC, lineD)).toBe(null); // Line overlapping line is not intersection!
  139. expect(segmentsIntersectAt(lineE, lineD)).toBe(null);
  140. expect(segmentsIntersectAt(lineF, lineG)).toBe(null);
  141. });
  142. });