-- 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 = true -- image file resolution (not world resolution!) local wimresx = 3000 local wimresy = 3000 -- one pixel is ... nodes local wimscale = 4 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="" elseif type(t)=="userdata" then str="" 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") -- Load saves local file, err = io.open(datapath.."advtrains", "r") local tbl = minetest.deserialize(file:read("*a")) if type(tbl) ~= "table" then error("not a table") end if tbl.version then advtrains.ndb.load_data(tbl.ndb) else error("Incompatible save format!") end file:close() -- open svg file local svgfile = io.open(datapath.."out.svg", "w") svgfile:write([[ ') svgfile:write([[ ]]) if wimg then local wimx = -(wimresx*wimscale/2) local wimy = -(wimresy*wimscale/2) local wimw = wimresx*wimscale local wimh = wimresy*wimscale svgfile:write('') end local function writec(text) --print("\n"..text) svgfile:write("\n") 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 = , connid = , conn = } -- 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 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 polyline_write(pl) local str = {'\n') svgfile:write(table.concat(str)) plcnt = plcnt + 1 end -- while there are entries in the nodedb -- 1. find a starting point local stpos, conns = advtrains.ndb.mapper_find_starting_point() while stpos do writec("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) 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() 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)