Skip to content

fix(@turf/polygon-tangents): return distinct tangents when nearest vertex is below viewpoint inside bbox#3083

Open
JSap0914 wants to merge 3 commits into
Turfjs:masterfrom
JSap0914:fix/polygon-tangents-degenerate-ltan-issue-2898
Open

fix(@turf/polygon-tangents): return distinct tangents when nearest vertex is below viewpoint inside bbox#3083
JSap0914 wants to merge 3 commits into
Turfjs:masterfrom
JSap0914:fix/polygon-tangents-degenerate-ltan-issue-2898

Conversation

@JSap0914

Copy link
Copy Markdown
Contributor

Summary

polygonTangents returns the same point for both tangents when the viewpoint lies inside the polygon bounding box and the nearest polygon vertex is below the viewpoint.

Root cause. When the point is inside the bbox, the existing code initialises both rtan and ltan to the nearest vertex (line 63–65 of index.ts). When that nearest vertex is below the viewpoint, processPolygon cannot update ltan to any candidate above the viewpoint, because every such candidate is considered isAbove the current ltan and therefore rejected. The traversal ends with rtan === ltan.

Fix. After processPolygon returns, detect the degenerate case (rtan === ltan and nearestPtIndex !== 0) and retry with ltan reset to polyCoords[0][0]. This allows the second traversal to find the correct left-tangent vertex while preserving the existing behaviour for all other cases (including the concave-edge fix introduced for issues #1050, #785, and #1032).

Resolves

Closes #2898

Verification

TAP version 13

turf-polygon-tangents

ok 1 concave
ok 2 high
ok 3 issue#1032
ok 4 issue#1050
ok 5 issue#2898
ok 6 issue#785
ok 7 multipolygon
ok 8 polygonWithHole
ok 9 square

turf-polygon-tangents - Geometry Objects

ok 10 should be truthy

turf-polygon-tangents - Prevent Input Mutation

ok 11 pt should not mutate
ok 12 poly should not mutate

turf-polygon-tangents - Issue #1050

ok 13 should be truthy

turf-polygon-tangents - Issue #2898

ok 14 returns two features
ok 15 tangent points must be distinct vertices

1..15

tests 15

pass 15

ok

All 12 pre-existing tests still pass. The 3 new tests (1 fixture snapshot + 2 inline assertions) go RED on the original code and GREEN after this fix.

AI-assisted contribution.

JSap0914 added 2 commits June 27, 2026 18:46
When start and end points are identical, rhumbBearing() was returning 0
(north) because Math.atan2(0, 0) === 0. This is misleading since no
bearing can be defined for a zero-length segment.

The Geodesy library (which this implementation is adapted from) explicitly
guards for this case and returns NaN. Align turf's behaviour accordingly.

Closes Turfjs#2478
…rtex is below viewpoint inside bbox

When the viewpoint lies inside the polygon bounding box and the nearest
polygon vertex is below the viewpoint, the existing code initialises both
rtan and ltan to that same nearest vertex.  processPolygon then cannot
update ltan because every above-viewpoint candidate compares as 'above'
the current ltan (which is already below the viewpoint), so the function
returns the same point for both tangents.

Detect this degenerate outcome (rtan === ltan after processPolygon) and
retry with ltan reset to vertex[0], which lets the traversal find the
correct left-tangent vertex.

Fixes Turfjs#2898
Copilot AI review requested due to automatic review settings June 27, 2026 09:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

polygonTangents returns two of the same point

2 participants