EDIT: As of 2023, Tools are now Models, so you can just call GetBoundingBox
on them!
In lieu of having said API, the following (well optimized) code from the Studio draggers can be used to compute a bounding box without making a temporary model:
local function computeBoundingBox(basisCFrame: CFrame, allParts: {BasePart}, allAttachments: {Attachment})
local inverseBasis = basisCFrame:Inverse()
local xmin, xmax = math.huge, -math.huge
local ymin, ymax = math.huge, -math.huge
local zmin, zmax = math.huge, -math.huge
local terrain = Workspace.Terrain
for _, part in ipairs(allParts) do
if part ~= terrain then
local cframe = part.CFrame
local size = part.Size
local sx, sy, sz = size.X, size.Y, size.Z
-- Calculation for bounding box in the space of basisCFrame1
local localCFrame1 = inverseBasis * cframe -- put cframe in our local basis
local _, _, _,
t00, t01, t02,
t10, t11, t12,
t20, t21, t22 = localCFrame1:components()
local hw = 0.5 * (math.abs(sx * t00) + math.abs(sy * t01) + math.abs(sz * t02))
local hh = 0.5 * (math.abs(sx * t10) + math.abs(sy * t11) + math.abs(sz * t12))
local hd = 0.5 * (math.abs(sx * t20) + math.abs(sy * t21) + math.abs(sz * t22))
local x, y, z = localCFrame1.X, localCFrame1.Y, localCFrame1.Z
xmin = math.min(xmin, x - hw)
xmax = math.max(xmax, x + hw)
ymin = math.min(ymin, y - hh)
ymax = math.max(ymax, y + hh)
zmin = math.min(zmin, z - hd)
zmax = math.max(zmax, z + hd)
end
end
for _, attachment in ipairs(allAttachments) do
local localPosition = basisCFrame:PointToObjectSpace(attachment.WorldPosition)
local x, y, z = localPosition.X, localPosition.Y, localPosition.Z
xmin = math.min(xmin, x)
xmax = math.max(xmax, x)
ymin = math.min(ymin, y)
ymax = math.max(ymax, y)
zmin = math.min(zmin, z)
zmax = math.max(zmax, z)
end
local boundingBoxOffset = Vector3.new(
0.5 * (xmin + xmax),
0.5 * (ymin + ymax),
0.5 * (zmin + zmax)
)
local boundingBoxSize = Vector3.new(
xmax - xmin,
ymax - ymin,
zmax - zmin
)
return boundingBoxOffset, boundingBoxSize
end