nodes2-ts icon indicating copy to clipboard operation
nodes2-ts copied to clipboard

Incorrect IDs from -45 to -135 lng

Open TurtIeSocks opened this issue 1 year ago • 1 comments

Hello!

Thank you so much for the great library! I realize that Node/JavaScript can't natively work with 64bit numbers but I seem to be getting inconsistent results when trying to extract the S2 ID, even as a string.

From -45° to 180° and from -135° to -180° the IDs returned by my tests are consistent, but from -45° to -135° I'm getting negative/incorrect IDs from nodes2ts. I'm using the S2 Rust lib, and the other js package as points of comparison. I also had a friend double check my results in GO, he confirmed that the results match with Rust.

Here is the TS code block used to look at my comparisons:

  const bounds = getMapBounds(map)
  const cell = S2LatLngRect.fromLatLng(
    S2LatLng.fromDegrees(bounds.min_lat, bounds.min_lon),
    S2LatLng.fromDegrees(bounds.max_lat, bounds.max_lon),
  )
  const coverer = new S2RegionCoverer()
  coverer.setMinLevel(level)
  coverer.setMaxLevel(level)
  const cells: S2Response[] = coverer.getCoveringCells(cell).map((c) => {
    const newCell = new S2Cell(c)
    const coords = [0, 1, 2, 3].map((i) => {
      const ll = newCell.getVertex(i)
      const latLng = S2LatLng.fromPoint(ll)

      return [latLng.latDegrees, latLng.lngDegrees]
    })
    return {
      id: BigInt(c.id).toString(),
      coords,
    }
  })
  const signal = new AbortController()
  fetch(`/api/v1/s2/${level}`, {
    method: 'POST',
    body: JSON.stringify(getMapBounds(map)),
    headers: {
      'Content-Type': 'application/json',
    },
    signal: signal.signal,
  }).then((res) => {
    if (res) {
      const center = map.getCenter()
      const point = S2CellId.fromPoint(
        S2LatLng.fromDegrees(center.lat, center.lng).toPoint(),
      )
      console.log(
        JSON.stringify(
          {
            node: cells.map((s) => s.id),
            rust: res.data.map((s) => s.id),
            nodes2ts: point.id.toString(),
            s2geo: S2.keyToId(S2.latLngToKey(center.lat, center.lng, level)),
            rustVsNode: cells.every((s, i) => s.id === res.data[i].id),
            nodes2tsVsS2geo:
              S2CellId.fromPoint(
                S2LatLng.fromDegrees(center.lat, center.lng).toPoint(),
              ).id.toString() ===
              S2.keyToId(S2.latLngToKey(center.lat, center.lng, 30)),
          },
          null,
          2,
        ),
      )
    }
  })

And Rust:

#[derive(Debug, Clone, Serialize)]
pub struct S2Response {
    id: String,
    coords: [[f64; 2]; 4],
}

pub fn get_cells(
    cell_size: u8,
    min_lat: f64,
    min_lon: f64,
    max_lat: f64,
    max_lon: f64,
) -> Vec<S2Response> {
    let region = Rect::from_degrees(min_lat, min_lon, max_lat, max_lon);
    let cov = RegionCoverer {
        max_level: cell_size,
        min_level: cell_size,
        level_mod: 1,
        max_cells: 1000,
    };
    let cells = cov.covering(&region);

    cells.0.iter().map(get_polygon).collect()
}

fn get_polygon(id: &CellID) -> S2Response {
    let cell = Cell::from(id);
    S2Response {
        id: id.0.to_string(),
        coords: [
            [
                cell.vertex(0).latitude().deg(),
                cell.vertex(0).longitude().deg(),
            ],
            [
                cell.vertex(1).latitude().deg(),
                cell.vertex(1).longitude().deg(),
            ],
            [
                cell.vertex(2).latitude().deg(),
                cell.vertex(2).longitude().deg(),
            ],
            [
                cell.vertex(3).latitude().deg(),
                cell.vertex(3).longitude().deg(),
            ],
        ],
    }
}

Result outside of -45° to -135°:

{
  "node": [
    "8646911246970388480",
    "8646911249117872128",
    "8646911251265355776",
    "8646911253412839424",
    "8646911255560323072",
    "8646911257707806720",
    "8646911294215028736",
    "8646911296362512384",
    "8646911298509996032",
    "8646911300657479680",
    "8646911408031662080",
    "8646911410179145728"
  ],
  "rust": [
    "8646911246970388480",
    "8646911249117872128",
    "8646911251265355776",
    "8646911253412839424",
    "8646911255560323072",
    "8646911257707806720",
    "8646911294215028736",
    "8646911296362512384",
    "8646911298509996032",
    "8646911300657479680",
    "8646911408031662080",
    "8646911410179145728"
  ],
  "nodes2ts": "8646911252234482625",
  "s2geo": "8646911251265355776",
  "rustVsNode": true,
  "nodes2tsVsS2geo": true
}

Within -45° to -135°:

{
  "node": [
    "-8839064871157891072",
    "-8839064869010407424",
    "-8070450539764121600",
    "-8070450533321670656",
    "-8070450531174187008",
    "-8070450524731736064",
    "-7301836195485450240",
    "-7301836193337966592"
  ],
  "rust": [
    "9607679202551660544",
    "9607679204699144192",
    "10376293533945430016",
    "10376293540387880960",
    "10376293542535364608",
    "10376293548977815552",
    "11144907878224101376",
    "11144907880371585024"
  ],
  "nodes2ts": "-8070450532247915995",
  "s2geo": "10376293542535364608",
  "rustVsNode": false,
  "nodes2tsVsS2geo": false
}

Thank you!

TurtIeSocks avatar Mar 18 '23 15:03 TurtIeSocks