Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clip circle & degenerate polygons #196

Closed
Fil opened this issue May 3, 2020 · 0 comments · Fixed by #197
Closed

Clip circle & degenerate polygons #196

Fil opened this issue May 3, 2020 · 0 comments · Fixed by #197

Comments

@Fil
Copy link
Member

Fil commented May 3, 2020

The issue in vega/vega#2572 seems to be due to a clip circle problem when faced with a degenerate polygon.

https://observablehq.com/d/5380dd24622eca74 shows a reduced test case, with a (south) polar cap expressed as a polygon that has a line pluging to the south pole then coming back up.

(Note that, though this looks like a "fringe" case but this type of degeneracy can be quite common when using certain types of GeoJSON; for instance, in the vega example, it's due to geometries produced by a rectangular contour analysis. In the wild, a lot of GeoJSON files are similarly constrained to [-180,180] longitudes.)

{
  type: "Polygon",
  coordinates: [ [[-120, -30],[0, -30],[0, -90],[0 + !!eps * 1e-6, -30],[120, -30],[-120, -30]] ]
}

A rectangular projection shows the polar cap in gray ((north pole in red):
Capture d’écran 2020-05-03 à 10 52 39

with any d3 azimuthal projection centered on the north pole, the south pole is projected to the circumference of the sphere. clipAngle(170) ensures that we don't reach this "point" by limiting the projection to latitude -80°.

projection = d3.geoAzimuthalEquidistant().rotate([0, -90, 0]).clipAngle(170)

As you can see from the two next images, adding 1e-6 to one of the polygon's vertices makes the drawing "flip".

without epsilon:
Capture d’écran 2020-05-03 à 10 52 54

with epsilon:
Capture d’écran 2020-05-03 à 10 52 48

It looks like this is due to the test at https://github.com/d3/d3-geo/blob/master/src/clip/rejoin.js#L25 concluding that we have two closed rings, and dropping the case for "rejoining by interpolating along the clip edge".

A quick fix is to trick the algorithm out of thinking these are closed rings, by adding an epsilon in https://github.com/d3/d3-geo/blob/master/src/clip/circle.js#L83 ; it works in the test case and in the vega example, but this might lead to unexpected bugs somewhere else.

Fil added a commit that referenced this issue May 3, 2020
instead of adding epsilons at the "clipcircle" stage, we pass an explicit message in coordinate z that this point should not be mixed with the previous point, and add the epsilons later, at the "rejoin" stage.
Closes #196 and vega/vega#2572

Relevant notebooks:
- https://observablehq.com/d/4175cc6263b949d1 (reproduces the original bug)
- https://observablehq.com/d/32bce1e0b8e4f9a1 (fixes the bug with geoStitch)
- https://observablehq.com/d/5380dd24622eca74 (reduced test case)
- https://observablehq.com/d/495020ca139c39bd (images for the unit test in this commit)
@Fil Fil closed this as completed in #197 May 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

1 participant