Bounding box of a rectangle

I’m trying to find the bounding box of a rotated basepart. This is what is came up with:

Where x is the corners i marked with “x” and 5 and 3 are just example sizes for the rectangle. I know this calculation will only work for a rectangle and not a rectangular prism but i think it won’t get much more complicated to get it to work in 3d, just some more cosines and sines. But when i try this in roblox (in the command bar), it works fine when there is no rotation, but when i rotate 90 degrees, cos(x) * 3 should result in 0, so the result should only be sin(x) * 5 (sin(90) = 1 so the resul would just be 5, which is logical since you rotated it 90 degrees) but in roblox it outputs this:

The code i used:

local p = game.Workspace.P --P is a default rectangular part
print((math.sin(p.Rotation.Y) * p.Size.X) + (math.cos(p.Rotation.Y) * p.Size.Z)) --Calculation from the image except 5 and 3 are changed with variables.

When it’s rotated 0 or 180 degrees along Y it outputs this:

The parts size is 2 along Z so thats what it’s supposed to do, but when it is turned 90 degrees it outputs this:

As you can see the part is rotated 90°:
image

It should output 4 instead (the size of the part along X).

Does someone know how to fix this? Is there something wrong with my code or my math?
Thanks for reading!

3 Likes

Unfortunately, 3D rotations get a lot more complicated. It’s possible, just hard!

I’ll check on your math later, but in the meantime I want to offer this alternative way to get the bounding box size which works for any orientation in 3D:

2 Likes

Thanks, i’m now on my phone so i don’t have acces to rblx studio but i will try your code as soon as i can!

Nvm i figured out my problem! I was using degrees but didn’t know math.sin() and math.cos() take radians as input. Thanks for responding but your code only works when i rotate the part 90 degrees. That would be good for a temporary solution but in the future i want to give more snap options for rotating parts, if i run into any problems with the code i posted in the OP i will use your code as a temporary solution while i develop other things until i find another solution!

You’re right, missed that! I suppose you’d have to get all the vertices of the part in world space and then find the min/max on each axis:

slow code
local VERTICES = {
  Vector3.new(1, 1, 1),
  Vector3.new(1, 1, -1),
  Vector3.new(1, -1, 1),
  Vector3.new(1, -1, -1),
  Vector3.new(-1, 1, 1),
  Vector3.new(-1, 1, -1),
  Vector3.new(-1, -1, 1),
  Vector3.new(-1, -1, -1),
}

-- returns the size of the part's bounds
local function GetBounds(part: BasePart, obj: {Vector3}?): (Vector3, Vector3)
  obj = obj or VERTICES
  local halfSize = part.Size / 2

  local minX, maxX = math.huge, -math.huge
  local minY, maxY = math.huge, -math.huge
  local minZ, maxZ = math.huge, -math.huge

  for i, v in ipairs(obj) do
    local vert = part.CFrame:PointToWorldSpace(v * halfSize)
    local x, y, z = vert.X, vert.Y, vert.Z
    if x < minX then minX = x end
    if x > maxX then maxX = x end
    if y < minY then minY = y end
    if y > maxY then maxY = y end
    if z < minZ then minZ = z end
    if z > maxZ then maxZ = z end
  end

  return Vector3.new(maxX - minX, maxY - minY, maxZ - minZ)
end

Faster version: Absolute size of a part - #22 by nicemike40

This might be 10 days ago and solved already. But I also found a solution that works with multiple parts, however this is twice as slow.

local function GetBounds(Parts: {BasePart}): Vector3
	local model = Instance.new("Model")
	for _, v in ipairs(Parts) do
		local clone = Instance.new("Part",model)
		clone.Size = v.Size
		clone.CFrame = v.CFrame
	end
	model.WorldPivot = CFrame.identity
	return select(2,model:GetBoundingBox())
end