How can I find the distance from one part to another but not from the centre of these parts?

Hello everyone, I hope you are having a good day.

So my question is if its possible to find the distance between one part to another, but not from their centres like:

local distanceBetween = (secondPart.Position - firstPart.Position).Magnitude

But like how actually close they are from workspace, so if the part is at an angle, instead of finding the centre of that part and then using it to calculate distance, I want to find the closest distance from any point on that part to any point on the other part. Like actually how close they are in the workspace and not simply from their centre positions.

I hope this makes sense and thank you.

can’t you just cast a ray from part a to part b and check result.Distance? edit: With filterdescendantinstances set to part b and filtertype to include.

local parta =
local partb = 

local params = RaycastParams.new()
params.FilterDescendantsInstances = {partb}
params.FilterType = Enum.RaycastFilterType.Include

local result = workspace:Raycast(parta.Position, (partb.Position - parta.Position).Unit, params)
print(result.Distance)--your distance.

The answer is a bit complicated I know where to start but doing it would require a lot of thinking.
2 box parts would be harder than spheres and cylinders, but is probably what you want.
To start you want to localize one part with respect to the other part.

local function minDistance(part1 : BasePart, part2 : BasePart)
	local size1, size2 = part1.Size/2, part2.Size/2 -- size half is easier to compare with
	local cframe2 = part1.CFrame:Inverse() * part2.CFrame -- localized part2 cframe
	-- compare size1 at origin to size2 at cframe2
	
end

When you localize or object space the part2 cframe, you will treat part1 cframe as the origin, or CFrame.identity.

My next thought is to figure out the corner closest to the origin.

After that is cases where it falls on a line.

This wouldn’t work since the rays would hit in the middle instead of the closest points. But it would be closer than just comparing center distances. And in that thinking you might want 2 raycasts in both directions and compare resulting positions for slightly more accuracy.

Wow, okay so I tried to complete your function: (tell me if this is correct)

local function hisDist(part1: BasePart, part2: BasePart): number
	local size1, size2 = part1.Size/2, part2.Size/2
	local cframe2 = part1.CFrame:Inverse() * part2.CFrame
	
	local x, y, z = math.abs(cframe2.X) - (size2.X + size1.X),
		math.abs(cframe2.Y) - (size2.Y + size1.Y),
		math.abs(cframe2.Z) - (size2.Z + size1.Z)
	
	return math.sqrt(math.max(x, 0)^2 + math.max(y, 0)^2 + math.max(z, 0)^2)
end

and then I made this:


local start = os.clock()
print(generalDist(part1, part2))
print("Time: ", os.clock() - start)

start = os.clock()
print(myDist(part1, part2))
print("Time: ", os.clock() - start)

start = os.clock()
print(hisDist(part1, part2))
print("Time: ", os.clock() - start)

where generaldist is the (pos2 - pos1).Magnitude, mydist is my function and hisdist is your function.
Your function returns ~12.46, mine returns ~13.84 and the general distance returns ~14.71.

Yours seems to be the most accurate, but for some reason it is also the slowest, I ran this script 100 times and general distance is 0.0001s slower than mine, yours is 0.0001/0.0002s slower than mine, but I’m assuming yours is also the most optimal because I haven’t checked how much memory raycasting uses, if you were to run this every tick in like .HeartBeat, I’m just assuming yours would be optimal there. The difference is also very small.

So yes you’re completely right, haven’t thought of that.

If you you really want accuracy of everything else I think you would need to do two rays.

ray1HitLoc = result of ray fired from part1 to part2. Should give you the position of where the ray hit the outside part2, fired from the inside of part1.
ray2HitLoc = Ray fired from ray1HitLoc towards part1. This would be a ray fired from the outside of part2(ray1HitLoc) to where it hits the outside of part1.

Your function does not work when I tested it in studio. It gives a number way too big.
Visual parts:


Measured distance (grey part size):
image
Function result:

Code implementation:

local function dist(part1: BasePart, part2: BasePart): number
	local size1, size2 = part1.Size/2, part2.Size/2
	local cframe2 = part1.CFrame:Inverse() * part2.CFrame

	local x, y, z =
		math.abs(cframe2.X) - (size2.X + size1.X),
		math.abs(cframe2.Y) - (size2.Y + size1.Y),
		math.abs(cframe2.Z) - (size2.Z + size1.Z)

	return math.sqrt(math.max(x, 0)^2 + math.max(y, 0)^2 + math.max(z, 0)^2)
end

local part1 = workspace:WaitForChild("Part1")
local part2 = workspace:WaitForChild("Part2")
print(dist(part1, part2))

This monster seems to be accurate.

local function dist(part1: BasePart, part2: BasePart): number
	local size1, size2 = part1.Size/2, part2.Size/2
	local cframe2 = part1.CFrame:Inverse() * part2.CFrame

	local rv = cframe2.RightVector * size2.X
	local uv = cframe2.UpVector * size2.Y
	local lv = cframe2.LookVector * size2.Z
	local center = cframe2.Position
	local minCorner = Vector3.new(
		math.min(
			math.abs(center.X + rv.X + uv.X + lv.X),
			math.abs(center.X + rv.X + uv.X - lv.X),
			math.abs(center.X + rv.X - uv.X + lv.X),
			math.abs(center.X + rv.X - uv.X - lv.X),
			math.abs(center.X - rv.X + uv.X + lv.X),
			math.abs(center.X - rv.X + uv.X - lv.X),
			math.abs(center.X - rv.X - uv.X + lv.X),
			math.abs(center.X - rv.X - uv.X - lv.X)
		),
		math.min(
			math.abs(center.Y + rv.Y + uv.Y + lv.Y),
			math.abs(center.Y + rv.Y + uv.Y - lv.Y),
			math.abs(center.Y + rv.Y - uv.Y + lv.Y),
			math.abs(center.Y + rv.Y - uv.Y - lv.Y),
			math.abs(center.Y - rv.Y + uv.Y + lv.Y),
			math.abs(center.Y - rv.Y + uv.Y - lv.Y),
			math.abs(center.Y - rv.Y - uv.Y + lv.Y),
			math.abs(center.Y - rv.Y - uv.Y - lv.Y)
		),
		math.min(
			math.abs(center.Z + rv.Z + uv.Z + lv.Z),
			math.abs(center.Z + rv.Z + uv.Z - lv.Z),
			math.abs(center.Z + rv.Z - uv.Z + lv.Z),
			math.abs(center.Z + rv.Z - uv.Z - lv.Z),
			math.abs(center.Z - rv.Z + uv.Z + lv.Z),
			math.abs(center.Z - rv.Z + uv.Z - lv.Z),
			math.abs(center.Z - rv.Z - uv.Z + lv.Z),
			math.abs(center.Z - rv.Z - uv.Z - lv.Z)
		)
	)
	
	return (minCorner - size1):Max(Vector3.zero).Magnitude
	
	--[=[
	return math.sqrt(
		  math.max(0, minCorner.X - size1.X)^2
		+ math.max(0, minCorner.Y - size1.Y)^2
		+ math.max(0, minCorner.Z - size1.Z)^2
	)
	--]=]
end


local part1 = workspace:WaitForChild("Part1")
local part2 = workspace:WaitForChild("Part2")


print(dist(part1, part2))

A little unoptimized I would say.

1 Like

Alright so I thought about ways to optimize and could only think of 1 way and it did not work in practice. So this is my final function. I was able to achieve some optimization from native code generation, so I would recommend using that with this function.
image[from ScriptProfiler]

@native
local function dist(part1: BasePart, part2: BasePart): number
	local size1, size2 = part1.Size/2, part2.Size/2
	local cframe2 = part1.CFrame:Inverse() * part2.CFrame

	local rv = cframe2.RightVector * size2.X
	local uv = cframe2.UpVector * size2.Y
	local lv = cframe2.LookVector * size2.Z
	local center = cframe2.Position

	local minCorner = Vector3.new(
		math.min(
			math.abs(center.X + rv.X + uv.X + lv.X),
			math.abs(center.X + rv.X + uv.X - lv.X),
			math.abs(center.X + rv.X - uv.X + lv.X),
			math.abs(center.X + rv.X - uv.X - lv.X),
			math.abs(center.X - rv.X + uv.X + lv.X),
			math.abs(center.X - rv.X + uv.X - lv.X),
			math.abs(center.X - rv.X - uv.X + lv.X),
			math.abs(center.X - rv.X - uv.X - lv.X)
		),
		math.min(
			math.abs(center.Y + rv.Y + uv.Y + lv.Y),
			math.abs(center.Y + rv.Y + uv.Y - lv.Y),
			math.abs(center.Y + rv.Y - uv.Y + lv.Y),
			math.abs(center.Y + rv.Y - uv.Y - lv.Y),
			math.abs(center.Y - rv.Y + uv.Y + lv.Y),
			math.abs(center.Y - rv.Y + uv.Y - lv.Y),
			math.abs(center.Y - rv.Y - uv.Y + lv.Y),
			math.abs(center.Y - rv.Y - uv.Y - lv.Y)
		),
		math.min(
			math.abs(center.Z + rv.Z + uv.Z + lv.Z),
			math.abs(center.Z + rv.Z + uv.Z - lv.Z),
			math.abs(center.Z + rv.Z - uv.Z + lv.Z),
			math.abs(center.Z + rv.Z - uv.Z - lv.Z),
			math.abs(center.Z - rv.Z + uv.Z + lv.Z),
			math.abs(center.Z - rv.Z + uv.Z - lv.Z),
			math.abs(center.Z - rv.Z - uv.Z + lv.Z),
			math.abs(center.Z - rv.Z - uv.Z - lv.Z)
		)
	)

	return (minCorner - size1):Max(Vector3.zero).Magnitude
end
1 Like