EXIF geodata, and what if you took a picture on the moon?

This is a repost promoting content originally published elsewhere. See more things Dan's reposted.

A conversation about staying private and stripping EXIF tags on blogs lead to shdwcat asking the question “what would happen if you took a picture on the moon?”

However, I figured we could do better than “a point high above the Earth.” If you could state the coordinate system, you should be able to list an actual point on the moon.

It’s a fun question. Sure, you need to shoot down the naysayers who, like colin, rightly point out that you couldn’t reasonably expect to get a GPS/GNSS signal on the moon, but still.

GPS on Earth

GPS (and most other GNSS technologies) fundamentally work by the principle of trilateration. Here’s the skinny of what happens when your GPS receiver – whether that’s your phone, smartwatch, SatNav, or indeed digital camera – needs to work out where on Earth it is:

  1. It listens for the signal that’s transmitted from the satellites. This is already an amazing feat of engineering given that the signal is relatively quiet and it’s being transmitted from around 20,000km above the surface of the planet1.
  2. The signal fundamentally says, for example “Hi, I’m satellite #18, and the time is [some time].” Assuming your GPS receiver doesn’t contain an atomic clock2, it listens for the earliest time – i.e. the closest satellite (the signals “only” travel at the speed of light) – and assumes that this satellite’s time represents the actual time at your location.
  3. Your GPS receiver keeps listening until it’s found three more satellites, and compares the times that they claim it is. Using this, and knowing the speed of light, it’s able to measure the distance to each of those three satellites. The satellites themselves are on reasonably-stable orbits, so as long as you’ve been installing your firmware updates at least once every 5-10 years, your device knows where those satellites are expected to be.
  4. If you know your distance from one satellite, in 3D space, you know that your location is on the surface of an imaginary sphere with a radius of that distance, centered on the satellite. Once you’ve measured your distance from a second satellite, you know that you must be at a point where those two spheres intersect: i.e. somewhere on a circle. With a third satellite found and the distance measured, you’re able to cut that down to just two points (of which one is likely to be about 40,000km into space, so it’s probably not that one3).
  5. Your device will keep finding more passing satellites, measuring and re-measuring, and refining/averaging your calculated location for maximum accuracy.

So yeah: that tiny computer on top of your camera or within your wristwatch? It’s differentiating to miniscule precision measurements of the speed of light, from spacecraft as far away as half the circumference of the planet, while compensating for not being a timekeeping device accurate enough to do so and working-around the time dilation resulting from the effect of general relativity on the satellites4.

GPS on Luna

Supposing you could pick out GPS signals from Earth orbit, from the surface of the moon (which – again – you probably can’t – especially if you were on the dark side of the moon where you wouldn’t get a view of the Earth). Could it work?

I can’t see why not. You’d want to recalibrate your GPS receiver to assume that the “time” satellite – the one with the earliest-apparent clock – was much further away (and therefore that the real time was later than it appears to be) than an Earth-based GPS receiver would: the difference in the order of 1.3 seconds, which is a long time in terms of GNSS calculation.

Again, once you had distance measurements from three spatial satellites you’d be able to pinpoint your location, to within some sphere of uncertainty, to one of two points. One would be on the moon (where you know that you are5), and one would be on the far side of the Earth by almost the same distance. That’s a good start. And additional satellites could help narrow it down even more.

You might even be able to get a slightline to more satellites than is typically possible on Earth, not being limited by Earth curvature, nor being surrounded by relatively-large Earth features like mountains, buildings, trees, and unusually-tall humans. It’s feasible.

How about… LPS?

If we wanted to go further – and some day, if we aim to place permanent human settlements on the moon, we might – then we might consider a Lunar Positioning System: a network of a dozen or so orbiters whizzing around the moon to facilitate accurate positioning on its surface. They’d want to be in low orbits to avoid the impact of tidal forces from the much-larger nearby Eath, and with no atmosphere to scrape against there’s little harm in that.

By the time you’re doing that, though, you might as well ditch trilateration and use the doppler effect, Transit-style. It works great in low orbits but its accuracy on Eath was always limited by the fact that you can’t make the satellites fly low enough without getting atmospheric drag. There’s no such limitation on the moon. Maybe that’s the way forward.

Maybe far-future mobile phones and cameras will support satellite positioning and navigation networks on both Earth and Luna. And maybe then we’ll start seeing EXIF metadata spanning both the WGS-84 datum and the LRO-ME datum.

Footnotes

1 That’s still only about a twentieth of the way to the moon, by the way. But there are other challenging factors, like our atmosphere and all of the obstructions both geographic and human-made that litter our globe.

2 Protip: it doesn’t.

3 Satnav voice: “After falling for forty thousand kilometres, you will reach your destination.”

4 The relativistic effects on GPS satellites cannot be understated. Without compensation, GPS accuracy would drift by up to 10km for every day that the satellites were in orbit, which I reckon would make them useless for anything more than telling you what hemisphere you were in within 5½ years!

5 If you’re on the moon and don’t know it, you have a whole different problem.

Multi-Phase Maps in FoundryVTT

FoundryVTT is a fantastic Web-based environment for tabletop roleplaying adventures1 and something I particularly enjoy is the freedom for virtually-unlimited scripting. Following a demonstration to a fellow DM at work last week I promised to throw together a quick tutorial into scripting simple multi-phase maps using Foundry.2

Why multi-phase maps?

Animated battlemap which organically grows into a leafy flower over six stages.
For this demonstration, I’ll be using AtraxianBear’s Growing Flower Dungeon.

You might use a multi-phase map to:

  • Allow the development and expansion of a siege camp outside the fortress where the heroes are holed-up.3
  • Rotate through day and night cycles or different times of day, perhaps with different things to interact with in each.4
  • Gradually flood a sewer with rising water… increasing the range of the monster that dwells within.5
  • Re-arrange parts of the dungeon when the characters flip certain switches, opening new paths… and closing others.

I’ll use the map above to create a simple linear flow, powered by a macro in the hotbar. Obviously, more-complex scenarios are available, and combining this approach with a plugin like Monk’s Active Tile Triggers can even be used to make the map appear to dynamically change in response to the movement or actions of player characters!

Setting the scene

Create a scene, using the final state of the map as the background. Then, in reverse-order, add the previous states as tiles above it.

Not shown, but highly-recommended: lock each tile when you’re done placing it, so that you don’t accidentally interact with it when you mean to e.g. drag-select multiple actors.

Make a note of the X-position that your tiles are in when they’re where they supposed to be: we’ll “move” the tiles off to the side when they’re hidden, to prevent their ghostly half-hidden forms getting in your way as game master. We’ll also use this X-position to detect which tiles have already been moved/hidden.

Also make note of each tile’s ID, so your script can reference them. It’s easiest to do this as you go along. When you’re ready to write your macro, reverse the list, because we’ll be hiding each tile in the opposite order from the order you placed them.

Writing the script

Next, create a new script macro, e.g. by clicking an empty slot in the macro bar. When you activate this script, the map will move forward one phase (or, if it’s at the end, it’ll reset).

I find Foundry’s built-in script editor a little… small? So I write my scripts in my favourite text editor and then copy-paste.

Here’s the code you’ll need – the 👈 emoji identifies the places you’ll need to modify the code, specifically:

  1. const revealed_tiles_default_x = 250 should refer to the X-position of your tiles when they’re in the correct position.
  2. const revealed_tiles_modified_x = 2825 should refer to the X-position they’ll appear at “off to the right” of your scene. To determine this, just move one tile right until it’s sufficiently out of the way of the battlemap and then check what it’s X-position is! Or just take the default X-position, add the width of your map in pixels, and then add a tiny bit more.
  3. const revealed_tiles = [ ... ] is a list of the tile IDs of each tile what will be hidden, in turn. In my example there are five of them (the sixth and final image being the scene background).
const revealed_tiles_default_x = 250;   // 👈 X-position of tiles when displayed
const revealed_tiles_modified_x = 2825; // 👈 X-position of tiles when not displayed
const revealed_tiles = [
  '2xG7S8Yqk4x1eAdr',                   // 👈 list of tile IDs in order that they should be hidden
  'SjNQDBImHvrjAHWX',                   //     (top to bottom)
  'tuYg4FvLgIla1l21',
  'auX4sj64PWmkAteR',
  'yAL4YP0I4Cv4Sevt',
].map(t=>canvas.tiles.get(t));

/*************************************************************************************************/

// Get the topmost tile that is still visible:
const next_revealed_tile_to_move = revealed_tiles.find(t=>
  t.position.x == revealed_tiles_default_x
);

// If there are NO still-visible tiles, we must need to reset the map:
if( ! next_revealed_tile_to_move ) {
  // To reset the map, we go through each tile and put it back where it belongs -
  for(tile of revealed_tiles){
    canvas.scene.updateEmbeddedDocuments("Tile", [ {
      _id: tile.id,
      x: revealed_tiles_default_x,
      hidden: false
    } ]);
  }
} else {
  // Otherwise, hide the topmost visible tile (and move it off to the side to help the GM) -
  canvas.scene.updateEmbeddedDocuments("Tile", [ {
    _id: next_revealed_tile_to_move.id,
    x: revealed_tiles_modified_x,
    hidden: true
  } ]);
}

I hope that the rest of the code is moderately self-explanatory for anybody with a little JavaScript experience, but if you’re just following this kind of simple, linear case then you don’t need to modify it anyway. But to summarise, what it does is:

  1. Finds the first listed tile that isn’t yet hidden (by comparing its X-position to the pre-set X-position).
  2. If there aren’t any such tiles, we must have hidden them all already, so perform a reset: to do this – iterate through each tile and set its X-position to the pre-set X-position, and un-hide it.
  3. Otherwise, move the first not-hidden tile to the alternative X-position and hide it.

I hope you have fun with scripting your own multi-phase maps. Just don’t get so caught-up in your awesome scenes that you fail to give the players any agency!

Footnotes

1 Also, it’s on sale at 20% off this week to celebrate its fourth anniversary. Just sayin’.

2 I can neither confirm nor deny that a multi-phase map might be in the near future of The Levellers‘ adventure…

3 AtraxianBear has a great series of maps inspired by the 1683 siege of Vienna by the Ottomans that could be a great starting point for a “gradually advancing siege” map.

4 If you’re using Dungeon Alchemist as part of your mapmaking process you can just export orthographic or perspective outputs with different times of day and your party’s regular inn can be appropriately lit for any time of day, even if the party decides to just “wait at this table until nightfall”.

5 Balatro made a stunning map with rising water as a key feature: there’s a preview available.

×

My Geo*ing Limits

I thought it might be fun to try to map the limits of my geocaching/geohashing. That is, to draw the smallest possible convex polygon that surrounds all of the geocaches I’ve found and geohashpoints I’ve successfully visited.

World map showing the outer extent of the areas in which Dan has geocached/geohashed. A shaded polygon covers the UK (except the far North of Scotland), parts of California, Cape Town, and parts of Italy and Austria.

Mathematically, such a shape is a convex hull – the smallest polygon encircling a set of points without concavity. Here’s how I made it:

1. Extract all the longitude/latitude pairs for every successful geocaching find and geohashpoint expedition. I keep them in my blog database, so I was able to use some SQL to fetch them:

SELECT DISTINCT coord_lon.meta_value lon, coord_lat.meta_value lat
FROM wp_posts
LEFT JOIN wp_postmeta expedition_result ON wp_posts.ID = expedition_result.post_id AND expedition_result.meta_key = 'checkin_type'
LEFT JOIN wp_postmeta coord_lat ON wp_posts.ID = coord_lat.post_id AND coord_lat.meta_key = 'checkin_latitude'
LEFT JOIN wp_postmeta coord_lon ON wp_posts.ID = coord_lon.post_id AND coord_lon.meta_key = 'checkin_longitude'
LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
LEFT JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
LEFT JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id
WHERE wp_posts.post_type = 'post' AND wp_posts.post_status = 'publish'
AND wp_term_taxonomy.taxonomy = 'kind'
AND wp_terms.slug = 'checkin'
AND expedition_result.meta_value IN ('Found it', 'found', 'coordinates reached', 'Attended');

2. Next, I determine the convex hull of these points. There are an interesting variety of algorithms for this so I adapted the Monotone Chain approach (there are convenient implementations in many languages). The algorithm seems pretty efficient, although that doesn’t matter much to me because I’m caching the results for a fortnight.

Animation showing an algorithm draw lines from point to point, selecting each point by avoiding counter-clockwise turns.
I watched way too many animations of different convex hull algorithms before selecting this one… pretty-much arbitrarily.

3. Finally, I push the hull coordinates into Geoapify, who provide mapping services to me. My full source code is available.

An up-to-date (well, no-more than two weeks outdated) version of the map appears on my geo* stats page. I don’t often get to go caching/hashing outside the bounds already-depicted, but I’m excited to try to find opportunities to push the boundaries outwards as I continue to explore the world!

(I could, I suppose, try to draw a second larger area of places I’ve visited: the difference between the smaller and larger areas would represent all of the opportunities I’d missed to find a hashpoint!)

× ×

The Road (Segment) Less Travelled

Map showing approximate location of Dan's house, on a set of rural roads that connect to the A40 in two different places, with the segment between the two relevant junctions marked.

There are two junctions at which I can join the A40 trunk road from my house. When I drive East, I use the Easternmost of the two; when I drive West, I use the Westernmost; but I almost never drive the stretch of road between them!

A few years ago I generated heatmaps of my movements based on my long-running personal location log and, indeed, it shows a “cool spot” along this section of road too:

Heatmap showing a "cool spot" on the road (segment) less-travelled.

It’s inevitable I suppose that there should exist a “road (segment) less-travelled” right on my doorstep, but it still feels strange. Like when you live near a tourist attraction that you never get around to visiting. Except instead of a tourist attraction, I live near a major highway I rarely use.

Maybe I’m missing out on something great. Probably the commuters who use that road to get into and out of Oxford don’t think so.

× ×