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