Sun position
Sun position algorithm
Why define vector and matrix arrays as structs?

This has been done to assist compiler error checking, and reduce the chances of bugs that can potentially be rather difficult to diagnose.

Take for example the following code. It has a vector of rectangular coordinates vec[], which contains the values one gets from converting polar angles of 45° and 45° to rectangular form. This program simply converts this rectangular vector back to polar form and writes out the two angles, after converting from radian back to degrees.

#include <math.h>
#include <stdio.h>

void rectToPolar(double *alpha, double *delta, double rect[])
{
     alpha = atan2(rect[1], rect[0]);
     delta = atan2(rect[2], sqrt(rect[0] * rect[0] + rect[1] * rect[1]));
}

int main(void)
{
    double azimuth = 0.5;       // Dummy initial value, will be replaced
    double elevation = 0.5;     // Ditto
    double vec[3] = { 0.5, 0.5, 0.70710678119 };

    rectToPolar(vec, &azimuth, &elevation);
    printf("Azimuth = %f, Elevation = %f\n",
           azimuth * 180.0 / 3.141592653589793,
           elevation * 180.0 / 3.141592653589793);
}

There is a bug in the code, which in this short example is rather easy to see, but in a large program might not be. The expected output from this code is

Azimuth = 45.000000, Elevation = 45.000000

But what do you get if you compile and run it? On my running this program, I got

Azimuth = 48.002776, Elevation = 28.647890

You may get something else. But in any case, the results may look sufficiently plausible that you might not immediately notice that you have got a garbage answer. Depending on your program, this might end up being quite time-consuming to debug.

Now instead, compile the following code, which uses our V3D_Vector struct instead of using a simple array:

#include <math.h>
#include <stdio.h>

#include "vectors3d.h"

int main(void)
{
    double azimuth = 0.5;       // Dummy initial value, will be replaced
    double elevation = 0.5;     // Ditto
    V3D_Vector vec = {{ 0.5, 0.5, 0.70710678119 }};

    v3d_rectToPolar(&vec, &azimuth, &elevation);
    printf("Azimuth = %f, Elevation = %f\n",
           azimuth * 180.0 / 3.141592653589793,
           elevation * 180.0 / 3.141592653589793);
}

This time, you get two warning messages from the compiler. With the clang compiler, the messages are as follows:

vec2.c:12:21: warning: incompatible pointer types passing 'V3D_Vector *'
      to parameter of type 'double *' [-Wincompatible-pointer-types]
    v3d_rectToPolar(&vec, &azimuth, &elevation);
                    ^~~~
./vectors3d.h:74:30: note: passing argument to parameter 'alpha_rad' here
void v3d_rectToPolar(double *alpha_rad,
                             ^
vec2.c:12:37: warning: incompatible pointer types passing 'double *' to
      parameter of type 'const V3D_Vector *' [-Wincompatible-pointer-types]
    v3d_rectToPolar(&vec, &azimuth, &elevation);
                                    ^~~~~~~~~~
./vectors3d.h:76:40: note: passing argument to parameter 'srcV' here
                     const V3D_Vector *srcV);

(Actually, there is a case here for elevating this warning to an error that stops compilation, using -Werror=incompatible-pointer-types)

I believe that this justifies using this slightly more awkward way of implementing the vectors and arrays needed for 3-D geometry.

It also allows one to use a simple assignment statement to copy a vector or matrix, as opposed to needing to write a function to do it. (Or in the case of the IAU SOFA routines for matrix copying - two functions!)