2D Map Projections of Earth

On 2D map, use two finger swipe to pan/zoom. Not sure how a mouse works with it.

Demo showing various Earth 2D map projections and quickly changing between them and a sphere.

Uses GIS library PROJ/PROJ4/proj4js for projections.

Also including a selection of a few image textures.

Had to figure out how to:

  • manually create and update mesh data
  • save and modify camera view
  • set UV data to re-use the same texture/image on all projections, including sphere

There’s a lot of test code in there. Mercator1 and Azimuthal Equidistant aren’t displaying at the moment.

7 Likes

lat/long lines would be interesting

cc @georgie

1 Like

This is intended as an efficient and lightweight method for applying a sphere-wrapping texture to a mesh/plane and to display it in a variety of 2d geographic projections.

I wonder if this techique could produce box sides for a cube or skybox? (see Box Side projections below).

Major improvements:

  • much wider selection of projections, supported by proj4js
  • retrieve projection definitions from spatialreference.org
  • optional longitude and latitude lines (“Grid” button)
  • includes points grid among the available texture options.
  • Button colors: green: done, yellow: working on it, black: no indices after projecting
  • workaround for proj4js processing non-decimal degrees for angle parameters.

Debugging features:

  • occasionally will show pro4js string in a popup window.
  • Lots of (too many!) console logs
  • can rotate camera even in “flat map” 2d view. This helps detect the triangle-winding issue (described below).

UVs are calculated from vertex positions so the underlying texture is mapped/stretched linearly within each calculated triangle. Because the underlying texture remains unchanged and UVs are relative to the texture, the calculated UVs also remain unchanged. Only positions are projected/calculated, and mesh indices are generated using only positions that have non-NaN values.

It is generally presumed that the projection is a world view, so all points within the static range of -180 to 180 longitude and -90 to 90 latitude (inclusive) are converted.

There are visual issues with some projected points.

  1. Incontinuity - some projections have incontinuities that result on texture stretching across a map area that is supposed to be empty.
  2. Extents - when projected from outside the expected data range (based on the projection itself), some projected points result in oddly shaped and occasionally-overlapping triangles (on which the texture is placed).
  3. Backward - some conversions result in oppositely-wound triangles, which affect the calculation of normals, so the texture appears on the “back” of those triangles.
  4. “Backward” includes some conversions where a triangle vertex wraps to the other side of the map, which can also result in backward-facing triangles.

Projections (issue observed):

  • Rectangular: Equirectangular, NSIDC Ease-Grid 2.0, Mercator, Cylindrical Equal Area, World Equidistant Cylindrical, Longitude/Latitude (Geographic), Miller Cylindrical (extents), Swiss Oblique Mercator (extents, overlap)
  • Curved Rectangular: Robinson, Mollweide, Sinusoidal, Equal Earth
    Circular: Bonne (ish), geos, Tilted, Geocentric, Geostationary Satellite View, Azimuthal equidistant (small overlap), Lambert Azimithal Equal Area (small overlap), North Pole Orthographic, South Pole Orthographic, van der Grinten
  • Conic: Albers Equal Area Conic (incontinuity), Equidistant Conic, Polyconic
  • Box sides: frontside, backside, leftside, rightside, topside, bottomside (some of these have small issues of triangle wrapping)

Cassini and Mercator

  • Cassini and Mercator are supposed to be used within a limited input range. Cassini displays with wild extents and overlapping triangles.
  • Oblique Mercator has similar issues, plain Mercator less so.

Some projections from proj4js I haven’t fully debugged, they are not available from the interface. And many projections aren’t even included in proj4js.

Possible mitigations (not sure if/when):

  • input range checking (input clipping?).
  • triangle vertex wrapping detection.
  • output clipping and/or output geometry intersect
  • output wrapping detection (clip, intersect, or adaptive tesselation?)

The code is still a mess, but I’ll eventually make this into a class for use in another project of mine.

2 Likes

So cool! I’m using either a robinson or equal earth approximation for a current vibe project :slight_smile:

Updated to put functions in a class. I’m not fully happy with all the methods defined or the general api, but it’s a start.

There’s a simple test for ultra-narrow triangles, or those facing backwards on the 2d map. Those triangles are not included in the indices array and thus not shown.

I’ve also added a projection to proj4js after loading, to see if I could, called “Space Oblique Mercator.”

There are still some artifacts of wrapping and overlap, but that’s mostly a result of not clipping the input.

The api and code need cleanup and additional testing.

1 Like