Angle Snapping?

I want to draw a line on the XZ plane that is snapped to angle increments. I’ve found the snapped angle, but I’m having trouble translating that back to the X and Z coordinates. Here’s my code:

local snapAngle = math.rad(studioService.RotateIncrement)

local vector = position - startPosition
local angle = math.atan2(vector.Z, vector.X)
local snappedAngle = math.floor(angle / snapAngle + 0.5) * snapAngle

local r = vector.Magnitude
local x = r * math.cos(snappedAngle)
local z = r * math.sin(snappedAngle)

local angleSnappedPosition = Vector3.new(x, position.Y, z)

In the above code I’m trying to calculate the snapped x and z values based on this snippet from the Wikipedia article on atan2:

The snappedAngle is correct, but the snapped x and z values are all over the place. Sometimes positive x and z values are getting translated to negative values.

Where have I gone wrong?

Do you have a more detailed description of the problem? Maybe a gif or video?

I think the code is working correctly, that meaning that x and z values are going to give the correct values in the circle depending on the angle. However, you have not given an initial orientation that those coordinates should be relative to. Usually, the forward vector is Vector3.new(0, 0, -1), so maybe setting the angleSnappedPosition to:

angleSnappedCFrame = CFrame.lookAt(OriginPosition, OriginPosition + Vector3.new(0, 0, -1), Vector3.new(0, 1, 0)) * CFrame.new(x, 0, z)
angleSnappedPosition = angleSnappedCFrame.Position

OriginPosition should be the position at the origin of the circle

Thanks. I am confident I can get it working if I use CFrames, but I’ve got no rotations or need to translate between coordinate systems so I’m trying to keep everything in pure trig. I’d really like to clear up my misunderstanding of the x = r * cos(angle) equation.

BTW the angles are referenced off the positive x axis:
image

I think they’re looking for something similar to Photoshop’s angle snapping when you draw a line:

1 Like

Exactly, thanks! [character minimum]

1 Like

Then in that case, the math looks correct. There shouldn’t be any problems with your code unless something else that you did not show is causing the problem. I went ahead and replicated this in an empty baseplate, and everything seems to be working fine.

https://gyazo.com/65f7276fd4e8c8ddc1d23f196831553c

edit: forgot to include the code in this post

local origin = Vector3.new(0, 0.5, 0)
local target = workspace.Target
local line = Instance.new("Part", workspace)
line.CanCollide = false
line.Anchored = true
local angleIncrement = 22.5

while wait() do
	local snapAngle = math.rad(angleIncrement)
	
	local vector = target.Position - origin
	local angle = math.atan2(vector.Z, vector.X)
	local snappedAngle = math.floor(angle / snapAngle + 0.5) * snapAngle

	local r = vector.Magnitude
	local x = r * math.cos(snappedAngle)
	local z = r * math.sin(snappedAngle)
	
	line.Size = Vector3.new(0.1, 0.1, r)
	line.CFrame = CFrame.new(Vector3.new(x * 0.5, 0.5, z * 0.5), Vector3.new(x, 0.5, z))
end
1 Like

Thanks so much!!

My problem was that

local angleSnappedPosition = Vector3.new(x, position.Y, z)

should have been:

local angleSnappedVector = Vector3.new(x, 0, z)
local angleSnappedPosition = startPosition + angleSnappedVector

*facepalm*

I had such low confidence in my trig that expected the problem to be there. Thanks so much for confirming the maths.

1 Like