Jump to content
NEWMidgetMAN

Space Map with Warp Cell Calculator

Recommended Posts

----Edits

09/27      Changed math from U.S. tons to tonnes.  907.185 -> 1000
10/07      Updated svg bootstrap and ADDED MasterOfAll's Newer Version.


NEW VERSION MADE BY
MasterOfAll  
dualuniverse_2020-10-07t21h05m53s.png
Features
Time till Destination   = TTD
Displays Destination that was chosen.
Does Speed displayed as Velocity
Comes with Sleek White Buttons.

Pasteable Form Here Just Paste to PB and Link Screen and Core.

{"slots":{"0":{"name":"screen","type":{"events":[],"methods":[]}},"1":{"name":"core","type":{"events":[],"methods":[]}},"2":{"name":"slot3","type":{"events":[],"methods":[]}},"3":{"name":"slot4","type":{"events":[],"methods":[]}},"4":{"name":"slot5","type":{"events":[],"methods":[]}},"5":{"name":"slot6","type":{"events":[],"methods":[]}},"6":{"name":"slot7","type":{"events":[],"methods":[]}},"7":{"name":"slot8","type":{"events":[],"methods":[]}},"8":{"name":"slot9","type":{"events":[],"methods":[]}},"9":{"name":"slot10","type":{"events":[],"methods":[]}},"-1":{"name":"unit","type":{"events":[],"methods":[]}},"-2":{"name":"system","type":{"events":[],"methods":[]}},"-3":{"name":"library","type":{"events":[],"methods":[]}}},"handlers":[{"code":"MapScreenMouseX = x\nMapScreenMouseY = y\nMapScreenMouseDown = false\nlocal buttonNo = evaluateButtons()\nif MapScreenButtonSelected > 0 and MapScreenButtonSelected == buttonNo then\n    onButtonUp(buttonNo)\n    onClick(buttonNo)\nend\nMapScreenButtonSelected = -buttonNo","filter":{"args":[{"variable":"*"},{"variable":"*"}],"signature":"mouseUp(x,y)","slotKey":"0"},"key":"0"},{"code":"MapScreenMouseX = x\nMapScreenMouseY = y\nMapScreenMouseDown = true\nMapScreenButtonSelected = evaluateButtons()\nonButtonDown(MapScreenButtonSelected)\n","filter":{"args":[{"variable":"*"},{"variable":"*"}],"signature":"mouseDown(x,y)","slotKey":"0"},"key":"1"},{"code":"function Atlas()\n        return {\n    [0] = {\n      [1]={\n        GM=6930729684,\n        bodyId=1,\n        center={x=17465536.000,y=22665536.000,z=-34464.000},\n        name='Madis',\n        planetarySystemId=0,\n        radius=44300\n      },\n      [2]={\n        GM=157470826617,\n        bodyId=2,\n        center={x=-8.000,y=-8.000,z=-126303.000},\n        name='Alioth',\n        planetarySystemId=0,\n        radius=126068\n      },\n      [3]={\n        GM=11776905000,\n        bodyId=3,\n        center={x=29165536.000,y=10865536.000,z=65536.000},\n        name='Thades',\n        planetarySystemId=0,\n        radius=49000\n      },\n      [4]={\n        GM=14893847582,\n        bodyId=4,\n        center={x=-13234464.000,y=55765536.000,z=465536.000},\n        name='Talemai',\n        planetarySystemId=0,\n        radius=57450\n      },\n      [5]={\n        GM=16951680000,\n        bodyId=5,\n        center={x=-43534464.000,y=22565536.000,z=-48934464.000},\n        name='Feli',\n        planetarySystemId=0,\n        radius=60000\n      },\n      [6]={\n        GM=10502547741,\n        bodyId=6,\n        center={x=52765536.000,y=27165538.000,z=52065535.000},\n        name='Sicari',\n        planetarySystemId=0,\n        radius=51100\n      },\n      [7]={\n        GM=13033380591,\n        bodyId=7,\n        center={x=58665538.000,y=29665535.000,z=58165535.000},\n        name='Sinnen',\n        planetarySystemId=0,\n        radius=54950\n      },\n      [8]={\n        GM=18477723600,\n        bodyId=8,\n        center={x=80865538.000,y=54665536.000,z=-934463.940},\n        name='Teoma',\n        planetarySystemId=0,\n        radius=62000\n      },\n      [9]={\n        GM=18606274330,\n        bodyId=9,\n        center={x=-94134462.000,y=12765534.000,z=-3634464.000},\n        name='Jago',\n        planetarySystemId=0,\n        radius=61590\n      },\n      [10]={\n        GM=78480000,\n        bodyId=10,\n        center={x=17448118.224,y=22966846.286,z=143078.820},\n        name='Madis Moon 1',\n        planetarySystemId=0,\n        radius=10000\n      },\n      [11]={\n        GM=237402000,\n        bodyId=11,\n        center={x=17194626.000,y=22243633.880,z=-214962.810},\n        name='Madis Moon 2',\n        planetarySystemId=0,\n        radius=11000\n      },\n      [12]={\n        GM=265046609,\n        bodyId=12,\n        center={x=17520614.000,y=22184730.000,z=-309989.990},\n        name='Madis Moon 3',\n        planetarySystemId=0,\n        radius=15005\n      },\n      [21]={\n        GM=2118960000,\n        bodyId=21,\n        center={x=457933.000,y=-1509011.000,z=115524.000},\n        name='Alioth Moon 1',\n        planetarySystemId=0,\n        radius=30000\n      },\n      [22]={\n        GM=2165833514,\n        bodyId=22,\n        center={x=-1692694.000,y=729681.000,z=-411464.000},\n        name='Alioth Moon 4',\n        planetarySystemId=0,\n        radius=30330\n      },\n      [26]={\n        GM=68234043600,\n        bodyId=26,\n        center={x=-1404835.000,y=562655.000,z=-285074.000},\n        name='Sanctuary',\n        planetarySystemId=0,\n        radius=83400\n      },\n      [30]={\n        GM=211564034,\n        bodyId=30,\n        center={x=29214402.000,y=10907080.695,z=433858.200},\n        name='Thades Moon 1',\n        planetarySystemId=0,\n        radius=14002\n      },\n      [31]={\n        GM=264870000,\n        bodyId=31,\n        center={x=29404193.000,y=10432768.000,z=19554.131},\n        name='Thades Moon 2',\n        planetarySystemId=0,\n        radius=15000\n      },\n      [40]={\n        GM=141264000,\n        bodyId=40,\n        center={x=-13503090.000,y=55594325.000,z=769838.640},\n        name='Talemai Moon 2',\n        planetarySystemId=0,\n        radius=12000\n      },\n      [41]={\n        GM=106830900,\n        bodyId=41,\n        center={x=-12800515.000,y=55700259.000,z=325207.840},\n        name='Talemai Moon 3',\n        planetarySystemId=0,\n        radius=11000\n      },\n      [42]={\n        GM=264870000,\n        bodyId=42,\n        center={x=-13058408.000,y=55781856.000,z=740177.760},\n        name='Talemai Moon 1',\n        planetarySystemId=0,\n        radius=15000\n      },\n      [50]={\n        GM=499917600,\n        bodyId=50,\n        center={x=-43902841.780,y=22261034.700,z=-48862386.000},\n        name='Feli Moon 1',\n        planetarySystemId=0,\n        radius=14000\n      },\n      [70]={\n        GM=396912600,\n        bodyId=70,\n        center={x=58969616.000,y=29797945.000,z=57969449.000},\n        name='Sinnen Moon 1',\n        planetarySystemId=0,\n        radius=17000\n      },\n      [100]={\n        GM=13975172474,\n        bodyId=100,\n        center={x=98865536.000,y=-13534464.000,z=-934461.990},\n        name='Lacobus',\n        planetarySystemId=0,\n        radius=55650\n      },\n      [101]={\n        GM=264870000,\n        bodyId=101,\n        center={x=98905288.170,y=-13950921.100,z=-647589.530},\n        name='Lacobus Moon 3',\n        planetarySystemId=0,\n        radius=15000\n      },\n      [102]={\n        GM=444981600,\n        bodyId=102,\n        center={x=99180968.000,y=-13783862.000,z=-926156.400},\n        name='Lacobus Moon 1',\n        planetarySystemId=0,\n        radius=18000\n      },\n      [103]={\n        GM=211503600,\n        bodyId=103,\n        center={x=99250052.000,y=-13629215.000,z=-1059341.400},\n        name='Lacobus Moon 2',\n        planetarySystemId=0,\n        radius=14000\n      },\n      [110]={\n        GM=9204742375,\n        bodyId=110,\n        center={x=14165536.000,y=-85634465.000,z=-934464.300},\n        name='Symeon',\n        planetarySystemId=0,\n        radius=49050\n      },\n      [120]={\n        GM=7135606629,\n        bodyId=120,\n        center={x=2865536.700,y=-99034464.000,z=-934462.020},\n        name='Ion',\n        planetarySystemId=0,\n        radius=44950\n      },\n      [121]={\n        GM=106830900,\n        bodyId=121,\n        center={x=2472916.800,y=-99133747.000,z=-1133582.800},\n        name='Ion Moon 1',\n        planetarySystemId=0,\n        radius=11000\n      },\n      [122]={\n        GM=176580000,\n        bodyId=122,\n        center={x=2995424.500,y=-99275010.000,z=-1378480.700},\n        name='Ion Moon 2',\n        planetarySystemId=0,\n        radius=15000\n      }\n     }\n    }\n    end\nfunction PlanetRef()\n--[[\n  Provide coordinate transforms and access to kinematic related parameters\n  Author: JayleBreak\n  Usage (unit.start):\n  PlanetaryReference = require('planetref')\n  galaxyReference = PlanetaryReference(referenceTableSource)\n  helios = galaxyReference[0] -- PlanetaryReference.PlanetarySystem instance\n  alioth = helios[2]          -- PlanetaryReference.BodyParameters instance\n  Methods:\n    PlanetaryReference:getPlanetarySystem - based on planetary system ID.\n    PlanetaryReference.isMapPosition - 'true' if an instance of 'MapPosition'\n    PlanetaryReference.createBodyParameters - for entry into reference table\n    PlanetaryReference.BodyParameters - a class containing a body's information.\n    PlanetaryReference.MapPosition - a class for map coordinates\n    PlanetaryReference.PlanetarySystem - a container for planetary system info.\n    PlanetarySystem:castIntersections - from a position in a given direction.\n    PlanetarySystem:closestBody - to the specified coordinates.\n    PlanetarySystem:convertToBodyIdAndWorldCoordinates - from map coordinates.\n    PlanetarySystem:getBodyParameters - from reference table.\n    PlanetarySystem:getPlanetarySystemId - for the instance.\n    BodyParameters:convertToWorldCoordinates - from map coordinates\n    BodyParameters:convertToMapPosition - from world coordinates\n    BodyParameters:getAltitude - of world coordinates\n    BodyParameters:getDistance - from center to world coordinates\n    BodyParameters:getGravity - at a given position in world coordinates.\n  Description\n  An instance of the 'PlanetaryReference' \"class\" can contain transform and\n  kinematic reference information for all planetary systems in DualUniverse.\n  Each planetary system is identified by a numeric identifier. Currently,\n  the only planetary system, Helios, has the identifier: zero. This \"class\"\n  supports the indexing ('[]') operation which is equivalent to the\n  use of the 'getPlanetarySystem' method. It also supports the 'pairs()'\n  method for iterating over planetary systems.\n\n  An instance of the 'PlanetarySystem' \"class\" contains all reference\n  information for a specific system. It supports the indexing ('[]') and\n  'pairs()' functions which allows iteration over each \"body\" in the\n  system where the key is the numeric body ID. It also supports the\n  'tostring()' method.\n  An instance of the 'BodyParameters' \"class\" contains all reference\n  information for a single celestial \"body\" (a moon or planet). It supports\n  the 'tostring()' method, and contains the data members:\n          planetarySystemId - numeric planetary system ID\n          bodyId            - numeric body ID\n          radius            - radius of the body in meters (zero altitude)\n          center            - world coordinates of the body's center position\n          GM                - the gravitation parameter (g = GM/radius^2)\n  Note that the user is allowed to add custom fields (e.g. body name), but\n  should insure that complex table values have the '__tostring' metamethod\n  implemented.\n  Transform and Kinematics:\n  \"World\" coordinates is a cartesian coordinate system with an origin at an\n  arbitrary fixed point in a planetary system and with distances measured in\n  meters. The coordinates are expressible either as a simple table of 3 values\n  or an instance of the 'vec3' class.  In either case, the planetary system\n  identity is implicit.\n  \"Map\" coordinates is a geographic coordinate system with an origin at the\n  center of an identified (by a numeric value) celestial body which is a\n  member of an identified (also a numeric value) planetary system. Note that\n  the convention that latitude, longitude, and altitude values will be the\n  position's x, y, and z world coordinates in the special case of body ID 0.\n  The kinematic parameters in the reference data permit calculations of the\n  gravitational attraction of the celestial body on other objects.\n  Reference Data:\n  This is an example of reference data with a single entry assigned to\n  planetary system ID 0, and body ID 2 ('Alioth'):\n    referenceTable = {\n          [0] = { [2] = { planetarySystemId = 0,\n                          bodyId = 2,\n                          radius = 126068,\n                          center = vec3({x=-8, y=-8, z=-126303}),\n                          GM = 1.572199+11 } -- as in F=-GMm/r^2\n          }\n      }\n    ref=PlanetaryReference(referenceTable)\n  Collecting Reference Data:\n  A combination of information from the \"Map\" screen in the DU user interface,\n  and values reported by the DU Lua API can be the source of the reference\n  table's data (planetarySystemId, bodyId, and surfaceArea is from the user\n  interface):\n    referenceTable = {}\n    referenceTable[planetarySystemId][bodyId] =\n         PlanetaryReference.createBodyParameters(planetarySystemId,\n                                                 bodyId,\n                                                 surfaceArea,\n                                                 core.getConstructWorldPos(),\n                                                 core.getWorldVertical(),\n                                                 core.getAltitude(),\n                                                 core.g())\n  Adapting Data Sources:\n  Other sources of data can be adapted or converted. An example of adapting a\n  table, defined in the file: 'planets.lua', containing information on a single\n  planetary system and using celestial body name as the key follows (note that\n  a 'name' field is added to the BodyParameters instance transparently after\n  construction, and the '__pairs' meta function is required to support the\n  'closestBody' and '__tostring' methods):\n    ref=PlanetaryReference(\n        {[0] = setmetatable(require('planets'),\n                        { __index = function(bodies, bodyId)\n                             for _,v in pairs(bodies) do\n                                 if v and v.bodyId == bodyId then return v end\n                             end\n                             return nil\n                           end,\n                         __pairs = function(bodies)\n                             return function(t, k)\n                                     local nk, nv = next(t, k)\n                                     if nv then\n                                         local GM = nv.gravity * nv.radius^2\n                                         local bp = BodyParameters(0,\n                                                                   nv.id,\n                                                                   nv.radius,\n                                                                   nv.pos,\n                                                                   GM)\n                                         bp.name = nk\n                                         return nk, bp\n                                    end\n                                    return nk, nv\n                                 end, bodies, nil\n                           end })\n    })\n\n  Converting Data Sources:\n  An instance of 'PlanetaryReference' that has been adapted to a data source\n  can be used to convert that source to simple table. For example,\n  using the adapted instance shown above:\n    load('convertedData=' .. tostring(ref))()\n    newRef=PlanetaryReference(convertedData)\n  Also See: kepler.lua\n  ]]--\n--[[                    START OF LOCAL IMPLEMENTATION DETAILS             ]]--\n-- Type checks\nlocal function isNumber(n)  return type(n)           == 'number' end\nlocal function isSNumber(n) return type(tonumber(n)) == 'number' end\nlocal function isTable(t)   return type(t)           == 'table'  end\nlocal function isString(s)  return type(s)           == 'string' end\nlocal function isVector(v)  return isTable(v)\n                                    and isNumber(v.x and v.y and v.z) end\nlocal function isMapPosition(m) return isTable(m) and isNumber(m.latitude  and\n                                                               m.longitude and\n                                                               m.altitude  and\n                                                               m.bodyId    and\n                                                               m.systemId) end\n-- Constants\nlocal deg2rad    = math.pi/180\nlocal rad2deg    = 180/math.pi\nlocal epsilon    = 1e-10\nlocal num        = ' *([+-]?%d+%.?%d*e?[+-]?%d*)'\nlocal posPattern = '::pos{' .. num .. ',' .. num .. ',' ..  num .. ',' ..\n                   num ..  ',' .. num .. '}'\n-- Utilities\nlocal utils  = require('cpml.utils')\nlocal vec3   = require('cpml.vec3')\nlocal clamp  = utils.clamp\nlocal function float_eq(a,b)\n    if a == 0 then return math.abs(b) < 1e-09 end\n    if b == 0 then return math.abs(a) < 1e-09 end\n    return math.abs(a - b) < math.max(math.abs(a),math.abs(b))*epsilon\nend\nlocal function formatNumber(n)\n    local result = string.gsub(\n                    string.reverse(string.format('%.4f',n)),\n                    '^0*%.?','')\n    return result == '' and '0' or string.reverse(result)\nend\nlocal function formatValue(obj)\n    if isVector(obj) then\n        return string.format('{x=%.3f,y=%.3f,z=%.3f}', obj.x, obj.y, obj.z)\n    end\n    if isTable(obj) and not getmetatable(obj) then\n        local list = {}\n        local nxt  = next(obj)\n        if type(nxt) == 'nil' or nxt == 1 then -- assume this is an array\n            list = obj\n        else\n            for k,v in pairs(obj) do\n                local value = formatValue(v)\n                if type(k) == 'number' then\n                    table.insert(list, string.format('[%s]=%s', k, value))\n                else\n                    table.insert(list, string.format('%s=%s',   k, value))\n                end\n            end\n        end\n        return string.format('{%s}', table.concat(list, ','))\n    end\n    if isString(obj) then\n        return string.format(\"'%s'\", obj:gsub(\"'\",[[\\']]))\n    end\n    return tostring(obj)\nend\n-- CLASSES\n-- BodyParameters: Attributes of planetary bodies (planets and moons)\nlocal BodyParameters = {}\nBodyParameters.__index = BodyParameters\nBodyParameters.__tostring =\n    function(obj, indent)\n        local sep = indent or ''\n        local keys = {}\n        for k in pairs(obj) do table.insert(keys, k) end\n        table.sort(keys)\n        local list = {}\n        for _, k in ipairs(keys) do\n            local value = formatValue(obj[k])\n            if type(k) == 'number' then\n                table.insert(list, string.format('[%s]=%s', k, value))\n            else\n                table.insert(list, string.format('%s=%s', k, value))\n            end\n        end\n        if indent then\n            return string.format('%s%s',\n                                 indent,\n                                 table.concat(list, ',\\n' .. indent))\n        end\n        return string.format('{%s}', table.concat(list, ','))\n    end\nBodyParameters.__eq = function(lhs, rhs)\n        return lhs.planetarySystemId == rhs.planetarySystemId and\n               lhs.bodyId            == rhs.bodyId            and\n               float_eq(lhs.radius, rhs.radius)               and\n               float_eq(lhs.center.x, rhs.center.x)           and\n               float_eq(lhs.center.y, rhs.center.y)           and\n               float_eq(lhs.center.z, rhs.center.z)           and\n               float_eq(lhs.GM, rhs.GM)\n    end\nlocal function mkBodyParameters(systemId, bodyId, radius, worldCoordinates, GM)\n    -- 'worldCoordinates' can be either table or vec3\n    assert(isSNumber(systemId),\n           'Argument 1 (planetarySystemId) must be a number:' .. type(systemId))\n    assert(isSNumber(bodyId),\n           'Argument 2 (bodyId) must be a number:' .. type(bodyId))\n    assert(isSNumber(radius),\n           'Argument 3 (radius) must be a number:' .. type(radius))\n    assert(isTable(worldCoordinates),\n           'Argument 4 (worldCoordinates) must be a array or vec3.' ..\n           type(worldCoordinates))\n    assert(isSNumber(GM),\n           'Argument 5 (GM) must be a number:' .. type(GM))\n    return setmetatable({planetarySystemId = tonumber(systemId),\n                         bodyId            = tonumber(bodyId),\n                         radius            = tonumber(radius),\n                         center            = vec3(worldCoordinates),\n                         GM                = tonumber(GM) }, BodyParameters)\nend\n-- MapPosition: Geographical coordinates of a point on a planetary body.\nlocal MapPosition = {}\nMapPosition.__index = MapPosition\nMapPosition.__tostring = function(p)\n        return string.format('::pos{%d,%d,%s,%s,%s}',\n                             p.systemId,\n                             p.bodyId,\n                             formatNumber(p.latitude*rad2deg),\n                             formatNumber(p.longitude*rad2deg),\n                             formatNumber(p.altitude))\n    end\nMapPosition.__eq       = function(lhs, rhs)\n        return lhs.bodyId   == rhs.bodyId              and\n               lhs.systemId == rhs.systemId            and\n               float_eq(lhs.latitude,   rhs.latitude)  and\n               float_eq(lhs.altitude,   rhs.altitude)  and\n               (float_eq(lhs.longitude, rhs.longitude) or\n                float_eq(lhs.latitude, math.pi/2)      or\n                float_eq(lhs.latitude, -math.pi/2))\n    end\n-- latitude and longitude are in degrees while altitude is in meters\nlocal function mkMapPosition(overload, bodyId, latitude, longitude, altitude)\n    local systemId = overload -- Id or '::pos{...}' string\n    if isString(overload) and not longitude and not altitude and\n                              not bodyId    and not latitude then\n        systemId, bodyId, latitude, longitude, altitude =\n                                            string.match(overload, posPattern)\n        assert(systemId, 'Argument 1 (position string) is malformed.')\n    else\n        assert(isSNumber(systemId),\n               'Argument 1 (systemId) must be a number:' .. type(systemId))\n        assert(isSNumber(bodyId),\n               'Argument 2 (bodyId) must be a number:' .. type(bodyId))\n        assert(isSNumber(latitude),\n               'Argument 3 (latitude) must be in degrees:' .. type(latitude))\n        assert(isSNumber(longitude),\n               'Argument 4 (longitude) must be in degrees:' .. type(longitude))\n        assert(isSNumber(altitude),\n               'Argument 5 (altitude) must be in meters:' .. type(altitude))\n    end\n    systemId  = tonumber(systemId)\n    bodyId    = tonumber(bodyId)\n    latitude  = tonumber(latitude)\n    longitude = tonumber(longitude)\n    altitude  = tonumber(altitude)\n    if bodyId == 0 then -- this is a hack to represent points in space\n        return setmetatable({latitude  = latitude,\n                             longitude = longitude,\n                             altitude  = altitude,\n                             bodyId    = bodyId,\n                             systemId  = systemId}, MapPosition)\n    end\n    return setmetatable({latitude  = deg2rad*clamp(latitude, -90, 90),\n                         longitude = deg2rad*(longitude % 360),\n                         altitude  = altitude,\n                         bodyId    = bodyId,\n                         systemId  = systemId}, MapPosition)\nend\n-- PlanetarySystem - map body IDs to BodyParameters\nlocal PlanetarySystem = {}\nPlanetarySystem.__index = PlanetarySystem\nPlanetarySystem.__tostring =\n    function (obj, indent)\n        local sep = indent and (indent .. '  ' )\n        local bdylist = {}\n        local keys = {}\n        for k in pairs(obj) do table.insert(keys, k) end\n        table.sort(keys)\n        for _, bi in ipairs(keys) do\n            bdy = obj[bi]\n            local bdys = BodyParameters.__tostring(bdy, sep)\n            if indent then\n                table.insert(bdylist,\n                             string.format('[%s]={\\n%s\\n%s}',\n                                           bi, bdys, indent))\n            else\n                table.insert(bdylist, string.format('  [%s]=%s', bi, bdys))\n            end\n        end\n        if indent then\n            return string.format('\\n%s%s%s',\n                                 indent,\n                                 table.concat(bdylist, ',\\n' .. indent),\n                                 indent)\n        end\n        return string.format('{\\n%s\\n}', table.concat(bdylist, ',\\n'))\n    end\nlocal function mkPlanetarySystem(referenceTable)\n    local atlas = {}\n    local pid\n    for _, v in pairs(referenceTable) do\n        local id = v.planetarySystemId\n        if type(id) ~= 'number' then\n            error('Invalid planetary system ID: ' .. tostring(id))\n        elseif pid and id ~= pid then\n            error('Mismatch planetary system IDs: ' .. id .. ' and '\n                  .. pid)\n        end\n        local bid = v.bodyId\n        if type(bid) ~= 'number' then\n            error('Invalid body ID: ' .. tostring(bid))\n        elseif atlas[bid] then\n            error('Duplicate body ID: ' .. tostring(bid))\n        end\n        setmetatable(v.center, getmetatable(vec3.unit_x))\n        atlas[bid] = setmetatable(v, BodyParameters)\n        pid = id\n    end\n    return setmetatable(atlas, PlanetarySystem)\nend\n-- PlanetaryReference - map planetary system ID to PlanetarySystem\nPlanetaryReference = {}\nlocal function mkPlanetaryReference(referenceTable)\n    return setmetatable({ galaxyAtlas = referenceTable or {} },\n                          PlanetaryReference)\nend\nPlanetaryReference.__index        =\n    function(t,i)\n        if type(i) == 'number' then\n            local system = t.galaxyAtlas[i]\n            return mkPlanetarySystem(system)\n        end\n        return rawget(PlanetaryReference, i)\n    end\nPlanetaryReference.__pairs        =\n    function(obj)\n        return  function(t, k)\n                    local nk, nv = next(t, k)\n                    return nk, nv and mkPlanetarySystem(nv)\n                end, obj.galaxyAtlas, nil\n    end\nPlanetaryReference.__tostring     =\n    function (obj)\n        local pslist = {}\n        for _,ps in pairs(obj or {}) do\n            local psi = ps:getPlanetarySystemId()\n            local pss = PlanetarySystem.__tostring(ps, '    ')\n            table.insert(pslist,\n                         string.format('  [%s]={%s\\n  }', psi, pss))\n        end\n        return string.format('{\\n%s\\n}\\n', table.concat(pslist,',\\n'))\n    end\n--[[                       START OF PUBLIC INTERFACE                       ]]--\n-- PlanetaryReference CLASS METHODS:\n--\n-- BodyParameters - create an instance of BodyParameters class\n-- planetarySystemId  [in]: the body's planetary system ID.\n-- bodyId             [in]: the body's ID.\n-- radius             [in]: the radius in meters of the planetary body.\n-- bodyCenter         [in]: the world coordinates of the center (vec3 or table).\n-- GM                 [in]: the body's standard gravitational parameter.\n-- return: an instance of BodyParameters class.\n--\nPlanetaryReference.BodyParameters = mkBodyParameters\n--\n-- MapPosition - create an instance of the MapPosition class\n-- overload [in]: either a planetary system ID or a position string ('::pos...')\n-- bodyId [in]:   (ignored if overload is a position string) the body's ID.\n-- latitude [in]: (ignored if overload is a position string) the latitude.\n-- longitude [in]:(ignored if overload is a position string) the longitude.\n-- altitude [in]: (ignored if overload is a position string) the altitude.\n-- return: the class instance\n--\nPlanetaryReference.MapPosition    = mkMapPosition\n--\n-- PlanetarySystem - create an instance of PlanetarySystem class\n-- referenceData [in]: a table (indexed by bodyId) of body reference info.\n-- return: the class instance\n--\nPlanetaryReference.PlanetarySystem = mkPlanetarySystem\n--\n-- createBodyParameters - create an instance of BodyParameters class\n-- planetarySystemId  [in]: the body's planetary system ID.\n-- bodyId             [in]: the body's ID.\n-- surfaceArea        [in]: the body's surface area in square meters.\n-- aPosition          [in]: world coordinates of a position near the body.\n-- verticalAtPosition [in]: a vector pointing towards the body center.\n-- altitudeAtPosition [in]: the altitude in meters at the position.\n-- gravityAtPosition  [in]: the magnitude of the gravitational acceleration.\n-- return: an instance of BodyParameters class.\n--\nfunction PlanetaryReference.createBodyParameters(planetarySystemId,\n                                                 bodyId,\n                                                 surfaceArea,\n                                                 aPosition,\n                                                 verticalAtPosition,\n                                                 altitudeAtPosition,\n                                                 gravityAtPosition)\n    assert(isSNumber(planetarySystemId),\n           'Argument 1 (planetarySystemId) must be a number:' ..\n           type(planetarySystemId))\n    assert(isSNumber(bodyId),\n           'Argument 2 (bodyId) must be a number:' .. type(bodyId))\n    assert(isSNumber(surfaceArea),\n           'Argument 3 (surfaceArea) must be a number:' .. type(surfaceArea))\n    assert(isTable(aPosition),\n           'Argument 4 (aPosition) must be an array or vec3:' ..\n           type(aPosition))\n    assert(isTable(verticalAtPosition),\n           'Argument 5 (verticalAtPosition) must be an array or vec3:' ..\n           type(verticalAtPosition))\n    assert(isSNumber(altitudeAtPosition),\n           'Argument 6 (altitude) must be in meters:' ..\n           type(altitudeAtPosition))\n    assert(isSNumber(gravityAtPosition),\n           'Argument 7 (gravityAtPosition) must be number:' ..\n           type(gravityAtPosition))\n    local radius   = math.sqrt(surfaceArea/4/math.pi)\n    local distance = radius + altitudeAtPosition\n    local center   = vec3(aPosition) + distance*vec3(verticalAtPosition)\n    local GM       = gravityAtPosition * distance * distance\n    return mkBodyParameters(planetarySystemId, bodyId, radius, center, GM)\nend\n--\n-- isMapPosition - check for the presence of the 'MapPosition' fields\n-- valueToTest [in]: the value to be checked\n-- return: 'true' if all required fields are present in the input value\n--\nPlanetaryReference.isMapPosition  = isMapPosition\n-- PlanetaryReference INSTANCE METHODS:\n--\n-- getPlanetarySystem - get the planetary system using ID or MapPosition as key\n-- overload [in]: either the planetary system ID or a MapPosition that has it.\n-- return: instance of 'PlanetarySystem' class or nil on error\n--\nfunction PlanetaryReference:getPlanetarySystem(overload)\n    --if galaxyAtlas then\n        local planetarySystemId = overload\n        if isMapPosition(overload) then\n            planetarySystemId = overload.systemId\n        end\n        if type(planetarySystemId) == 'number' then\n            local system = self.galaxyAtlas[i]\n            if system then\n                if getmetatable(nv) ~= PlanetarySystem then\n                    system = mkPlanetarySystem(system)\n                end\n                return system\n            end\n        end\n    --end\n    --return nil\nend\n-- PlanetarySystem INSTANCE METHODS:\n--\n-- castIntersections - Find the closest body that intersects a \"ray cast\".\n-- origin [in]: the origin of the \"ray cast\" in world coordinates\n-- direction [in]: the direction of the \"ray cast\" as a 'vec3' instance.\n-- sizeCalculator [in]: (default: returns 1.05*radius) Returns size given body.\n-- bodyIds[in]: (default: all IDs in system) check only the given IDs.\n-- return: The closest body that blocks the cast or 'nil' if none.\n--\nfunction PlanetarySystem:castIntersections(origin,\n                                           direction,\n                                           sizeCalculator,\n                                           bodyIds)\n    local sizeCalculator = sizeCalculator or\n                            function (body) return 1.05*body.radius end\n    local candidates = {}\n    if bodyIds then\n        for _,i in ipairs(bodyIds) do candidates[i] = self[i] end\n    else\n        bodyIds = {}\n        for k,body in pairs(self) do\n            table.insert(bodyIds, k)\n            candidates[k] = body\n        end\n    end\n    local function compare(b1,b2)\n        local v1 = candidates[b1].center - origin\n        local v2 = candidates[b2].center - origin\n        return v1:len() < v2:len()\n    end\n    table.sort(bodyIds, compare)\n    local dir = direction:normalize()\n    for i, id in ipairs(bodyIds) do\n        local body   = candidates[id]\n        local c_oV3  = body.center - origin\n        local radius = sizeCalculator(body)\n        local dot    = c_oV3:dot(dir)\n        local desc   = dot^2 - (c_oV3:len2() - radius^2)\n        if desc >= 0 then\n            local root     = math.sqrt(desc)\n            local farSide  = dot + root\n            local nearSide = dot - root\n            if nearSide > 0 then\n                return body, farSide, nearSide\n            elseif farSide > 0 then\n                return body, farSide, nil\n            end\n        end\n    end\n    return nil, nil, nil\nend\n--\n-- closestBody - find the closest body to a given set of world coordinates\n-- coordinates       [in]: the world coordinates of position in space\n-- return: an instance of the BodyParameters object closest to 'coordinates'\n--\nfunction PlanetarySystem:closestBody(coordinates)\n    assert(type(coordinates) == 'table', 'Invalid coordinates.')\n    local minDistance2, body\n    local coord = vec3(coordinates)\n    for _,params in pairs(self) do\n        local distance2 = (params.center - coord):len2()\n        if not body or distance2 < minDistance2 then\n            body         = params\n            minDistance2 = distance2\n        end\n    end\n    return body\nend\n--\n-- convertToBodyIdAndWorldCoordinates - map to body Id and world coordinates\n-- overload [in]: an instance of MapPosition or a position string ('::pos...)\n-- return: a vec3 instance containing the world coordinates or 'nil' on error.\n--\nfunction PlanetarySystem:convertToBodyIdAndWorldCoordinates(overload)\n    local mapPosition = overload\n    if isString(overload) then\n        mapPosition = mkMapPosition(overload)\n    end\n    if mapPosition.bodyId == 0 then\n        return 0, vec3(mapPosition.latitude,\n                       mapPosition.longitude,\n                       mapPosition.altitude)\n    end\n    local params = self:getBodyParameters(mapPosition)\n    if params then\n        return mapPosition.bodyId,\n               params:convertToWorldCoordinates(mapPosition)\n    end\nend\n--\n-- getBodyParameters - get or create an instance of BodyParameters class\n-- overload [in]: either an instance of MapPosition or a body's ID.\n-- return: a BodyParameters instance or 'nil' if body ID is not found.\n--\nfunction PlanetarySystem:getBodyParameters(overload)\n    local bodyId = overload\n    if isMapPosition(overload) then\n        bodyId = overload.bodyId\n    end\n    assert(isSNumber(bodyId),\n               'Argument 1 (bodyId) must be a number:' .. type(bodyId))\n    return self[bodyId]\nend\n--\n-- getPlanetarySystemId - get the planetary system ID for this instance\n-- return: the planetary system ID or nil if no planets are in the system.\n--\nfunction PlanetarySystem:getPlanetarySystemId()\n    local k, v = next(self)\n    return v and v.planetarySystemId\nend\n-- BodyParameters INSTANCE METHODS:\n--\n-- convertToMapPosition - create an instance of MapPosition from coordinates\n-- worldCoordinates [in]: the world coordinates of the map position.\n-- return: an instance of MapPosition class\n--\nfunction BodyParameters:convertToMapPosition(worldCoordinates)\n    assert(isTable(worldCoordinates),\n           'Argument 1 (worldCoordinates) must be an array or vec3:' ..\n           type(worldCoordinates))\n    local worldVec  = vec3(worldCoordinates)\n    if self.bodyId == 0 then\n        return setmetatable({latitude  = worldVec.x,\n                             longitude = worldVec.y,\n                             altitude  = worldVec.z,\n                             bodyId    = 0,\n                             systemId  = self.planetarySystemId}, MapPosition)\n    end\n    local coords    = worldVec - self.center\n    local distance  = coords:len()\n    local altitude  = distance - self.radius\n    local latitude  = 0\n    local longitude = 0\n    if not float_eq(distance, 0) then\n        local phi = math.atan(coords.y, coords.x)\n        longitude = phi >= 0 and phi or (2*math.pi + phi)\n        latitude  = math.pi/2 - math.acos(coords.z/distance)\n    end\n    return setmetatable({latitude  = latitude,\n                         longitude = longitude,\n                         altitude  = altitude,\n                         bodyId    = self.bodyId,\n                         systemId  = self.planetarySystemId}, MapPosition)\nend\n--\n-- convertToWorldCoordinates - convert a map position to world coordinates\n-- overload [in]: an instance of MapPosition or a position string ('::pos...')\n--\nfunction BodyParameters:convertToWorldCoordinates(overload)\n    local mapPosition = isString(overload) and\n                                           mkMapPosition(overload) or overload\n    if mapPosition.bodyId == 0 then -- support deep space map position\n        return vec3(mapPosition.latitude,\n                    mapPosition.longitude,\n                    mapPosition.altitude)\n    end\n    assert(isMapPosition(mapPosition),\n           'Argument 1 (mapPosition) is not an instance of \"MapPosition\".')\n    assert(mapPosition.systemId == self.planetarySystemId,\n           'Argument 1 (mapPosition) has a different planetary system ID.')\n    assert(mapPosition.bodyId == self.bodyId,\n           'Argument 1 (mapPosition) has a different planetary body ID.')\n    local xproj = math.cos(mapPosition.latitude)\n    return self.center + (self.radius + mapPosition.altitude) *\n           vec3(xproj*math.cos(mapPosition.longitude),\n                xproj*math.sin(mapPosition.longitude),\n                math.sin(mapPosition.latitude))\nend\n--\n-- getAltitude - calculate the altitude of a point given in world coordinates.\n-- worldCoordinates [in]: the world coordinates of the point.\n-- return: the altitude in meters\n--\nfunction BodyParameters:getAltitude(worldCoordinates)\n    return (vec3(worldCoordinates) - self.center):len() - self.radius\nend\n--\n-- getDistance - calculate the distance to a point given in world coordinates.\n-- worldCoordinates [in]: the world coordinates of the point.\n-- return: the distance in meters\n--\nfunction BodyParameters:getDistance(worldCoordinates)\n    return (vec3(worldCoordinates) - self.center):len()\nend\n--\n-- getGravity - calculate the gravity vector induced by the body.\n-- worldCoordinates [in]: the world coordinates of the point.\n-- return: the gravity vector in meter/seconds^2\n--\nfunction BodyParameters:getGravity(worldCoordinates)\n    local radial = self.center - vec3(worldCoordinates) -- directed towards body\n    local len2   = radial:len2()\n    return (self.GM/len2) * radial/math.sqrt(len2)\nend\n-- end of module\nreturn setmetatable(PlanetaryReference,\n                    { __call = function(_,...)\n                                    return mkPlanetaryReference(...)\n                               end })\nend\nfunction Keplers()\n    --[[\n  Provides methods for computing orbital information for an object\n  Usage:\n  Kepler = require('autoconf.custom.kepler')\n  alioth = Kepler({ GM=157470826617,\n                    bodyId=2,\n                    center={x=-8.000,y=-8.000,z=-126303.000},\n                    name='Alioth',\n                    planetarySystemId=0,\n                    radius=126068\n                  })\n  altitude = 6000\n  position = '::pos{0,2,0,0,6000}'\n  e, o     = alioth:escapeAndOrbitalSpeed(altitude)\n  orbit    = alioth:orbitalParameters(position, {0, o+1, 0})\n  print(\"Eccentricity \" .. orbit.eccentricity)\n  print(\"Perihelion \" .. orbit.periapsis.altitude)\n  print(\"Max. speed \" .. orbit.periapsis.speed)\n  print(\"Circular orbit speed \" .. orbit.periapsis.circularOrbitSpeed)\n  print(\"Aphelion \"  .. orbit.apoapsis.altitude)\n  print(\"Min. speed \" .. orbit.apoapsis.speed)\n  print(\"Orbital period \" .. orbit.period)\n  --- output:\n    Eccentricity 0.0018324307017878\n    Perihelion 6000.0\n    Max. speed 1092.9462297033\n    Circular orbit speed 1091.9462297033\n    Aphelion 6484.8994605062\n    Min. speed 1088.9480596194\n    Orbital period 762.02818214049\n  Methods:\n    Kepler:escapeAndOrbitalSpeed - for a given celestial body and altitude.\n    Kepler:orbitalParameters - for a given massless object and a celestial body.\n  Description\n  The motion of an object in the vicinity of substantially larger mass is\n  in the domain of the \"2-body problem\". By assuming the object whose motion\n  is of interest is of negligable mass simplifies the calculations of:\n  the speed to escape the body, the speed of a circular orbit, and the\n  parameters defining the orbit of the object (or the lack of orbit as the\n  case may be).\n  Orbital Parameters:\n     periapsis - the closest approach to the planet\n      apoapsis - the furthest point from the planet if in orbit (otherwise nil)\n  eccentricity - 0 for circular orbits\n                <1 for elliptical orbits\n                 1 for parabiolic trajectory\n                >1 for hyperbolic trajectory\n        period - time (in seconds) to complete an orbit\n  Also See: planetref.lua\n]]--\nlocal vec3       = require('cpml.vec3')\nlocal PlanetRef  = PlanetRef()\nlocal function isString(s) return type(s)   == 'string' end\nlocal function isTable(t)  return type(t)   == 'table'  end\nlocal function float_eq(a,b)\n    if a == 0 then return math.abs(b) < 1e-09 end\n    if b == 0 then return math.abs(a) < 1e-09 end\n    return math.abs(a - b) < math.max(math.abs(a),math.abs(b))*epsilon\nend\nKepler = {}\nKepler.__index = Kepler\n--\n-- escapeAndOrbitalSpeed - speed required to escape and for a circular orbit\n-- altitude [in]: the height of the orbit in meters above \"sea-level\"\n-- return: the speed in m/s needed to escape the celestial body and to orbit it.\n--\nfunction Kepler:escapeAndOrbitalSpeed(altitude)\n    assert(self.body)\n    -- P = -GMm/r and KE = mv^2/2 (no lorentz factor used)\n    -- mv^2/2 = GMm/r\n    -- v^2 = 2GM/r\n    -- v = sqrt(2GM/r1)\n    local distance = altitude + self.body.radius\n    if not float_eq(distance, 0) then\n        local orbit = math.sqrt(self.body.GM/distance)\n        return math.sqrt(2)*orbit, orbit\n    end\n    return nil, nil\nend\n--\n-- orbitalParameters: determine the orbital elements for a two-body system.\n-- overload [in]: the world coordinates or map coordinates of a massless object.\n-- velocity [in]: The velocity of the massless point object in m/s.\n-- return: the 6 orbital elements for the massless object.\n--\nfunction Kepler:orbitalParameters(overload, velocity)\n    assert(self.body)\n    assert(isTable(overload) or isString(overload))\n    assert(isTable(velocity))\n    local pos = (isString(overload) or PlanetRef.isMapPosition(overload)) and\n                            self.body:convertToWorldCoordinates(overload) or\n                vec3(overload)\n    local v   = vec3(velocity)\n    local r   = pos - self.body.center\n    local v2  = v:len2()\n    local d   = r:len()\n    local mu  = self.body.GM\n    local e   = ((v2 - mu/d)*r - r:dot(v)*v)/mu\n    local a   = mu/(2*mu/d - v2)\n    local ecc = e:len()\n    local dir = e:normalize()\n    local pd  = a*(1-ecc)\n    local ad  = a*(1+ecc)\n    local per = pd*dir + self.body.center\n    local apo = ecc <= 1 and -ad*dir + self.body.center or nil\n    local trm = math.sqrt(a*mu*(1-ecc*ecc))\n    local Period = apo and 2*math.pi*math.sqrt(a^3/mu)\n    -- These are great and all, but, I need more.\n    local trueAnomaly = math.acos((e:dot(r))/(ecc*d))\n    if r:dot(v) < 0 then\n        trueAnomaly = -(trueAnomaly - 2*math.pi)\n    end\n    -- Apparently... cos(EccentricAnomaly) = (cos(trueAnomaly) + eccentricity)/(1 + eccentricity * cos(trueAnomaly))\n    local EccentricAnomaly = math.acos((math.cos(trueAnomaly) + ecc)/(1 + ecc * math.cos(trueAnomaly)))\n    -- Then.... apparently if this is below 0, we should add 2pi to it\n    -- I think also if it's below 0, we're past the apoapsis?\n    local timeTau = EccentricAnomaly\n    if timeTau < 0 then\n        timeTau = timeTau + 2*math.pi\n    end\n    -- So... time since periapsis...\n    -- Is apparently easy if you get mean anomly.  t = M/n where n is mean motion, = 2*pi/Period\n\n\n    local MeanAnomaly = timeTau - ecc * math.sin(timeTau)\n    local TimeSincePeriapsis = MeanAnomaly/(2*math.pi/Period)\n    --system.print(MeanAnomaly .. \" - \" .. TimeSincePeriapsis .. \" - \" .. Period .. \" - \" .. EccentricAnomaly .. \" - \" .. timeTau .. \" - \" .. trueAnomaly)\n    -- Mean anom is 0 at periapsis, positive before it... and positive after it.\n    -- I guess this is why I needed to use timeTau and not EccentricAnomaly here\n\n    local TimeToPeriapsis = Period - TimeSincePeriapsis\n    local TimeToApoapsis = TimeToPeriapsis + Period/2\n    if trueAnomaly - math.pi > 0 then -- TBH I think something's wrong in my formulas because I needed this.\n        TimeToPeriapsis = TimeSincePeriapsis\n        TimeToApoapsis = TimeToPeriapsis + Period/2\n    end\n    if TimeToApoapsis > Period then\n        TimeToApoapsis = TimeToApoapsis - Period\n    end\n    return { periapsis       = { position           = per,\n                                 speed              = trm/pd,\n                                 circularOrbitSpeed = math.sqrt(mu/pd),\n                                 altitude           = pd - self.body.radius},\n             apoapsis        = apo and\n                               { position           = apo,\n                                 speed              = trm/ad,\n                                 circularOrbitSpeed = math.sqrt(mu/ad),\n                                 altitude           = ad - self.body.radius},\n             currentVelocity = v,\n             currentPosition = pos,\n             eccentricity    = ecc,\n             period          = Period,\n             eccentricAnomaly = EccentricAnomaly,\n             meanAnomaly = MeanAnomaly,\n             timeToPeriapsis = TimeToPeriapsis,\n             timeToApoapsis = TimeToApoapsis\n           }\nend\n\nlocal function new(bodyParameters)\n    local params = PlanetRef.BodyParameters(bodyParameters.planetarySystemId,\n                                            bodyParameters.bodyId,\n                                            bodyParameters.radius,\n                                            bodyParameters.center,\n                                            bodyParameters.GM)\n    return setmetatable({body = params}, Kepler)\nend\nreturn setmetatable(Kepler, { __call = function(_,...) return new(...) end })\nend\nfunction Kinematics()\n    --[[\n  DualUniverse kinematic equations\n  Author: JayleBreak\n  Usage (unit.start):\n  Kinematics = require('autoconf.custom.kinematics')\n  Methods:\n   computeAccelerationTime - \"relativistic\" version of t = (vf - vi)/a\n   computeDistanceAndTime - Return distance & time needed to reach final speed.\n   computeTravelTime - \"relativistic\" version of t=(sqrt(2ad+v^2)-v)/a\n  Description\n  DualUniverse increases the effective mass of constructs as their absolute\n  speed increases by using the \"lorentz\" factor (from relativity) as the scale\n  factor.  This results in an upper bound on the absolute speed of constructs\n  (excluding \"warp\" drive) that is set to 30 000 KPH (8 333 MPS). This module\n  provides utilities for computing some physical quantities taking this\n  scaling into account.\n]]--\nlocal Kinematic = {} -- just a namespace\nlocal C       = 30000000/3600\nlocal C2      = C*C\nlocal ITERATIONS = 100 -- iterations over engine \"warm-up\" period\nlocal function lorentz(v) return 1/math.sqrt(1 - v*v/C2) end\n--\n-- computeAccelerationTime - \"relativistic\" version of t = (vf - vi)/a\n-- initial      [in]: initial (positive) speed in meters per second.\n-- acceleration [in]: constant acceleration until 'finalSpeed' is reached.\n-- final        [in]: the speed at the end of the time interval.\n-- return: the time in seconds spent in traversing the distance\n--\nfunction Kinematic.computeAccelerationTime(initial, acceleration, final)\n    -- The low speed limit of following is: t=(vf-vi)/a (from: vf=vi+at)\n    local k1 = C*math.asin(initial/C)\n    return (C * math.asin(final/C) - k1)/acceleration\nend\n--\n-- computeDistanceAndTime - Return distance & time needed to reach final speed.\n-- initial[in]:     Initial speed in meters per second.\n-- final[in]:       Final speed in meters per second.\n-- restMass[in]:    Mass of the construct at rest in Kg.\n-- thrust[in]:      Engine's maximum thrust in Newtons.\n-- t50[in]:         (default: 0) Time interval to reach 50% thrust in seconds.\n-- brakeThrust[in]: (default: 0) Constant thrust term when braking.\n-- return: Distance (in meters), time (in seconds) required for change.\n--\nfunction Kinematic.computeDistanceAndTime(initial,\n                                          final,\n                                          restMass,\n                                          thrust,\n                                          t50,\n                                          brakeThrust)\n    -- This function assumes that the applied thrust is colinear with the\n    -- velocity. Furthermore, it does not take into account the influence\n    -- of gravity, not just in terms of its impact on velocity, but also\n    -- its impact on the orientation of thrust relative to velocity.\n    -- These factors will introduce (usually) small errors which grow as\n    -- the length of the trip increases.\n    t50            = t50 or 0\n    brakeThrust    = brakeThrust or 0 -- usually zero when accelerating\n    local tau0     = lorentz(initial)\n    local speedUp  = initial <= final\n    local a0       = thrust * (speedUp and 1 or -1)/restMass\n    local b0       = -brakeThrust/restMass\n    local totA     = a0+b0\n    if speedUp and totA <= 0 or not speedUp and totA >= 0 then\n        return -1, -1 -- no solution\n    end\n    local distanceToMax, timeToMax = 0, 0\n    -- If, the T50 time is set, then assume engine is at zero thrust and will\n    -- reach full thrust in 2*T50 seconds. Thrust curve is given by:\n    -- Thrust: F(z)=(a0*(1+sin(z))+2*b0)/2 where z=pi*(t/t50 - 1)/2\n    -- Acceleration is given by F(z)/m(z) where m(z) = m/sqrt(1-v^2/c^2)\n    -- or v(z)' = (a0*(1+sin(z))+2*b0)*sqrt(1-v(z)^2/c^2)/2\n    if a0 ~= 0 and t50 > 0 then\n        -- Closed form solution for velocity exists:\n        -- v(t) = -c*tan(w)/sqrt(tan(w)^2+1) => w = -asin(v/c)\n        -- w=(pi*t*(a0/2+b0)-a0*t50*sin(pi*t/2/t50)+*pi*c*k1)/pi/c\n        -- @ t=0, v(0) = vi\n        -- pi*c*k1/pi/c = -asin(vi/c)\n        -- k1 = asin(vi/c)\n        local k1  = math.asin(initial/C)\n        local c1  = math.pi*(a0/2+b0)\n        local c2  = a0*t50\n        local c3  = C*math.pi\n        local v = function(t)\n            local w  = (c1*t - c2*math.sin(math.pi*t/2/t50) + c3*k1)/c3\n            local tan = math.tan(w)\n            return C*tan/math.sqrt(tan*tan+1)\n        end\n        local speedchk = speedUp and function(s) return s >= final end or\n                                     function(s) return s <= final end\n        timeToMax  = 2*t50\n        if speedchk(v(timeToMax)) then\n            local lasttime = 0\n            while math.abs(timeToMax - lasttime) > 0.5 do\n                local t = (timeToMax + lasttime)/2\n                if speedchk(v(t)) then\n                    timeToMax = t\n                else\n                    lasttime = t\n                end\n            end\n        end\n        -- There is no closed form solution for distance in this case.\n        -- Numerically integrate for time t=0 to t=2*T50 (or less)\n        local lastv = initial\n        local tinc  = timeToMax/ITERATIONS\n        for step = 1, ITERATIONS do\n            local speed = v(step*tinc)\n            distanceToMax = distanceToMax + (speed+lastv)*tinc/2\n            lastv = speed\n        end\n        if timeToMax < 2*t50 then\n            return distanceToMax, timeToMax\n        end\n        initial     = lastv\n    end\n    -- At full thrust, acceleration only depends on the Lorentz factor:\n    -- v(t)' = (F/m(v)) = a*sqrt(1-v(t)^2/c^2) where a = a0+b0\n    -- -> v = c*sin((at+k1)/c)\n    -- @ t=0, v=vi: k1 = c*asin(vi/c)\n    -- -> t = (c*asin(v/c) - k1)/a\n    -- x(t)' = c*sin((at+k1)/c)\n    -- x = k2 - c^2 cos((at+k1)/c)/a\n    -- @ t=0, x=0: k2 = c^2 * cos(k1/c)/a\n    local k1       = C*math.asin(initial/C)\n    local time     = (C * math.asin(final/C) - k1)/totA\n    local k2       = C2 *math.cos(k1/C)/totA\n    local distance = k2 - C2 * math.cos((totA*time + k1)/C)/totA\n    return distance+distanceToMax, time+timeToMax\nend\n--\n-- computeTravelTime - \"relativistic\" version of t=(sqrt(2ad+v^2)-v)/a\n-- initialSpeed [in]: initial (positive) speed in meters per second\n-- acceleration [in]: constant acceleration until 'distance' is traversed\n-- distance [in]: the distance traveled in meters\n-- return: the time in seconds spent in traversing the distance\n--\nfunction Kinematic.computeTravelTime(initial, acceleration, distance)\n    -- The low speed limit of following is: t=(sqrt(2ad+v^2)-v)/a\n    -- (from: d=vt+at^2/2)\n    if distance == 0 then return 0 end\n    if acceleration > 0 then\n        local k1       = C*math.asin(initial/C)\n        local k2       = C2*math.cos(k1/C)/acceleration\n        return (C*math.acos(acceleration*(k2 - distance)/C2) - k1)/acceleration\n    end\n    assert(initial > 0, 'Acceleration and initial speed are both zero.')\n    return distance/initial\nend\nfunction Kinematic.lorentz(v) return lorentz(v) end\nreturn Kinematic\nend\nPlanetaryReference = PlanetRef()\ngalaxyReference = PlanetaryReference(Atlas())\nKinematic = Kinematics()\nKep = Keplers()\nfunction getDistanceDisplayString(distance)\n    local su = distance > 100000\n    local result = \"\"\n    if su then\n        -- Convert to SU\n        result = round(distance/1000/200,1) .. \" SU\"\n    else\n        -- Convert to KM\n        result = round(distance/1000,1) .. \" KM\"\n    end\n\n    return result\nend\n\nPlanetaryReference = PlanetRef()\ngalaxyReference = PlanetaryReference(Atlas())\n\nMapScreenButtons = {}\nMapScreenMouseX = 0\nMapScreenMouseY = 0\nMapScreenMouseDown = false\nMapScreenButtonSelected = 0\nlocal worldPos = vec3(core.getConstructWorldPos())\nlocal locX = (worldPos.x/400000)\nlocal locY = (worldPos.y/400000)*(-1)\nlocal destX = 0\nlocal destY = 0\nlocal sudistance = 0\nlocal loc = vec3(core.getConstructWorldPos())\nlocal ion = galaxyReference[0][120]  ---uses Atlas functions\nlocal thades = vec3(29165536.000, 10865536.000, 65536.000)\nlocal sinnen = vec3(58665536.000, 29665536.000, 58165536.000)\nlocal alioth = galaxyReference[0][2]    ---uses Atlas functions\nlocal madis = vec3(17465536.000, 22665536.000, -34464.000)\nlocal jago = vec3(-94134464.000, 12765536.000, -3634464.000)\nlocal symeon = vec3(14165536.000, -85634464.000, -934464.000)\nlocal lacobus = vec3(98865536.000, -13534464.000, -934464.000)\nlocal teoma = vec3(80865536.000, 54665536.000, -934464.000)\nlocal feli = vec3(-43534464.000, 22565536.000, -48934464.000)\nlocal talemai = vec3(-13234464.000, 55765536.000, 465536.000)\nlocal sicari = vec3(52765536.000, 27165536.000, 52065536.000)\nlocal distion = math.floor(ion:getDistance(loc)/200000)   ---uses getDistance functions----\nlocal distthades = string.format(\"%.2f\", math.sqrt((loc.x-thades.x)^2+(loc.y-thades.y)^2+(loc.z-thades.z)^2)/200000)\nlocal distalioth = math.floor(alioth:getDistance(loc)/200000)   ---uses getDistance functions----\nlocal distmadis = string.format(\"%.2f\", math.sqrt((loc.x-madis.x)^2+(loc.y-madis.y)^2+(loc.z-madis.z)^2)/200000)\nlocal distjago = string.format(\"%.2f\", math.sqrt((loc.x-jago.x)^2+(loc.y-jago.y)^2+(loc.z-jago.z)^2)/200000)\nlocal distlacobus = string.format(\"%.2f\", math.sqrt((loc.x-lacobus.x)^2+(loc.y-lacobus.y)^2+(loc.z-lacobus.z)^2)/200000)\nlocal distteoma = string.format(\"%.2f\", math.sqrt((loc.x-teoma.x)^2+(loc.y-teoma.y)^2+(loc.z-teoma.z)^2)/200000)\nlocal distsymeon = string.format(\"%.2f\", math.sqrt((loc.x-symeon.x)^2+(loc.y-symeon.y)^2+(loc.z-symeon.z)^2)/200000)\nlocal distfeli = string.format(\"%.2f\", math.sqrt((loc.x-feli.x)^2+(loc.y-feli.y)^2+(loc.z-feli.z)^2)/200000)\nlocal distsinnen = string.format(\"%.2f\", math.sqrt((loc.x-sinnen.x)^2+(loc.y-sinnen.y)^2+(loc.z-sinnen.z)^2)/200000)\nlocal disttalemai = string.format(\"%.2f\", math.sqrt((loc.x-talemai.x)^2+(loc.y-talemai.y)^2+(loc.z-talemai.z)^2)/200000)\nlocal distsicari = string.format(\"%.2f\", math.sqrt((loc.x-sicari.x)^2+(loc.y-sicari.y)^2+(loc.z-sicari.z)^2)/200000)\nselection = 0\n\n\n      for i = 1,1 do\n   local button = {id = (\"b\"..1), enabled=true, td=\"<td>\", top=2/100, bottom=13/100, left=1/100, right=28/100}\n    table.insert(MapScreenButtons, button)\nend\n  for i = 2,2 do\n   local button = {id = (\"b\"..2), enabled=true, td=\"<td>\", top=15/100, bottom=26/100, left=1/100, right=30/100}\n    table.insert(MapScreenButtons, button)\nend\n    for i = 3,3 do\n    local button = {id = (\"b\"..3), enabled=true, td=\"<td>\", top=27/100, bottom=38/100, left=1/100, right=28/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 4,4 do\n    local button = {id = (\"b\"..4), enabled=true, td=\"<td>\", top=39/100, bottom=50/100, left=1/100, right=28/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 5,5 do\n    local button = {id = (\"b\"..5), enabled=true, td=\"<td>\", top=51/100, bottom=62/100, left=1/100, right=28/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 6,6 do\n    local button = {id = (\"b\"..6), enabled=true, td=\"<td>\", top=64/100, bottom=75/100, left=1/100, right=28/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 7,7 do\n    local button = {id = (\"b\"..7), enabled=true, td=\"<td>\", top=2/100, bottom=13/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 8,8 do\n    local button = {id = (\"b\"..8), enabled=true, td=\"<td>\", top=15/100, bottom=26/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 9,9 do\n    local button = {id = (\"b\"..9), enabled=true, td=\"<td>\", top=27/100, bottom=38/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 10,10 do\n    local button = {id = (\"b\"..10), enabled=true, td=\"<td>\", top=39/100, bottom=50/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 11,11 do\n    local button = {id = (\"b\"..11), enabled=true, td=\"<td>\", top=51/100, bottom=62/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 12,12 do\n    local button = {id = (\"b\"..12), enabled=true, td=\"<td>\", top=64/100, bottom=75/100, left=75/100, right=100/100}\n      table.insert(MapScreenButtons, button)\nend\n    for i = 13,13 do\n    local button = {id = (\"b\"..13), enabled=true, td=\"<td>\", top=90/100, bottom=100/100, left=1/100, right=18/100}\n    table.insert(MapScreenButtons, button)\nend\nfunction evaluateButtons()\n  local selected = 0\n\n  if #MapScreenButtons >= 1 then\n -- Set button styles\n       for i, button in ipairs(MapScreenButtons) do\n            if button.left < MapScreenMouseX and MapScreenMouseX < button.right and button.top < MapScreenMouseY and MapScreenMouseY < button.bottom then\n                if MapScreenMouseDown and MapScreenButtonSelected == i then\n                end\n                selected = i\n            end\n            if not button.enabled then\n            end\n\n        end\n  end\n  return selected\nend\n\nfunction onButtonDown(buttonNo)\n  local button = MapScreenButtons[buttonNo]\n  if not button or not button.enabled then\n\treturn\n  end\nend\nfunction onButtonUp(buttonNo)\n  local button = MapScreenButtons[buttonNo]\n  if not button or not button.enabled then\n    return\n  end\nfunction onClick(buttonNo)\n  local button = MapScreenButtons[buttonNo]\n  if not button or not button.enabled then\n    return\n  end\nend\n\n\n\n  if buttonNo == 1 then\ndestX = 0\ndestY = 0\nselection = 1\nsudistance = distalioth\n  elseif buttonNo == 2 then\ndestX = 43\ndestY = -56\nselection = 2\nsudistance = distmadis\n  elseif buttonNo == 3 then\ndestX = 73\ndestY = -27\nselection = 3\nsudistance = distthades\n  elseif buttonNo == 4 then\ndestX = -33\ndestY = -139\nselection = 4\nsudistance = disttalemai\n  elseif buttonNo == 5 then\ndestX = -109\ndestY = -56\nselection = 5\nsudistance = distfeli\n  elseif buttonNo == 6 then\ndestX = 131\ndestY = -68\nselection = 6\nsudistance = distsicari\n  elseif buttonNo == 7 then\ndestX = 35\ndestY = 214\nselection = 7\nsudistance = distsymeon\n  elseif buttonNo == 8 then\ndestX = 146\ndestY = -74\nselection = 8\nsudistance = distsinnen\n  elseif buttonNo == 9 then\ndestX = -235\ndestY = -32\nselection = 9\nsudistance = distjago\n  elseif buttonNo == 10 then\ndestX = 202\ndestY = -137\nselection = 10\nsudistance = distteoma\n  elseif buttonNo == 11 then\ndestX = 7\ndestY = 247\nselection = 11\nsudistance = distion\n  elseif buttonNo == 12 then\ndestX = 247\ndestY = 34\nselection = 12\nsudistance = distlacobus\n  elseif buttonNo == 13 then\n  unit.exit()\n  end\nend\n\n\nlocal floor = math.floor\nlocal concat = table.concat\n\nlocal secondsInMinute = 60\nlocal secondsInHour = secondsInMinute * 60\nlocal secondsInDay = secondsInHour * 24\nlocal secondsInYear = 365.2419 * secondsInDay\n\nlocal minTotalSecondsToShowOnlyYears = secondsInYear * 10\n\n---@param totalSeconds number\n---@param maxComponents nil|number\nlocal function formatTimeWithUnits (totalSeconds, maxComponents)\n  maxComponents = maxComponents or 2\n\n  local buffer = {}\n\n  if totalSeconds < 0 then\n    buffer[#buffer + 1] = \"-\"\n    totalSeconds = -totalSeconds\n    maxComponents = maxComponents + 1\n  end\n\n  local showOnlyYears = totalSeconds > minTotalSecondsToShowOnlyYears\n\n  local years = floor(totalSeconds / secondsInYear)\n  if years > 0 then buffer[#buffer + 1] = years .. \"y\" end\n\n  if #buffer < maxComponents and not showOnlyYears then\n    local days = floor(totalSeconds % secondsInYear / secondsInDay)\n    if days > 0 then buffer[#buffer + 1] = days .. \"d\" end\n  end\n\n  if #buffer < maxComponents and not showOnlyYears then\n    local hours = floor(totalSeconds % secondsInDay / secondsInHour)\n    if hours > 0 then buffer[#buffer + 1] = hours .. \"h\" end\n  end\n\n  if #buffer < maxComponents and not showOnlyYears then\n    local minutes = floor(totalSeconds % secondsInHour / secondsInMinute)\n    if minutes > 0 then buffer[#buffer + 1] = minutes .. \"m\" end\n  end\n\n  if #buffer < maxComponents and not showOnlyYears then\n    local seconds = floor(totalSeconds % secondsInMinute)\n    if seconds > 0 then buffer[#buffer + 1] = seconds .. \"s\" end\n  end\n\n  if #buffer == 0 then return \"0s\" end\n\n  return concat(buffer, \" \")\n\nend\n\n\n\n\nfunction updateScreen()\n\nloc = vec3(core.getConstructWorldPos())\n\nlocal shipVelocity = vec3(core.getVelocity()):len() * 3.6\nlocal shipAcceleration = vec3(core.getVelocity()):len() * 3.6\nlocal time_to_distance = 0\nlocal display_selection = \"\"\n\nif selection == 1 then\n    alioth = galaxyReference[0][2]    ---uses Atlas functions\n    distalioth = math.floor(alioth:getDistance(loc)/200000)   ---uses getDistance functions----\n    time_to_distance = distalioth * 200 / shipVelocity\n    display_selection = \"alioth\"\nelseif selection == 2 then\n    madis = vec3(17465536.000, 22665536.000, -34464.000)\n    distmadis = string.format(\"%.2f\", math.sqrt((loc.x-madis.x)^2+(loc.y-madis.y)^2+(loc.z-madis.z)^2)/200000)\n    time_to_distance = distmadis * 200 / shipVelocity\n    display_selection = \"madis\"\nelseif selection == 3 then\n    thades = vec3(29165536.000, 10865536.000, 65536.000)\n    distthades = string.format(\"%.2f\", math.sqrt((loc.x-thades.x)^2+(loc.y-thades.y)^2+(loc.z-thades.z)^2)/200000)\n    time_to_distance = distthades * 200 / shipVelocity\n    display_selection = \"thades\"\nelseif selection == 4 then\n    talemai = vec3(-13234464.000, 55765536.000, 465536.000)\n    disttalemai = string.format(\"%.2f\", math.sqrt((loc.x-talemai.x)^2+(loc.y-talemai.y)^2+(loc.z-talemai.z)^2)/200000)\n    time_to_distance = disttalemai * 200 / shipVelocity\n    display_selection = \"talemai\"\nelseif selection == 5 then\n    feli = vec3(-43534464.000, 22565536.000, -48934464.000)\n    distfeli = string.format(\"%.2f\", math.sqrt((loc.x-feli.x)^2+(loc.y-feli.y)^2+(loc.z-feli.z)^2)/200000)\n    time_to_distance = distfeli * 200 / shipVelocity\n    display_selection = \"feli\"\nelseif selection == 6 then\n    sicari = vec3(52765536.000, 27165536.000, 52065536.000)\n    distsicari = string.format(\"%.2f\", math.sqrt((loc.x-sicari.x)^2+(loc.y-sicari.y)^2+(loc.z-sicari.z)^2)/200000)\n    time_to_distance = distsicari * 200 / shipVelocity\n    display_selection = \"sicari\"\nelseif selection == 7 then\n    symeon = vec3(14165536.000, -85634464.000, -934464.000)\n    distsymeon = string.format(\"%.2f\", math.sqrt((loc.x-symeon.x)^2+(loc.y-symeon.y)^2+(loc.z-symeon.z)^2)/200000)\n    time_to_distance = distsymeon * 200 / shipVelocity\n    display_selection = \"symeon\"\nelseif selection == 8 then\n    sinnen = vec3(58665536.000, 29665536.000, 58165536.000)\n    distsinnen = string.format(\"%.2f\", math.sqrt((loc.x-sinnen.x)^2+(loc.y-sinnen.y)^2+(loc.z-sinnen.z)^2)/200000)\n    time_to_distance = distsinnen * 200 / shipVelocity\n    display_selection = \"sinnen\"\nelseif selection == 9 then\n    jago = vec3(-94134464.000, 12765536.000, -3634464.000)\n    distjago = string.format(\"%.2f\", math.sqrt((loc.x-jago.x)^2+(loc.y-jago.y)^2+(loc.z-jago.z)^2)/200000)\n    time_to_distance = distjago * 200 / shipVelocity\n    display_selection = \"jago\"\nelseif selection == 10 then\n    teoma = vec3(80865536.000, 54665536.000, -934464.000)\n    distteoma = string.format(\"%.2f\", math.sqrt((loc.x-teoma.x)^2+(loc.y-teoma.y)^2+(loc.z-teoma.z)^2)/200000)\n    time_to_distance = distteoma * 200 / shipVelocity\n    display_selection = \"teoma\"\nelseif selection == 11 then\n    ion = galaxyReference[0][120]  ---uses Atlas functions\n    distion = math.floor(ion:getDistance(loc)/200000)   ---uses getDistance functions----\n    time_to_distance = distion * 200 / shipVelocity\n    display_selection = \"ion\"\nelseif selection == 12 then\n    lacobus = vec3(98865536.000, -13534464.000, -934464.000)\n    distlacobus = string.format(\"%.2f\", math.sqrt((loc.x-lacobus.x)^2+(loc.y-lacobus.y)^2+(loc.z-lacobus.z)^2)/200000)\n    time_to_distance = distlacobus * 200 / shipVelocity\n    display_selection = \"lacobus\"\nelse\n    time_to_distance = sudistance * 200 / shipVelocity\n    display_selection = \"none\"\nend\nshipVelocity = string.format(\"%.2f\", shipVelocity)\nwarpmath = math.floor(math.floor(core.getConstructMass()/ 1000)  * sudistance * 0.00025)\n\ntime_to_distance_min = time_to_distance * 60\ntime_to_distance_min_sec = time_to_distance_min * 60\n\ntime_to_distance = formatTimeWithUnits (time_to_distance_min_sec, 3)\n\nhtml= ([[\n<svg class=\"bootstrap\" viewBox=\"0 0 1024 1024\" style=\"width:100%; height:100%\">\n\n<circle cx=\"500\" cy=\"500\" r=\"400\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\"></circle>\n<circle cx=\"500\" cy=\"500\" r=\"350\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\" stroke-opacity=\"0.2\"></circle>\n<circle cx=\"500\" cy=\"500\" r=\"300\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\"></circle><circle cx=\"500\" cy=\"500\" r=\"250\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\" stroke-opacity=\"0.2\"></circle>\n<circle cx=\"500\" cy=\"500\" r=\"200\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\"></circle><circle cx=\"500\" cy=\"500\" r=\"150\" stroke=\"#FFF\" stroke-width=\"3\" transform=\"\" stroke-opacity=\"0.2\"></circle>\n<circle cx=\"500\" cy=\"500\" r=\"100\" stroke=\"lightblue\" stroke-width=\"3\" transform=\"\"></circle><circle cx=\"500\" cy=\"500\" r=\"50\" stroke=\"lightblue\" stroke-width=\"3\" transform=\"\" stroke-opacity=\"0.2\"></circle>\n<circle cx=\"500\" cy=\"500\" r=\"20\" stroke=\"Orange\" stroke-width=\"2\" transform=\"\"></circle><text x=\"510\" y=\"510\" fill=\"Yellow\">Helios</text>\n<circle cx=\"-0.00\" cy=\"0\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"-0.00\" y=\"0\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Alioth</text><circle cx=\"7.16\" cy=\"247.59\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"7.16\" y=\"247.59\" transform=\"translate(480,480)\" fill=\"white\" font-size=\"20\">Ion</text><circle cx=\"35.41\" cy=\"214.09\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"35.41\" y=\"214.09\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Symeon</text><circle cx=\"-33.09\" cy=\"-139.41\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"-33.09\" y=\"-139.41\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Talemai</text><circle cx=\"202.16\" cy=\"-136.66\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"202.16\" y=\"-136.66\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Teoma</text><circle cx=\"247.16\" cy=\"33.84\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"247.16\" y=\"33.84\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Lacobus</text><circle cx=\"-108.84\" cy=\"-56.41\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"-108.84\" y=\"-56.41\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Feli</text><circle cx=\"72.91\" cy=\"-27.16\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"72.91\" y=\"-27.16\" transform=\"translate(500,485)\" fill=\"white\" font-size=\"20\">Thades</text><circle cx=\"43.66\" cy=\"-56.66\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"43.66\" y=\"-56.66\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Madis</text><circle cx=\"-235.34\" cy=\"-31.91\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"-235.34\" y=\"-31.91\" transform=\"translate(500,480)\" fill=\"white\" font-size=\"20\">Jago</text><circle cx=\"131.91\" cy=\"-67.91\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"131.91\" y=\"-67.91\" transform=\"translate(475,480)\" fill=\"white\" font-size=\"20\">Sicari</text><circle cx=\"146.66\" cy=\"-74.16\" r=\"10\" stroke=\"black\" stroke-width=\"1\" fill=\"blue\" transform=\"translate(500,500)\"></circle>\n<text x=\"146.66\" y=\"-74.16\" transform=\"translate(515,480)\" fill=\"white\" font-size=\"20\">Sinnen</text>\n<line stroke-linecap=\"undefined\" stroke-linejoin=\"undefined\" id=\"svg_1\" y2=\"]]..destY..[[\" x2=\"]]..destX..[[\" y1=\"]]..locY..[[\" x1=\"]]..locX..[[\" transform=\"translate(500,500)\" stroke-width=\"5\" stroke=\"#ff0000\" fill=\"none\"/>\n<circle cx=\"]]..locX..[[\" cy=\"]]..locY..[[\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"limegreen\" transform=\"translate(500,500)\"></circle>\n<text x=\"]]..locX..[[\" y=\"]]..locY..[[\" transform=\"translate(500,500)\"\nfill=\"limegreen\" font-size= \"4.5vh\" font-weight= \"bold\">//SHIP POSITION</text>\n</svg>\n<svg class=\"bootstrap\" viewBox=\"0 0 1024 612\" style=\"width:100%; height:100%\">\n\n <g>\n  <title>Layer 1</title>\n  <g id=\"svg_24\">\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_8\" y=\"70\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Alioth  :]]..distalioth..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_14\" y=\"170\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Madis  :]]..distmadis..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_17\" y=\"270\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Thades  :]]..distthades..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_20\" y=\"370\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Talemai  :]]..disttalemai..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_23\" y=\"470\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Feli  :]]..distfeli..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_26\" y=\"570\" x=\"55\" stroke-width=\"0\" fill=\"Yellow\">Sicari  :]]..distsicari..[[ SU</text>\n   <g id=\"svg_12\">\n    <rect rx=\"10\" id=\"svg_1\" height=\"50\" width=\"250\" y=\"30\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_3\" height=\"50\" width=\"250\" y=\"105\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_7\" height=\"50\" width=\"250\" y=\"180\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_9\" height=\"50\" width=\"250\" y=\"255\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_10\" height=\"50\" width=\"250\" y=\"330\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_11\" height=\"50\" width=\"250\" y=\"405\" x=\"15\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n   </g>\n  </g>\n  <g id=\"svg_40\">\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_25\" y=\"70\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Symeon  :]]..distsymeon..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_27\" y=\"170\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Sinnen  :]]..distsinnen..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_28\" y=\"270\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Jago  :]]..distjago..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_30\" y=\"370\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Teoma  :]]..distteoma..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_31\" y=\"470\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Ion  :]]..distion..[[ SU</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"20\" id=\"svg_32\" y=\"570\" x=\"997.163642\" stroke-width=\"0\" fill=\"Yellow\">Lacobus  :]]..distlacobus..[[ SU</text>\n   <g id=\"svg_39\">\n    <rect rx=\"10\" id=\"svg_33\" height=\"50\" width=\"250\" y=\"30\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_34\" height=\"50\" width=\"250\" y=\"105\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_35\" height=\"50\" width=\"250\" y=\"180\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_36\" height=\"50\" width=\"250\" y=\"255\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_37\" height=\"50\" width=\"250\" y=\"330\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n    <rect rx=\"10\" id=\"svg_38\" height=\"50\" width=\"250\" y=\"405\" x=\"760\" stroke-width=\"10\" stroke=\"#FFF\" fill=\"none\"/>\n   </g>\n  </g>\n </g>\n  <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"30\" id=\"svg_32\" y=\"700\" x=\"20\" stroke-width=\"0\" fill=\"LightBlue\">Est. Warp Cost: ]]..warpmath..[[</text>\n  <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"30\" id=\"svg_32\" y=\"750\" x=\"20\" stroke-width=\"0\" fill=\"LightBlue\">Construct Weight: ]]..math.floor(core.getConstructMass()/ 1000)..[[ tons</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"30\" id=\"svg_32\" y=\"700\" x=\"500\" stroke-width=\"0\" fill=\"LightBlue\">TTD: ]]..time_to_distance..[[ </text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"30\" id=\"svg_32\" y=\"750\" x=\"500\" stroke-width=\"0\" fill=\"LightBlue\">VELOC: ]]..shipVelocity..[[ km/h</text>\n   <text stroke=\"null\" transform=\"matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) \" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Helvetica, Arial, sans-serif\" font-size=\"30\" id=\"svg_32\" y=\"700\" x=\"900\" stroke-width=\"0\" fill=\"LightBlue\">DEST: ]]..display_selection..[[ </text>\n\n</svg>\n\n    ]])\n\nscreen.setHTML(html)\n--screen2.setHTML(html)\nend\nunit.setTimer(\"spacemap\",.08)\n\n","filter":{"args":[],"signature":"start()","slotKey":"-1"},"key":"2"},{"code":"updateScreen()","filter":{"args":[{"value":"spacemap"}],"signature":"tick(timerId)","slotKey":"-1"},"key":"3"}],"methods":[],"events":[]}





----Older Version In Multiple formats for Learning Purposes. DU IT :)
Space Map with Warp Calculation

Credits to All of DU Lua Community


Requirements:
1 Dynamic Construct
1 Screen
1 Program Board

Link Screen then Core

Two Versions are available and do the same thing.

One uses variables and math with some built in functions from Lua to get the values.
One uses Functions from JayleBreak's atlas and functions to get the values.

 


*KNOWN BUGS*

----On fresh login, Core has to be ran one time to send Construct weight data over the server, otherwise math will be wrong.
So sit down in pilot seat one time and then run programming board. After that its always set. ---Server Bug


----Currently has Bug with Screen Flickers on half of the svg during setHTML redraw update-- 9/23 Patch

 

 


Planets are organized similar to DU ingame map and are stationary svg.
---------- Math and Variables Version---------

---Space Map
---Unit Start
MapScreenButtons = {}
MapScreenMouseX = 0
MapScreenMouseY = 0
MapScreenMouseDown = false
MapScreenButtonSelected = 0



local worldPos = vec3(core.getConstructWorldPos())
local locX = (worldPos.x/400000)
local locY = (worldPos.y/400000)*(-1)
local destX = 0
local destY = 0
local sudistance = 0
local loc = vec3(core.getConstructWorldPos())
local ion = vec3(2865536.000, -99034464.000, -934464.000)
local thades = vec3(29165536.000, 10865536.000, 65536.000)
local sinnen = vec3(58665536.000, 29665536.000, 58165536.000)
local alioth = vec3(-8.000, -8.000, -126303.000)
local madis = vec3(17465536.000, 22665536.000, -34464.000)
local jago = vec3(-94134464.000, 12765536.000, -3634464.000)
local symeon = vec3(14165536.000, -85634464.000, -934464.000)
local lacobus = vec3(98865536.000, -13534464.000, -934464.000)
local teoma = vec3(80865536.000, 54665536.000, -934464.000)
local feli = vec3(-43534464.000, 22565536.000, -48934464.000)
local talemai = vec3(-13234464.000, 55765536.000, 465536.000)
local sicari = vec3(52765536.000, 27165536.000, 52065536.000)
local distion = string.format("%.2f", math.sqrt((loc.x-ion.x)^2+(loc.y-ion.y)^2+(loc.z-ion.z)^2)/200000)
local distthades = string.format("%.2f", math.sqrt((loc.x-thades.x)^2+(loc.y-thades.y)^2+(loc.z-thades.z)^2)/200000)
local distalioth = string.format("%.2f", math.sqrt((loc.x-alioth.x)^2+(loc.y-alioth.y)^2+(loc.z-alioth.z)^2)/200000)
local distmadis = string.format("%.2f", math.sqrt((loc.x-madis.x)^2+(loc.y-madis.y)^2+(loc.z-madis.z)^2)/200000)
local distjago = string.format("%.2f", math.sqrt((loc.x-jago.x)^2+(loc.y-jago.y)^2+(loc.z-jago.z)^2)/200000)
local distlacobus = string.format("%.2f", math.sqrt((loc.x-lacobus.x)^2+(loc.y-lacobus.y)^2+(loc.z-lacobus.z)^2)/200000)
local distteoma = string.format("%.2f", math.sqrt((loc.x-teoma.x)^2+(loc.y-teoma.y)^2+(loc.z-teoma.z)^2)/200000)
local distsymeon = string.format("%.2f", math.sqrt((loc.x-symeon.x)^2+(loc.y-symeon.y)^2+(loc.z-symeon.z)^2)/200000)
local distfeli = string.format("%.2f", math.sqrt((loc.x-feli.x)^2+(loc.y-feli.y)^2+(loc.z-feli.z)^2)/200000)
local distsinnen = string.format("%.2f", math.sqrt((loc.x-sinnen.x)^2+(loc.y-sinnen.y)^2+(loc.z-sinnen.z)^2)/200000)
local disttalemai = string.format("%.2f", math.sqrt((loc.x-talemai.x)^2+(loc.y-talemai.y)^2+(loc.z-talemai.z)^2)/200000)
local distsicari = string.format("%.2f", math.sqrt((loc.x-sicari.x)^2+(loc.y-sicari.y)^2+(loc.z-sicari.z)^2)/200000)



      for i = 1,1 do
   local button = {id = ("b"..1), enabled=true, td="<td>", top=2/100, bottom=13/100, left=1/100, right=28/100}
    table.insert(MapScreenButtons, button)
end
  for i = 2,2 do
   local button = {id = ("b"..2), enabled=true, td="<td>", top=15/100, bottom=26/100, left=1/100, right=30/100}
    table.insert(MapScreenButtons, button)
end
    for i = 3,3 do
    local button = {id = ("b"..3), enabled=true, td="<td>", top=27/100, bottom=38/100, left=1/100, right=28/100}
      table.insert(MapScreenButtons, button)
end
    for i = 4,4 do   
    local button = {id = ("b"..4), enabled=true, td="<td>", top=39/100, bottom=50/100, left=1/100, right=28/100}
      table.insert(MapScreenButtons, button)
end
    for i = 5,5 do   
    local button = {id = ("b"..5), enabled=true, td="<td>", top=51/100, bottom=62/100, left=1/100, right=28/100}
      table.insert(MapScreenButtons, button)
end
    for i = 6,6 do   
    local button = {id = ("b"..6), enabled=true, td="<td>", top=64/100, bottom=75/100, left=1/100, right=28/100}
      table.insert(MapScreenButtons, button)
end
    for i = 7,7 do   
    local button = {id = ("b"..7), enabled=true, td="<td>", top=2/100, bottom=13/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 8,8 do   
    local button = {id = ("b"..8), enabled=true, td="<td>", top=15/100, bottom=26/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 9,9 do   
    local button = {id = ("b"..9), enabled=true, td="<td>", top=27/100, bottom=38/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 10,10 do   
    local button = {id = ("b"..10), enabled=true, td="<td>", top=39/100, bottom=50/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 11,11 do   
    local button = {id = ("b"..11), enabled=true, td="<td>", top=51/100, bottom=62/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 12,12 do   
    local button = {id = ("b"..12), enabled=true, td="<td>", top=64/100, bottom=75/100, left=75/100, right=100/100}
      table.insert(MapScreenButtons, button)
end
    for i = 13,13 do   
    local button = {id = ("b"..13), enabled=true, td="<td>", top=90/100, bottom=100/100, left=1/100, right=18/100}
    table.insert(MapScreenButtons, button)
end
function evaluateButtons()
  local selected = 0
  
  if #MapScreenButtons >= 1 then
 -- Set button styles
       for i, button in ipairs(MapScreenButtons) do
            if button.left < MapScreenMouseX and MapScreenMouseX < button.right and button.top < MapScreenMouseY and MapScreenMouseY < button.bottom then
                if MapScreenMouseDown and MapScreenButtonSelected == i then
                end
                selected = i
            end
            if not button.enabled then
            end

        end
  end
  return selected
end

function onButtonDown(buttonNo)
  local button = MapScreenButtons[buttonNo]    
  if not button or not button.enabled then
	return
  end
end
function onButtonUp(buttonNo)
  local button = MapScreenButtons[buttonNo]    
  if not button or not button.enabled then
    return
  end
function onClick(buttonNo)
  local button = MapScreenButtons[buttonNo]    
  if not button or not button.enabled then
    return
  end
end
  if buttonNo == 1 then
destX = 0
destY = 0
sudistance = distalioth
  elseif buttonNo == 2 then
destX = 43
destY = -56
sudistance = distmadis
  elseif buttonNo == 3 then
destX = 73
destY = -27
sudistance = distthades        
  elseif buttonNo == 4 then
destX = -33
destY = -139
sudistance = disttalemai
  elseif buttonNo == 5 then
destX = -109
destY = -56
sudistance = distfeli        
  elseif buttonNo == 6 then
destX = 131
destY = -68
sudistance = distsicari        
  elseif buttonNo == 7 then
destX = 35
destY = 214
sudistance = distsymeon
  elseif buttonNo == 8 then
destX = 146
destY = -74
sudistance = distsinnen        
  elseif buttonNo == 9 then
destX = -235
destY = -32
sudistance = distjago       
  elseif buttonNo == 10 then
destX = 202
destY = -137
sudistance = distteoma        
  elseif buttonNo == 11 then
destX = 7
destY = 247
sudistance = distion        
  elseif buttonNo == 12 then
destX = 247
destY = 34
sudistance = distlacobus
  elseif buttonNo == 13 then
  unit.exit()
  end
end

function updateScreen() 
warpmath = math.floor(math.floor(core.getConstructMass()/ 1000)  * sudistance * 0.00025)
html= ([[
<svg class="bootstrap" viewBox="0 0 1024 1024" style="width:100%; height:100%">      
<circle cx="500" cy="500" r="400" stroke="darkgreen" stroke-width="3" transform=""></circle><circle cx="500" cy="500" r="350" stroke="darkgreen" stroke-width="3" transform="" stroke-opacity="0.2"></circle><circle cx="500" cy="500" r="300" stroke="darkgreen" stroke-width="3" transform=""></circle><circle cx="500" cy="500" r="250" stroke="darkgreen" stroke-width="3" transform="" stroke-opacity="0.2"></circle><circle cx="500" cy="500" r="200" stroke="darkgreen" stroke-width="3" transform=""></circle><circle cx="500" cy="500" r="150" stroke="darkgreen" stroke-width="3" transform="" stroke-opacity="0.2"></circle><circle cx="500" cy="500" r="100" stroke="lightblue" stroke-width="3" transform=""></circle><circle cx="500" cy="500" r="50" stroke="lightblue" stroke-width="3" transform="" stroke-opacity="0.2"></circle><circle cx="500" cy="500" r="20" stroke="Orange" stroke-width="2" transform=""></circle><text x="510" y="510" fill="Yellow">Helios</text><circle cx="-0.00" cy="0" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="-0.00" y="0" transform="translate(500,480)" fill="white" font-size="20">Alioth</text><circle cx="7.16" cy="247.59" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="7.16" y="247.59" transform="translate(480,480)" fill="white" font-size="20">Ion</text><circle cx="35.41" cy="214.09" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="35.41" y="214.09" transform="translate(500,480)" fill="white" font-size="20">Symeon</text><circle cx="-33.09" cy="-139.41" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="-33.09" y="-139.41" transform="translate(500,480)" fill="white" font-size="20">Talemai</text><circle cx="202.16" cy="-136.66" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="202.16" y="-136.66" transform="translate(500,480)" fill="white" font-size="20">Teoma</text><circle cx="247.16" cy="33.84" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="247.16" y="33.84" transform="translate(500,480)" fill="white" font-size="20">Lacobus</text><circle cx="-108.84" cy="-56.41" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="-108.84" y="-56.41" transform="translate(500,480)" fill="white" font-size="20">Feli</text><circle cx="72.91" cy="-27.16" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="72.91" y="-27.16" transform="translate(500,485)" fill="white" font-size="20">Thades</text><circle cx="43.66" cy="-56.66" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="43.66" y="-56.66" transform="translate(500,480)" fill="white" font-size="20">Madis</text><circle cx="-235.34" cy="-31.91" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="-235.34" y="-31.91" transform="translate(500,480)" fill="white" font-size="20">Jago</text><circle cx="131.91" cy="-67.91" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="131.91" y="-67.91" transform="translate(475,480)" fill="white" font-size="20">Sicari</text><circle cx="146.66" cy="-74.16" r="10" stroke="black" stroke-width="1" fill="blue" transform="translate(500,500)"></circle><text x="146.66" y="-74.16" transform="translate(515,480)" fill="white" font-size="20">Sinnen</text>
<line stroke-linecap="undefined" stroke-linejoin="undefined" id="svg_1" y2="]]..destY..[[" x2="]]..destX..[[" y1="]]..locY..[[" x1="]]..locX..[[" transform="translate(500,500)" stroke-width="5" stroke="#ff0000" fill="none"/>        
<circle cx="]]..locX..[[" cy="]]..locY..[[" r="3" stroke="black" stroke-width="1" fill="limegreen" transform="translate(500,500)"></circle>
<text x="]]..locX..[[" y="]]..locY..[[" transform="translate(500,500)" 
fill="limegreen" font-size= "4.5vh" font-weight= "bold">//SHIP POSITION</text>
</svg>
<svg class="bootstrap" viewBox="0 0 1024 612" style="width:100%; height:100%">
 <g>
  <title>Layer 1</title>
  <g id="svg_24">
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_8" y="70" x="55" stroke-width="0" fill="Yellow">Alioth  :]]..distalioth..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_14" y="170" x="55" stroke-width="0" fill="Yellow">Madis  :]]..distmadis..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_17" y="270" x="55" stroke-width="0" fill="Yellow">Thades  :]]..distthades..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_20" y="370" x="55" stroke-width="0" fill="Yellow">Talemai  :]]..disttalemai..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_23" y="470" x="55" stroke-width="0" fill="Yellow">Feli  :]]..distfeli..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_26" y="570" x="55" stroke-width="0" fill="Yellow">Sicari  :]]..distsicari..[[ SU</text>
   <g id="svg_12">
    <rect rx="10" id="svg_1" height="50" width="250" y="30" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_3" height="50" width="250" y="105" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_7" height="50" width="250" y="180" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_9" height="50" width="250" y="255" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_10" height="50" width="250" y="330" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_11" height="50" width="250" y="405" x="15" stroke-width="20" stroke="#00ff00" fill="none"/>
   </g>
  </g>
  <g id="svg_40">
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_25" y="70" x="997.163642" stroke-width="0" fill="Yellow">Symeon  :]]..distsymeon..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_27" y="170" x="997.163642" stroke-width="0" fill="Yellow">Sinnen  :]]..distsinnen..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_28" y="270" x="997.163642" stroke-width="0" fill="Yellow">Jago  :]]..distjago..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_30" y="370" x="997.163642" stroke-width="0" fill="Yellow">Teoma  :]]..distteoma..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_31" y="470" x="997.163642" stroke-width="0" fill="Yellow">Ion  :]]..distion..[[ SU</text>
   <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="20" id="svg_32" y="570" x="997.163642" stroke-width="0" fill="Yellow">Lacobus  :]]..distlacobus..[[ SU</text>
   <g id="svg_39">
    <rect rx="10" id="svg_33" height="50" width="250" y="30" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_34" height="50" width="250" y="105" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_35" height="50" width="250" y="180" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_36" height="50" width="250" y="255" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_37" height="50" width="250" y="330" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
    <rect rx="10" id="svg_38" height="50" width="250" y="405" x="760" stroke-width="20" stroke="#00ff00" fill="none"/>
   </g>
  </g>
 </g>
<text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="30" id="svg_32" y="700" x="20" stroke-width="0" fill="LightBlue">Est. Warp Cost: ]]..warpmath..[[</text>
  <text stroke="null" transform="matrix(0.7907331239400577,0,0,0.7600725676692406,3.135703637258853,5.731969683147472) " xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="30" id="svg_32"