From faa4a7b065bc3454bbdb5ea8af99b7c4c638b68e Mon Sep 17 00:00:00 2001 From: Anthony Zhang Date: Sat, 27 Jul 2013 21:34:42 -0400 Subject: [PATCH] More speedups for //hollowsphere, //sphere, //hollowdome, //dome, //cylinder, better module loader, fix message in //volume. --- worldedit/init.lua | 10 +- worldedit/primitives.lua | 222 +++++++++++++++++++----------------- worldedit_commands/init.lua | 6 +- 3 files changed, 130 insertions(+), 108 deletions(-) diff --git a/worldedit/init.lua b/worldedit/init.lua index f41d740..18e3490 100644 --- a/worldedit/init.lua +++ b/worldedit/init.lua @@ -1,9 +1,15 @@ local path = minetest.get_modpath(minetest.get_current_modname()) local loadmodule = function(path) - return pcall(function() + local results = {pcall(function() return dofile(path) - end) + end)} + if results[1] then --successfully loaded module + table.remove(results, 1) --remove status indicator + return unpack(results) --return all results + else --load error + print(results[2]) + end end loadmodule(path .. "/manipulations.lua") diff --git a/worldedit/primitives.lua b/worldedit/primitives.lua index 85bc3b3..2656b4b 100644 --- a/worldedit/primitives.lua +++ b/worldedit/primitives.lua @@ -20,24 +20,20 @@ worldedit.hollow_sphere = function(pos, radius, nodename) --fill selected area with node local node_id = minetest.get_content_id(nodename) local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1) - local ystride, zstride = area.ystride, area.zstride - local x, y, z = -radius, -radius, -radius + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride local count = 0 - for i in area:iterp(pos1, pos2) do - local squared = x * x + y * y + z * z - if squared >= min_radius and squared <= max_radius then --position is on surface of sphere - nodes[i] = node_id - count = count + 1 - end - - --move to the next position - x = x + 1 - if x > radius then - x = -radius - y = y + 1 - if y > radius then - y = -radius - z = z + 1 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + for y = -radius, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + local squared = x * x + y * y + z * z + if squared >= min_radius and squared <= max_radius then --position is on surface of sphere + local i = newy + (x + offsetx) + 1 + nodes[i] = node_id + count = count + 1 + end end end end @@ -69,23 +65,19 @@ worldedit.sphere = function(pos, radius, nodename) --fill selected area with node local node_id = minetest.get_content_id(nodename) local max_radius = radius * (radius + 1) - local ystride, zstride = area.ystride, area.zstride - local x, y, z = -radius, -radius, -radius + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride local count = 0 - for i in area:iterp(pos1, pos2) do - if x * x + y * y + z * z <= max_radius then --position is inside sphere - nodes[i] = node_id - count = count + 1 - end - - --move to the next position - x = x + 1 - if x > radius then - x = -radius - y = y + 1 - if y > radius then - y = -radius - z = z + 1 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + for y = -radius, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + if x * x + y * y + z * z <= max_radius then --position is inside sphere + local i = newy + (x + offsetx) + 1 + nodes[i] = node_id + count = count + 1 + end end end end @@ -117,24 +109,20 @@ worldedit.hollow_dome = function(pos, radius, nodename) --fill selected area with node local node_id = minetest.get_content_id(nodename) local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1) - local ystride, zstride = area.ystride, area.zstride - local x, y, z = -radius, 0, -radius + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride local count = 0 - for i in area:iterp(pos1, pos2) do - local squared = x * x + y * y + z * z - if squared >= min_radius and squared <= max_radius then --position is on surface of sphere - nodes[i] = node_id - count = count + 1 - end - - --move to the next position - x = x + 1 - if x > radius then - x = -radius - y = y + 1 - if y > radius then - y = 0 - z = z + 1 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + for y = 0, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + local squared = x * x + y * y + z * z + if squared >= min_radius and squared <= max_radius then --position is on surface of sphere + local i = newy + (x + offsetx) + 1 + nodes[i] = node_id + count = count + 1 + end end end end @@ -166,23 +154,19 @@ worldedit.dome = function(pos, radius, nodename) --wip: use bresenham sphere for --fill selected area with node local node_id = minetest.get_content_id(nodename) local max_radius = radius * (radius + 1) - local ystride, zstride = area.ystride, area.zstride - local x, y, z = -radius, 0, -radius + local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z + local zstride, ystride = area.zstride, area.ystride local count = 0 - for i in area:iterp(pos1, pos2) do - if x * x + y * y + z * z <= max_radius then --position is inside sphere - nodes[i] = node_id - count = count + 1 - end - - --move to the next position - x = x + 1 - if x > radius then - x = -radius - y = y + 1 - if y > radius then - y = 0 - z = z + 1 + for z = -radius, radius do + local newz = (z + offsetz) * zstride + for y = 0, radius do + local newy = newz + (y + offsety) * ystride + for x = -radius, radius do + if x * x + y * y + z * z <= max_radius then --position is inside sphere + local i = newy + (x + offsetx) + 1 + nodes[i] = node_id + count = count + 1 + end end end end @@ -281,50 +265,54 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename, env) --wip: r currentpos[axis] = currentpos[axis] - length end - --create schematic for single node column along the axis - local node = {name=nodename, param1=0, param2=0} + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local pos1 = { + [axis]=currentpos[axis], + [other1]=currentpos[other1] - radius, + [other2]=currentpos[other2] - radius + } + local pos2 = { + [axis]=currentpos[axis] + length - 1, + [other1]=currentpos[other1] + radius, + [other2]=currentpos[other2] + radius + } + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore local nodes = {} - for i = 1, length do - nodes[i] = node + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore end - local schematic = {size={[axis]=length, [other1]=1, [other2]=1}, data=nodes} - local place_schematic = minetest.place_schematic + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + local max_radius = radius * (radius + 1) + local stride = {x=1, y=area.ystride, z=area.zstride} + local offset = {x=currentpos.x - emerged_pos1.x, y=currentpos.y - emerged_pos1.y, z=currentpos.z - emerged_pos1.z} + local min_slice, max_slice = offset[axis], offset[axis] + length - 1 local count = 0 - local offset1, offset2 = 0, radius - local delta = -radius - while offset1 <= offset2 do - --connect each pair of octants taking advantage of symmetry along two axes - currentpos[other1] = pos[other1] - offset1 - local second1, second2 = pos[other2] + offset2, pos[other2] - offset2 - for i = 0, offset1 * 2 do - currentpos[other2] = second1 - place_schematic(currentpos, schematic) --octant 1 to 4 - currentpos[other2] = second2 - place_schematic(currentpos, schematic) --octant 5 to 8 - currentpos[other1] = currentpos[other1] + 1 - end - currentpos[other1] = pos[other1] - offset2 - local second1, second2 = pos[other2] + offset1, pos[other2] - offset1 - for i = 0, offset2 * 2 do - currentpos[other2] = second1 - place_schematic(currentpos, schematic) --octant 2 to 3 - currentpos[other2] = second2 - place_schematic(currentpos, schematic) --octant 6 to 7 - currentpos[other1] = currentpos[other1] + 1 - end - - count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken since node positions may coincide - - --move to next location - delta = delta + (offset1 * 2) + 1 - offset1 = offset1 + 1 - if delta >= 0 then - offset2 = offset2 - 1 - delta = delta - (offset2 * 2) + for axis1 = -radius, radius do + local newaxis1 = (axis1 + offset[other1]) * stride[other1] + for axis2 = -radius, radius do + local newaxis2 = newaxis1 + (axis2 + offset[other2]) * stride[other2] + if axis1 * axis1 + axis2 * axis2 <= max_radius then + for slice = min_slice, max_slice do + local i = newaxis2 + slice * stride[axis] + 1 + nodes[i] = node_id + end + count = count + length + end end end - count = count * length --apply the length to the number of nodes + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + return count end @@ -334,7 +322,31 @@ worldedit.pyramid = function(pos, height, nodename, env) --wip: rewrite this usi local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height local pos = {x=0, y=pos1y, z=0} - --wip: make this faster using base sized schematics that are then resized while moving upwards, or if that's not possible, add new rows/columns while looping + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + --set up voxel manipulator + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + + --fill emerged area with ignore + local nodes = {} + local ignore = minetest.get_content_id("ignore") + for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do + nodes[i] = ignore + end + + --fill selected area with node + local node_id = minetest.get_content_id(nodename) + for i in area:iterp(pos1, pos2) do + nodes[i] = node_id + end + + --update map nodes + manip:set_data(nodes) + manip:write_to_map() + manip:update_map() + local count = 0 local node = {name=nodename} if env == nil then env = minetest.env end diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 3ef247d..4e23122 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -210,7 +210,11 @@ minetest.register_chatcommand("/volume", { end local volume = worldedit.volume(pos1, pos2) - worldedit.player_notify(name, "current region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")") + local abs = math.abs + worldedit.player_notify(name, "current region has a volume of " .. volume .. " nodes (" + .. abs(pos2.x - pos1.x) .. "*" + .. abs(pos2.y - pos1.y) .. "*" + .. abs(pos2.z - pos1.z) .. ")") end, })