How to get the distance between peak and trough of a part?

How would you retrieve the distance from top-to-bottom (represented by the red lines) of the following part with different orientations?

part.Size.Y does not work in this scenarios as it returns the Y value relative to the part itself.

1 Like
local AbsoluteYSize = math.abs(workspace.Part.Size.Y)
print(AbsoluteYSize)
2 Likes

Absolute in-terms of orientation, not the number itself.

2 Likes

Ever tried raycasting from above and from below? Acquire both points and do the math.

Woops, alright. I have realized that you want the absolute Y-size from the peak of the part to the bottom of it.

Do you mean how much it has turned or how to get the Absolute Y Axis Size thanks to the Absolute Orientation

I’m asking it this way because I don’t understand the problem very well. If you turn the part then the Absolute Y Size is the same, because you don’t change the Part.Size.Y, you only change the Part.Orientation.Y. (In other words, the Absolute Y Size remains the same, or am I wrong?

If you rotate a part, it’s relative Y-size will remain the same, however it’s absolute Y-size relative to the workspace will change. It’s this size (the distance between the top and bottom of the part relative to the workspace, represented by the red lines in the picture) I’m trying to find using the simplest method.

I’m not smart, but have you tried that?

local Top = Vector3.fromNormalId(Part.TopSurface)
local Back = Vector3.fromNormalId(Part.BackSurface)
local AbsoluteY = math.abs(Top - Back)

That doesn’t apply to all orientations. The goal is to acquire the bottom Y point from global Y-axis and also the top Y point, to calculate the height.

Also the code doesn’t work, because the argument accepts enums.

But the Vector3.FromNormalId() transforms the enum into a vector, why shouldn’t it?
Edit: I have understood it.

Hey! This is a really good question; what I ended up doing is found each corner of your part, then I took the highest point and the lowest point & subtracted to two to get the distance.

I took some math from Stravants Gap Fill to grab the vertices.

Heres what I came up with!

local function getCorners(part)
	local size, cframe, pos = part.Size, part.CFrame, part.CFrame.p
	local x, y, z = size.X/2, size.Y/2, size.Z/2
	local r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12 = cframe:components()
	local xV, yV, zV = Vector3.new(r4, r7, r10), Vector3.new(r5, r8, r11), Vector3.new(r6, r9, r12)
	local xVX, yVY = xV * x, yV * y
	local Corners = {
		pos + xVX + yVY + zV * z, pos + xVX + yVY - zV * z,
		pos - xVX + yVY + zV * z, pos - xVX + yVY - zV * z,
		pos + xVX - yVY + zV * z, pos + xVX - yVY - zV * z,
		pos - xVX - yVY + zV * z, pos - xVX - yVY - zV * z
	}
	return Corners
end

while wait() do
	local Corners = getCorners(game:GetService("Workspace"):WaitForChild("Selection"))
	if Corners then
		local y1, y2 = -math.huge, math.huge
		for _,pos in pairs(Corners) do
			local Y = pos.Y
			if Y > y1 then
				y1 = Y
			end
			if Y < y2 then
				y2 = Y
			end
		end
		local diff = y1 - y2
		print("Difference : "..diff)
	end
end

Keep in mind that this will work on every axis as well; https://i.imgur.com/XmaYUZO.png

4 Likes

The above solution is very clever. The way I would have done it is using RayCasting. First I would define the “axis” to measure the height of, then I would use Model:GetBoundingBox to get the “maximum size” using the pythagorean theorem. Next I would RayCast from this position (offset by a tiny amount) to the center of the part which would give me the position of the edge of the part. I would repeat this for the opposite side of the part giving me two positions. Next I’d just get the distance between the two points.

2 Likes

I don’t get it.

Is it possible to get the position of the corners of the part? If so, could you explain it better?

That function will return a table full of each corner’s position!

1 Like

Why this? Is it very important?

We use that in order to compared it to all of the other Y values and see if its the highest or lowest one, if it is then we store it.

1 Like

Talk about overcomplicating things.

cf = part.CFrame
sz = part.Size
a = cf.TopVector * sz.Y
b = cf.LookVector * sz.Z
c = cf.RightVector * sz.X
yTop = math.max(math.max(a.y, b.y), c.y)
YBottom = math.min(math.min(a.y, b.y), c.y)

Same idea could be used for the x and z extents too. Wait, this actually needs a bit more detail… I need a sum somewhere in there.

1 Like

I’ve probably posted about this trick before – multiply the |second row of the rotation matrix| by size, then sum.

local function worldHeight(part)
    local w = part.Size*part.CFrame:inverse().upVector
    return math.abs(w.x) + math.abs(w.y) + math.abs(w.z)
end

Here’s a ghetto visualization:

The inversion is a quick way to isolate the second row of the matrix, since inversion is equivalent to transposition when you’re working with rotations.

10 Likes