polygon.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { pointsEqual } from "./point";
  2. import { lineSegment, pointOnLineSegment } from "./segment";
  3. import type { GlobalPoint, LocalPoint, Polygon } from "./types";
  4. import { PRECISION } from "./utils";
  5. export function polygon<Point extends GlobalPoint | LocalPoint>(
  6. ...points: Point[]
  7. ) {
  8. return polygonClose(points) as Polygon<Point>;
  9. }
  10. export function polygonFromPoints<Point extends GlobalPoint | LocalPoint>(
  11. points: Point[],
  12. ) {
  13. return polygonClose(points) as Polygon<Point>;
  14. }
  15. export const polygonIncludesPoint = <Point extends LocalPoint | GlobalPoint>(
  16. point: Point,
  17. polygon: Polygon<Point>,
  18. ) => {
  19. const x = point[0];
  20. const y = point[1];
  21. let inside = false;
  22. for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
  23. const xi = polygon[i][0];
  24. const yi = polygon[i][1];
  25. const xj = polygon[j][0];
  26. const yj = polygon[j][1];
  27. if (
  28. ((yi > y && yj <= y) || (yi <= y && yj > y)) &&
  29. x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
  30. ) {
  31. inside = !inside;
  32. }
  33. }
  34. return inside;
  35. };
  36. export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>(
  37. p: Point,
  38. poly: Polygon<Point>,
  39. threshold = PRECISION,
  40. ) => {
  41. let on = false;
  42. for (let i = 0, l = poly.length - 1; i < l; i++) {
  43. if (pointOnLineSegment(p, lineSegment(poly[i], poly[i + 1]), threshold)) {
  44. on = true;
  45. break;
  46. }
  47. }
  48. return on;
  49. };
  50. function polygonClose<Point extends LocalPoint | GlobalPoint>(
  51. polygon: Point[],
  52. ) {
  53. return polygonIsClosed(polygon)
  54. ? polygon
  55. : ([...polygon, polygon[0]] as Polygon<Point>);
  56. }
  57. function polygonIsClosed<Point extends LocalPoint | GlobalPoint>(
  58. polygon: Point[],
  59. ) {
  60. return pointsEqual(polygon[0], polygon[polygon.length - 1]);
  61. }