d3-contour icon indicating copy to clipboard operation
d3-contour copied to clipboard

Option to remove points along straight lines?

Open mbostock opened this issue 8 years ago • 7 comments

We currently emit one point per pixel in the grid, which leads to many extra coordinates along straight edges. For example this:

{
  "type": "MultiPolygon",
  "value": 0.5,
  "coordinates": [
    [
      [[6, 7.5], [6, 6.5], [6, 5.5], [6, 4.5], [6, 3.5], [5.5, 3], [4.5, 3],
       [3.5, 3], [3, 3.5], [3, 4.5], [3, 5.5], [3, 6.5], [3, 7.5], [3.5, 8],
       [4.5, 8], [5.5, 8], [6, 7.5]]
    ]
  ]
}

Could be reduce to this:

{
  "type": "MultiPolygon",
  "value": 0.5,
  "coordinates": [
    [
      [[6, 7.5], [6, 3.5], [5.5, 3], [3.5, 3], [3, 3.5], [3, 7.5], [3.5, 8], [5.5, 8], [6, 7.5]]
    ]
  ]
}

mbostock avatar Jun 24 '17 14:06 mbostock

The tricky thing is that for geographic coordinates (as in GeoTIFF Contours II) we want to retain the intersecting points along the antimeridian, which may not be possible if we eliminate all the straight line points. Also, parallels are not great arcs, so removing these points changes the interpretation in spherical coordinates.

mbostock avatar Jun 25 '17 15:06 mbostock

Is it possible to add an option to remove the rectangular outer border when it's part of the generated path? RaumZeit/MarchingSquares.js provided a noFrame option to remove it.

purejoy avatar Nov 26 '19 09:11 purejoy

Contour simplification could be an option of d3-contour, but I believe it's enough to leave this to topojson as in https://observablehq.com/d/4fe65b865ccf545d

The tricky thing is for geographic coordinates

Shameless plug: for spatial contours we can use d3-geo-voronoi’s geoContour.

Fil avatar Jun 02 '20 15:06 Fil

Regarding noFrame it seems that the solution is to filter out the multipolygons that have exactly 1 polygon with 1 ring with an area equal to n * m - 1/2, like so:

      p.coordinates.length === 1 &&
      p.coordinates[0].length === 1 &&
      2 * d3.polygonArea(p.coordinates[0][0]) === 2 * n * m - 1

The solution works both with smoothed/non smoothed contours. It seems to work for all n, m but we can fortify it against calculation drift by testing d3.polygonArea(p.coordinates[0][0]) > n * m - 3/4

The test is fast enough (exits immediately on most polygons, and 2*area is computed anyway), so it could be added at no cost as a property to the polygons as a property polygon.sphere or polygon.isFrame, leaving the API otherwise unchanged. It can also be left to the user as shown here.

Fil avatar Jun 25 '20 13:06 Fil

Re: "noFrame", I think that returning the area (since we've computed it) as p.area could be the simplest solution. Beyond "filtering out frames", it can be used to compute stats. (Implemented in #47)

Re: contour simplification, I propose to leave that to topojson.

All in all, closing this issue. Feel free to comment/reopen etc as necessary.

Fil avatar Jul 09 '20 14:07 Fil

I don’t think #47 is sufficiently helpful here: the points along straight lines occur not only when a contour polygon covers the entire frame, but whenever any contour polygon abuts the frame. In other words the darker blue polygons in the #47 example also have many points along straight lines that could be removed.

I think what I want here is to detect perfectly horizontal (x1 === x2) or perfectly vertical (y1 === y2) line segments and remove the extraneous intermediate points. But per https://github.com/d3/d3-contour/issues/14#issuecomment-310909722 this should be optional.

mbostock avatar Jul 09 '20 14:07 mbostock

Yes, #47 was only about the "noFrame" sub-issue.

Fil avatar Jul 09 '20 14:07 Fil