Skip to content

Conversation

seveibar
Copy link
Contributor

@seveibar seveibar commented Oct 2, 2025

Summary

  • add polygon utility module with point containment, overlap, and inclusion helpers for bounds and rect inputs
  • document new helpers in the README and expose rect typing information

Testing

  • bunx tsc --noEmit
  • bun test tests/polygon.test.ts

https://chatgpt.com/codex/tasks/task_b_68df0607c7c0832e8c2a977c463aad35

@seveibar seveibar merged commit 826d039 into main Oct 2, 2025
2 checks passed
Comment on lines +32 to +66
test("isPointInsidePolygon detects interior and exterior points", () => {
expect(isPointInsidePolygon({ x: 5, y: 5 }, square)).toBe(true)
expect(isPointInsidePolygon({ x: -1, y: -1 }, square)).toBe(false)
expect(isPointInsidePolygon({ x: 0, y: 5 }, square)).toBe(true)
})

test("areBoundsOverlappingPolygon returns true when overlap exists", () => {
const insideBounds: Bounds = { minX: 2, minY: 2, maxX: 4, maxY: 4 }
const overlappingBounds: Bounds = { minX: 8, minY: 8, maxX: 12, maxY: 12 }
const outsideBounds: Bounds = { minX: 12, minY: 12, maxX: 15, maxY: 15 }

expect(areBoundsOverlappingPolygon(insideBounds, square)).toBe(true)
expect(areBoundsOverlappingPolygon(overlappingBounds, square)).toBe(true)
expect(areBoundsOverlappingPolygon(outsideBounds, square)).toBe(false)
})

test("areBoundsCompletelyInsidePolygon handles concave polygons", () => {
const insideConcave: Bounds = { minX: 1, minY: 1, maxX: 3, maxY: 2 }
const crossingConcave: Bounds = { minX: 3, minY: 2, maxX: 5, maxY: 4 }

expect(areBoundsCompletelyInsidePolygon(insideConcave, concave)).toBe(true)
expect(areBoundsCompletelyInsidePolygon(crossingConcave, concave)).toBe(
false,
)
})

test("rect convenience wrappers use x/y/width/height format", () => {
const rectInside: Rect = { x: 1, y: 1, width: 2, height: 2 }
const rectCross: Rect = { x: 7, y: 7, width: 4, height: 4 }

expect(isRectCompletelyInsidePolygon(rectInside, square)).toBe(true)
expect(isRectOverlappingPolygon(rectInside, square)).toBe(true)
expect(isRectOverlappingPolygon(rectCross, square)).toBe(true)
expect(isRectCompletelyInsidePolygon(rectCross, square)).toBe(false)
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file violates the constraint that *.test.ts files may contain at most one test() function. The file contains four test() calls on lines 32, 38, 48, and 58. Split this into separate numbered files: polygon1.test.ts, polygon2.test.ts, polygon3.test.ts, and polygon4.test.ts, with each file containing exactly one test() function.

Spotted by Diamond (based on custom rule: Custom rule)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment on lines +134 to +146
export const areBoundsCompletelyInsidePolygon = (
bounds: Bounds,
polygon: Polygon,
): boolean => {
if (polygon.length < 3) return false

const corners = getBoundsCorners(bounds)
if (!corners.every((corner) => isPointInsidePolygon(corner, polygon))) {
return false
}

return !doesPolygonIntersectBounds(bounds, polygon)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of areBoundsCompletelyInsidePolygon contains a logical error. The function currently returns !doesPolygonIntersectBounds(bounds, polygon) as its final check, but this is incorrect for determining complete containment.

For bounds to be completely inside a polygon, checking that all corners are inside the polygon (as done in the first condition) is sufficient. The edge intersection check is not only unnecessary but can produce false negatives in cases where a polygon edge passes through the interior of the bounds without intersecting any of the bounds' edges.

The function should be simplified to:

export const areBoundsCompletelyInsidePolygon = (
  bounds: Bounds,
  polygon: Polygon,
): boolean => {
  if (polygon.length < 3) return false

  const corners = getBoundsCorners(bounds)
  return corners.every((corner) => isPointInsidePolygon(corner, polygon))
}
Suggested change
export const areBoundsCompletelyInsidePolygon = (
bounds: Bounds,
polygon: Polygon,
): boolean => {
if (polygon.length < 3) return false
const corners = getBoundsCorners(bounds)
if (!corners.every((corner) => isPointInsidePolygon(corner, polygon))) {
return false
}
return !doesPolygonIntersectBounds(bounds, polygon)
}
export const areBoundsCompletelyInsidePolygon = (
bounds: Bounds,
polygon: Polygon,
): boolean => {
if (polygon.length < 3) return false
const corners = getBoundsCorners(bounds)
return corners.every((corner) => isPointInsidePolygon(corner, polygon))
}

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant