summaryrefslogtreecommitdiff
path: root/worldedit/primitives.lua
diff options
context:
space:
mode:
Diffstat (limited to 'worldedit/primitives.lua')
-rw-r--r--worldedit/primitives.lua503
1 files changed, 153 insertions, 350 deletions
diff --git a/worldedit/primitives.lua b/worldedit/primitives.lua
index 1baa29e..6d3b026 100644
--- a/worldedit/primitives.lua
+++ b/worldedit/primitives.lua
@@ -1,470 +1,273 @@
-worldedit = worldedit or {}
-local minetest = minetest --local copy of global
-
---adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.hollow_sphere = function(pos, radius, nodename)
- --set up voxel manipulator
- local manip = minetest.get_voxel_manip()
- local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
- local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + 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 = {}
- local ignore = minetest.get_content_id("ignore")
- for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
- nodes[i] = ignore
- end
+--- Functions for creating primitive shapes.
+-- @module worldedit.primitives
- --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 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 z = -radius, radius do
- local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
- 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)
- nodes[i] = node_id
- count = count + 1
- end
- end
- end
- end
+local mh = worldedit.manip_helpers
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
- return count
-end
+--- Adds a sphere of `node_name` centered at `pos`.
+-- @param pos Position to center sphere at.
+-- @param radius Sphere radius.
+-- @param node_name Name of node to make shere of.
+-- @param hollow Whether the sphere should be hollow.
+-- @return The number of nodes added.
+function worldedit.sphere(pos, radius, node_name, hollow)
+ local manip, area = mh.init_radius(pos, radius)
---adds a sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.sphere = function(pos, radius, nodename)
- --set up voxel manipulator
- local manip = minetest.get_voxel_manip()
- local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
- local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + 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 = {}
- local ignore = minetest.get_content_id("ignore")
- for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
- nodes[i] = ignore
- end
+ local data = mh.get_empty_data(area)
- --fill selected area with node
- local node_id = minetest.get_content_id(nodename)
- local max_radius = radius * (radius + 1)
- 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
+ -- Fill selected area with node
+ local node_id = minetest.get_content_id(node_name)
+ local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
+ local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+ local stride_z, stride_y = area.zstride, area.ystride
local count = 0
for z = -radius, radius do
- local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
+ -- Offset contributed by z plus 1 to make it 1-indexed
+ local new_z = (z + offset_z) * stride_z + 1
for y = -radius, radius do
- local newy = newz + (y + offsety) * ystride
+ local new_y = new_z + (y + offset_y) * stride_y
for x = -radius, radius do
- if x * x + y * y + z * z <= max_radius then --position is inside sphere
- local i = newy + (x + offsetx)
- nodes[i] = node_id
+ local squared = x * x + y * y + z * z
+ if squared <= max_radius and (not hollow or squared >= min_radius) then
+ -- Position is on surface of sphere
+ local i = new_y + (x + offset_x)
+ data[i] = node_id
count = count + 1
end
end
end
end
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
+ mh.finish(manip, data)
return count
end
---adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.hollow_dome = function(pos, radius, nodename)
- --set up voxel manipulator
- local manip = minetest.get_voxel_manip()
- local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
- local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + 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 = {}
- local ignore = minetest.get_content_id("ignore")
- for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
- nodes[i] = ignore
- end
- local miny, maxy = 0, radius
+--- Adds a dome.
+-- @param pos Position to center dome at.
+-- @param radius Dome radius. Negative for concave domes.
+-- @param node_name Name of node to make dome of.
+-- @param hollow Whether the dome should be hollow.
+-- @return The number of nodes added.
+-- TODO: Add axis option.
+function worldedit.dome(pos, radius, node_name, hollow)
+ local min_y, max_y = 0, radius
if radius < 0 then
radius = -radius
- miny, maxy = -radius, 0
+ min_y, max_y = -radius, 0
end
- --fill selected area with node
- local node_id = minetest.get_content_id(nodename)
+ local manip, area = mh.init_axis_radius(pos, "y", radius)
+ local data = mh.get_empty_data(area)
+
+ -- Add dome
+ local node_id = minetest.get_content_id(node_name)
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
- 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 offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+ local stride_z, stride_y = area.zstride, area.ystride
local count = 0
for z = -radius, radius do
- local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
- for y = miny, maxy do
- local newy = newz + (y + offsety) * ystride
+ local new_z = (z + offset_z) * stride_z + 1 --offset contributed by z plus 1 to make it 1-indexed
+ for y = min_y, max_y do
+ local new_y = new_z + (y + offset_y) * stride_y
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)
- nodes[i] = node_id
- count = count + 1
- end
- end
- end
- end
-
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
-
- return count
-end
-
---adds a dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.dome = function(pos, radius, nodename)
- --set up voxel manipulator
- local manip = minetest.get_voxel_manip()
- local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
- local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + 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 = {}
- local ignore = minetest.get_content_id("ignore")
- for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
- nodes[i] = ignore
- end
-
- local miny, maxy = 0, radius
- if radius < 0 then
- radius = -radius
- miny, maxy = -radius, 0
- end
-
- --fill selected area with node
- local node_id = minetest.get_content_id(nodename)
- local max_radius = radius * (radius + 1)
- 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 z = -radius, radius do
- local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
- for y = miny, maxy 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)
- nodes[i] = node_id
+ if squared <= max_radius and (not hollow or squared >= min_radius) then
+ -- Position is in dome
+ local i = new_y + (x + offset_x)
+ data[i] = node_id
count = count + 1
end
end
end
end
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
+ mh.finish(manip, data)
return count
end
---adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
- local other1, other2
- if axis == "x" then
- other1, other2 = "y", "z"
- elseif axis == "y" then
- other1, other2 = "x", "z"
- else --axis == "z"
- other1, other2 = "x", "y"
- end
-
- --handle negative lengths
- local currentpos = {x=pos.x, y=pos.y, z=pos.z}
+--- Adds a cylinder.
+-- @param pos Position to center base of cylinder at.
+-- @param axis Axis ("x", "y", or "z")
+-- @param length Cylinder length.
+-- @param radius Cylinder radius.
+-- @param node_name Name of node to make cylinder of.
+-- @param hollow Whether the cylinder should be hollow.
+-- @return The number of nodes added.
+function worldedit.cylinder(pos, axis, length, radius, node_name, hollow)
+ local other1, other2 = worldedit.get_axis_others(axis)
+
+ -- Handle negative lengths
+ local current_pos = {x=pos.x, y=pos.y, z=pos.z}
if length < 0 then
length = -length
- currentpos[axis] = currentpos[axis] - length
+ current_pos[axis] = current_pos[axis] - length
end
- --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 = {}
- local ignore = minetest.get_content_id("ignore")
- for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
- nodes[i] = ignore
- end
+ -- Set up voxel manipulator
+ local manip, area = mh.init_axis_radius_length(current_pos, axis, radius, length)
+ local data = mh.get_empty_data(area)
- --fill selected area with node
- local node_id = minetest.get_content_id(nodename)
+ -- Add cylinder
+ local node_id = minetest.get_content_id(node_name)
local min_radius, max_radius = radius * (radius - 1), 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 offset = {
+ x = current_pos.x - area.MinEdge.x,
+ y = current_pos.y - area.MinEdge.y,
+ z = current_pos.z - area.MinEdge.z,
+ }
local min_slice, max_slice = offset[axis], offset[axis] + length - 1
local count = 0
for index2 = -radius, radius do
- local newindex2 = (index2 + offset[other1]) * stride[other1] + 1 --offset contributed by other axis 1 plus 1 to make it 1-indexed
+ -- Offset contributed by other axis 1 plus 1 to make it 1-indexed
+ local new_index2 = (index2 + offset[other1]) * stride[other1] + 1
for index3 = -radius, radius do
- local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2]
+ local new_index3 = new_index2 + (index3 + offset[other2]) * stride[other2]
local squared = index2 * index2 + index3 * index3
- if squared >= min_radius and squared <= max_radius then --position is on surface of cylinder
- for index1 = min_slice, max_slice do --add column along axis
- local i = newindex3 + index1 * stride[axis]
- nodes[i] = node_id
+ if squared <= max_radius and (not hollow or squared >= min_radius) then
+ -- Position is in cylinder
+ -- Add column along axis
+ for index1 = min_slice, max_slice do
+ local vi = new_index3 + index1 * stride[axis]
+ data[vi] = node_id
end
count = count + length
end
end
end
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
+ mh.finish(manip, data)
return count
end
---adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.cylinder = function(pos, axis, length, radius, nodename)
- local other1, other2
- if axis == "x" then
- other1, other2 = "y", "z"
- elseif axis == "y" then
- other1, other2 = "x", "z"
- else --axis == "z"
- other1, other2 = "x", "y"
- end
-
- --handle negative lengths
- local currentpos = {x=pos.x, y=pos.y, z=pos.z}
- if length < 0 then
- length = -length
- currentpos[axis] = currentpos[axis] - length
- end
-
- --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 = {}
- 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)
- 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
- for index2 = -radius, radius do
- local newindex2 = (index2 + offset[other1]) * stride[other1] + 1 --offset contributed by other axis 1 plus 1 to make it 1-indexed
- for index3 = -radius, radius do
- local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2]
- if index2 * index2 + index3 * index3 <= max_radius then --position is within cylinder
- for index1 = min_slice, max_slice do --add column along axis
- local i = newindex3 + index1 * stride[axis]
- nodes[i] = node_id
- end
- count = count + length
- end
- end
- end
-
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
- return count
-end
+--- Adds a pyramid.
+-- @param pos Position to center base of pyramid at.
+-- @param axis Axis ("x", "y", or "z")
+-- @param height Pyramid height.
+-- @param node_name Name of node to make pyramid of.
+-- @return The number of nodes added.
+function worldedit.pyramid(pos, axis, height, node_name)
+ local other1, other2 = worldedit.get_axis_others(axis)
---adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
-worldedit.pyramid = function(pos, axis, height, nodename)
- local other1, other2
- if axis == "x" then
- other1, other2 = "y", "z"
- elseif axis == "y" then
- other1, other2 = "x", "z"
- else --axis == "z"
- other1, other2 = "x", "y"
- end
-
- local pos1 = {x=pos.x - height, y=pos.y - height, z=pos.z - height}
- local pos2 = {x=pos.x + height, y=pos.y + height, z=pos.z + height}
+ -- Set up voxel manipulator
+ local manip, area = mh.init_axis_radius(pos, axis,
+ height >= 0 and height or -height)
+ local data = mh.get_empty_data()
- --handle inverted pyramids
- local startaxis, endaxis, step
+ -- Handle inverted pyramids
+ local start_axis, end_axis, step
if height > 0 then
height = height - 1
step = 1
- pos1[axis] = pos[axis] --upper half of box
else
height = height + 1
step = -1
- pos2[axis] = pos[axis] --lower half of box
- end
-
- --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)
+ -- Add pyramid
+ local node_id = minetest.get_content_id(node_name)
local stride = {x=1, y=area.ystride, z=area.zstride}
- local offset = {x=pos.x - emerged_pos1.x, y=pos.y - emerged_pos1.y, z=pos.z - emerged_pos1.z}
+ local offset = {
+ x = pos.x - area.MinEdge.x,
+ y = pos.y - area.MinEdge.y,
+ z = pos.z - area.MinEdge.z,
+ }
local size = height * step
local count = 0
- for index1 = 0, height, step do --go through each level of the pyramid
- local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed
+ -- For each level of the pyramid
+ for index1 = 0, height, step do
+ -- Offset contributed by axis plus 1 to make it 1-indexed
+ local new_index1 = (index1 + offset[axis]) * stride[axis] + 1
for index2 = -size, size do
- local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1]
+ local new_index2 = new_index1 + (index2 + offset[other1]) * stride[other1]
for index3 = -size, size do
- local i = newindex2 + (index3 + offset[other2]) * stride[other2]
- nodes[i] = node_id
+ local i = new_index2 + (index3 + offset[other2]) * stride[other2]
+ data[i] = node_id
end
end
count = count + (size * 2 + 1) ^ 2
size = size - 1
end
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
+ mh.finish(manip, data)
return count
end
---adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
-worldedit.spiral = function(pos, length, height, spacer, nodename)
+--- Adds a spiral.
+-- @param pos Position to center spiral at.
+-- @param length Spral length.
+-- @param height Spiral height.
+-- @param spacer Space between walls.
+-- @param node_name Name of node to make spiral of.
+-- @return Number of nodes added.
+-- TODO: Add axis option.
+function worldedit.spiral(pos, length, height, spacer, node_name)
local extent = math.ceil(length / 2)
- local pos1 = {x=pos.x - extent, y=pos.y, z=pos.z - extent}
- local pos2 = {x=pos.x + extent, y=pos.y + height, z=pos.z + extent}
-
- --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
- --set up variables
- local node_id = minetest.get_content_id(nodename)
+ local manip, area = mh.init_axis_radius_length(pos, "y", extent, height)
+ local data = mh.get_empty_data(area)
+
+ -- Set up variables
+ local node_id = minetest.get_content_id(node_name)
local stride = {x=1, y=area.ystride, z=area.zstride}
- local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
- local i = offsetz * stride.z + offsety * stride.y + offsetx + 1
+ local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+ local i = offset_z * stride.z + offset_y * stride.y + offset_x + 1
- --add first column
+ -- Add first column
local count = height
local column = i
for y = 1, height do
- nodes[column] = node_id
+ data[column] = node_id
column = column + stride.y
end
- --add spiral segments
- local strideaxis, strideother = stride.x, stride.z
+ -- Add spiral segments
+ local stride_axis, stride_other = stride.x, stride.z
local sign = -1
local segment_length = 0
spacer = spacer + 1
- for segment = 1, math.floor(length / spacer) * 2 do --go through each segment except the last
- if segment % 2 == 1 then --change sign and length every other turn starting with the first
+ -- Go through each segment except the last
+ for segment = 1, math.floor(length / spacer) * 2 do
+ -- Change sign and length every other turn starting with the first
+ if segment % 2 == 1 then
sign = -sign
segment_length = segment_length + spacer
end
- for index = 1, segment_length do --fill segment
- i = i + strideaxis * sign --move along the direction of the segment
+ -- Fill segment
+ for index = 1, segment_length do
+ -- Move along the direction of the segment
+ i = i + stride_axis * sign
local column = i
- for y = 1, height do --add column
- nodes[column] = node_id
+ -- Add column
+ for y = 1, height do
+ data[column] = node_id
column = column + stride.y
end
end
count = count + segment_length * height
- strideaxis, strideother = strideother, strideaxis --swap axes
+ stride_axis, stride_other = stride_other, stride_axis -- Swap axes
end
- --add shorter final segment
+ -- Add shorter final segment
sign = -sign
for index = 1, segment_length do
- i = i + strideaxis * sign
+ i = i + stride_axis * sign
local column = i
- for y = 1, height do --add column
- nodes[column] = node_id
+ -- Add column
+ for y = 1, height do
+ data[column] = node_id
column = column + stride.y
end
end
count = count + segment_length * height
- --update map nodes
- manip:set_data(nodes)
- manip:write_to_map()
- manip:update_map()
+ mh.finish(manip, data)
return count
-end \ No newline at end of file
+end