Fix a few small bugs

This commit is contained in:
Starbeamrainbowlabs 2018-06-10 13:48:11 +01:00
parent 4b3833649c
commit f3745dc6ba
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
5 changed files with 185 additions and 4 deletions

View file

@ -50,6 +50,23 @@ Creates a hollow ellipsoid at position 1 with the radius `(rx, ry, rz)`. Works t
//hollowellipsoid 21 11 41 stone //hollowellipsoid 21 11 41 stone
``` ```
### `//torus <major_radius > <minor_radius> <node_name>`
Creates a solid torus at position 1 with the specified major and minor radii. The major radius is the distance from the centre of the torus to the centre of the circle bit, and the minor radius is the radius of the circle bit.
```
//torus 10 5 15 ice
//torus 3 5 10 dirt
//torus 20 10 40 air
```
### `//hollowtorus <rx> <ry> <rz> <node_name>`
Creates a hollow torus at position 1 with the radius `(rx, ry, rz)`. Works the same way as `//torus` does.
```
//hollowtorus 10 5 15 glass
//hollowtorus 21 11 41 stone
```
## Contributing ## Contributing
Contributions are welcome! Please state in your pull request(s) that you release your contribution under the _Mozilla Public License 2.0_. Contributions are welcome! Please state in your pull request(s) that you release your contribution under the _Mozilla Public License 2.0_.

View file

@ -18,8 +18,6 @@ function worldedit.ellipsoid(position, radius, target_node, hollow)
local node_id_air = minetest.get_content_id("air") local node_id_air = minetest.get_content_id("air")
local stride_z, stride_y = area.zstride, area.ystride local stride_z, stride_y = area.zstride, area.ystride
-- TODO: This won't work, because we need to vary the calculation we use this in based on what part of the ellipsoid we're working on / in, not compare to a static value
local radius_distance_sq = worldeditadditions.vector.lengthsquared(radius)
local count = 0 -- The number of nodes replaced local count = 0 -- The number of nodes replaced

View file

@ -11,3 +11,4 @@ dofile(minetest.get_modpath("worldeditadditions") .. "/utils.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/floodfill.lua") dofile(minetest.get_modpath("worldeditadditions") .. "/floodfill.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/overlay.lua") dofile(minetest.get_modpath("worldeditadditions") .. "/overlay.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/ellipsoid.lua") dofile(minetest.get_modpath("worldeditadditions") .. "/ellipsoid.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/torus.lua")

View file

@ -0,0 +1,78 @@
--- Overlap command. Places a specified node on top of
-- @module worldeditadditions.overlay
function worldedit.torus(position, major_radius, minor_radius, target_node, hollow)
-- position = { x, y, z }
local total_radius = major_radius + minor_radius
local inner_minor_radius = minor_radius - 1.75
local major_radius_sq = major_radius*major_radius
local minor_radius_sq = minor_radius*minor_radius
local inner_minor_radius_sq = inner_minor_radius*inner_minor_radius
-- Fetch the nodes in the specified area
-- OPTIMIZE: We should be able to calculate a more efficient box-area here
local manip, area = worldedit.manip_helpers.init_radius(position, total_radius)
local data = manip:get_data()
local node_id = minetest.get_content_id(target_node)
local node_id_air = minetest.get_content_id("air")
local stride_z, stride_y = area.zstride, area.ystride
local count = 0 -- The number of nodes replaced
local idx_z_base = area:index(position.x - total_radius, position.y - total_radius, position.z - total_radius) -- initial z offset
for z = -total_radius, total_radius do
local z_sq = z*z
local idx_y_base = idx_z_base
for y = -total_radius, total_radius do
local y_sq = y*y
local i = idx_y_base
for x = -total_radius, total_radius do
local x_sq = x*x
-- (x^2+y^2+z^2-(a^2+b^2))^2-4 a b (b^2-z^2)
-- Where:
-- (x, y, z) is the point
-- a is the major radius (centre to centre of circle)
-- b is the minor radius (radius of circle
local comp_a = (x_sq+y_sq+z_sq - (major_radius_sq+minor_radius_sq))
local test_value = comp_a*comp_a - 4*major_radius*minor_radius*(minor_radius_sq-z_sq)
-- If we're inside the torus, then fill it in
if test_value <= 1 then
local place_ok = not hollow;
if not place_ok then
-- It must be hollow! Do some additional calculations.
local inner_comp_a = (x_sq+y_sq+z_sq - (major_radius_sq+inner_minor_radius_sq))
local inner_test_value = inner_comp_a*inner_comp_a - 4*major_radius*inner_minor_radius*(inner_minor_radius_sq-z_sq)
-- It's only ok to place it if it's outside our inner torus
place_ok = inner_test_value >= 0
end
if place_ok then
data[i] = node_id
count = count + 1
end
end
i = i + 1
end
idx_y_base = idx_y_base + stride_y
end
idx_z_base = idx_z_base + stride_z
end
-- Save the modified nodes back to disk & return
worldedit.manip_helpers.finish(manip, data)
return count
end

View file

@ -158,7 +158,7 @@ minetest.register_chatcommand("/ellipsoid", {
-- TODO: This duplicates a lot of code. Perhaps we can trim it down a bit? -- TODO: This duplicates a lot of code. Perhaps we can trim it down a bit?
minetest.register_chatcommand("/hollowellipsoid", { minetest.register_chatcommand("/hollowellipsoid", {
params = "<rx> <ry> <rz> <replace_node>", params = "<rx> <ry> <rz> <replace_node>",
description = "Creates a 3D hollow ellipsoid with a radius of (rx, ry, rz) at pos1, filled with <replace_node>.", description = "Creates a 3D hollow ellipsoid with a radius of (rx, ry, rz) at pos1, made out of <replace_node>.",
privs = { worldedit = true }, privs = { worldedit = true },
func = safe_region(function(name, params_text) func = safe_region(function(name, params_text)
local target_node, radius = parse_params_ellipsoid(params_text) local target_node, radius = parse_params_ellipsoid(params_text)
@ -181,10 +181,97 @@ minetest.register_chatcommand("/hollowellipsoid", {
end, function(name, params_text) end, function(name, params_text)
local target_node, radius = parse_params_ellipsoid(params_text) local target_node, radius = parse_params_ellipsoid(params_text)
if not target_node or not radius then if not target_node or not radius then
worldedit.player_notify(name, "Error: Invalid input '" .. params_text .. "'. Try '/help /ellipsoid' to learn how to use this command.") worldedit.player_notify(name, "Error: Invalid input '" .. params_text .. "'. Try '/help /hollowellipsoid' to learn how to use this command.")
return 0 return 0
end end
return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z) return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z)
end) end)
}) })
-- ████████ ██████ ██████ ██ ██ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██ ██████ ██ ██ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██████ ██ ██ ██████ ███████
local function parse_params_torus(params_text)
local found, _, major_radius, minor_radius, replace_node = params_text:find("([0-9]+)%s+([0-9]+)%s+([a-z:_\\-]+)")
if found == nil then
return nil, nil
end
major_radius = tonumber(major_radius)
minor_radius = tonumber(minor_radius)
replace_node = worldedit.normalize_nodename(replace_node)
return replace_node, major_radius, minor_radius
end
minetest.register_chatcommand("/torus", {
params = "<major_radius> <minor_radius> <replace_node>",
description = "Creates a 3D torus with a major radius of <major_radius> and a minor radius of <minor_radius> at pos1, filled with <replace_node>.",
privs = { worldedit = true },
func = safe_region(function(name, params_text)
local target_node, major_radius, minor_radius = parse_params_torus(params_text)
if not target_node then
worldedit.player_notify(name, "Error: Invalid node name.")
return false
end
if not major_radius or not minor_radius then
worldedit.player_notify(name, "Error: Invalid radius(es).")
return false
end
local start_time = os.clock()
local replaced = worldedit.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, false)
local time_taken = os.clock() - start_time
worldedit.player_notify(name, replaced .. " nodes replaced in " .. time_taken .. "s")
minetest.log("action", name .. " used //torus at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. replaced .. " nodes in " .. time_taken .. "s")
end, function(name, params_text)
local target_node, major_radius, minor_radius = parse_params_torus(params_text)
if not target_node or not major_radius or not minor_radius then
worldedit.player_notify(name, "Error: Invalid input '" .. params_text .. "'. Try '/help /torus' to learn how to use this command.")
return 0
end
return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius)
end)
})
-- TODO: This duplicates a lot of code. Perhaps we can trim it down a bit?
minetest.register_chatcommand("/hollowtorus", {
params = "<major_radius> <minor_radius> <replace_node>",
description = "Creates a 3D hollow torus with a major radius of <major_radius> and a minor radius of <minor_radius> at pos1, made out of <replace_node>.",
privs = { worldedit = true },
func = safe_region(function(name, params_text)
local target_node, major_radius, minor_radius = parse_params_torus(params_text)
if not target_node then
worldedit.player_notify(name, "Error: Invalid node name.")
return false
end
if not major_radius or not minor_radius then
worldedit.player_notify(name, "Error: Invalid radius(es).")
return false
end
local start_time = os.clock()
local replaced = worldedit.torus(worldedit.pos1[name], major_radius, minor_radius, target_node, true)
local time_taken = os.clock() - start_time
worldedit.player_notify(name, replaced .. " nodes replaced in " .. time_taken .. "s")
minetest.log("action", name .. " used //hollowtorus at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. replaced .. " nodes in " .. time_taken .. "s")
end, function(name, params_text)
local target_node, major_radius, minor_radius = parse_params_torus(params_text)
if not target_node or not major_radius or not minor_radius then
worldedit.player_notify(name, "Error: Invalid input '" .. params_text .. "'. Try '/help /hollowtorus' to learn how to use this command.")
return 0
end
return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius)
end)
})