Compare commits
No commits in common. "wip" and "master" have entirely different histories.
305
geojson.lua
305
geojson.lua
|
@ -1,305 +0,0 @@
|
||||||
-- advtrains track map generator
|
|
||||||
-- Usage: lua main.lua path/to/world
|
|
||||||
|
|
||||||
-- Viewport maximum coordinate in all directions
|
|
||||||
local maxc = 5000
|
|
||||||
|
|
||||||
-- embed an image called "world.png"
|
|
||||||
local wimg = false
|
|
||||||
-- image file resolution (not world resolution!)
|
|
||||||
local wimresx = 3000
|
|
||||||
local wimresy = 3000
|
|
||||||
-- one pixel is ... nodes
|
|
||||||
local wimscale = 4
|
|
||||||
|
|
||||||
-- y ranges and line colors
|
|
||||||
-- Minimum y level drawn
|
|
||||||
local drminy = -30
|
|
||||||
-- Color of min y level
|
|
||||||
local colminy = {r=0, g=0, b=255}
|
|
||||||
-- Intermediate color
|
|
||||||
local colmedy = {r=255, g=0, b=0}
|
|
||||||
-- Maximum y level drawn
|
|
||||||
local drmaxy = 80
|
|
||||||
-- Color of max y level
|
|
||||||
local colmaxy = {r=255, g=255, b=0}
|
|
||||||
|
|
||||||
|
|
||||||
datapath = (arg[1] or "").."/"
|
|
||||||
|
|
||||||
|
|
||||||
--Constant for maximum connection value/division of the circle
|
|
||||||
AT_CMAX = 16
|
|
||||||
|
|
||||||
advtrains = {}
|
|
||||||
minetest = {}
|
|
||||||
core = minetest
|
|
||||||
|
|
||||||
--table for track nodes/connections
|
|
||||||
trackconns = {}
|
|
||||||
|
|
||||||
-- math library seems to be missing this function
|
|
||||||
math.hypot = function(a,b) return math.sqrt(a*a + b*b) end
|
|
||||||
|
|
||||||
-- need to declare this for trackdefs
|
|
||||||
function attrans(str) return str end
|
|
||||||
|
|
||||||
-- pos to string
|
|
||||||
local function pts(pos)
|
|
||||||
return pos.x .. "," .. pos.y .. "," .. pos.z
|
|
||||||
end
|
|
||||||
|
|
||||||
--Advtrains dump (special treatment of pos and sigd)
|
|
||||||
function atdump(t, intend)
|
|
||||||
local str
|
|
||||||
if type(t)=="table" then
|
|
||||||
if t.x and t.y and t.z then
|
|
||||||
str=minetest.pos_to_string(t)
|
|
||||||
elseif t.p and t.s then -- interlocking sigd
|
|
||||||
str="S["..minetest.pos_to_string(t.p).."/"..t.s.."]"
|
|
||||||
else
|
|
||||||
str="{"
|
|
||||||
local intd = (intend or "") .. " "
|
|
||||||
for k,v in pairs(t) do
|
|
||||||
if type(k)~="string" or not string.match(k, "^path[_]?") then
|
|
||||||
-- do not print anything path-related
|
|
||||||
str = str .. "\n" .. intd .. atdump(k, intd) .. " = " ..atdump(v, intd)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
str = str .. "\n" .. (intend or "") .. "}"
|
|
||||||
end
|
|
||||||
elseif type(t)=="boolean" then
|
|
||||||
if t then
|
|
||||||
str="true"
|
|
||||||
else
|
|
||||||
str="false"
|
|
||||||
end
|
|
||||||
elseif type(t)=="function" then
|
|
||||||
str="<function>"
|
|
||||||
elseif type(t)=="userdata" then
|
|
||||||
str="<userdata>"
|
|
||||||
else
|
|
||||||
str=""..t
|
|
||||||
end
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
dofile("vector.lua")
|
|
||||||
dofile("serialize.lua")
|
|
||||||
dofile("helpers.lua")
|
|
||||||
dofile("tracks.lua")
|
|
||||||
dofile("track_defs.lua")
|
|
||||||
|
|
||||||
dofile("nodedb.lua")
|
|
||||||
|
|
||||||
|
|
||||||
function parse_args(argv)
|
|
||||||
local i = 1
|
|
||||||
local no_trains = false
|
|
||||||
local datapath, mappath, worldimage
|
|
||||||
while i <= #argv do
|
|
||||||
local a = argv[i]
|
|
||||||
if (a == "-m") or (a == "--map-file") then
|
|
||||||
-- only draw trains – requires specifying an already drawn file
|
|
||||||
i = i+1
|
|
||||||
if not argv[i] then
|
|
||||||
error(("missing filename after `%s'"):format(a))
|
|
||||||
end
|
|
||||||
mappath = argv[i]
|
|
||||||
elseif (a == "-t") or (a == "--no-trains") then
|
|
||||||
-- do not draw trains
|
|
||||||
no_trains = true
|
|
||||||
elseif (a == "-w") or (a == "--world-image") then
|
|
||||||
-- overlay over world image
|
|
||||||
i = i+1
|
|
||||||
if not argv[i] then
|
|
||||||
error(("missing filename after `%s'"):format(a))
|
|
||||||
end
|
|
||||||
worldimage = argv[i]
|
|
||||||
else
|
|
||||||
datapath = a
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
return datapath, mappath, no_trains, worldimage
|
|
||||||
end
|
|
||||||
|
|
||||||
datapath, mappath, no_trains, worldimage = parse_args(arg)
|
|
||||||
|
|
||||||
-- Load saves
|
|
||||||
local file, err = io.open(datapath.."advtrains_trains", "r")
|
|
||||||
local tbl = minetest.deserialize(file:read("*a"))
|
|
||||||
if type(tbl) ~= "table" then
|
|
||||||
error("Trains file: not a table")
|
|
||||||
end
|
|
||||||
advtrains.trains = tbl
|
|
||||||
file:close()
|
|
||||||
|
|
||||||
--ndb contains the defs, while ndb2 is the actual contents
|
|
||||||
file, err = io.open(datapath.."advtrains_ndb", "r")
|
|
||||||
tbl = minetest.deserialize(file:read("*a"))
|
|
||||||
if type(tbl) ~= "table" then
|
|
||||||
error("Node database file: not a table")
|
|
||||||
end
|
|
||||||
advtrains.ndb.load_data(tbl)
|
|
||||||
file:close()
|
|
||||||
|
|
||||||
-- open svg file
|
|
||||||
|
|
||||||
local svgfile = io.open(datapath.."trains.json", "w")
|
|
||||||
|
|
||||||
|
|
||||||
if mappath then
|
|
||||||
mapfile = io.open(mappath, "r")
|
|
||||||
cont = mapfile:read("*a"):sub(1, -7) -- remove </svg> end tag
|
|
||||||
svgfile:write(cont)
|
|
||||||
else
|
|
||||||
svgfile:write([[
|
|
||||||
[
|
|
||||||
]])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- everything set up. Start generating an SVG
|
|
||||||
-- All nodes that have been fit into a polyline are removed from the NDB, in order to not draw them again.
|
|
||||||
|
|
||||||
-- "Restart points" for the breadth-first traverser (set when more than 2 conns present)
|
|
||||||
-- {pos = <position>, connid = <int>, conn = <conndef>}
|
|
||||||
-- Note that the node at "pos" is already deleted from the NDB at the time of recall, therefore "conn" is specified
|
|
||||||
local bfs_rsp = {}
|
|
||||||
|
|
||||||
local ndb_nodes_handled = 0
|
|
||||||
|
|
||||||
-- Points of the current polyline. Inserted as xyz vectors, maybe we'll use the y value one day
|
|
||||||
local current_polyline = {}
|
|
||||||
|
|
||||||
-- Traverser function from interlocking, highly modified
|
|
||||||
local function gen_rsp_polyline(rsp)
|
|
||||||
|
|
||||||
-- trick a bit
|
|
||||||
local pos, connid, conns = rsp.pos, 1, {rsp.conn}
|
|
||||||
current_polyline[#current_polyline+1] = pos
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, conns, connid)
|
|
||||||
if not adj_pos then
|
|
||||||
-- proceed one more node, for seamless turnout transitions
|
|
||||||
current_polyline[#current_polyline+1] = advtrains.pos_add_dir(pos, conns[connid].c)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- continue traversing
|
|
||||||
local conn_mainbranch
|
|
||||||
for nconnid, nconn in ipairs(next_conns) do
|
|
||||||
if adj_connid ~= nconnid then
|
|
||||||
if not conn_mainbranch then
|
|
||||||
--use the first one found to continue
|
|
||||||
conn_mainbranch = nconnid
|
|
||||||
--writec(nconnid.." nconn mainbranch")
|
|
||||||
else
|
|
||||||
-- insert bfs reminders for other conns
|
|
||||||
table.insert(bfs_rsp, {pos = adj_pos, connid = nconnid, conn = nconn})
|
|
||||||
--writec(nconnid.." nconn bfs")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- save in polyline and delete from ndb
|
|
||||||
--writec("Saved pos: "..pts(adj_pos).." mainbranch cont "..conn_mainbranch.." nextconns "..atdump(next_conns))
|
|
||||||
current_polyline[#current_polyline+1] = adj_pos
|
|
||||||
advtrains.ndb.clear(adj_pos)
|
|
||||||
ndb_nodes_handled = ndb_nodes_handled + 1
|
|
||||||
|
|
||||||
pos, connid, conns = adj_pos, conn_mainbranch, next_conns
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
plcnt = 0
|
|
||||||
|
|
||||||
local function poly_angle(l, e)
|
|
||||||
local dx = (e.x - l.x)
|
|
||||||
local dz = (e.z - l.z)
|
|
||||||
return math.deg(math.atan2(dz, dx))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function polyline_write(pl)
|
|
||||||
local str = {}
|
|
||||||
|
|
||||||
table.insert(str, '{"type":"Feature","geometry":{"type":"LineString","coordinates":[')
|
|
||||||
|
|
||||||
local i
|
|
||||||
local e = nil
|
|
||||||
local l = nil
|
|
||||||
local last_angle = -1000
|
|
||||||
local lastcf = p1y
|
|
||||||
local lastldir = {x=0, y=0}
|
|
||||||
local consider = 0
|
|
||||||
--print("new polyline\n")
|
|
||||||
|
|
||||||
for i=1,#pl do
|
|
||||||
local first = true
|
|
||||||
|
|
||||||
consider = 0
|
|
||||||
e = pl[i]
|
|
||||||
-- print("point " .. e.x .. "x" .. e.z .. "x" .. e.y)
|
|
||||||
|
|
||||||
if (l ~= nil) then
|
|
||||||
local angle = poly_angle(l, e)
|
|
||||||
if (angle ~= last_angle) then
|
|
||||||
table.insert(str, "[".. l.x .. "," .. (l.z) .. "],")
|
|
||||||
last_angle = angle
|
|
||||||
end
|
|
||||||
end
|
|
||||||
l = e
|
|
||||||
end
|
|
||||||
if (e ~= nil) then
|
|
||||||
table.insert(str, "[".. l.x .. "," .. (l.z) .. "]")
|
|
||||||
end
|
|
||||||
table.insert(str, ']},"properties":{"name":""}},\n')
|
|
||||||
svgfile:write(table.concat(str))
|
|
||||||
plcnt = plcnt + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- while there are entries in the nodedb
|
|
||||||
-- 1. find a starting point
|
|
||||||
if not mappath then
|
|
||||||
local stpos, conns = advtrains.ndb.mapper_find_starting_point()
|
|
||||||
while stpos do
|
|
||||||
|
|
||||||
--print("Restart at position "..pts(stpos))
|
|
||||||
for connid, conn in ipairs(conns) do
|
|
||||||
table.insert(bfs_rsp, {pos = stpos, connid = connid, conn = conn})
|
|
||||||
end
|
|
||||||
advtrains.ndb.clear(stpos)
|
|
||||||
|
|
||||||
-- 2. while there are BFS entries
|
|
||||||
while #bfs_rsp > 0 do
|
|
||||||
-- make polylines
|
|
||||||
local current_rsp = bfs_rsp[#bfs_rsp]
|
|
||||||
bfs_rsp[#bfs_rsp] = nil
|
|
||||||
--print("Starting polyline at "..pts(current_rsp.pos).."/"..current_rsp.connid)
|
|
||||||
|
|
||||||
|
|
||||||
current_polyline = {}
|
|
||||||
|
|
||||||
gen_rsp_polyline(current_rsp)
|
|
||||||
|
|
||||||
polyline_write(current_polyline)
|
|
||||||
|
|
||||||
--break
|
|
||||||
|
|
||||||
io.write("Progress ", ndb_nodes_handled, "+", ndb_nodes_notrack, "/", ndb_nodes_total, "=", math.floor(((ndb_nodes_handled+ndb_nodes_notrack)/ndb_nodes_total)*100), "%\r")
|
|
||||||
end
|
|
||||||
stpos, conns = advtrains.ndb.mapper_find_starting_point()
|
|
||||||
--break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
svgfile:write("{}]")
|
|
||||||
svgfile:close()
|
|
||||||
|
|
||||||
print("\nWrote",plcnt,"polylines. Processed", ndb_nodes_handled, "track,",ndb_nodes_notrack, "non-track nodes out of", ndb_nodes_total)
|
|
Loading…
Reference in New Issue