From 987cc5a6a425b1f9bcd9000608dc389a45c675a1 Mon Sep 17 00:00:00 2001
From: you <ovvv@web.de>
Date: Mon, 05 Jun 2017 16:51:59 +0200
Subject: [PATCH] Add api documentation (#361)

---
 technic/helpers.lua |  153 ++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 109 insertions(+), 44 deletions(-)

diff --git a/technic/helpers.lua b/technic/helpers.lua
index 164cf7e..5780f27 100644
--- a/technic/helpers.lua
+++ b/technic/helpers.lua
@@ -63,64 +63,129 @@
 end
 
 
--- Based on code by Uberi: https://gist.github.com/Uberi/3125280
+--- Iterates over the node positions along the specified ray.
+-- The returned positions will not include the starting position.
 function technic.trace_node_ray(pos, dir, range)
-	local p = vector.round(pos)
-	local x_step,      y_step,      z_step      = 0, 0, 0
-	local x_component, y_component, z_component = 0, 0, 0
-	local x_intersect, y_intersect, z_intersect = 0, 0, 0
+	local x_step = dir.x > 0 and 1 or -1
+	local y_step = dir.y > 0 and 1 or -1
+	local z_step = dir.z > 0 and 1 or -1
 
-	if dir.x == 0 then
-		x_intersect = math.huge
-	elseif dir.x > 0 then
-		x_step = 1
-		x_component = 1 / dir.x
-		x_intersect = x_component
-	else
-		x_step = -1
-		x_component = 1 / -dir.x
-	end
-	if dir.y == 0 then
-		y_intersect = math.huge
-	elseif dir.y > 0 then
-		y_step = 1
-		y_component = 1 / dir.y
-		y_intersect = y_component
-	else
-		y_step = -1
-		y_component = 1 / -dir.y
-	end
-	if dir.z == 0 then
-		z_intersect = math.huge
-	elseif dir.z > 0 then
-		z_step = 1
-		z_component = 1 / dir.z
-		z_intersect = z_component
-	else
-		z_step = -1
-		z_component = 1 / -dir.z
-	end
+	local i = 1
+	return function(p)
+		-- Approximation of where we should be if we weren't rounding
+		-- to nodes.  This moves forward a bit faster then we do.
+		-- A correction is done below.
+		local real_x = pos.x + (dir.x * i)
+		local real_y = pos.y + (dir.y * i)
+		local real_z = pos.z + (dir.z * i)
 
-	return function()
-		if x_intersect < y_intersect then
-			if x_intersect < z_intersect then
+		-- How far off we've gotten from where we should be.
+		local dx = math.abs(real_x - p.x)
+		local dy = math.abs(real_y - p.y)
+		local dz = math.abs(real_z - p.z)
+
+		-- If the real position moves ahead too fast, stop it so we
+		-- can catch up.  If it gets too far ahead it will smooth
+		-- out our movement too much and we won't turn fast enough.
+		if dx + dy + dz < 2 then
+			i = i + 1
+		end
+
+		-- Step in whichever direction we're most off course in.
+		if dx > dy then
+			if dx > dz then
 				p.x = p.x + x_step
-				x_intersect = x_intersect + x_component
 			else
 				p.z = p.z + z_step
-				z_intersect = z_intersect + z_component
 			end
-		elseif y_intersect < z_intersect then
+		elseif dy > dz then
 			p.y = p.y + y_step
-			y_intersect = y_intersect + y_component
 		else
 			p.z = p.z + z_step
-			z_intersect = z_intersect + z_component
 		end
 		if vector.distance(pos, p) > range then
 			return nil
 		end
 		return p
-	end
+	end, vector.round(pos)
+end
+
+
+--- Like trace_node_ray, but includes extra positions close to the ray.
+function technic.trace_node_ray_fat(pos, dir, range)
+	local x_step = dir.x > 0 and 1 or -1
+	local y_step = dir.y > 0 and 1 or -1
+	local z_step = dir.z > 0 and 1 or -1
+
+	local next_poses = {}
+
+	local i = 1
+	return function(p)
+		local ni, np = next(next_poses)
+		if np then
+			next_poses[ni] = nil
+			return np
+		end
+
+		-- Approximation of where we should be if we weren't rounding
+		-- to nodes.  This moves forward a bit faster then we do.
+		-- A correction is done below.
+		local real_x = pos.x + (dir.x * i)
+		local real_y = pos.y + (dir.y * i)
+		local real_z = pos.z + (dir.z * i)
+
+		-- How far off we've gotten from where we should be.
+		local dx = math.abs(real_x - p.x)
+		local dy = math.abs(real_y - p.y)
+		local dz = math.abs(real_z - p.z)
+
+		-- If the real position moves ahead too fast, stop it so we
+		-- can catch up.  If it gets too far ahead it will smooth
+		-- out our movement too much and we won't turn fast enough.
+		if dx + dy + dz < 2 then
+			i = i + 1
+		end
+
+		-- Step in whichever direction we're most off course in.
+		local sx, sy, sz  -- Whether we've already stepped along each axis
+		if dx > dy then
+			if dx > dz then
+				sx = true
+				p.x = p.x + x_step
+			else
+				sz = true
+				p.z = p.z + z_step
+			end
+		elseif dy > dz then
+			sy = true
+			p.y = p.y + y_step
+		else
+			sz = true
+			p.z = p.z + z_step
+		end
+
+		if vector.distance(pos, p) > range then
+			return nil
+		end
+
+		-- Add other positions that we're significantly off on.
+		-- We can just use fixed integer keys here because the
+		-- table will be completely cleared before we reach this
+		-- code block again.
+		local dlen = math.sqrt(dx*dx + dy*dy + dz*dz)
+		-- Normalized axis deltas
+		local dxn, dyn, dzn = dx / dlen, dy / dlen, dz / dlen
+		if not sx and dxn > 0.5 then
+			next_poses[1] = vector.new(p.x + x_step, p.y, p.z)
+		end
+		if not sy and dyn > 0.5 then
+			next_poses[2] = vector.new(p.x, p.y + y_step, p.z)
+		end
+		if not sz and dzn > 0.5 then
+			next_poses[3] = vector.new(p.x, p.y, p.z + z_step)
+		end
+
+		return p
+	end, vector.round(pos)
 end
 

--
Gitblit v1.8.0