Report the overlap akgl_collide_rectangles could not see
It asked whether either rectangle enclosed one of the other's four corners -- eight akgl_collide_point_rectangle calls, stopping at the first hit. That is a different question from "do these overlap", and it has the wrong answer for one arrangement: a tall thin rectangle crossing a short wide one overlaps in a plus sign with no corner of either inside the other, and all eight tests said no. A long thin platform crossing a tall thin character is exactly that shape, so this is a shape a 2D game produces, not a curiosity. util.h carried an @note describing it and docs/18-utilities.md had a diagram of it, both under the heading of a limitation rather than a defect, and there was no test for it at all -- nor for full containment, nor for a shared edge. It is four comparisons now, on both axes. `<=` rather than `<` because akgl_collide_point_rectangle is inclusive on all four edges and these two have always agreed that touching counts; a span test written with `<` would have silently changed a contract both the header and the manual state. The test was written first and failed on the cross before the fix went in. Two answers change for a caller upgrading, and both are in the header note and the chapter: - The cross reports `true`, which is the point. - The comparison is in float rather than through akgl_Point's int members, so a sub-pixel overlap is no longer truncated away. A pickup test that was accidentally forgiving by up to a pixel is no longer forgiving. Both tutorials use this for coins and hazards; both still pass. Faster as a side effect rather than a goal, and worth recording because the numbers move a documented budget: 24.9 ns -> 6.1 overlapping, 57.9 -> 6.1 disjoint, and the all-pairs sweep over 64 actors 115 us -> 12.2. The disjoint case gained most because it was the one that ran all eight tests before answering. The three moved rows are re-recorded in PERFORMANCE.md and nothing else is. akgl_rectangle_points is untouched by this change and reads 6.1 in the same run against the 4.0 recorded, so 6 ns is this run's floor and the new figure means "too cheap to measure" rather than "exactly 6.1" -- said in the prose so the next reader does not re-baseline the table around it. Co-Authored-By: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,10 +89,14 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_point_rectangle(akgl_Point *p, a
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p r1, @p r2, or @p collide is `NULL`.
|
||||
*
|
||||
* @note A corner-containment test misses the one arrangement where two
|
||||
* rectangles overlap in a cross without either enclosing a corner of the
|
||||
* other -- a tall thin rectangle crossing a short wide one. Both are
|
||||
* reported as not colliding.
|
||||
* @note Fixed in 0.8.0. This was eight corner-containment tests, which answer a
|
||||
* different question and get the cross wrong: a tall thin rectangle
|
||||
* crossing a short wide one overlaps without either enclosing a corner of
|
||||
* the other, and every corner test said no. It is a span comparison on
|
||||
* both axes now. Two consequences for a caller upgrading: that
|
||||
* arrangement starts reporting `true`, and the comparison is in `float`
|
||||
* rather than through akgl_Point's `int` members, so an overlap smaller
|
||||
* than one pixel is no longer truncated away.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_rectangles(SDL_FRect *r1, SDL_FRect *r2, bool *collide);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user