Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Template for new versions:
## Fixes

## Misc Improvements
gui/export-world-map: more precise bridge coordinates
gui/export-world-map: export of bridge and road materials


## Removed

Expand Down
1 change: 0 additions & 1 deletion gui/export-world-map.lua
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ local SELECTED_ICON = dfhack.pen.parse{ch=string.char(251), fg=COLOR_LIGHTGREEN}
local DISABLED_ICON = dfhack.pen.parse{ch='x', fg=COLOR_RED}

function ExportMap:getChoices()
print("getChoices")
local choices = {}
for _, export in ipairs(exports) do
table.insert(choices, {
Expand Down
88 changes: 69 additions & 19 deletions internal/export-world-map/export-roads.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,93 @@
local json = require('json')
local util = reqscript('internal/export-world-map/util')

local function getConstructionAndGeometryType(construction)
local constructions = df.global.world.world_data.constructions

local function getConstructionAndGeometryType(construction, bridge_squares_by_id)
if df.world_construction_roadst:is_instance(construction) then
local square = construction.square_obj[0] -- df populates square_obj for roads and tunnels (only)
local subtype = ""
if df.item_type[construction.square_obj[0]["item_type"]] == "BLOCKS" then
local material = ""

if df.item_type[square.item_type] == "BLOCKS" then
subtype = "paved"
else
material = dfhack.matinfo.decode(square.mat_type, square.mat_index):toString()
elseif df.item_type[square.item_type] == "NONE" then
subtype = "dirt"
end
return "road", "LineString", subtype

return "road", "LineString", subtype, material
elseif df.world_construction_bridgest:is_instance(construction) then
return "bridge", "Point", ""
local square = bridge_squares_by_id[construction.id] -- df does NOT populate square_obj for bridges
local subtype = ""
local material = ""

if df.item_type[square.item_type] == "WOOD" then
subtype = "wooden"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a strong preference, but I would prefer:

Suggested change
subtype = "wooden"
subtype = "wood"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the precedent of "paved" for paved roads, I prefer "wooden" for wooden bridges here - the subtype attribute being an adjective makes for nicer labeling in GIS software as well.
(The material attribute, of course, is the noun instead; "peach wood", "willow", "mudstone" etc.)

material = dfhack.matinfo.decode(square.mat_type, square.mat_index):toString()
elseif df.item_type[square.item_type] == "BLOCKS" then
subtype = "stone"
material = dfhack.matinfo.decode(square.mat_type, square.mat_index):toString()
end

return "bridge", "Point", subtype, material
elseif df.world_construction_tunnelst:is_instance(construction) then
return "tunnel", "LineString", ""
-- df assigns world construction squares to tunnels like it does to roads,
-- but tunnel squares have nothing besides positional data: no material info, no nothing.
return "tunnel", "LineString", "", ""
else
qerror("unknown construction type")
end
end

local function listBridgeSquaresById()
local squares = {}

local tile_array_width = constructions.width
local tile_array_height = constructions.height

for i = 0, (tile_array_width - 1) do
for j = 0, (tile_array_height - 1) do
for _, square in ipairs(constructions.map[i]:_displace(j).square) do
if df.world_construction_square_bridgest:is_instance(square) then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of an instance check you may want to try using square:getType()

squares[square.construction_id] = square
end
end
end
end

return squares
end

local function gatherFeatures()
local features = {}
for _, construction in ipairs(df.global.world.world_data.constructions.list) do
local type, geometry_type, subtype = getConstructionAndGeometryType(construction)

local bridge_squares_by_id = listBridgeSquaresById()

for _, construction in ipairs(constructions.list) do
local type, geometry_type, subtype, material = getConstructionAndGeometryType(construction, bridge_squares_by_id)

local coordinates
if geometry_type == "Point" then
-- only world tile - not sure where to get region tile coordinates from
-- perhaps it gets them from neighbouring roads?
-- dwarf fortress doesn't populate square_obj for bridges, only for roads and tunnels.
-- but all world tiles are listed in df.global.world.world_data.constructions.map (not list),
-- a 2D array that has to be iterated over with _displace()
local region_x = construction.square_pos["x"][0]
local region_y = construction.square_pos["y"][0]
Comment thread
Nekkowe marked this conversation as resolved.
local midmap_x = bridge_squares_by_id[construction.id].embark_x[0]
local midmap_y = bridge_squares_by_id[construction.id].embark_y[0]

coordinates = {
construction.square_pos["x"][0]*768,
-(construction.square_pos["y"][0]*768)
region_x * 768 + midmap_x * 48 + 24,
-(region_y * 768 + midmap_y * 48 + 24)
}
else
coordinates = {}
for _,square_obj in ipairs(construction.square_obj) do
for i=0,#square_obj.embark_x-1 do
for _, square_obj in ipairs(construction.square_obj) do
for i = 0, (#square_obj.embark_x - 1) do
table.insert(coordinates, {
square_obj.region_pos["x"]*768+square_obj.embark_x[i]*48+24,
-(square_obj.region_pos["y"]*768+square_obj.embark_y[i]*48+24)
square_obj.region_pos.x * 768 + square_obj.embark_x[i] * 48 + 24,
-(square_obj.region_pos.y * 768 + square_obj.embark_y[i] * 48 + 24)
})
end
end
Expand All @@ -49,10 +98,11 @@ local function gatherFeatures()
type = "Feature",
properties = {
id = construction.id,
name_df = dfhack.df2utf(dfhack.translation.translateName(construction["name"],false)),
name_en = dfhack.df2utf(dfhack.translation.translateName(construction["name"],true)),
name_df = dfhack.df2utf(dfhack.translation.translateName(construction["name"], false)),
name_en = dfhack.df2utf(dfhack.translation.translateName(construction["name"], true)),
construction_type = type,
construction_subtype = subtype,
construction_material = material,
},
geometry = {
type = geometry_type,
Expand All @@ -68,7 +118,7 @@ function export(by_world, by_date)
return function()
json.encode_file(
{ type = "FeatureCollection", features = gatherFeatures() },
util.getOutputFolder(by_world, by_date).."roads.geojson"
util.getOutputFolder(by_world, by_date) .. "roads.geojson"
)
end
end