2 Line Intersection

Lets say that i want to know where 2 lines intersect (Resulting in Vector3).
The lines are just two Vector3 position (start, end).
Ignore Y axis.
How to i should calculate that in a script?

This Thead dont provided script examples and I dont understand it.

2 Likes

So, each line has two Vector3 positions (the start and end) associated with it? Making for 4 total Vector3 positions?

I expected this to be a simple vector problem, but I actually couldn’t think of anything myself. Here’s a video explaining it and it links to the code in the description. You’ll have to translate it into lua. https://youtu.be/wCR48FqkI4w

EDIT: @Bakkikins Yeah, that’s my impression of what he said.

Here’s the code that calculates it, assuming my previous comment’s assumption is true.

function intersection_point(line_1_start, line_1_end, line_2_start, line_2_end)
    local line_1_m = (line_1_end.Z - line_1_start.Z) / (line_1_end.X - line_1_start.X)
    local line_2_m = (line_2_end.Z - line_2_start.Z) / (line_2_end.X - line_2_start.X)
    local line_1_b = line_1_start.Z - (line_1_m * line_1_start.X)
    local line_2_b = line_2_start.Z - (line_2_m * line_2_start.X)
    local intersect_x = (line_2_b - line_1_b) / (line_1_m - line_2_m)
    local intersect_z = (line_1_m * intersect_x) + line_1_b
    return Vector3.new(intersect_x, line_1_start.Y, intersect_z)
end

Explaining how it works would involve me explaining quite a bit of algebra and calculus, and would take way too long for something this simple. I’ve tested it and, to my knowledge, it should work.

EDIT: Here’s some lines to test it out with (these are the ones I actually used). Pick any x and y values on either side of the point where they intersect for each line (these will be your Vector3 x and z values) and plug it in, and it should work.

7 Likes

The solution given is not 100% accurate what if a there is a cross point on a vertical line? Vertical lines have no slope. This modified code will include all cross points of any lines.
Note This code was compiled from typescript to lua

local function intersection_point(startPoint1, endPoint1, startPoint2, endPoint2)
    local point_1_x1 = startPoint1.X
    local point_1_y1 = startPoint1.Z
    local point_1_x2 = endPoint1.X
    local point_1_y2 = endPoint1.Z
    local point_2_x1 = startPoint2.X
    local point_2_y1 = startPoint2.Z
    local point_2_x2 = endPoint2.X
    local point_2_y2 = endPoint2.Z
    -- m = (y1 - y2) / (x1 - x2)
    local line_1_m = 0
    local line_2_m = 0
    -- b = -(mx1) + y1
    local line_1_b = 0
    local line_2_b = 0
    local intersect_x = 0
    local intersect_z = 0
    local isLineOneVertical = ((point_1_x1 / point_1_x2) % 2) == 1
    local isLineTwoVertical = ((point_2_x1 / point_2_x2) % 2) == 1
    if isLineOneVertical and isLineTwoVertical then
        error(error("There is no cross point"))
    end
    -- Line 1
    if isLineOneVertical then
        line_2_m = (point_2_y1 - point_2_y2) / (point_2_x1 - point_2_x2)
        line_2_b = -(line_2_m * point_2_x1) + point_2_y1
        intersect_x = point_1_x1
        intersect_z = (line_2_m * intersect_x) + line_2_b
        -- Line 2
    elseif isLineTwoVertical then
        line_1_m = (point_1_y1 - point_1_y2) / (point_1_x1 - point_1_x2)
        line_1_b = -(line_1_m * point_1_x1) + point_1_y1
        intersect_x = point_2_x1
        intersect_z = (line_1_m * intersect_x) + line_1_b
    else
        line_1_m = (point_1_y1 - point_1_y2) / (point_1_x1 - point_1_x2)
        line_2_m = (point_2_y1 - point_2_y2) / (point_2_x1 - point_2_x2)

        if line_1_m == line_2_m then
            error(error("There is no cross point"))
        end
        line_1_b = -(line_1_m * point_1_x1) + point_1_y1
        line_2_b = -(line_2_m * point_2_x1) + point_2_y1
        intersect_x = (line_2_b - line_1_b) / (line_1_m - line_2_m)
        intersect_z = (line_1_m * intersect_x) + line_1_b

    end

    return Vector3.new(intersect_x, point_1_y1, intersect_z)
end
3 Likes

Sorry to bump this, but this also doesn’t work on all line intersections :confused:

Removing these error messages makes it work, but it’ll sometimes get intersections that don’t exist


(creates red poles in space, which means that it’s getting intersections here for some reason)

Upon further testing, this seems to extrapolate lines, and thus creates a point of intersection


As you can see, even though the lines end, it’s still saying there’s an intersection point

Because of


Unsure how to stop this from happening tho :confused: I thought it’d only get from start-end of lines

That’s what the errors were for. You should be able to switch them out with return to return nothing when there’s no cross point.

That’s what I ended up doing, but the intersections are still detected and created

local function GetLineIntersection(startPoint1, endPoint1, startPoint2, endPoint2)
	local point_1_x1 = startPoint1.X
	local point_1_y1 = startPoint1.Z
	local point_1_x2 = endPoint1.X
	local point_1_y2 = endPoint1.Z
	local point_2_x1 = startPoint2.X
	local point_2_y1 = startPoint2.Z
	local point_2_x2 = endPoint2.X
	local point_2_y2 = endPoint2.Z
	-- m = (y1 - y2) / (x1 - x2)
	local line_1_m = 0
	local line_2_m = 0
	-- b = -(mx1) + y1
	local line_1_b = 0
	local line_2_b = 0
	local intersect_x = 0
	local intersect_z = 0
	local isLineOneVertical = ((point_1_x1 / point_1_x2) % 2) == 1
	local isLineTwoVertical = ((point_2_x1 / point_2_x2) % 2) == 1
	if isLineOneVertical and isLineTwoVertical then
		print("error")
		return
		--error("There is no cross point")
	end
	-- Line 1
	if isLineOneVertical then
		print(1)
		line_2_m = (point_2_y1 - point_2_y2) / (point_2_x1 - point_2_x2)
		line_2_b = -(line_2_m * point_2_x1) + point_2_y1
		intersect_x = point_1_x1
		intersect_z = (line_2_m * intersect_x) + line_2_b
		-- Line 2
	elseif isLineTwoVertical then
		print(2)
		line_1_m = (point_1_y1 - point_1_y2) / (point_1_x1 - point_1_x2)
		line_1_b = -(line_1_m * point_1_x1) + point_1_y1
		intersect_x = point_2_x1
		intersect_z = (line_1_m * intersect_x) + line_1_b
	else
		print(3)
		line_1_m = (point_1_y1 - point_1_y2) / (point_1_x1 - point_1_x2)
		line_2_m = (point_2_y1 - point_2_y2) / (point_2_x1 - point_2_x2)
		print(line_1_m, line_2_m)
		if line_1_m == line_2_m then
			print("error")
			return
			--error("There is no cross point")
		end
		line_1_b = -(line_1_m * point_1_x1) + point_1_y1
		line_2_b = -(line_2_m * point_2_x1) + point_2_y1
		intersect_x = (line_2_b - line_1_b) / (line_1_m - line_2_m)
		intersect_z = (line_1_m * intersect_x) + line_1_b

	end
	print(startPoint1, endPoint1, startPoint2, endPoint2)
	print(Vector3.new(intersect_x, startPoint1.Y, intersect_z))
	return Vector3.new(intersect_x, startPoint1.Y, intersect_z)
end

20:23:35.511 3 - Server - Script:47
20:23:35.511 -0 -1 - Server - Script:50
20:23:35.512 -52, 6, -19 3, 6, -19 -12, 6, -64 -47, 6, -29 - Server - Script:62
20:23:35.512 -57, 6, -19 - Server - Script:63

Only errors when the 2 lines are parralel to each other

I’m not too sure what’s going on in that function so I can’t really modify it, but I came up with this typed function which should be what you’re looking for:

function FindLineIntersection2D(l1p1: Vector2, l1p2: Vector2, l2p1: Vector2, l2p2: Vector2, l1Seg: boolean?, l2Seg: boolean?): Vector2?
	local a1: number = l1p2.Y - l1p1.Y
	local b1: number = l1p1.X - l1p2.X
	local a2: number = l2p2.Y - l2p1.Y
	local b2: number = l2p1.X - l2p2.X
	local c1: number = a1 * l1p1.X + b1 * l1p1.Y
	local c2: number = a2 * l2p1.X + b2 * l2p1.Y
	local determinant: number = a1 * b2 - a2 * b1
	
	if (determinant == 0) then
		return -- lines are parallel
	end
	
	local x: number = (b2 * c1 - b1 * c2) / determinant
	local y: number = (a1 * c2 - a2 * c1) / determinant
	
	if (l1Seg or l2Seg) then
		if l1Seg and not (math.min(l1p1.X, l1p2.X) <= x 
			and x <= math.max(l1p1.X, l1p2.X) 
			and math.min(l1p1.Y, l1p2.Y) <= y 
			and y <= math.max(l1p1.Y, l1p2.Y)) 
		or l2Seg and not (math.min(l2p1.X, l2p2.X) <= x 
			and x <= math.max(l2p1.X, l2p2.X)
			and math.min(l2p1.Y, l2p2.Y) <= y 
			and y <= math.max(l2p1.Y, l2p2.Y)) then
			return  -- lines dont intersect
		end
	end
	
	return Vector2.new(x, y)
end

If you want the function to take the lengths of the lines or one of the lines into account, simply pass l1Seg and l2Seg as true respectively.

Test code
function V3ToV2(vector: Vector3): Vector2
	-- ignore Y component
	return Vector2.new(vector.X, vector.Z)
end

local l1, l2 = workspace.l1, workspace.l2

local p: Part = Instance.new("Part")
p.Shape = Enum.PartType.Ball
p.Anchored = true
p.Parent = workspace
p.Size = Vector3.new(2, 2, 2)

task.spawn(function()
	while task.wait() do
		local p1, p2, p3, p4 =
			(l1.CFrame * CFrame.new(0, 0, -l1.Size.Z/2)).Position,
			(l1.CFrame * CFrame.new(0, 0, l1.Size.Z/2)).Position,
			(l2.CFrame * CFrame.new(0, 0, -l2.Size.Z/2)).Position,
			(l2.CFrame * CFrame.new(0, 0, l2.Size.Z/2)).Position
		
		local point = FindLineIntersection2D(V3ToV2(p1), V3ToV2(p2), V3ToV2(p3), V3ToV2(p4), true, true)
		p.Transparency = point and 0 or 1
		if point then
			p.Position = Vector3.new(point.X, p1.Y, point.Y)
		end
	end
end)
4 Likes

Hello, it has been a little over a year, but recently I came across this post. If anyone was looking to find the interception of 3D vectors, here is the code. I want to say it took me hours to find it :sweat_smile:


https://gyazo.com/00deba47f31f44066e190eb5db7ce95d

local start1, end1 = workspace.Terrain.Attachment1.WorldPosition, workspace.Terrain.Attachment2.WorldPosition
local start2, end2 = workspace.Terrain.Attachment11.WorldPosition, workspace.Terrain.Attachment22.WorldPosition


-->> for checking intersections
local function IntersectingLines3D(line1Point, line1Direction, line2Point, line2Direction)
	local u = line1Direction:Cross(line2Direction)
	local denominator = u:Dot(u)

	-- Check if the lines are parallel
	if denominator == 0 then
		return false, Vector3.new() -- No intersection
	end

	local v = line2Point - line1Point
	local t = v:Cross(line2Direction):Dot(u) / denominator
	local intersectionPoint = line1Point + line1Direction * t

	return true, intersectionPoint -- Intersection point
end


-->> finds the intersect of 2 3D segment lines
local function intersect(point1Start, point1End, point2Start, point2End)
	local distanceAmountToBeTouching = .05 -- min distance to be seen as interceting 
	local vectDirection1 = (point1End-point1Start) -- direction from point 1
	local vectDirection2 = (point2End-point2Start) -- direction from point 2
	local failed1, pointOnLine1 = IntersectingLines3D(point1Start, vectDirection1, point2Start, vectDirection2) -- point on ray relative to second ray
	local failed2, pointOnLine2 = IntersectingLines3D(point2Start, vectDirection2, point1Start, vectDirection1) -- point on ray relative to first ray
	if (not failed1) or (not failed2) then return false end -- failed to find one return false
	
	
	-->> if the manigute does exceed the segment return false
	if (pointOnLine1-(point1Start+(vectDirection1/2))).Magnitude > vectDirection1.Magnitude/2 then return false end
	if (pointOnLine2-(point2Start+(vectDirection2/2))).Magnitude > vectDirection2.Magnitude/2 then return false end
	
	-->> plots points
	workspace.Terrain.Attachment01.WorldPosition = pointOnLine1
	workspace.Terrain.Attachment02.WorldPosition = pointOnLine2
	
	-->> if the distance from each other is close enough
	return (pointOnLine1-pointOnLine2).Magnitude <= distanceAmountToBeTouching
end

local intersected = intersect(start1, end1, start2, end2)


print(intersected)
4 Likes