#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "test_common.h"
#include "tests.h"
static void check_compare_circles(
struct yac_circle * circle_a,
int a_is_lat,
int are_identical);
struct point_2d {double lon, lat;};
{
struct {
struct point_2d a, b;
int edge_ordering;
int circle_idx;
int contains_north_pole;
} test_data[] =
{{.a = {.lon = 45.0, .lat = 0.0},
.b = {.lon = -45.0, .lat = 0.0},
.edge_ordering = -1,
.circle_idx = 0,
.contains_north_pole = 1},
{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.edge_ordering = 1,
.circle_idx = 0,
.contains_north_pole = 1},
{.a = {.lon = 45.0, .lat = 0.0},
.b = {.lon = -45.0, .lat = 0.0},
.edge_ordering = 1,
.circle_idx = 1,
.contains_north_pole = 0},
{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.edge_ordering = -1,
.circle_idx = 1,
.contains_north_pole = 0},
{.a = {.lon = 0.0, .lat = 88.0},
.b = {.lon = 180.0, .lat = 88.0},
.edge_ordering = 1,
.circle_idx = 2,
.contains_north_pole = 0},
{.a = {.lon = 180.0, .lat = 88.0},
.b = {.lon = 0.0, .lat = 88.0},
.edge_ordering = -1,
.circle_idx = 2,
.contains_north_pole = 0},
{.a = {.lon = 0.0, .lat = -1.0},
.b = {.lon = 0.0, .lat = 1.0},
.edge_ordering = -1,
.circle_idx = 3,
.contains_north_pole = 0},
{.a = {.lon = 10.0, .lat = 10.0},
.b = {.lon = 10.0, .lat = 20.0},
.edge_ordering = -1,
.circle_idx = 4,
.contains_north_pole = 0},
{.a = {.lon = 10.0, .lat = 10.0},
.b = {.lon = 10.0, .lat = 20.0},
.edge_ordering = 1,
.circle_idx = 5,
.contains_north_pole = 0},
{.a = {.lon = 45.0, .lat = 89.0},
.b = {.lon = 45.0+180.0, .lat = 85.0},
.edge_ordering = 1,
.circle_idx = 6,
.contains_north_pole = 0},
{.a = {.lon = 45.0, .lat = 89.0},
.b = {.lon = 45.0+180.0, .lat = 85.0},
.edge_ordering = -1,
.circle_idx = 7,
.contains_north_pole = 0},
{.a = {.lon = 10.0, .lat = 70.0},
.b = {.lon = 20.0, .lat = 70.0},
.edge_ordering = 1,
.circle_idx = 8,
.contains_north_pole = 1},
{.a = {.lon = 10.0, .lat = 70.0},
.b = {.lon = 20.0, .lat = 70.0},
.edge_ordering = -1,
.circle_idx = 9,
.contains_north_pole = 0},
{.a = {.lon = -5.0, .lat = 15.0},
.b = {.lon = 5.0, .lat = 15.0},
.edge_ordering = 1,
.circle_idx = 10,
.contains_north_pole = 1}};
enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
for (size_t i = 0; i < NUM_TESTS; ++i) {
double a[3], b[3];
LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
a, b, test_data[i].edge_type, test_data[i].edge_ordering,
&test_circles[i]);
}
for (size_t i = 0; i < NUM_TESTS; ++i) {
test_data[i].contains_north_pole)
PUT_ERR("error in yac_circle_contains_north_pole");
for (size_t j = 0; j < NUM_TESTS; ++j) {
check_compare_circles(
test_data[i].circle_idx == test_data[j].circle_idx);
}
}
}
{
struct {
struct point_2d a, b, point;
int edge_ordering;
int is_inside;
} test_data[] =
{{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.point = {.lon = 0.0, .lat = 90.0},
.edge_ordering = 1,
.is_inside = 1},
{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.point = {.lon = 0.0, .lat = 90.0},
.edge_ordering = -1,
.is_inside = 0},
{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.point = {.lon = 0.0, .lat = 0.0},
.edge_ordering = 1,
.is_inside = 2},
{.a = {.lon = -45.0, .lat = 0.0},
.b = {.lon = 45.0, .lat = 0.0},
.point = {.lon = 1.0, .lat = 1.0},
.edge_ordering = 1,
.is_inside = 1},
{.a = {.lon = 15.0, .lat = 25.0},
.b = {.lon = 15.0, .lat = 30.0},
.point = {.lon = 10.0, .lat = 10.0},
.edge_ordering = 1,
.is_inside = 1},
{.a = {.lon = 15.0, .lat = 25.0},
.b = {.lon = 15.0, .lat = 30.0},
.point = {.lon = 10.0, .lat = 10.0},
.edge_ordering = -1,
.is_inside = 0},
{.a = {.lon = 15.0, .lat = 25.0},
.b = {.lon = 15.0, .lat = 30.0},
.point = {.lon = 10.0, .lat = 90.0},
.edge_ordering = -1,
.is_inside = 2},
{.a = {.lon = 15.0, .lat = 25.0},
.b = {.lon = 15.0, .lat = 30.0},
.point = {.lon = 15.0, .lat = 60.0},
.edge_ordering = -1,
.is_inside = 2},
{.a = {.lon = 75.0, .lat = 75.0},
.b = {.lon = 80.0, .lat = 75.0},
.point = {.lon = 15.0, .lat = 80.0},
.edge_ordering = 1,
.is_inside = 1},
{.a = {.lon = 75.0, .lat = 75.0},
.b = {.lon = 80.0, .lat = 75.0},
.point = {.lon = 15.0, .lat = 90.0},
.edge_ordering = 1,
.is_inside = 1},
{.a = {.lon = 75.0, .lat = 75.0},
.b = {.lon = 80.0, .lat = 75.0},
.point = {.lon = 15.0, .lat = 80.0},
.edge_ordering = -1,
.is_inside = 0},
{.a = {.lon = 75.0, .lat = 75.0},
.b = {.lon = 80.0, .lat = 75.0},
.point = {.lon = 15.0, .lat = 90.0},
.edge_ordering = -1,
.is_inside = 0},
{.a = {.lon = 75.0, .lat = 75.0},
.b = {.lon = 80.0, .lat = 75.0},
.point = {.lon = 15.0, .lat = 75.0},
.edge_ordering = 1,
.is_inside = 2}};
enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
for (size_t i = 0; i < NUM_TESTS; ++i) {
double point[3];
test_data[i].point.lat, point);
double a[3], b[3];
LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
a, b, test_data[i].edge_type, test_data[i].edge_ordering,
&test_circle);
test_data[i].is_inside)
PUT_ERR("error in yac_circle_point_is_inside");
}
}
{
struct {
struct point_2d a, b, point_a, point_b;
int compare;
} test_data[] =
{{.a = {.lon = -1.0, .lat = -1.0},
.b = {.lon = 1.0, .lat = 1.0},
.point_a = {.lon = -1.0, .lat = 1.0},
.point_b = {.lon = -2.0, .lat = 2.0},
.compare = -1},
{.a = {.lon = -1.0, .lat = -1.0},
.b = {.lon = 1.0, .lat = 1.0},
.point_a = {.lon = -2.0, .lat = 2.0},
.point_b = {.lon = -1.0, .lat = 1.0},
.compare = 1},
{.a = {.lon = -1.0, .lat = -1.0},
.b = {.lon = 1.0, .lat = 1.0},
.point_a = {.lon = -2.0, .lat = 2.0},
.point_b = {.lon = 2.0, .lat = -2.0},
.compare = 0},
{.a = {.lon = -1.0, .lat = -1.0},
.b = {.lon = 1.0, .lat = 1.0},
.point_a = {.lon = 0.0, .lat = 0.0},
.point_b = {.lon = 2.0, .lat = -2.0},
.compare = -1},
{.a = {.lon = -1.0, .lat = -1.0},
.b = {.lon = 1.0, .lat = 1.0},
.point_a = {.lon = 2.0, .lat = -2.0},
.point_b = {.lon = 0.0, .lat = 0.0},
.compare = 1},
{.a = {.lon = 2.0, .lat = -1.0},
.b = {.lon = 2.0, .lat = 1.0},
.point_a = {.lon = 1.0, .lat = 1.0},
.point_b = {.lon = 4.0, .lat = -1.0},
.compare = -1},
{.a = {.lon = 2.0, .lat = -1.0},
.b = {.lon = 2.0, .lat = 1.0},
.point_a = {.lon = 4.0, .lat = -1.0},
.point_b = {.lon = 1.0, .lat = 1.0},
.compare = 1},
{.a = {.lon = 2.0, .lat = -1.0},
.b = {.lon = 2.0, .lat = 1.0},
.point_a = {.lon = 3.0, .lat = -1.0},
.point_b = {.lon = 1.0, .lat = 1.0},
.compare = 0},
{.a = {.lon = -1.0, .lat = 60.0},
.b = {.lon = 1.0, .lat = 60.0},
.point_a = {.lon = 7.0, .lat = 59.0},
.point_b = {.lon = -13.0, .lat = 62.0},
.compare = -1},
{.a = {.lon = -1.0, .lat = 60.0},
.b = {.lon = 1.0, .lat = 60.0},
.point_a = {.lon = -13.0, .lat = 62.0},
.point_b = {.lon = 7.0, .lat = 59.0},
.compare = 1},
{.a = {.lon = -1.0, .lat = 60.0},
.b = {.lon = 1.0, .lat = 60.0},
.point_a = {.lon = 7.0, .lat = 59.0},
.point_b = {.lon = -13.0, .lat = 61.0},
.compare = 0},
{.a = {.lon = 45.0, .lat = 45.0},
.b = {.lon = 45.0, .lat = 45.0},
.point_a = {.lon = 46.0, .lat = 46.0},
.point_b = {.lon = 47.0, .lat = 47.0},
.compare = -1},
{.a = {.lon = 45.0, .lat = 45.0},
.b = {.lon = 45.0, .lat = 45.0},
.point_a = {.lon = 47.0, .lat = 47.0},
.point_b = {.lon = 46.0, .lat = 46.0},
.compare = 1},
{.a = {.lon = 45.0, .lat = 45.0},
.b = {.lon = 45.0, .lat = 45.0},
.point_a = {.lon = 40.0, .lat = 40.0},
.point_b = {.lon = -45.0, .lat = -45.0},
.compare = -1},
{.a = {.lon = 45.0, .lat = 45.0},
.b = {.lon = 45.0, .lat = 45.0},
.point_a = {.lon = -45.0, .lat = -45.0},
.point_b = {.lon = 40.0, .lat = 40.0},
.compare = 1},
{.a = {.lon = 45.0, .lat = 45.0},
.b = {.lon = 45.0, .lat = 45.0},
.point_a = {.lon = 45.0, .lat = 90.0},
.point_b = {.lon = 45.0, .lat = 0.0},
.compare = 0}};
enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
for (size_t i = 0; i < NUM_TESTS; ++i) {
double point_a[3], point_b[3];
test_data[i].point_a.lat, point_a);
test_data[i].point_b.lat, point_b);
double a[3], b[3];
LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
a, b, test_data[i].edge_type, 1, &test_circle);
test_data[i].compare)
PUT_ERR("error in yac_circle_compare_distances");
}
}
{
struct {
struct {
} circles[2];
int ret_value;
} test_data[] =
{{.circles = {{.points = {{.lon = -1.0, .lat = -1.0},
{.lon = 1.0, .lat = 1.0}},
{.points = {{.lon = -1.0, .lat = 1.0},
{.lon = 1.0, .lat = -1.0}},
.p = {.lon = 0.0, .lat = 0.0},
.q = {.lon = 180.0, .lat = 0.0},
.ret_value = 2},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = 180.0, .lat = -2.0},
{.lon = 180.0, .lat = 2.0}},
.p = {.lon = 0.0, .lat = 0.0},
.q = {.lon = 0.0, .lat = 0.0},
.ret_value = -1},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = 6.0, .lat = 45.0},
{.lon = 9.0, .lat = 45.0}},
.p = {.lon = 0.0, .lat = 45.0},
.q = {.lon = 180.0, .lat = 45.0},
.ret_value = 2},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = 6.0, .lat = 90.0},
{.lon = 9.0, .lat = 90.0}},
.p = {.lon = 0.0, .lat = 90.0},
.q = {.lon = 180.0, .lat = -90.0},
.ret_value = 1},
{.circles = {{.points = {{.lon = 1.0, .lat = 0.0},
{.lon = 2.0, .lat = 0.0}},
{.points = {{.lon = 6.0, .lat = 45.0},
{.lon = 9.0, .lat = 45.0}},
.p = {.lon = 0.0, .lat = 0.0},
.q = {.lon = 0.0, .lat = 0.0},
.ret_value = 0},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = 17.0, .lat = -1.0},
{.lon = 17.0, .lat = 1.0}},
.p = {.lon = 0.0, .lat = 90.0},
.q = {.lon = 0.0, .lat = -90.0},
.ret_value = 2},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = 0.0, .lat = 45.0},
{.lon = 0.0, .lat = 50.0}},
.p = {.lon = 0.0, .lat = 90.0},
.q = {.lon = 0.0, .lat = -90.0},
.ret_value = -1},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = -1.0, .lat = 45.0},
{.lon = 1.0, .lat = 45.0}},
.p = {.lon = 0.0, .lat = 45.0},
.q = {.lon = 180.0, .lat = 45.0},
.ret_value = 2},
{.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = -1.0, .lat = -90.0},
{.lon = 1.0, .lat = -90.0}},
.p = {.lon = 0.0, .lat = -90.0},
.q = {.lon = 180.0, .lat = 90.0},
.ret_value = 1},
{.circles = {{.points = {{.lon = 0.0, .lat = 0.0},
{.lon = 0.0, .lat = 0.0}},
{.points = {{.lon = -1.0, .lat = 0.0},
{.lon = 1.0, .lat = 0.0}},
.p = {.lon = 0.0, .lat = 0.0},
.q = {.lon = 180.0, .lat = 0.0},
.ret_value = 1},
{.circles = {{.points = {{.lon = 0.0, .lat = 1.0},
{.lon = 0.0, .lat = 1.0}},
{.points = {{.lon = -1.0, .lat = 0.0},
{.lon = 1.0, .lat = 0.0}},
.p = {.lon = 0.0, .lat = 0.0},
.q = {.lon = 180.0, .lat = 0.0},
.ret_value = 0},
{.circles = {{.points = {{.lon = 0.0, .lat = 45.0},
{.lon = 0.0, .lat = 45.0}},
{.points = {{.lon = -1.0, .lat = 45.0},
{.lon = 1.0, .lat = 45.0}},
.p = {.lon = 0.0, .lat = 45.0},
.q = {.lon = 180.0, .lat = 45.0},
.ret_value = 1},
{.circles = {{.points = {{.lon = 0.0, .lat = 0.0},
{.lon = 0.0, .lat = 0.0}},
{.points = {{.lon = -1.0, .lat = 45.0},
{.lon = 1.0, .lat = 45.0}},
.p = {.lon = 0.0, .lat = 45.0},
.q = {.lon = 180.0, .lat = 45.0},
.ret_value = 0},
{.circles = {{.points = {{.lon = 5.0, .lat = 5.0},
{.lon = 5.0, .lat = 5.0}},
{.points = {{.lon = 5.0, .lat = 5.0},
{.lon = 5.0, .lat = 5.0}},
.p = {.lon = 5.0, .lat = 5.0},
.q = {.lon = 185.0, .lat = -5.0},
.ret_value = 1}};
enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
for (size_t i = 0; i < NUM_TESTS; ++i) {
for (int j = 0; j < 2; ++j) {
double points_3d[2][3];
for (int k = 0; k < 2; ++k)
test_data[i].circles[j].
points[k].
lat, points_3d[k]);
points_3d[0], points_3d[1], test_data[i].circles[j].edge_type,
1, &test_circles[j]);
}
double ref_p[3], ref_q[3],
p[3], q[3];
LLtoXYZ_deg(test_data[i].q.lon, test_data[i].q.lat, ref_q);
for (int j = 0; j < 2; ++j) {
test_circles[j], test_circles[j^1],
p, q) !=
test_data[i].ret_value)
PUT_ERR("error in yac_circle_intersect");
if (test_data[i].ret_value > 0)
PUT_ERR("error in yac_circle_intersect");
}
}
}
return TEST_EXIT_CODE;
}
static void check_compare_circles(
struct yac_circle * circle_a,
int a_is_lat,
int are_identical) {
if ((are_identical && (ret_a || ret_b)) ||
(!are_identical &&
((!ret_a || !ret_b) ||
(ret_a != - ret_b) ||
((a_is_lat != b_is_lat) &&
((ret_a > ret_b) ^ a_is_lat)))))
PUT_ERR("error in yac_circle_compare");
}
int yac_circle_point_is_inside(double const point[3], struct yac_circle *circle)
int yac_circle_compare(void const *a, void const *b)
int yac_circle_contains_north_pole(struct yac_circle *circle)
void yac_circle_generate(double const *a, double const *b, enum yac_edge_type type, int edge_ordering, struct yac_circle *circle)
int yac_circle_compare_distances(double const a[3], double const b[3], struct yac_circle *circle)
int main(int argc, char **argv)
int yac_circle_intersect(struct yac_circle a, struct yac_circle b, double p[3], double q[3])
static void LLtoXYZ_deg(double lon, double lat, double p_out[])
static double get_vector_angle(double const a[3], double const b[3])
@ YAC_GREAT_CIRCLE_EDGE
great circle
@ YAC_LAT_CIRCLE_EDGE
latitude circle
@ YAC_LON_CIRCLE_EDGE
longitude circle
struct yac_circle::@2::@4 lat
struct yac_circle::@2::@3 lon
struct yac_circle::@2::@5 p
static struct user_input_data_points ** points