More speedups for //hollowsphere, //sphere, //hollowdome, //dome, //cylinder, better module loader, fix message in //volume.

This commit is contained in:
Anthony Zhang 2013-07-27 21:34:42 -04:00
parent 8b9054a1cc
commit faa4a7b065
3 changed files with 130 additions and 108 deletions

View File

@ -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")

View File

@ -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

View File

@ -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,
})