mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
The planar map's `RectIndex` sorted rectangles narrow in x by their left edge and those narrow in y by their top edge, and scanned the rest for every lookup. A long diagonal segment is narrow in neither, so a hatch of diagonals put every line in the scanned list and `Outlines::source_at` (one lookup per edge) cost a scan of the hatch per edge: quadratic in the hatch below the 65,536-segment cap, as CodeRabbit found on #3357. `RectIndex` is now a grid of about one cell per item, each cell listing the items touching it; a lookup reads the cells around the point. An item is filed under a footprint of rectangles: its bounds (`new`), or, for a segment, the bounds of its pieces about a cell long (`with_footprint`, `segment_footprint`), so a diagonal is filed under the cells along it, not under every cell its bounds cover. A footprint rectangle covering more than 64 cells or two rows/columns (a face covering most of the art) is scanned for every point as before; a thin stripe face is filed under its column of cells. Cells hold `u32` indices. Tests: `rect_index_reads_a_diagonal_hatch_only_near_the_point` (2,000 diagonals a tenth of a point apart: a lookup got 1,001 candidates with the old index, now at most n/4, and still every line through the point; a hatch of stripe faces is filed, not scanned; a collinear, degenerate grid). `rect_index_finds_every_rectangle_holding_a_point` keeps the bounds-only contract. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gCpjL3yUhaH3jRp7ksufh