Skip to content

turf.angle does not return signed angle as claimed #2703

@wchargin

Description

@wchargin

I'm trying to get the behavior of PostGIS ST_Angle in client-side JavaScript, so I turned to @turf/angle. Compare docs:

ST_Angle: Computes the clockwise angle […] enclosed by the points P1-P2-P3

@turf/angle: Finds the angle formed by two adjacent segments defined by 3 points. The result will be the (positive clockwise) angle with origin on the startPointmidPoint segment

These both look like they do what I want: in particular, they both specify that they return the clockwise angle. So I can determine whether a point B lies to the right or the left of my line OA by checking whether the result of angle(A, O, B) is in [0°, 180°] or [180°, 360°]:

$ psql -tc "SELECT degrees(ST_Angle('POINT(0 1)', 'POINT(0 0)', 'POINT(1 0)'))"
      90

$ psql -tc "SELECT degrees(ST_Angle('POINT(0 1)', 'POINT(0 0)', 'POINT(-1 0)'))"
     270

But Turf gives the same answer for both queries:

> turf = require("@turf/turf")  // v7.0.0
> turf.angle([0, 1], [0, 0], [1, 0])  // okay
90
> turf.angle([0, 1], [0, 0], [-1, 0])  // wrong!
90

I tested on version 7.0.0. I also see this behavior represented in test cases:

t.equal(round(angle([5, 5], [5, 6], [3, 4])), 45, "45 degrees");
t.equal(round(angle([3, 4], [5, 6], [5, 5])), 45, "45 degrees -- inverse");

Isn't this in error? The positive-clockwise angle from A=(0, 1) to B=(−1, 0) with origin O=(0, 0) is not 90°; it is 270° or −90°. The only points 90° clockwise of A are (x, 0) for x > 0.

I see #1192, which discusses this issue and raises a similar question (see the second diagram in particular, with the blue solid and dashed angles). But that PR "just added a few test cases to confirm and highlight the current behavior" and did not actually either change the default behavior or add an absolute option.

What is the best way to get the documented functionality within Turf? I can compute bearing(O, B) - bearing(O, A) and normalize to [−180°, 180°], but it seems like that's roughly what @turf/angle does before it calls Math.abs and throws away the useful sign information that it promises to return, which seems strange to me so I want to check if there's something that I'm missing.


  • The version of Turf you are using, and any other relevant versions: v7.0.0
  • GeoJSON data: not necessary; see repros above
  • Snippet of source code: see above
  • Verify this issue hasn't already been reported: searched for clockwise angle and read all issues

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions