Trigonometry help!

Hello!

Recently, I’ve been trying to view the math aspects of coding, and I’m on the very basic level so far. I’ve taken many math courses up until second year university yet I just cannot wrap my head around this problem :pensive:

I currently have this for code:

local multiplication = 0
while  multiplication  < 2 do
	local pi = math.pi

	local a = Instance.new("Part")
	a.Size = Vector3.new(1,1,1)
	a.Anchored = true
	a.CFrame = CFrame.new(0,0,0)+Vector3.new(math.cos(pi*multiplication),0,math.sin(pi*multiplication))
	a.Parent = workspace
	multiplication = multiplication + 0.1

	
end

which ends up forming a simplistic circle as follows:

image

However, I want to smooth out the edges, as well as (hopefully) dissolve the clipping. If anyone would be able to leave an in-depth explanation as to how to do this, it would help me tons! (I probably will ask additional questions! just be fore-warned)

Also, I wanna ask that you don’t just post the answer UNLESS its for explanitory purposes, I want to learn this stuff, not have it handed to me.

Thanks!

The rough edges are caused by the multiplication changing at “too large” of an interval. To make a perfect circle (completely smooth), ideally you would let multiplication change by the smallest number possible. However using this technique you would never get a perfectly smooth edge but the closer the number is to 0, the better. Heads up thought, this will create a lot of parts into your workspace.

As for the clipping, I personally would just change the texture to something flat so it wouldn’t even be a problem; but I’m not sure if that is your goal.

I hope my answer was helpful and I bid you good luck on fixing the problem!

Im moreso invested on how to manipulate “*CFrame.Angles” to form the smooth circle - if even possible, however, that is good insight :slight_smile:

Are you trying to do this:

thats EXACTLY what I want! I also wanna learn how to manipulate the radius for each circle

(This probably is not going to be the best explanation D: )
Lets start at the manipulation of the radius of the circle.

The parameterization of a circle is x = cos(t) * radius, y = sin(t) * radius.

Lets start on how we derive that parameterization first. I would like to try to explain this myself but I’m awful at explaining concepts, so I suggest reading this: Parametric Equation of a Circle - Math Open Reference
Using this we can see why we the number multiplied to the result of cos(t) and sin(t) is the the radius.

Now onto how I made the “smooth” effect. I have actually deceived you! My circle is not a collection of points that have been rotated, but instead a collection of lines rotated to point from the previous point and the next one. We can see this if we lower the amount of points in our polygon (to 10 for example):

I would prefer to show you the code (hey this code is like 8 or 9 months old so it might look weird) because I’m bad at explaining and it will probably be pretty beneficial for you to read.

Click HERE to see 1 year old code.
-- [[ Service Declarations ]] --

local workspace = game:GetService("Workspace")

-- [[ Prebuilt Library Declarations ]] --

--// Variables

local pi = math.pi

--// Functions

local cos = math.cos
local sin = math.sin

-- [[ Line Class Declarations ]] --

local line = {}

do
	--// Line Methods
	
	function line.new(positionA, positionB, lineWidth)
		local newLine = Instance.new("Part")

		local distance = (positionA - positionB).Magnitude
	
		newLine.Anchored = true
		
		newLine.Size = Vector3.new(lineWidth, lineWidth, distance)
		newLine.CFrame = CFrame.new(positionA, positionB) * CFrame.new(lineWidth / 2, 0, -distance / 2)
		
		newLine.Parent = workspace

		return newLine	
	end
end

-- [[ Shape Class Declarations ]] --

local shape = {}

do
	--// Shape Methods
	
	function shape.new(pointCount, radius, lineWidth)
		local newShape = {}
		
		do
			--// Calculate Points
			
			local points = {}
			
			local angle = (pi * 2) / pointCount
			
			for i = 1, pointCount do
				local currentAngle = angle * i
				
				local xPosition = cos(currentAngle) * radius
				local zPosition = sin(currentAngle) * radius
				
				local position = Vector3.new(xPosition, 0, zPosition)
				
				do
					--// Render Point
					
					local newPoint = Instance.new("Part")
					
					newPoint.Anchored = true
					
					newPoint.Transparency = .5
					
					newPoint.Size = Vector3.new(1, 1, 1)
					newPoint.CFrame = CFrame.new(position)
					
					newPoint.Parent = workspace
				end
				
				points[#points + 1] = position
			end
			
			newShape.points = points
		end
		
		do
			--// Generate Lines
			
			local points = newShape.points
			
			for i = 1, #points do
				local index = (i % #points) + 1
				local nextIndex = ((i + 1) % #points) + 1
				
				local currentPoint = points[index]
				local nextPoint = points[nextIndex]
				
				line.new(currentPoint, nextPoint, lineWidth)
			end
		end
		
		return newShape
	end
end

-- [[ Init ]] --

do
	--// Generate Shape
	
	shape.new(24, 50, 1) --// shape.new(pointCount, radius, lineWidth)
end

image

Here we generate the points for our polygon. pi * 2 is the max radians in a circle and so if we want to draw a regular polygon of n points our angle between each point would be (pi * 2) / n. We would then multiply the current index of that angle value to get the currentAngle. Then we draw the coordinates of the circle at that given point in “time” (currentAngle)

image

Here is where the magic comes in that makes everything look “smooth”. (You will want to comment out the lines producing the point part in workspace which is line 64-77)

We create a new line by first getting the current point. (OK I might have over complicated the index and newIndex section but basically it makes “cyclic” index. For example if I have an array with 6 elements and I index for the 7th element it will instead return the 1st element. We do this because the last line will need to connect to the first line to connect everything together.

The line function is pretty reasonable. We just create a part with size lineWidth, lineWidth, distance and then set its position to positionA and pointing towards positionB then offset it by half the negative distance. (Negative because Roblox’s Z plane flipped and division of distance because the side of a rectangle is derived from origin + size / 2 since the center of a rectangle is half the length of the rectangle away from the side [ok that sounds confusing but theres hope you might understand!])

When we set our first parameter of shape.new to a high number like 100 (this means we make 100 parts) it will look “smooth” because we will have tons line segments.

If you go crazy and set it to 1000 points you can make a very convincing circle with a 1000-gon.

8 Likes

This helps TONS! Thanks so much for this! I think I just need to re-read it a couple times to fully grasp at it, but it definitely enhanced my knowledge on the subject!

I have a really (probably stupid) question though; for your angles, you did CFrame X CFrame. Whats the difference between multiplying 2 CFrames and doing CFrame X CFrame.Angles?

1 Like

I’m not entirely sure how CFrame multiplication works but to my knowledge CFrameA * CFrameB is basically offsetting CFrameA with CFrameB, whilst CFrameA * CFrameAngles is rotating CFrameA by CFrameAngles

1 Like

Ooooooooooooh ok, so its basically like adding a Vector3 to the CFrame?

I don’t think that is the best way to put it (I myself am not too sure how it works).

I think a more technical answer can be found here:

1 Like