From 8629b4ae415b4441b799e70730503e52fdb49bae Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 28 Aug 2024 11:42:20 +0200 Subject: [PATCH] spherical rendering fixes --- src/App.tsx | 83 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index a5471cc..aeca173 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,6 @@ import "maplibre-gl/dist/maplibre-gl.css"; import { r1, s2, s1 } from "s2js"; import { greatCircle } from "@turf/great-circle"; import { flatten } from "@turf/flatten"; -import { polygonize } from "@turf/polygonize"; import { TerraDraw, TerraDrawMapLibreGLAdapter, @@ -20,16 +19,31 @@ import { Polygon, LineString, FeatureCollection, + MultiLineString, } from "geojson"; const initialUnion = (): s2.CellUnion => { const union = new s2.CellUnion(); - union.push(s2.cellid.fromFace(0)); - union.push(s2.cellid.fromFace(1)); + // union.push(s2.cellid.fromFace(0)); + // union.push(s2.cellid.fromFace(1)); // union.push(s2.cellid.fromFace(2)); - union.push(s2.cellid.fromFace(3)); - union.push(s2.cellid.fromFace(4)); + // union.push(s2.cellid.fromFace(3)); + // union.push(s2.cellid.fromFace(4)); // union.push(s2.cellid.fromFace(5)); + + // union.push(2985886552946638848n); + // union.push(3008404551083491328n); + // union.push(3098476543630901248n); + // union.push(7710162562058289152n); + // union.push(7854277750134145024n); + // union.push(8286623314361712640n); + // union.push(11957057010668666880n); + // union.push(11979575008805519360n); + // union.push(12087661399862411264n); + // union.push(12393906174523604992n); + // union.push(5719853001737240576n); + // union.push(5476377146882523136n); + // union.push(4899916394579099648n); return union; }; @@ -79,6 +93,8 @@ const fixAntimeridianCrossings = (arcLines: FeatureCollection) => { let last = arcLines.features.at(-1)!.geometry.coordinates.at(-1)!; arcLines.features.forEach((f) => { const first = f.geometry.coordinates.at(0)!; + console.error("first", first); + console.error("last", last); if ( (last[0] === 180 && first[0] === -180) || (last[0] === -180 && first[0] === 180) @@ -97,6 +113,30 @@ const fixAntimeridianCrossings = (arcLines: FeatureCollection) => { }); }; +const fixPolarFaces = (arcs: Feature[]) => { + arcs.forEach((arc: Feature) => { + if (arc.geometry.type === "MultiLineString") { + const A = arc.geometry.coordinates[0].at(-1)!; + const B = arc.geometry.coordinates[1].at(0)!; + + // sanity checks + if (!A || Math.abs(A[0]) !== 180 || !B || Math.abs(B[0]) !== 180) { + return; + } + + // the target polar latitude + const E = Math.sign(A[0]) * 90; + + // draw a line to the pole, across, and back again + arc.geometry.coordinates = [ + arc.geometry.coordinates[0], + [A, [A[0], E], [B[0], E], B], + arc.geometry.coordinates[1], + ]; + } + }); +}; + const getCellVisualization = (union: s2.CellUnion): FeatureCollection => { const degrees = s1.angle.degrees; let features = [...union].map((cellid): Feature => { @@ -111,6 +151,17 @@ const getCellVisualization = (union: s2.CellUnion): FeatureCollection => { const p2 = [degrees(v2.lng), degrees(v2.lat)]; const p3 = [degrees(v3.lng), degrees(v3.lat)]; + if ([p0, p1, p2, p3].filter((p) => !p[0]).length % 2 !== 0) { + console.error("potential issue!", cellid); + console.error(p0, p1, p2, p3); + } + + // fix antimeridian corssings in the southern hemisphere + if (p1[0] === 180 && p2[0] === 180) { + p1[0] = Math.sign(p0[0]) * 180; + p2[0] = Math.sign(p0[0]) * 180; + } + const level = cell.level; const npoints = 20 + (30 - level) * 3; const arc0 = greatCircle(p0, p1, { npoints }); @@ -118,6 +169,12 @@ const getCellVisualization = (union: s2.CellUnion): FeatureCollection => { const arc2 = greatCircle(p2, p3, { npoints }); const arc3 = greatCircle(p3, p0, { npoints }); + // planar hacks for the two polar faces + const POLAR_FACES = [s2.cellid.fromFace(2), s2.cellid.fromFace(5)]; + if (POLAR_FACES.includes(cellid)) { + fixPolarFaces([arc0, arc1, arc2, arc3]); + } + const arcLines: FeatureCollection = { type: "FeatureCollection", features: [ @@ -128,23 +185,15 @@ const getCellVisualization = (union: s2.CellUnion): FeatureCollection => { ], }; - fixAntimeridianCrossings(arcLines); - - // const poly = polygonize(arcLines).features[0]; - // poly.properties = { level: cell.level }; - // return poly; + // fixes; + if (!POLAR_FACES.includes(cellid)) { + fixAntimeridianCrossings(arcLines); + } const coordinates = arcLines.features .map((f) => f.geometry.coordinates) .flat(1); - // const coordinates = [ - // ...arc0.features.map((f) => f.geometry.coordinates).flat(1), - // ...arc1.features.map((f) => f.geometry.coordinates).flat(1), - // ...arc2.features.map((f) => f.geometry.coordinates).flat(1), - // ...arc3.features.map((f) => f.geometry.coordinates).flat(1), - // ] as Position[]; - return { type: "Feature", geometry: {