Detect if Part FULLY Contains Another Part

Hey there! I’m looking for a way to determine if a part is FULLY inside of another part, not just touching. I’ve got a way to go about this, but it would be costly and performance heavy, so I’d really prefer to use another method.

In basic terms, I want to see if this circle:
image

is fully encompassed within the grey part, or if it exceeds the boundaries:

Any assistance or resources you can provide would be very helpful.

1 Like

Why do you want to do this? If you can go into detail of how this will be beneficial for you (like what you’ll use it for), myself or others might be able to provide a more performant option.

I plan to use this function to query potential positions for creating (miniaturized) buildings. I need something that I can run A LOT without too much kick. My game features a world map made up of 100’s of provinces each with unique shapes, some abnormal and some box-like. I’m using a method I found previously on the DevForum to get a random position based off of the province’s point of origin, and now I need to determine whether this random position is suitable to build the construction on.

Probably a bad idea but what about using a super small raycast on the corners or edges. If it hits within the part, its safe, if it hits outside the area/nothing, its not inside and needs to be nudged in/readjusted then rechecked :man_shrugging:

Probably bad idea of course, there’s probably a function but remembering names aint my thing :sweat_smile: . If you’re creating miniaturized buildings/a load of miniaturized buildings, how about creating them on the client as to the server to minimize load? If you want other players to see it, just FireAllClients

It’s not the buildings that would cause the problems, running this query function is what’s leading to issues.

I don’t think ray casting would be a viable option.

1 Like

Not a scripter, but maybe you could circle the building’s sides with invisible parts and detect if the part in question reaches into the surrounding parts. Although with hundreds of buildings that may cause lag and overlapping.

Basically, what you’ll want to do is check each side of your cylinder to make sure its edges are in bounds of the part. What I do is check the unit direction of the edge of the base part compared to the edge of the other part. Since I suck at explaining things here are some images to illustrate what I mean:

This example would be valid because the endpoint of the red line is within bounds of the green line.

This example would be invalid because the end point of the red line exceeds the end point of the green line.

When you’re actually using this technique in code, it’ll look something like this: (Note: this function is fairly simplistic and is more of an example; it doesn’t work with rotated parts. If you’re using parts that have been rotated then you’ll have to do some funky math to find the proper side positions)

local BasePart = workspace.BasePart -- The part that is acting as our boundaries
local ControlPart = workspace.ControlPart -- The part we'll be checking

local Vectors = {
	Vector3.new(0,0,1),
	Vector3.new(0,0,-1),
	Vector3.new(1,0,0),
	Vector3.new(-1,0,0),
	Vector3.new(0,1,0),
	Vector3.new(0,-1,0)
}

local function CheckIfPartIsInsideAnotherPart () --Pls rename this
	for _, Vector in pairs(Vectors) do
		local BaseEnd = BasePart.Position + (BasePart.Size * Vector)/2 --Finds the edge of the base part
		local ControlEnd = ControlPart.Position + (ControlPart.Size * Vector)/2 --Finds the edge of the control part
		
		local BaseDirection = (BasePart.Position - BaseEnd).Unit
		local ControlDirection = (BaseEnd - ControlEnd).Unit * BaseDirection
		
		--What we'll end up doing is checking the unit direction of the base part and the control part, compared it to the BaseDirection 
		--What ends up happening is if the direction is negative, it's in bounds. if it's positive, it's out of bounds
		if ControlDirection.X > 0 or ControlDirection.Y > 0 or ControlDirection.Z > 0 then
			return false
		end
	end 
	return true
end

print(CheckIfPartIsInsideAnotherPart())

Hope this helps!

6 Likes

ive created a module just for this situlation.

https://www.roblox.com/library/8619423153/PartChecker

1 Like

The module isn’t for sale, can’t get it.

1 Like

I can’t seem to replicate this with your code, is there anything specific I need to do with the parts?

It should be fairly straight forward, just make sure the parts aren’t rotated. Can you send a screenshot of what the parts/code looks like?

Must have messed something setting it up the first time, it works perfectly now. Thanks for the help.

1 Like

I haven’t tested this to see if my method works 100%, however I made it so that it can detect if any part (regardless of rotation) is encompassed by a boundary, using Absolute size of a part - #22 by nicemike40 and @zeuxcg’s code for AABBs

I also edited the format of it a bit to copy a game I am testing with… …I apologize

local allVectors = {
	Vector3.new(0,0,1),
	Vector3.new(0,0,-1),
	Vector3.new(1,0,0),
	Vector3.new(-1,0,0),
	Vector3.new(0,1,0),
	Vector3.new(0,-1,0)
}

function GetWorldSize(part)
	local abs = math.abs

	local cf = part.CFrame
	local size = part.Size
	local sx, sy, sz = size.X, size.Y, size.Z

	local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = cf:components() 

	local wsx = abs(R00) * sx + abs(R01) * sy + abs(R02) * sz
	local wsy = abs(R10) * sx + abs(R11) * sy + abs(R12) * sz
	local wsz = abs(R20) * sx + abs(R21) * sy + abs(R22) * sz

	return Vector3.new(wsx, wsy, wsz)
end

function CheckIfPartIsInsideAnotherPart(boundary, part)
	for _, Vector in pairs(allVectors) do
		local boundaryGlobalSize = GetWorldSize(boundary)
		local partGlobalSize = GetWorldSize(part)
		
		local BaseEnd = boundary.Position + (boundaryGlobalSize * Vector) / 2
		local ControlEnd = part.Position + (partGlobalSize * Vector) / 2

		local BaseDirection = (boundary.Position - BaseEnd).Unit
		local ControlDirection = (BaseEnd - ControlEnd).Unit * BaseDirection

		if ControlDirection.X > 0 or ControlDirection.Y > 0 or ControlDirection.Z > 0 then
			return false
		end
	end 
	
	return true
end

Lol no problem you’re welcome to reformat my code any way you’d like. Although do note I wrote that like a year and a half ago so it’s a bit outdated now lol.

If you want though you can use the current version I use now which is much more simplified and also accounts for rotation.

local function IsPointInVolume(point: Vector3, volumeCenter: CFrame, volumeSize: Vector3): boolean
	local volumeSpacePoint = volumeCenter:PointToObjectSpace(point)
	return volumeSpacePoint.X >= -volumeSize.X/2
		and volumeSpacePoint.X <= volumeSize.X/2
		and volumeSpacePoint.Y >= -volumeSize.Y/2
		and volumeSpacePoint.Y <= volumeSize.Y/2
		and volumeSpacePoint.Z >= -volumeSize.Z/2
		and volumeSpacePoint.Z <= volumeSize.Z/2
end

local function IsPartInBoundry (part: Part, boundryPart: Part): boolean
	for x = -1, 1, 2 do
		for z = -1, 1, 2 do
			for y = -1, 1, 2 do
				local corner = part.Position 
					+ part.Size.X/2 * x * part.CFrame.RightVector
					+ part.Size.Y/2 * y * part.CFrame.UpVector
					+ part.Size.Z/2 * x * part.CFrame.LookVector
				
				if not IsPointInVolume(corner, boundryPart.CFrame, boundryPart.Size) then
					return false
				end
			end
		end
	end	
	
	return true
end

7 Likes