C: Added Astronomy_VectorFromSphere, astro_spherical_t.

Added new data type astro_spherical_t that represents generic spherical coordinates.
Implemented Astronomy_VectorFromSphere to convert spherical coordinates
to Cartesian coordinates. Included unit test to verify it is working as expected.
This commit is contained in:
Don Cross
2019-12-08 13:48:27 -05:00
parent 63ae582893
commit bca3f808ae
5 changed files with 181 additions and 0 deletions

View File

@@ -1835,11 +1835,61 @@ fail:
return error;
}
static int TestVectorFromAngles(double lat, double lon, double x, double y, double z)
{
astro_spherical_t sphere;
astro_vector_t vector;
astro_time_t time;
double diff, dx, dy, dz;
/* Confirm the expected vector really is a unit vector. */
diff = fabs((x*x + y*y + z*z) - 1.0);
if (diff > 1.0e-16)
{
fprintf(stderr, "TestVectorFromAngles: EXCESSIVE unit error = %lg\n", diff);
return 1;
}
sphere.status = ASTRO_SUCCESS;
sphere.lat = lat;
sphere.lon = lon;
sphere.dist = 1.0;
time = Astronomy_MakeTime(2015, 3, 5, 12, 0, 0.0);
vector = Astronomy_VectorFromSphere(sphere, time);
if (vector.status != ASTRO_SUCCESS)
{
fprintf(stderr, "ERROR(TestVectorFromAngles): vector.status = %d\n", vector.status);
return 1;
}
dx = x - vector.x;
dy = y - vector.y;
dz = z - vector.z;
diff = sqrt(dx*dx + dy*dy + dz*dz);
printf("TestVectorFromAngles(%lf, %lf): diff = %lg\n", lat, lon, diff);
if (diff > 2.0e-16)
{
fprintf(stderr, "TestVectorFromAngles: EXCESSIVE ERROR.\n");
return 1;
}
return 0;
}
static int RotationTest(void)
{
int error;
CHECK(Rotation_MatrixInverse());
CHECK(Rotation_MatrixMultiply());
CHECK(TestVectorFromAngles(0.0, 0.0, 1.0, 0.0, 0.0));
CHECK(TestVectorFromAngles(0.0, 90.0, 0.0, 1.0, 0.0));
CHECK(TestVectorFromAngles(0.0, 180.0, -1.0, 0.0, 0.0));
CHECK(TestVectorFromAngles(0.0, 270.0, 0.0, -1.0, 0.0));
CHECK(TestVectorFromAngles(+90.0, 0.0, 0.0, 0.0, 1.0));
CHECK(TestVectorFromAngles(-90.0, 0.0, 0.0, 0.0, -1.0));
CHECK(TestVectorFromAngles(-30.0, +60.0, 0.43301270189221946, 0.75, -0.5));
error = 0;
fail:
return error;

View File

@@ -4143,6 +4143,44 @@ astro_rotation_t Astronomy_CombineRotation(astro_rotation_t a, astro_rotation_t
return c;
}
/**
* @brief Converts spherical coordinates to Cartesian coordinates.
*
* Given spherical coordinates and a time at which they are valid,
* returns a vector of Cartesian coordinates. The returned value
* includes the time, as required by the type #astro_vector_t.
*
* @param sphere
* Spherical coordinates to be converted.
*
* @param time
* The time that should be included in the return value.
*
* @return
* The vector form of the supplied spherical coordinates.
*/
astro_vector_t Astronomy_VectorFromSphere(astro_spherical_t sphere, astro_time_t time)
{
astro_vector_t vector;
double radlat, radlon, rcoslat;
if (sphere.status != ASTRO_SUCCESS)
return VecError(ASTRO_INVALID_PARAMETER, time);
radlat = sphere.lat * DEG2RAD;
radlon = sphere.lon * DEG2RAD;
rcoslat = sphere.dist * cos(radlat);
vector.status = ASTRO_SUCCESS;
vector.t = time;
vector.x = rcoslat * cos(radlon);
vector.y = rcoslat * sin(radlon);
vector.z = sphere.dist * sin(radlat);
return vector;
}
#if 0
/**
* @brief

View File

@@ -1136,6 +1136,31 @@ After calculating the date and time of an astronomical event in the form of an [
---
<a name="Astronomy_VectorFromSphere"></a>
### Astronomy_VectorFromSphere(sphere, time) &#8658; [`astro_vector_t`](#astro_vector_t)
**Converts spherical coordinates to Cartesian coordinates.**
Given spherical coordinates and a time at which they are valid, returns a vector of Cartesian coordinates. The returned value includes the time, as required by the type [`astro_vector_t`](#astro_vector_t).
**Returns:** The vector form of the supplied spherical coordinates.
| Type | Parameter | Description |
| --- | --- | --- |
| [`astro_spherical_t`](#astro_spherical_t) | `sphere` | Spherical coordinates to be converted. |
| [`astro_time_t`](#astro_time_t) | `time` | The time that should be included in the return value. |
---
<a name="Astronomy_VectorLength"></a>
@@ -1588,6 +1613,23 @@ You can create this structure directly, or you can call the convenience function
| [`astro_time_t`](#astro_time_t) | `dec_solstice` | The date and time of the December solstice for the specified year. |
---
<a name="astro_spherical_t"></a>
### `astro_spherical_t`
**Spherical coordinates: latitude, longitude, distance.**
| Type | Member | Description |
| ---- | ------ | ----------- |
| [`astro_status_t`](#astro_status_t) | `status` | ASTRO_SUCCESS if this struct is valid; otherwise an error code. |
| `double` | `lat` | The latitude angle: -90..+90 degrees. |
| `double` | `lon` | The longitude angle: 0..360 degrees. |
| `double` | `dist` | Distance in AU. |
---
<a name="astro_time_t"></a>

View File

@@ -5382,6 +5382,44 @@ astro_rotation_t Astronomy_CombineRotation(astro_rotation_t a, astro_rotation_t
return c;
}
/**
* @brief Converts spherical coordinates to Cartesian coordinates.
*
* Given spherical coordinates and a time at which they are valid,
* returns a vector of Cartesian coordinates. The returned value
* includes the time, as required by the type #astro_vector_t.
*
* @param sphere
* Spherical coordinates to be converted.
*
* @param time
* The time that should be included in the return value.
*
* @return
* The vector form of the supplied spherical coordinates.
*/
astro_vector_t Astronomy_VectorFromSphere(astro_spherical_t sphere, astro_time_t time)
{
astro_vector_t vector;
double radlat, radlon, rcoslat;
if (sphere.status != ASTRO_SUCCESS)
return VecError(ASTRO_INVALID_PARAMETER, time);
radlat = sphere.lat * DEG2RAD;
radlon = sphere.lon * DEG2RAD;
rcoslat = sphere.dist * cos(radlat);
vector.status = ASTRO_SUCCESS;
vector.t = time;
vector.x = rcoslat * cos(radlon);
vector.y = rcoslat * sin(radlon);
vector.z = sphere.dist * sin(radlat);
return vector;
}
#if 0
/**
* @brief

View File

@@ -170,6 +170,18 @@ typedef struct
}
astro_vector_t;
/**
* @brief Spherical coordinates: latitude, longitude, distance.
*/
typedef struct
{
astro_status_t status; /**< ASTRO_SUCCESS if this struct is valid; otherwise an error code. */
double lat; /**< The latitude angle: -90..+90 degrees. */
double lon; /**< The longitude angle: 0..360 degrees. */
double dist; /**< Distance in AU. */
}
astro_spherical_t;
/**
* @brief An angular value expressed in degrees.
*/
@@ -602,6 +614,7 @@ astro_apsis_t Astronomy_NextLunarApsis(astro_apsis_t apsis);
astro_rotation_t Astronomy_InverseRotation(astro_rotation_t rotation);
astro_rotation_t Astronomy_CombineRotation(astro_rotation_t a, astro_rotation_t b);
astro_vector_t Astronomy_VectorFromSphere(astro_spherical_t sphere, astro_time_t time);
#if 0
astro_rotation_t Astronomy_Rotation_EQD_EQJ(astro_time_t time);