Finding the closest points between 2 lines

As the title suggests, I want to find the closest points between 2 lines in 3D space, so I created a small module with the object Line. Here is a 2D simplified diagram of the math that I used:


(Of course, the lines extend infinitely in both directions. This is just a bad diagram)

Unfortunately, I’m also bad at math. Currently, the function generates two points that are close, but not the closest. I don’t know where I messed up. The similar tutorials that there are, I don’t understand, as I’m terrible at math.

Here are the main functions that are responsible. (Zero unit = 1, 0, 0)

--Subtract unit sphere
function Lines.sub(Unit1, Unit2, ZeroUnit)
	if ZeroUnit then
		Unit1 = Lines.sub(Unit1, ZeroUnit)
	end
	
	--Get X angles
	local Horizon1 = math.acos(Unit1.X)
	local Horizon2 = math.acos(Unit2.X)
	
	--Get Y angles
	local Zenith1 = math.asin(Unit1.Y)
	local Zenith2 = math.asin(Unit2.Y)
	
	--Get Z angles
	local Zed1 = math.asin(Unit1.Z)
	local Zed2 = math.asin(Unit2.Z)
	
	--Subtract angles
	local Horizon = Horizon1 - Horizon2
	local Zenith = Zenith1 - Zenith2
	local Zed = Zed1 - Zed2
	
	--Convert angles back to unit vector
	return Vector3.new(math.cos(Horizon), math.sin(Zenith), math.sin(Zed)).unit
end

--Rotates the line1 to zerounit
function Lines.relrot(Line_1, Line_2)
	--Rotate origins and directions
	local Direction1 = Lines.sub(Lines.clone(Line_1).Direction, Lines.clone(Line_1).Direction)
	local Direction2 = Lines.sub(Lines.clone(Line_2).Direction, Lines.clone(Line_1).Direction)
	
	--Distance between the origins of 2 lines
	local Origin2_DistMag = Line_2.Origin.magnitude
	
	--Copy of line2 origin
	local Origin2_Copy = Vector3.new(Line_2.Origin.X, Line_2.Origin.Y, Line_2.Origin.Z).unit
	local Origin2 = Lines.sub(Origin2_Copy, Lines.clone(Line_1).Direction)*Origin2_DistMag
	
	--Create new lines
	local Line1 = Lines.new(Line_1.Origin, Direction1)
	local Line2 = Lines.new(Origin2, Direction2)
	
	return Line1, Line2
end

--Find the closest points between two lines
function Lines:FindClosest(Line)
	local Line1, Line2 = Lines.relrot(self, Line)
	
	--Get the opposite difference of the line1 and line2 y position
	local Line_H = Line1.Origin.Y - Line2.Origin.Y
	
	--Get the difference between the intersection and line2 x position
	local Line2_xLen = (Line_H*Line2.Direction.X)/Line2.Direction.Y
	
	--Get the closest point for line1 by getting the relative distance of Line2_xLen to Line1 Origin
	local Line1_Closest = Line2_xLen + Line2.Origin.X - Line1.Origin.X
	
	--Get the intersection x and y position distance
	local Line2_XyDist = math.sqrt(Line2_xLen^2 + Line_H^2)
	
	--Get the distance between line1 and line2 z position
	local Line2_zLen = Line2.Direction.Z*Line_H
	
	--Get the closest point for line2 by pythagoras the xy value and z position intersect
	local Line2_Closest = math.sqrt(Line2_XyDist^2 + Line2_zLen^2)
	
	local Line1_Pos = self:GetPosition(Line1_Closest)
	local Line2_Pos = Line:GetPosition(Line2_Closest)
	local IntersectDist = (Line1_Pos - Line2_Pos).magnitude
	
	return Line1_Closest, Line2_Closest, IntersectDist
end

function Lines:GetPosition(Movement)
	return self.Origin + self.Direction*Movement
end
3 Likes