Garry's Mod Wiki

Revision Difference

Trigonometry#544718

<cat>Dev.Lua</cat> Trigonometry is a really useful tool to have in your coder's utility belt, and lots of people have a hard time grasping Sine and Cosine (and Tangent), so here's a crash course tutorial on their use. Trigonometry is the math of `right triangles` and `circles`. ## SOH, CAH, TOA First, let's look at **SOH**, **CAH**, **TOA**: ⤶ **SOH** = **S**ine equals **O**pposite over **H**ypotenuse **CAH** = **C**osine equals **A**djacent over **H**ypotenuse **TOA**= **T**angent equals **O**pposite over **A**djacent ⤶ - **SOH** = **S**ine equals **O**pposite over **H**ypotenuse - **CAH** = **C**osine equals **A**djacent over **H**ypotenuse - **TOA** = **T**angent equals **O**pposite over **A**djacent But what does this mean? The **Hypotenuse** of a right triangle is the longest of the three sides. It's always on the opposite end of the right angle. The other two sides aren't uniquely named. <image src="hypotenuse.gif"/> So depending on our situation, we can use one of the three equations to find out all we need to know about a right triangle. All we need is the length of one of the three sides and the degree of one of the two non-right angles. Refer to this diagram (not to scale): <image src="sohcahtoa.png"/> If we replace those sides with `a` and `b`, with the Hypotenuse being `c`, with the angle we know being `ang`, we can use this equation to find the length of side `b`. Here is a Lua example: ``` local a = 8 local b -- we're going to find out b. This is our "Opposite" side. local c = 16 local ang = 30 ang = math.rad( ang ) -- Turn our degrees into radians. This is a requirement for Lua. Don't worry too much about it now. -- Remember Sine equals Opposite over Hypotenuse. -- That is, the sine of the angle is equal to the opposite leg's length divided by the Hypotenuse's length. -- math.sin( ang ) == b / c -- Here is the same equation, solved for b: b = math.sin( ang ) * c -- Lua will calculate the sin of ang, as such: -- math.sin( math.rad( 30 ) ) = .5 print( b == .5 * 16 ) --Will output true. ``` Believe it or not, these basic right triangle calculations have **SO MANY USES**. Over `2200` years ago, mathematicians used these functions to calculate the radius of Earth. It's used literally every second of every day in GPS software (hence the term triangulation). It's used by police to track the location of a phone call. **SOH CAH TOA is the foundation of Trigonometry**. The three trigonometric functions are <page>math.sin</page>, <page>math.cos</page>, and <page>math.tan</page>. ## Unit Circle When we investigate the origins of Sine and Cosine, we can learn a thing or two about the fundamental properties of a circle. Consider the following: <image src="unitcircle.png"/> We have a circle with radius 1. In this circle, we have radius line which is tilted 30 degrees (counterclockwise, always counterclockwise) from the circle's right horizontal axis. Because it is a radius line, its length is equal to the radius of the circle, which is 1 in this case. So what is the length of b? If we recall SOH, we see that **Sin( ang ) = Opposite / Hypotenuse**. Plug in our values, and Sin( 30 ) = b / 1. Seeing as how any number divided by 1 is itself, we can conclude that: In a circle of radius 1, the **Y-value** of a point on a circle relative to the center of the circle is equal to the **sine** of the angle. In a circle of radius 1, the **X-value** of a point on a circle relative to the center of the circle is equal to the **cosine** of the angle. That is, ``` y = math.sin( ang ) x = math.cos( ang ) ``` Which we can see here: <image src="jvzRYnC.gif"/> But not all circles are of radius 1. When we have a circle that is larger than radius 1, we just multiply. ``` y = math.sin( ang ) * radius x = math.cos( ang ) * radius ``` Furthermore, we've been assuming that our circle is centered at point (0,0). If our circle's center is (100,453), we add. This is our complete formula: ``` y = math.sin( ang ) * radius + originY x = math.cos( ang ) * radius + originX ``` This is useful in GLua for drawing circles, arranging props in circles, and basically any other circle-based code. Here is an example which draws squares: ``` function PointOnCircle( ang, radius, offX, offY ) ang = math.rad( ang ) local x = math.cos( ang ) * radius + offX local y = math.sin( ang ) * radius + offY return x, y end local numSquares = 36 --How many squares do we want to draw? local interval = 360 / numSquares local centerX, centerY = 200, 500 local radius = 120 hook.Add("HUDPaint","Draw a circle of boxes!", function() for degrees = 1, 360, interval do --Start at 1, go to 360, and skip forward at even intervals. local x, y = PointOnCircle( degrees, radius, centerX, centerY ) draw.RoundedBox( 4, x, y, 30, 30, Color(255,255,0) ) end end) ``` Result: <image src="circleboxes.png"/> WOW! SO USEFUL! Radial menus, circular health bars, [chairs arranged around a circular table](http://steamcommunity.com/sharedfiles/filedetails/?id=382065862), ellipses, sound waves, and `MUCH MORE` are possible with Trigonometry. ## Inverse Functions The inverse function of a Trigonometric function is called the arc-function. The three inverse trigonometric functions are <page>math.asin</page>, <page>math.acos</page>, and <page>math.atan</page> or <page>math.atan2</page>. Arc functions work like so: ``` --The following two equations are equivalent: sin( a ) = b / c a = arcsin( b / c ) --The following two equations are equivalent: cos( a ) = b / c a = arccos( b / c ) ``` These are useful for doing reverse math, for example: ``` -- We know the length of A and B, and we want to find angle THETA, which is adjacent to B local A = 2 local B = 4 -- sin( ang ) == A / B -- ang == arcsin( A / B ) local ang = math.asin( A / B ) print(ang) -- Outputs 30; sin( 30 ) == .5 == 2/4 == A/B ``` These functions are useful if the unknown variable in question is your angle. There is a special Arc-Tangent function for programming called <page>math.atan2</page>. Think of tan(ang) as giving the slope - the rise over the run - of a line. So: ``` tan( ang ) = y / x ang = atan( y / x ) ``` However, when performing y/x, calculating 3/4 gives the same answer as calculating -3/-4. Likewise -3/4 gives the same answer as 3/-4. So we have atan2(y,x) that handles the individual signs correctly and prevents a divide-by-zero/infinity error. ``` ang = atan2( y, x ) ``` atan2's use is to get the angle of a line with a slope `m` as in the equation `y` = `mx` + `b` <image src="atan.png"/> ## Conclusion Trigonometry is required to create any circular structure, and to do math with right triangles. It is also useful to find the angle of a line given its slope. I hope you learned something `useful` here!