Trigonometry Functions

From the Oblivion ConstructionSet Wiki
Revision as of 19:45, 9 May 2006 by imported>DragoonWraith (changed to stage functions)
Jump to navigation Jump to search

This is a repository of functions used in trigonometry - namely Sine, Cosine, Tangent, Arcsine, Arccosine, and Arctangent.

There are many methods of obtaining any or all of these, and each has its own benefits and drawbacks in terms of length, efficiency, and speed. This page is a work in progress - please add any scripts you have for approximating these functions. Please remember to comment them thoroughly and to use generic variable names.

These are Stage Functions, and as such must be created as Quest Stages of a Global Script and called as a function. These examples assume a Quest called Wiki with the variables declared. Therefore, you must modify this code to include the name of your Quest (assuming it is not Wiki, which it shouldn't be).

Formulae

Right triangle

A + B + C = 180°

A + B = 90°

a² + b² = c²

sin(A) = a / c

cos(A) = b / c

tan(A) = a / b

tan(A) = sin(A) / cos(A)



Sine, Cosine, and Tangent

You can use a Taylor series to approximate the value of sine, cosine and tangent:


sin(x) = x^1/1! - x^3/3! + x^5/5! - x^7/7! + ...

cos(x) = x^0/0! - x^2/2! + x^4/4! - x^6/6! + ...

tan(x) = x^1/1! + x^3/3! + x^5/5! + x^7/7! + ...

Taylor Series Variant 1

This function requires the following variables to be declared in your Global Script:

float ang (the measure of the angle)
float rad (used internally)
float exp (used internally)
float sin (the sine of the angle)
float cos (the cosine of the angle)
float tan (the tangent of the angle)

You may rename these if you wish, but that means changing the code, which is not advised, as there are a lot of variables here. All of them must be floats.

; script originally by Galerion
; normalize angle
  if ( Wiki.ang < -180 )
    set Wiki.ang to ( Wiki.ang + 360 )
  elseif ( Wiki.ang > 180 )
    set ang to ( Wiki.ang - 360 )
  endif

; approximate sine and cosine of the angle
  set Wiki.rad to ( Wiki.ang * 0.0174533 )
  set Wiki.cos to 1
  set Wiki.exp to Wiki.rad                     ; 1st
  set Wiki.sin to Wiki.exp
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 2nd
  set Wiki.cos to ( Wiki.cos - Wiki.exp / 2 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 3rd
  set Wiki.sin to ( Wiki.sin - Wiki.exp / 6 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 4th
  set Wiki.cos to ( Wiki.cos + Wiki.exp / 24 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 5th
  set Wiki.sin to ( Wiki.sin + Wiki.exp / 120 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 6th
  set Wiki.cos to ( Wiki.cos - Wiki.exp / 720 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 7th
  set Wiki.sin to ( Wiki.sin - Wiki.exp / 5040 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 8th
  set Wiki.cos to ( Wiki.cos + Wiki.exp / 40320 )
  set Wiki.exp to ( Wiki.exp * Wiki.rad )           ; 9th
  set Wiki.sin to ( Wiki.sin + Wiki.exp / 362880 )

; get tangent
  set Wiki.tan to ( Wiki.sin / Wiki.cos )

End

This script is more accurate than it needs to be. Galerion suggests that only the first seven steps are necessary.


Taylor Series Variant 2

This function requires the following variables to be declared in your Global Script:

float angle (measure of the angle)
float t1 (used internally)
float t2 (used internally)
float t5 (used internally)
float t6 (used internally)
float sina  (sine of the angle)
float cosa  (cosine of the angle)
float tana  (tangent of the angle)

All must be floats. Though they can be renamed, doing so means changing the function code to match.

; script originally by JOG
; normalize the angle
set Wiki.angle to Wiki.angle + 360*(Wiki.angle < -180) - 360*(Wiki.angle > 180)
; precalculate powers of "angle"
set Wiki.t1 to Wiki.angle / 57.29577951
set Wiki.t2 to Wiki.t1*Wiki.t1
set Wiki.t5 to Wiki.t2*Wiki.t2*Wiki.t1
set Wiki.t6 to Wiki.t5*Wiki.t1
set Wiki.sina to Wiki.t1 - Wiki.t1*Wiki.t2/6 + Wiki.t5/120 - Wiki.t5*t2/5040 + Wiki.t6*Wiki.t2*Wiki.t1/362880 
set Wiki.cosa to 1 - Wiki.t2/2 + Wiki.t2*Wiki.t2/24 - Wiki.t6/720 + Wiki.t6*Wiki.t2/40320
set Wiki.tana to Wiki.sina/Wiki.cosa

Arcsine - Abramowitz/Stegun Approximation

Abramowitz and Stegun found this polynomal approximation for arcsine:

a0=1.5707288 / a1=-0.2121144 / a2=0.0742610 / a3=-0.0187293

arcsin(x) = 180/Pi * (pi/2 - sqrt(1 - x) * (a0 + a1*x + a2*x^2 + a3*x^3))

This function requires the following variables to be declared in your Global Script:

float x (the sine of the angle)
float n (used internally)
float arcsinx (the arcsine, that is, the measure of the angle)

These may be renamed, but doing so means changing them in the code.

; script originally by JOG
set Wiki.x to (player.getpos z - NPC.getpos z)/player.getdistance NPC
set Wiki.n to 1 - Wiki.x ; arcsinx = SquareRoot(1-x)
set Wiki.arcsinx to Wiki.n/2
set Wiki.arcsinx to (Wiki.arcsinx+(Wiki.n/Wiki.arcsinx))/2
set Wiki.arcsinx to (Wiki.arcsinx+(Wiki.n/Wiki.arcsinx))/2
set Wiki.arcsinx to (Wiki.arcsinx+(Wiki.n/Wiki.arcsinx))/2
set Wiki.n to (Wiki.arcsinx+(Wiki.n/Wiki.arcsinx))/2
set arcsinx to 57.2957795*(1.5707963-Wiki.n*(1.5707288-0.2121144*Wiki.x+0.0742610*Wiki.x*Wiki.x-0.0187293*Wiki.x*Wiki.x*Wiki.x))

This approximation is very accurate (99.9% - 99.9999%) for angles of 45 degrees and higher. For smaller angles you can get a higher precision when you use a taylor series with 15+ iterations.

Arcsine - Approximation by Taylor Series

According to Wikipedia, arcsine can be found with this series:

Arcsine.png

This can be approximated by Oblivion using a function. This function requires the following variables be declared in your Global Script:

float z (the sine of the angle)
float z3 (used internally)
float z5 (used internally)
float z7 (used internally)
float arcsinz (the arcsine, that is, the measure of the angle)

These can be renamed, but must also be changed in the code.

;script originally by DragoonWraith
set Wiki.z3 to (Wiki.z*Wiki.z*Wiki.z)
set Wiki.z5 to (Wiki.z3*Wiki.z*Wiki.z)
set Wiki.z7 to (Wiki.z5*Wiki.z*Wiki.z)

set arcsinz to (Wiki.z+(1/2)*(Wiki.z3/3)+(3/8)*(Wiki.z5/5)+(15/48)*(Wiki.z7/7))

More terms will increase accuracy. The larger the angle, the more terms are needed to get acceptable accuracy. As a rough guide use 3 terms for every 10° to get an accuracy of at least 1 decimal digit.


Arccosine

Arccos z = (PI / 2) - arcsin(z).

See above for method of obtaining arcsin. This may be useful when using the Law of Cosines to find the measure of an unknown angle, given three known sides.


Arctangent

Arctan z = z - (z^3/3) + (z^5/5) - (z^7/7) +...

This is very similar to the Taylor Expansion method of generating Arcsine, but without the extra multipliers, and with alternating signs.

This function requires the following variables be declared in your Global Script:

float z (the tangent of the angle)
float z3 (used internally)
float z5 (used internally)
float z7 (used internally)
float arcsinz (the arctangent, that is, the measure of the angle)

These can be renamed, but must also be changed in the code.

;modified from arcsine script supplied by DragoonWraith
  set z3 to ( z * z * z )
  set z5 to ( z3 * z * z )
  set z7 to ( z5 * z * z )

  set arctanz to ( z - (z3/3) + (z5/5) - (z7/7) )

Again, more terms equals more accuracy.

See Also

Elder Scrolls Forums - Trigonometry Function Workarounds?

Elder Scrolls Forums - Is there an actor for the target you are attacking currently?