- Remove utility script - Move vector extensions to dedicated file - Remove vector.convert, add vector.from_hash - Add vector.get to get x,y,z from varargs-ish - contraption:move returns moved nodesmain
							parent
							
								
									5969a2909e
								
							
						
					
					
						commit
						e4d4bacc89
					
				
				 4 changed files with 275 additions and 130 deletions
			
			
		@ -0,0 +1,143 @@ | 
				
			|||||||
 | 
					local math, setmetatable, vector | 
				
			||||||
 | 
					    = math, setmetatable, vector | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local math_min, math_max, math_floor, math_ceil, math_round | 
				
			||||||
 | 
					    = math.min, math.max, math.floor, math.ceil, math.round | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include("vector_extensions") | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local region = {} | 
				
			||||||
 | 
					local metatable = { __index = region } | 
				
			||||||
 | 
					region.metatable = metatable | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function fast_new(min, max) return setmetatable({ min = min, max = max }, metatable) end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns a new region from the specified `min` and `max` position vectors. | 
				
			||||||
 | 
					function region.new(min, max) return fast_new(vector.copy(min), vector.copy(max)) end | 
				
			||||||
 | 
					-- Returns a deep copy of this region. Can also be called as `region.copy(r))`. | 
				
			||||||
 | 
					function region:copy() return region.new(self.min, self.max) end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns this region's bounds as an array in the form of | 
				
			||||||
 | 
					-- `{ min.x, min.y, min.z, max.x, max.y, max.z }`, similar to `collisionbox`. | 
				
			||||||
 | 
					function region:to_array() return { self.min.x, self.min.y, self.min.z, self.max.x, self.max.y, self.max.z } end | 
				
			||||||
 | 
					-- Returns a new region from the specified array `a` in the form of | 
				
			||||||
 | 
					-- `{ min.x, min.y, min.z, max.x, max.y, max.z }`, similar to `collisionbox`. | 
				
			||||||
 | 
					function region.from_array(a) return fast_new(vector.new(a[1], a[2], a[3]), vector.new(a[4], a[5], a[6])) end | 
				
			||||||
 | 
					-- Returns a new region from the specified `ObjectRef` using its position and collision box. | 
				
			||||||
 | 
					function region.from_object(obj) return region.from_array(obj:get_properties().collisionbox):offset_in_place(obj:get_pos()) end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function region:size() return self.max - self.min end | 
				
			||||||
 | 
					function region:center() return (self.min + self.max) / 2 end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Offsets this region by the specified vector. | 
				
			||||||
 | 
					function region:offset_in_place(...) | 
				
			||||||
 | 
					    local x, y, z = vector.get(...) | 
				
			||||||
 | 
					    local min, max = self.min, self.max | 
				
			||||||
 | 
					    min.x = min.x + x | 
				
			||||||
 | 
					    min.y = min.y + y | 
				
			||||||
 | 
					    min.z = min.z + z | 
				
			||||||
 | 
					    max.x = max.x + x | 
				
			||||||
 | 
					    max.y = max.y + y | 
				
			||||||
 | 
					    max.z = max.z + z | 
				
			||||||
 | 
					    return self | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					-- Returns a new region offset by the specified vector. | 
				
			||||||
 | 
					function region:offset(...) | 
				
			||||||
 | 
					    return self:copy():offset_in_place(...) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Expanded this region in all directions by the specified amount. | 
				
			||||||
 | 
					-- For example, `region:expand_in_place(2)` expands the region by 2 meters in all directions. | 
				
			||||||
 | 
					function region:expand_in_place(...) | 
				
			||||||
 | 
					    local x, y, z = vector.get(...) | 
				
			||||||
 | 
					    local min, max = self.min, self.max | 
				
			||||||
 | 
					    min.x = min.x - x | 
				
			||||||
 | 
					    min.y = min.y - y | 
				
			||||||
 | 
					    min.z = min.z - z | 
				
			||||||
 | 
					    max.x = max.x + x | 
				
			||||||
 | 
					    max.y = max.y + y | 
				
			||||||
 | 
					    max.z = max.z + z | 
				
			||||||
 | 
					    return self | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					-- Returns a new region expanded in all directions by the specified amount. | 
				
			||||||
 | 
					-- For example, `region:expand(2)` expands the region by 2 meters in all directions. | 
				
			||||||
 | 
					function region:expand(...) | 
				
			||||||
 | 
					    return self:copy():expand_in_place(...) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Extends this region by the specified vector depending on the signedness of its components. | 
				
			||||||
 | 
					-- For example, `region:extend_in_place(0, -2, 0)` extends the region downwards by 2 meters. | 
				
			||||||
 | 
					function region:extend_in_place(...) | 
				
			||||||
 | 
					    local x, y, z = vector.get(...) | 
				
			||||||
 | 
					    local min, max = self.min, self.max | 
				
			||||||
 | 
					    min.x = min.x + math_min(0, x) | 
				
			||||||
 | 
					    min.y = min.y + math_min(0, y) | 
				
			||||||
 | 
					    min.z = min.z + math_min(0, z) | 
				
			||||||
 | 
					    max.x = max.x + math_max(0, x) | 
				
			||||||
 | 
					    max.y = max.y + math_max(0, y) | 
				
			||||||
 | 
					    max.z = max.z + math_max(0, z) | 
				
			||||||
 | 
					    return self | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					-- Returns a new region extended by the specified vector depending on the signedness of its components. | 
				
			||||||
 | 
					-- For example, `region:extend(0, -2, 0)` extends the region downwards by 2 meters. | 
				
			||||||
 | 
					function region:extend(...) | 
				
			||||||
 | 
					    return self:copy():extend_in_place(...) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function region:round_in_place() | 
				
			||||||
 | 
					    local min, max = self.min, self.max | 
				
			||||||
 | 
					    min.x = math_round(min.x) | 
				
			||||||
 | 
					    min.y = math_round(min.y) | 
				
			||||||
 | 
					    min.z = math_round(min.z) | 
				
			||||||
 | 
					    max.x = math_round(max.x) | 
				
			||||||
 | 
					    max.y = math_round(max.y) | 
				
			||||||
 | 
					    max.z = math_round(max.z) | 
				
			||||||
 | 
					    return self | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					function region:round() | 
				
			||||||
 | 
					    return self:copy():round_in_place() | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns if the specified `r` overlaps with this region. | 
				
			||||||
 | 
					function region:overlaps(r) | 
				
			||||||
 | 
					    return r.min.x < self.max.x and r.max.x > self.min.x | 
				
			||||||
 | 
					       and r.min.y < self.max.y and r.max.y > self.min.y | 
				
			||||||
 | 
					       and r.min.z < self.max.z and r.max.z > self.min.z | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns if the specified `pos` is contained within this region. | 
				
			||||||
 | 
					function region:contains(pos) | 
				
			||||||
 | 
					    return pos.x >= self.min.x and pos.x <= self.max.x | 
				
			||||||
 | 
					       and pos.y >= self.min.y and pos.y <= self.max.y | 
				
			||||||
 | 
					       and pos.z >= self.min.z and pos.z <= self.max.z | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function region:to_relative(abs_pos) return vector.subtract(abs_pos, self.min) end | 
				
			||||||
 | 
					function region:to_absolute(rel_pos) return vector.add(rel_pos, self.min) end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns an iterator over the node positions contained in this region. | 
				
			||||||
 | 
					function region:iter_node_positions() | 
				
			||||||
 | 
					    local min_x = math_ceil(self.min.x) | 
				
			||||||
 | 
					    local min_y = math_ceil(self.min.y) | 
				
			||||||
 | 
					    local min_z = math_ceil(self.min.z) | 
				
			||||||
 | 
					    local max_x = math_floor(self.max.x) | 
				
			||||||
 | 
					    local max_y = math_floor(self.max.y) | 
				
			||||||
 | 
					    local max_z = math_floor(self.max.z) | 
				
			||||||
 | 
					    local x, y, z = min_x, min_y, min_z | 
				
			||||||
 | 
					    return function() | 
				
			||||||
 | 
					        local result = vector.new(x, y, z) | 
				
			||||||
 | 
					        x = x + 1 | 
				
			||||||
 | 
					        if x > max_x then x = min_x; y = y + 1 end | 
				
			||||||
 | 
					        if y > max_y then y = min_y; z = z + 1 end | 
				
			||||||
 | 
					        if z > max_z then return nil end | 
				
			||||||
 | 
					        return result | 
				
			||||||
 | 
					    end | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function region.equals(a, b) | 
				
			||||||
 | 
					    return vector.equals(a.min, b.min) | 
				
			||||||
 | 
					       and vector.equals(a.max, b.max) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					metatable.__eq = region.equals | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return region | 
				
			||||||
@ -1,46 +0,0 @@ | 
				
			|||||||
local ipairs, setmetatable, tostring, print | 
					 | 
				
			||||||
    = ipairs, setmetatable, tostring, print | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local minetest, vector | 
					 | 
				
			||||||
    = minetest, vector | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local mod_name = minetest.get_current_modname() | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local utility = {} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
-- Prints an error message by concatenating the parameters as strings. | 
					 | 
				
			||||||
function error(...) | 
					 | 
				
			||||||
    local str = "[" .. mod_name .. "] " | 
					 | 
				
			||||||
    for _, v in ipairs({...}) do str = str + tostring(v) end | 
					 | 
				
			||||||
    print(str) | 
					 | 
				
			||||||
end | 
					 | 
				
			||||||
utility.error = utility | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if not vector.convert then | 
					 | 
				
			||||||
    function vector.convert(v) | 
					 | 
				
			||||||
        local t = type(v) | 
					 | 
				
			||||||
        if t == "number" then | 
					 | 
				
			||||||
            -- Assume the number was created by calling `vector.hash`. | 
					 | 
				
			||||||
            return setmetatable(minetest.get_position_from_hash(v), vector.metatable) | 
					 | 
				
			||||||
        elseif t == "string" then | 
					 | 
				
			||||||
            -- Assume the string is either in `(x, y, z)` or `{x=x, y=y, z=z}` format. | 
					 | 
				
			||||||
            local first_chr = v:byte(1) | 
					 | 
				
			||||||
            if     first_chr == "(" then return vector.from_string(v) | 
					 | 
				
			||||||
            elseif first_chr == "{" then return setmetatable(minetest.deserialize(v), vector.metatable) | 
					 | 
				
			||||||
                                    else error("Cannot convert string '" .. v .. "' to vector") end | 
					 | 
				
			||||||
        elseif t == "table" then | 
					 | 
				
			||||||
            -- Assume the table already has `x`, `y` and `z` entries. | 
					 | 
				
			||||||
            -- Returns the same table, making sure its metatable is set. | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return setmetatable(v, vector.metatable) | 
					 | 
				
			||||||
        else error("Cannot convert type '" .. t .. "' to vector") end | 
					 | 
				
			||||||
    end | 
					 | 
				
			||||||
end | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if not vector.hash then | 
					 | 
				
			||||||
    function vector:hash() | 
					 | 
				
			||||||
        return minetest.hash_node_position(self) | 
					 | 
				
			||||||
    end | 
					 | 
				
			||||||
end | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
return utility | 
					 | 
				
			||||||
@ -0,0 +1,25 @@ | 
				
			|||||||
 | 
					local setmetatable, minetest, vector | 
				
			||||||
 | 
					    = setmetatable, minetest, vector | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Creates a vector using `get_position_from_hash` from the specified `hash`. | 
				
			||||||
 | 
					function vector.from_hash(hash) | 
				
			||||||
 | 
					    return setmetatable(minetest.get_position_from_hash(hash), vector.metatable) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns the integer hash of this vector using `hash_node_position`. | 
				
			||||||
 | 
					function vector:hash() | 
				
			||||||
 | 
					    return minetest.hash_node_position(self) | 
				
			||||||
 | 
					end | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Returns vector components from the specified arguments. | 
				
			||||||
 | 
					-- * `(x, y, z)` returns `x, y, z`. | 
				
			||||||
 | 
					-- * `(number)` returns `n, n, n`. | 
				
			||||||
 | 
					-- * `(table)` returns `t.x, t.y, t.z`. | 
				
			||||||
 | 
					-- * `(array)` returns `t[1], t[2], t[3]`. | 
				
			||||||
 | 
					-- * Unexpected input returns undefined output. | 
				
			||||||
 | 
					function vector.get(x, y, z) | 
				
			||||||
 | 
					    if z then return x, y, z end | 
				
			||||||
 | 
					    if type(x) == "number" then return x, x, x end | 
				
			||||||
 | 
					    if x.z then return x.x, x.y, x.z end | 
				
			||||||
 | 
					    return x[1], x[2], x[3] | 
				
			||||||
 | 
					end | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue