Go to notes and algorithms index. ~ Go to home page.

squared_chord_length_to_angle(). Find the angle between two vectors in 3D space.


Integer version.

Find the angle between two vectors in 3D space.... or in other words find the apex angle of an isosceles triangle (assuming its equal sides are 4096 each in length and that you know its base length squared).

Vectors must be 4096 in length each. v_squared_chord_len is the only value that is required for the calculation because the routine assumes that both vectors are 4096 and so does not need anymore information supplied.

v_squared_chord_len could be calculated by subtracting the two end points of the vectors to get a dx, dy, and dz and then doing a pythagoras calculation on them but without doing the square root part of the equation.

Although this routine can find the angle between two 3D vectors in 3D space, there's no reason why you can't use it on 2D vectors.

When I say "in 3D space" I mean that the two vectors need not be aligned with any particular axis or be in any partiular plane.



long squared_chord_length_to_angle( long v_squared_chord_len )
   { // (c) Jon P 2001
   //
   // V1.0
   //
   // This function will return the angle between two lines radiating from
   // the centre of an imaginary sphere (with a 4096 radius) to its surface.
   // Thus both lines are 4096 in length.
   //
   // ... in other words find the angle between two normal lenth vectors
   // in 3D space.
   //
   // The resulting angle is calculated using the supplied parameter which must be the
   // length of the third side (squared): i.e. the chord connecting the two points
   // on the surface of the sphere.  The supplied param must therefore be between
   // 0 and 8192*8192
   //
   // The supplied length has to be squared.... this is so that the result from a
   // dx*dx+dy*dy+dz*dz calculation can be used directly without the need to do an
   // additional square-root calculation first.  This should save significant CPU
   // time.
   //
   // N.B. the result is returned as 0 to 4096, where 4096 equals 180degrees 2048
   // equals 90 degrees etc. 
   // If used on playstation 1, for example, the resulting angle would be typically
   // be divided by 2 in the calling code.
   //
   // This routine works by emulating the usual process of dividing the isosceles
   // triangle formed by the two lines and the chord into two right angled triangles,
   // then using the usual arc_sine method to find the angle.
   // Thus this routine is an emulation of:-
   //
   //    result = ( arc_sine( square_root( squared_chord_len ) / 2 / 4096 ) * 2 * 2
   //
   // ...and so this routine could also be used as a function that finds the angle of a right
   // angled triangle where the hypotenuse is 4096, if the opposite side's length is doubled
   // then squared and the result is divided by 4.
   //
   // See test program SQU_CH.BAS (quick basic) for graph etc.


   register long temp, temp2;
 
   temp = v_squared_chord_len;

   // The formula has to be split-up into a few ranges because one could not be fould
   // to match the whole curve....
   if ( temp <= 547 )
      { // Return very accurate angles (*4) for chord lengths of upto 23 squared...
      if ( temp > 416 ) return 7;
      if ( temp > 289 ) return 6;
      if ( temp > 196 ) return 5;
      if ( temp >= 121 ) return 4;
      if ( temp >= 64 ) return 3;
      if ( temp >= 22 ) return 2;
      if ( temp ) return 1;
      return 0;
      }
   else // Ranges 548 to 8192*8192...
      {
      if ( temp <= 40000 )
         { //(good at top end bad at low end (result out by +4.4)
         temp += 24810;
         temp = 2137856 / temp;
         temp = 96 - temp;
         }
      else
         {
         if ( temp <= 1200000 )
            {
            temp2 = temp;
            temp >>= 12;
            temp += 20;
            temp = -3200 / temp;
            temp += 160;
            temp -= temp2 * -176 / 1048576;
            }
         else
            {
            if ( temp < 49000000 )
               {
               temp2 = temp;
               temp += 3112960;
               temp = -2147000000 / temp;
               temp += 801 - ( temp2 / -25810 );
               }
            else // the last (righter most) range....
               {
               temp2 = temp;
               temp = 68408864 - temp;
               temp = 840000000 / temp;
               temp += 278;
               temp += temp2 / 21000;
               if ( temp > 4096 ) temp = 4096;
               }
            }
         }
      }
   
   // printf( "\nchord*chord=%d  answer=%d ", v_squared_chord_len, temp );
   
   return temp;
   }


   /*
   printf( "\n-----------" );
   squared_chord_length_to_angle( 40000 );
   squared_chord_length_to_angle( 10000 );
   squared_chord_length_to_angle( 1100000 );
   squared_chord_length_to_angle( 1200000 );
   squared_chord_length_to_angle( 10000000 );
   squared_chord_length_to_angle( 48000000 );
   squared_chord_length_to_angle( 49000000 );
   squared_chord_length_to_angle( 64000000 );
   squared_chord_length_to_angle( 67108864 );
   printf( "\n-----------" );
   */