Current section
Files
Jump to
Current section
Files
lib/colliders.ex
defmodule Colliders do
@moduledoc """
Colliders module for polygon operations and collision detection.
"""
alias Colliders.Clipper
alias Colliders.Polygon
alias Colliders.Types.BBox
alias Colliders.Types.PolygonPoint
@eps 1.0e-9
@doc """
Checks if a bounding box overlaps a polygon by at least `threshold`% of the bbox area.
Uses an AABB pre-check for fast rejection, then computes the exact overlap percentage
via the Sutherland-Hodgman clipping algorithm.
## Parameters
- bbox: A `%BBox{}` struct (x, y = top-left corner, w = width, h = height)
- polygon: A `%Polygon{}` struct (use `Colliders.Polygon.new/1` to create one)
- threshold: Minimum overlap percentage required (default: `5.0`)
"""
def bbox_intersects_polygon?(%BBox{} = bbox, %Polygon{} = polygon, threshold \\ 5.0) do
if outside_aabb?(bbox, polygon) do
false
else
bbox_overlap_percentage(bbox, polygon) + @eps >= threshold
end
end
@doc """
Returns the percentage of the bbox area that overlaps with the polygon.
A value of `100.0` means the bbox is fully inside the polygon.
A value of `0.0` means no overlap at all.
## Parameters
- bbox: A `%BBox{}` struct
- polygon: A `%Polygon{}` struct
"""
@spec bbox_overlap_percentage(BBox.t(), Polygon.t()) :: float()
def bbox_overlap_percentage(%BBox{} = bbox, %Polygon{points: points}) do
intersection_area =
points
|> Clipper.clip_polygon(bbox)
|> Clipper.area()
bbox_area =
bbox
|> bbox_to_polygon_points()
|> Clipper.area()
intersection_area / bbox_area * 100
end
# Returns true if the bbox is entirely outside the polygon's AABB
# AABB stads for Axis-Aligned Bounding Box, it is basically a bounding box for the polygon
defp outside_aabb?(
%BBox{x: bx, y: by, w: bw, h: bh},
%Polygon{min_x: min_x, max_x: max_x, min_y: min_y, max_y: max_y}
) do
bx + bw < min_x or bx > max_x or by + bh < min_y or by > max_y
end
defp bbox_to_polygon_points(%BBox{x: x, y: y, w: w, h: h}) do
[
# Top-left
%PolygonPoint{x: x, y: y},
# Top-right
%PolygonPoint{x: x + w, y: y},
# Bottom-right
%PolygonPoint{x: x + w, y: y + h},
# Bottom-left
%PolygonPoint{x: x, y: y + h}
]
end
end