mbostock/d3 — pull request #1638 by jasondavies (2013-11-18 12:03:47+00:00)
Title: Don’t output points at exactly -180° when clipping.

Previously, we were generating points along the antimeridian at λ=±180°
when clipping. Strictly speaking, on a sphere, -180° is the same
longitude as +180°. Internally, we can distinguish these “coincident”
points and preserve the longitude’s sign when converting to and from
Cartesian coordinates by assuming that atan2(sin(±π), x<0)=±π.

Up until now, this has worked, probably due to floating point roundoff
in Math.PI meaning that abs(λ) < π, and hence sin(±Math.PI) is a very
small non-zero number, effectively preserving the sign of the longitude.

It seems Chrome Canary has added some minor approximations, which
improve performance but bring to light our reliance on this behaviour,
since sin(+Math.PI) = sin(-Math.PI) = +0. Strictly speaking, I think
Chrome should return -0 for sin(-Math.PI), but we probably shouldn’t
rely on it, as it’s not in ECMAScript.

I had already made a minor modification to avoid generating these
“coincident” points in the clip-polygon branch. I decided longitudes
should be in the range [-180°, +180°), and thus points were output with
longitudes -π and π - ε. This was required to fix various issues with
handling of coincident points elsewhere.

In Chrome, this modification doesn’t actually fix the problem, because
atan2(sin(-π), x)=π where x<0, so λ=-180° becomes λ=+180° when
resampling. Instead, the range (-180, +180°] does in fact fix the
issue, using λ=ε-π and λ=π. As I mentioned above, it would be nice if
Chrome’s implementation gave atan2(sin(-Math.PI), x<0)=-Math.PI.

For good measure, I’ve enforced this in d3.geo.rotation too, ensuring
that input points with λ<ε-π become λ=+π.

We could go further and output points at abs(λ)=π-ε, but it seems
unnecessary as the above already preserves the longitude’s sign.

Note: I haven’t updated any tests for this change.

Fixes #1635.