Skip to content

Major optimization of Octree module #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: version2
Choose a base branch
from
41 changes: 19 additions & 22 deletions Modules/Shared/Region3/Octree/Octree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ Octree.ClassName = "Octree"
Octree.__index = Octree

function Octree.new()
local self = setmetatable({}, Octree)
return setmetatable({
_maxRegionSize = {512, 512, 512}, -- these should all be the same number
_maxDepth = 4,
_regionHashMap = {}
}, Octree)
end

function Octree:ClearNodes()
self._maxRegionSize = { 512, 512, 512 } -- these should all be the same number
self._maxDepth = 4
self._regionHashMap = {} -- [hash] = region
table.clear(self._regionHashMap)

return self
end
Expand All @@ -28,7 +34,7 @@ function Octree:GetAllNodes()
for _, regionList in pairs(self._regionHashMap) do
for _, region in pairs(regionList) do
for node, _ in pairs(region.nodes) do
options[#options+1] = node
table.insert(options, node)
end
end
end
Expand All @@ -48,19 +54,14 @@ function Octree:CreateNode(position, object)
end

function Octree:RadiusSearch(position, radius)
assert(typeof(position) == "Vector3")
assert(type(radius) == "number")

local px, py, pz = position.x, position.y, position.z
return self:_radiusSearch(px, py, pz, radius)
return self:_radiusSearch(assert(typeof(position) == "Vector3") and position.X, position.Y, position.Z, assert(type(radius) == "number") and radius)
end

function Octree:KNearestNeighborsSearch(position, k, radius)
assert(typeof(position) == "Vector3")
assert(type(radius) == "number")

local px, py, pz = position.x, position.y, position.z
local objects, nodeDistances2 = self:_radiusSearch(px, py, pz, radius)
local objects, nodeDistances2 = self:_radiusSearch(position.x, position.y, position.z, radius)

local sortable = {}
for index, dist2 in pairs(nodeDistances2) do
Expand All @@ -78,38 +79,34 @@ function Octree:KNearestNeighborsSearch(position, k, radius)
local knearestDist2 = {}
for i = 1, math.min(#sortable, k) do
local sorted = sortable[i]
knearestDist2[#knearestDist2 + 1] = sorted.dist2
knearest[#knearest + 1] = objects[sorted.index]
table.insert(knearestDist2, sorted.dist2)
table.insert(knearest, objects[sorted.index])
end

return knearest, knearestDist2
end

function Octree:GetOrCreateLowestSubRegion(px, py, pz)
local region = self:_getOrCreateRegion(px, py, pz)
return OctreeRegionUtils.getOrCreateSubRegionAtDepth(region, px, py, pz, self._maxDepth)
return OctreeRegionUtils.getOrCreateSubRegionAtDepth(self:_getOrCreateRegion(px, py, pz), px, py, pz, self._maxDepth)
end

function Octree:_radiusSearch(px, py, pz, radius)
local objectsFound = {}
local nodeDistances2 = {}

local diameter = self._maxRegionSize[1]
local searchRadiusSquared = OctreeRegionUtils.getSearchRadiusSquared(radius, diameter, EPSILON)
local searchRadiusSquared = OctreeRegionUtils.getSearchRadiusSquared(radius, self._maxRegionSize[1], EPSILON)

--debug.profilebegin('_regionHashMap loop')
for _, regionList in pairs(self._regionHashMap) do
for _, region in pairs(regionList) do
local rpos = region.position
local rpx, rpy, rpz = rpos[1], rpos[2], rpos[3]
local ox, oy, oz = px - rpx, py - rpy, pz - rpz
local dist2 = ox*ox + oy*oy + oz*oz

if dist2 <= searchRadiusSquared then
OctreeRegionUtils.getNeighborsWithinRadius(
region, radius, px, py, pz, objectsFound, nodeDistances2, self._maxDepth)
if (px - rpos[1])^2 + (py - rpos[2])^2 + (pz - rpos[3])^2 <= searchRadiusSquared then
OctreeRegionUtils.getNeighborsWithinRadius(region, radius, px, py, pz, objectsFound, nodeDistances2, maxDepth)
end
end
end
--debug.profileend()

return objectsFound, nodeDistances2
end
Expand Down
33 changes: 17 additions & 16 deletions Modules/Shared/Region3/Octree/OctreeNode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ OctreeNode.ClassName = "OctreeNode"
OctreeNode.__index = OctreeNode

function OctreeNode.new(octree, object)
local self = setmetatable({}, OctreeNode)
return setmetatable({
_octree = octree or error("No octree"),
_object = object or error("No object"),

self._octree = octree or error("No octree")
self._object = object or error("No object")

self._currentLowestRegion = nil
self._position = nil

return self
_currentLowestRegion = nil,
_position = nil
}, OctreeNode)
end

function OctreeNode:KNearestNeighborsSearch(k, radius)
Expand Down Expand Up @@ -46,15 +44,18 @@ function OctreeNode:SetPosition(position)
return
end

local px, py, pz = position.x, position.y, position.z
local px = position.x
local py = position.y
local pz = position.z

self._px = px
self._py = py
self._pz = pz
self._position = position

if self._currentLowestRegion then
if OctreeRegionUtils.inRegionBounds(self._currentLowestRegion, px, py, pz) then
local currentLowestRegion = self._currentLowestRegion
if currentLowestRegion then
if OctreeRegionUtils.inRegionBounds(currentLowestRegion, px, py, pz) then
return
end
end
Expand All @@ -66,18 +67,18 @@ function OctreeNode:SetPosition(position)
-- error("[OctreeNode.SetPosition] newLowestRegion is not in region bounds!")
-- end

if self._currentLowestRegion then
OctreeRegionUtils.moveNode(self._currentLowestRegion, newLowestRegion, self)
if currentLowestRegion then
OctreeRegionUtils.moveNode(currentLowestRegion, newLowestRegion, self)
else
OctreeRegionUtils.addNode(newLowestRegion, self)
end

self._currentLowestRegion = newLowestRegion
end

function OctreeNode:Destroy()
if self._currentLowestRegion then
OctreeRegionUtils.removeNode(self._currentLowestRegion, self)
local currentLowestRegion = self._currentLowestRegion
if currentLowestRegion then
OctreeRegionUtils.removeNode(currentLowestRegion, self)
end
end

Expand Down
Loading