High precision trigonometry?

gerth6000

Member
Licensed User
Longtime User
Not sure if my problem is because of the Sin/Cos functions or with the DrawCircle function....

Is there a library with Sin/Cos functions with high precision (10 digits or more)??

Or a DrawCircle function with high precision?



Explanation:
I'm working on an interactive 2-dimensional star map.

A particular star is placed in space with a set of x,y coordinates.

Its planet is then placed by using the radius of its orbit and its place in the orbit in radians, ie. I use Cos and Sin functions to calculate the planet's x,y coordinates.

I use the same star's coordinates and the orbit's radius to DrawCircle the orbit.

When zoomed out, that I can see planet and star on screen it looks perfect. Planet is on the circle. When zoomed in, that I can see the planet and its moons, the planet is off the circle by up to half a screen width.

I can calculate the misplacement as roughly 0.2% (2 in 1000) but it is not consistant. Bigger orbits have bigger misplacements.

For average applications I would think this error margin would be acceptable, but I use a zoom factor of up to 1 to 10 million (space is pretty big). Where 2 in 1000 is quite noticable.
 

gerth6000

Member
Licensed User
Longtime User
I just tried the Taylor-series function. The deviation between the standard Cos function and mc's version is less than 1 to 100000. At the worst point pi/8 the deviation between standard Cos and DrawCircle is 3 in 1000.

EDIT: I will try to make a function that compensates for DrawCircle's inaccuracy...
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Be careful, mc73s' Taylor series gives good results up to 90 degrees.
But at heigher values the difference is enormus.
mc73s' code checks only for the max value but not for the min value !
Setting in the cosd2 routine a value different from 20 gives different results.

Best regards.
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Be careful, mc73s' Taylor series gives good results up to 90 degrees.
But at heigher values the difference is enormus.
mc73s' code checks only for the max value but not for the min value !
Setting in the cosd2 routine a value different from 20 gives different results.

Best regards.
Ah, Klaus, you caught me :sign0079: I forgot to put an abs(), you're absolutely right!
Yes, we have to be careful with such series. In fact, after the 20th power, we can even receive a NAN result.
 
Upvote 0

gerth6000

Member
Licensed User
Longtime User
I tried to analyse the deviation, and it seems to repeat every 45 degrees. And it describes a progress that resembles a Cosine function.

So I tried to set up a cos-function that adds a 3:1000 modifier (maxed at 22.5 deg and minimum at 0 and 45 deg).

It improves, but to get the planets in line I have to repeat the concept several times. Add a 3:10,000 modifer at 0-22.5 deg, add a 3:100,000 modifier at 0-11.25 deg and so on. After 6 of these modifications, the planet's modified radius is close enough to the DrawCircle that you wouldn't notice the difference.

Well at least from 0-22.5 deg. I would need another set of 6 cosine functions for the 22.5-45 deg interval. :BangHead:

--

I have some to the conclusion that it is better to cheat.

When I zoom so close to the orbit that the circle just looks like a straight line, I am going to draw it as a straight line instead of DrawCircle. I know which point it has to go through and the angle it should have, so it is easy to make a line from screen edge to screen edge. Guaranteed precise at all zoom levels, and probably it will be faster as well.
 
Upvote 0

gerth6000

Member
Licensed User
Longtime User
Finally

Update - and solution.

Ok. I adapted my drawing routines so that it uses DrawLine when I have zoomed in really close and DrawCircle for stuff further out. But at the really close zoom rate where you won't notice the change from circle to line; the deviation could still be half a screen when worst.

So back to the drawing board. I investigated further and found that the deviation is mirrored on both X- and Y- axis. So I only needed to measure in the interval 0-90 degrees. I also found that the amount of deviation is the same in the interval 0-45 as 45-90.

In the interval 0-45 the deviation is symmetric mirrored around 22.5 degrees.

b4a-010912.png


I thought the shape would be the same in interval 0-11.25 as in interval 11.25-22.5, just negative. But the first interval is a bit steeper than the second.

So I have modelled an exponential function for this two intervals. (To enhance performance I have put the fixed number into global variables that are only calculated during application start.)

The input in the function is the rotation of the object you want to place on the DrawCircle shape (in degrees).

The output is multiplier in the range 1.000 to 1.003 approx. that extends the radius that the placement is calculated on.

Example of use:
B4X:
thisDCfactor = modifierCurrentRotation(objArray(index).CurrentRotation)
objArray(index).CurrentX = parentX+CosD(objArray(index).CurrentRotation)*objArray(index).BaseCircuitInner*thisDCfactor
objArray(index).CurrentY = parentY-SinD(objArray(index).CurrentRotation)*objArray(index).BaseCircuitInner*thisDCfactor

The actual function:
B4X:
Sub modifierCurrentRotation(rotation As Double)
  ' Constants declared other place:

  'conFirstModifier=42500000/Power(11.25,1.6)/25000000000
  'conSecondModifier=(78500000-42500000)/Power(11.25,1.8)
  'conThirdModifier=78500000
  'conFourthModifier=25000000000
  
  ' Might not have a positive rotation
  Do While rotation<0
    rotation=rotation+3600
  Loop
  
  ' Deviation is the same for every 45 degrees of the circle
  rotation = rotation Mod 45

  ' Deviation is symmetric around 22.5 degrees
  If rotation>22.5 Then
    rotation=45-rotation
  End If
  
  ' One function for the first half of the interval, and another function for the other half of the interval
  If rotation<=11.25 Then
    Return 1+Power(rotation,1.6)*conFirstModifier
  Else
   Return 1+(conThirdModifier-Power(22.5-rotation,1.8)*conSecondModifier)/conFourthModifier
  End If
  
End Sub
 
Upvote 0
Top