PathfinderWiki
Log in

Module:Distance

From PathfinderWiki

This module powers the {{Distance}} template.

Parameters

The module takes two unnamed parameters. Both should be cities in the {{City}} table with latlong coordinates. The module does not check for validity.

Usage

The distance between [[Mzali]] and [[Tymon]] is approximately {{#number_format:{{#invoke:Distance|Main|Mzali|Tymon}}}} miles.

Results in:

The distance between Mzali and Tymon is approximately 2,244 miles.

local p = {}
local cargo = mw.ext.cargo


local function distanceBetween( lat1, long1, lat2, long2 )
  -- Haversine great circle calculator based on Ed Williams, Chris Veness, et al.
  -- https://www.movable-type.co.uk/scripts/latlong.html

  -- Golarion radius in meters is assumed to be the same as Earth's
  local golarionRadius = 6378137; --Golarion radius in meters = Earth's

  -- Convert latitude to radians
  local lat1Rad = math.rad(lat1)
  local lat2Rad = math.rad(lat2)

  -- Get distance in radians
  local deltaLatRad = math.rad(lat2 - lat1)
  local deltaLongRad = math.rad(long2 - long1)

  -- "c is the angular distance in radians, and a is the square of half the chord length between the points"
  local a = math.sin(deltaLatRad/2) * math.sin(deltaLatRad/2) + math.cos(lat1Rad) * math.cos(lat2Rad) * math.sin(deltaLongRad/2) * math.sin(deltaLongRad/2)
  local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))

  local distanceMeters = golarionRadius * c;

  -- Return meters for easier conversion
  return distanceMeters;
end

local function round( num, numDecimalPlaces )
  local mult = 10 ^ ( numDecimalPlaces or 0 )
  return math.floor( num * mult + 0.5 ) / mult
end

function p.Main( frame )
  local tables = 'City'
  local fields = 'name,latlong'
  local args = {
    where = 'City.name="' .. frame.args[1] .. '" OR City.name="' .. frame.args[2] .. '"',
  }

  local locations = cargo.query( tables, fields, args )

  -- Parse coords from Cargo
  local lat = {}
  local long = {}
  local city = {}

  for i,thisCity in ipairs(locations) do
    -- thisCity["name"] = "Absalom", thisCity["latlong"] = "37.2921,0"
    thisLat, thisLong = thisCity["latlong"]:match("([^,]+),([^,]+)")

    city[i] = thisCity["name"]
    lat[i]  = tonumber(thisLat)
    long[i] = tonumber(thisLong)
  end

  -- Do we have enough coords? Spit out an error if not
  if #lat < 2 then return "ERROR" end

  -- Get distance in meters ...
  local distanceMeters = distanceBetween(lat[1], long[1], lat[2], long[2])

  -- ... return distance in statute miles.
  return math.floor(distanceMeters / 1609.344)
end

return p