How do I get the percentage of a part that's touching/inside another part?

Since im the image it shows the part is half in half out, would thet be 50%?

3 Likes

That’s just an example for illustrative purposes, the sizes and positions of the actual parts are way different. I need to figure it out with a script.

1 Like

Try see if chat gbt can help because im not too good at CFrames either

1 Like

All I was able to get out of it was this, which works unless the parts are rotated at all.

-- Assume you have references to Part A and Part B
local partA = workspace.PartA
local partB = workspace.PartB

-- Function to calculate overlap percentage
local function calculateOverlapPercentage(part1, part2)
    local sizeA = part1.Size
    local sizeB = part2.Size
    local positionA = part1.Position
    local positionB = part2.Position

    local halfSizeA = sizeA / 2
    local halfSizeB = sizeB / 2

    local overlapX = math.min(positionA.x + halfSizeA.x, positionB.x + halfSizeB.x) - math.max(positionA.x - halfSizeA.x, positionB.x - halfSizeB.x)
    local overlapY = math.min(positionA.y + halfSizeA.y, positionB.y + halfSizeB.y) - math.max(positionA.y - halfSizeA.y, positionB.y - halfSizeB.y)
    local overlapZ = math.min(positionA.z + halfSizeA.z, positionB.z + halfSizeB.z) - math.max(positionA.z - halfSizeA.z, positionB.z - halfSizeB.z)

    local overlapVolume = math.max(0, overlapX) * math.max(0, overlapY) * math.max(0, overlapZ)
    local totalVolume = sizeA.x * sizeA.y * sizeA.z

    local overlapPercentage = (overlapVolume / totalVolume) * 100
    return overlapPercentage
end

-- Calculate and print the overlap percentage
local percentage = calculateOverlapPercentage(partA, partB)
print("Overlap Percentage: " .. percentage .. "%")

Thanks for trying to help though!

1 Like

this might be another case of the xy problem
this is like… a super duper complex task… and we need a bit more detail on why you need this in the first place so that we could know if theres something more simple we could do or how precise this needs to be and whether or not rotation and other stuff needs to be accounted for

this is what shows up when you want to know when two rotated cubes even INTERSECT with each other…


i assume that this looks like an alien language to both of us… so detecting whether they overlap or not (without any external API) is pretty hard… LET ALONE getting the percentage of the overlap

girlie you might need another solution :sob:

3 Likes

but Part B is touching only 1/8th of Part A

2 Likes

so i did a bit of digging cuz I gotta help a sister out and came across this reddit post in the unity subreddit that leads you to this and that
which reminded me that roblox has a similar CSG manipulation thingy thing
this is where we start cooking
looking for a way to find the intersection i dug and found this announcement which actually lets you have the overlap between the two points become its own part
which led me to this function inside the documentation which returns the intersection instance

so…

  1. if you can get the intersection instance
  2. get its size
  3. and somehow compare it to the size of the two parts to get the percentage…
  4. you got this down!

(although, if you need the result fast… this aint the solution for you… the function yields and generally doing cursed CSG stuff like this at runtime goes wrong very easily…)
[only use this method if you fr just want to account for multiple different shapes and rotations]

2 Likes

Establish a bounding volume for each part. If the bounding boxes don’t interact, the parts aren’t touching / inside each other. If it does interact, using Separating Axis Theorem for convex shapes or Gilbert-Johnson-Keerthi algorithm would work. Once the algorithm detects a collision, you can compute the volume of intersection between two parts. To get the percentage, the formula is:

(intersection volume / total volume of part) * 100

Roblox has collision detection by default so, I would use that to minimize computational heavy-lifting.

Here’s a super simple implementation that probably doesn’t work completely but, should get you in the right direction:

-- Bounding box intersection
function checkBoundingBoxIntersection(part1, part2)
    local part1Min = part1.Position - part1.Size/2
    local part1Max = part1.Position + part1.Size/2
    local part2Min = part2.Position - part2.Size/2
    local part2Max = part2.Position + part2.Size/2
    return (part1Min.X < part2Max.X and part1Max.X > part2Min.X) and
           (part1Min.Y < part2Max.Y and part1Max.Y > part2Min.Y) and
           (part1Min.Z < part2Max.Z and part1Max.Z > part2Min.Z)
end

-- Intersection Volume via finding overlapping dimensions
function calculateIntersectionVolume(part1, part2)
    local overlapX = math.max(0, math.min(part1.Position.X + part1.Size.X/2, part2.Position.X + part2.Size.X/2) - math.max(part1.Position.X - part1.Size.X/2, part2.Position.X - part2.Size.X/2))
    local overlapY = math.max(0, math.min(part1.Position.Y + part1.Size.Y/2, part2.Position.Y + part2.Size.Y/2) - math.max(part1.Position.Y - part1.Size.Y/2, part2.Position.Y - part2.Size.Y/2))
    local overlapZ = math.max(0, math.min(part1.Position.Z + part1.Size.Z/2, part2.Position.Z + part2.Size.Z/2) - math.max(part1.Position.Z - part1.Size.Z/2, part2.Position.Z - part2.Size.Z/2))
    return overlapX * overlapY * overlapZ
end

-- Percentage of part that is touching other part
function calculatePercentage(part, intersectionVolume)
    local totalVolume = part.Size.X * part.Size.Y * part.Size.Z
    return (intersectionVolume / totalVolume) * 100
end
3 Likes
function calculateOverlapPercentage(box1, box2)
	local size1, size2 = box1.Size, box2.Size
	local position1, position2 = box1.Position, box2.Position

	local x1Min, x1Max = position1.X - size1.X / 2, position1.X + size1.X / 2
	local y1Min, y1Max = position1.Y - size1.Y / 2, position1.Y + size1.Y / 2
	local z1Min, z1Max = position1.Z - size1.Z / 2, position1.Z + size1.Z / 2

	local x2Min, x2Max = position2.X - size2.X / 2, position2.X + size2.X / 2
	local y2Min, y2Max = position2.Y - size2.Y / 2, position2.Y + size2.Y / 2
	local z2Min, z2Max = position2.Z - size2.Z / 2, position2.Z + size2.Z / 2

	local xOverlap = math.max(0, math.min(x1Max, x2Max) - math.max(x1Min, x2Min))
	local yOverlap = math.max(0, math.min(y1Max, y2Max) - math.max(y1Min, y2Min))
	local zOverlap = math.max(0, math.min(z1Max, z2Max) - math.max(z1Min, z2Min))

	local overlappingVolume = xOverlap * yOverlap * zOverlap
	local overlapPercentage = (overlappingVolume / (size1.X * size1.Y * size1.Z)) * 100
	return overlapPercentage
end

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

print("Percentage of Box Inside Other Box: " .. overlapPercentage .. "%")

Sanjay Seems we took the same approach. :laughing:
Almost the same variables too, sweet.

2 Likes

What kind of math can I study to learn more about this? Is this linear algebra?

aaah yeah sorry!! i never realized it was such a complicated task lol, i’m working on trying your :IntersectAsync method (which looks super promising, and i really appreciate the digging!!), but while i do that, i can for sure provide some more information!
i have a building system right now, and i need to be able to stop players from placing a build that’s like too far inside of another part if that makes sense?? like if more than 50% of the part that the player is placing is covered up by other parts placed by other players (or non-player built parts), then the player shouldn’t be able to place it.
this doesn’t need to be too precise, it can probably safely have a margin of error of like 10-15% at the highest.

@sanjay2003 and @2112Jay – y’all’s code would work, but only when rotation isn’t taken into account, which i forgot to mention that I need in my original post! i really do appreciate all of your help, and I’ll update this thread whenever i figure anything out!!!

oops nevermind ignore past me saying that a distance check would work does not account for non equilateral shapes :sob:

it definitely looks like there could be a simpler solution though, but thats when some teamwork or someone much smarter than me might need to step in haha

the :IntersectAsync should just be a temporary solution until you can find a simpler one

2 Likes

Are your parts axis aligned? Because that is obviously an easier special case where the intersection volume is also a rectangular prism.

For two arbitrarily-oriented parts (parts rotated any imaginable way), your best option is to find the edge-face intersection points first, which is line-plane intersection with some bounds checks, and then once you have all the points, you can do a convex decomposition of the intersection volume into tetrahedrons by picking a point in the center of the volume and dividing the volume up into tetrahedrons of all the corners and intersection points to that central point. There is an explicit formula for the volume of a tetrahedron. You can Google convex decomposition for more resources; the generalized n-dimensional form of this technique is called simplex decomposition.

2 Likes

ur so good, don’t worry abt it! i was doing some benchmarking, and it looks like :IntersectAsync with two cuboids takes just about 0.01 seconds, so it’s not too bad! there’s gotta be a simpler solution though, i agree! i can’t be the first person with this issue lol

1 Like

This is not as alien as you think. In your screenshot, h1, h2, h3 are what you know as Part.Size.X, Y, Z. And the basis e1, e2, e3, is just CFrame.RightVector, UpVector, LookVector. The 8 equations are just the cube center plus the diagonal to each corner.

Computational Geometry, from which many subproblems are going to involve linear algebra, but also geometry and trigonometry (and if you start working with more complex meshes, also some topology, graph theory, and measure theory).

1 Like

this would probably work! it sounds like you know what you’re talking about, but i borderline failed geometry freshman year, so this is definitely above my area of expertise.
it’ll probably help someone smarter than me though, thank you so much!

thanks for the explanation :smile: :+1:

yo thats actually much faster than I expected lmao

i made a function that does this! i can’t vouch for the efficiency of it, but from my testing, it works with a margin of error of <0.01%. It should run in under 0.01 seconds aswell, but that might vary.

local function GetOverlapPercents(PartA,PartB)
	local Intersection = PartA:IntersectAsync({PartB})
	if not Intersection then
		-- either parts are 100% perfectly overlapping eachother or the parts aren't touching at all
		for _,Part in ipairs(PartA:GetTouchingParts()) do
			if Part == PartB then return 100,100 end
		end
		return 0,0
	end
	local IntVol = Intersection:GetMass() / PhysicalProperties.new(Intersection.Material).Density
	local PartAVol = PartA:GetMass() / PhysicalProperties.new(PartA.Material).Density
	local PartBVol = PartB:GetMass() / PhysicalProperties.new(PartB.Material).Density
	
	local PartAIntPercentage = IntVol / PartAVol
	local PartBIntPercentage = IntVol/ PartBVol
	return PartAIntPercentage * 100, PartBIntPercentage * 100	
end

local AOverlap,BOverlap = GetOverlapPercents(workspace.PartA,workspace.PartB)
print(AOverlap.."% of PartA is overlapped by PartB.")
print(BOverlap.."% of PartB is overlapped by PartA.")

thanks @syyIvi for your help!! i wouldn’t have been able to think about that otherwise lol
and thank you to everyone else, really appreciate it!! :sparkling_heart:

4 Likes

make sure to consider any complications that come with other complex cases like different shapes + rotations

glad I could help!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.