uber / h3-js

h3-js provides a JavaScript version of H3, a hexagon-based geospatial indexing system.
https://uber.github.io/h3
Apache License 2.0
873 stars 79 forks source link

Different output from h3-js and postgis using cellToBoundary function #187

Closed jashanbhullar closed 11 months ago

jashanbhullar commented 11 months ago

So I was creating a map using different indexes of h3. The idea is to get all the h3index and convert them into geojson which can be loaded on the map. I wrote a simple script for this.

const h3 = require("h3-js");
const fs = require("fs");

CELLS_0 = h3.getRes0Cells();

function getAllHexagonsForResolution(resolution) {
  const hexagons = new Set();

  for (const cell of CELLS_0) {
    const h3indexes = h3.cellToChildren(cell, resolution);
    h3indexes.forEach(hexagons.add, hexagons);
  }

  return Array.from(hexagons);
}

const resolution = 0;
const allIndexes = getAllHexagonsForResolution(resolution);

const polygon = {
  type: "FeatureCollection",
  features: [],
};

for (const index of allIndexes) {
  const feature = {
    type: "Feature",
    geometry: {
      type: "Polygon",
      coordinates: [h3.cellToBoundary(index, true)],
    },
    properties: {},
  };
  polygon.features.push(feature);
}

fs.writeFileSync("polygon.json", JSON.stringify(polygon));
console.log("File written");

The file it writes has weird shapes. I tried creating the shapes from PostGIS and it's perfect.

From h3-js lib image From postgis geojson image

For Postgis I used

 create table h3_index_0 as select h3_cell_to_boundary_geometry(h3_get_res_0_cells) from h3_get_res_0_cells();

and then exported the table using ogr2ogr

ogr2ogr -f GeoJSON output.json PG:"host=localhost user=postgres dbname=sample_data " -sql "SELECT * FROM h3_index_0" 

I also noticed that some polygons in the postgis.json are MultiPolygons :thinking:

Attached are the files for reference, h3-js.polygon.json postgis.polygon.json

I want to understand why is this happening and how can I fix my script to get the same result I got from postgis!

nrabinowitz commented 11 months ago

The shapes aren't weird, they're just being rendered poorly. When H3 (and h3-js) outputs shapes that cross the antimeridian, we keep all longitude values within the -180 - 180 range, so you may have some cells that have some western coordinates at longitude 179 and some eastern coordinates at -179. Many maps will render this badly, but from a geographic shape perspective this is correct.

Either PostGIS or ogr2ogr is taking the approach of cutting these cells into multipolygons, with one poly on one side of the antimeridian and one poly on the other. Normally I'd expect to see the dividing line rendered as well, but possibly your renderer expects this input and drops the dividing border. This is a perfectly good rendering solution, but I don't consider it a good generic solution because it gives you two shapes for some cells, instead of one.

Depending on your requirements, you can post-process the h3-js output to render better, either by running it through a tool that can cut it up, or by normalizing the coordinates to extend past -180 and 180. See this fixTransmeridian function for an example of the latter approach.