Turfjs / turf

A modular geospatial engine written in JavaScript and TypeScript

Home Page:https://turfjs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Isoband and Isolines have precision build up error

JackTiber opened this issue · comments

Please provide the following when reporting an issue:

  • The version of Turf you are using, and any other relevant versions.
    I used version 6.5.0 for both library modules.

  • GeoJSON data as a gist file or geojson.io (filename extension must be .geojson).
    Source data as a gist is available (here)[https://gist.github.com/JackTiber/8e069e92d912b905f5043c06dd21f6e7]. This is the point grid for the smallest tile in the dataset, but gist was not able to handle a 134MB file apparently for the largest tile.

  • Snippet of source code or for complex examples use jsfiddle.

const example = (input) => {
  const { width, type, zoom, x, y } = input;
  const size = Math.floor(width / Math.pow(2, zoom));
  // Determine the requested tile's bbox
  const mercator = new GlobalMercator(size);
  const { minx, miny, maxx, maxy } = mercator.TileBounds(x, y, zoom);

  const threshold= 30;
  const start: [number, number] = [minx, miny];
  const points = [];

  const [, startPxX, startPxY] = valueAtMeters(start, mercator, zoom);
  for (let lonStep = 0; lonStep <= size; lonStep += 1) {
    for (let latStep = 0; latStep <= size; latStep += 1) {
      const [value, lon, lat] = valueAndCoordinates([startPxX + latStep, startPxY + lonStep]);
      points.push({
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [lon, lat],
        },
        properties: {
          [type]: value,
        },
      });
    }
  }
  const [min, max] = [-127, 128];
  const fc = {
    type: "FeatureCollection",
    features: points,
  };

  // Create contours for the points where our threshold has been exceeded
  const breaks = [-127, 31, 128]
  const bands = isobands(fc, breaks, { zProperty: type });
  const thresholdBand = bands.features[1];

  return {
    type: "FeatureCollection",
    features: [thresholdBand],
  };
}

When working with isobands or isolines a precision error seems to build up with a large point grid. I am dealing with a large raster image which contains simple temperature data and converting it to GeoJSON by first creating a point grid and determining if the pixel's value crosses a threshold set in the code. It is then passed to the isobands function with the appropriate breaks to create the needed contoured MultiPolygon for the pixels which exceed the set threshold.

The issue is when rendering this new polygon, it is noticeably shifted south on any user interface used to render it. The included gist is a point grid for a sample tile of the larger raster data, but below you can see the issue clearly when viewing the data in QGIS. Starting at tile zoom 3, x 1, y 3, I created a point grid following the above method and then saved it out to a JSON file. I loaded this file into QGIS, classified it using the same threshold and displayed it on the renderer. I then loaded the output from isobands after it contoured the same point grid, and the shift in the polygon from the original location of the points is very noticeable. Nearly an entire degree in latitude.

This seems to decrease as the zoom level increases, shrinking the point grid. Screenshots below show the same issue for zoom level 4 and 5, where at zoom level 5, the shift has become much less noticeable but is still present. The accuracy for the lon, lat points is also not the issue since it is nearly 10 decimal places for all points. Conversion from Mercator X, Y is being handled by proj4js and is consistently within .000001 degrees of accuracy.

I am including screenshots of what I am seeing in QGIS below. Any insight on approach or possible changes here to account for this drift would be appreciated.

3_1_3_pt_grid
close_overlay
high_overlay

commented

ok