[in3Utils, issue #1337] fix isCounterClockWise winding heuristic (not rotation-invariant) - #1338
Merged
fso42 merged 3 commits intoSep 10, 2026
Conversation
isCounterClockWise() decided a polygon's winding via a majority vote on vertex angles measured relative to whichever vertex is listed first. That heuristic is not rotation-invariant: the identical polygon can get two different answers depending on which vertex happens to be first, or on the polygon's absolute orientation in the plane -- reproduced on a plain convex square, not only concave shapes. polygon2Raster() uses the sign of this result to decide whether its `radius` tolerance dilates or shrinks a polygon before rasterizing it. A misjudged winding silently shrinks a release/entrainment/resistance area instead of dilating it -- on a real building-footprint release polygon (59 vertices) this reduced 6 legitimate non-empty release cells to 1, roughly 92% of the intended release mass dropped with no error or warning. Replace the heuristic with the shoelace formula, which is exact and rotation-invariant for any simple polygon, convex or concave. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bskerlak
commented
Sep 9, 2026
bskerlak
marked this pull request as ready for review
September 9, 2026 09:37
fso42
approved these changes
Sep 9, 2026
fso42
left a comment
Contributor
There was a problem hiding this comment.
Thanks for your PR! I have one minor comment...
Contributor
|
Standardtest ok, apart from known com5 |
bskerlak
pushed a commit
to bskerlak/AvaFrame
that referenced
this pull request
Sep 9, 2026
fso42
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
isCounterClockWise()decides a polygon's winding direction with amajority vote on vertex angles measured relative to whichever vertex is
listed first (
V0). This heuristic is not rotation-invariant: theidentical polygon can get a different (wrong) answer purely depending on
which vertex is listed first — or, with vertex order held completely
fixed, purely from the polygon's physical orientation in the plane
(
arctan2's ±180° branch cut lands in a different place relative to thevertex angles as the shape rotates). This is not limited to concave
shapes — a plain convex square is affected too.
polygon2Raster()uses the sign of this result to decide whether itsradiustolerance dilates or shrinks a polygon beforerasterizing it. The real release-raster call in
com1DFA.py(
radius = sqrt(2), used to buildrelRaster) is meant to dilateslightly, so cells whose center sits just outside the boundary are still
included; when winding is misjudged, the tolerance shrinks the polygon
instead. On a real 59-vertex building-footprint release polygon this
reduced 6 legitimate non-empty release cells to 1 — roughly 92% of the
intended release mass silently dropped, no error or warning.
Reproduce
PR Checklist
Please confirm before requesting review:
pytestlocally without failsConfirm before the final merge/rebase into master