raytracer-c/test/module_shapes/test_cylinder.c

220 lines
7.2 KiB
C

#include "../testutils.h"
#include <cylinder.h>
#include <ray.h>
#include <tuples.h>
#include <unity.h>
void setUp(void) {}
void tearDown(void) {}
void helper_ray_misses_cylinder(double ox, double oy, double oz, double dx, double dy, double dz) {
CYLINDER_Cylinder *c = CYLINDER_new();
TUPLES_Vector direction;
TUPLES_Point origin;
TUPLES_init_vector(&direction, dx, dy, dz);
TUPLES_normalize(&direction);
TUPLES_init_vector(&origin, ox, oy, oz);
RAY_Ray ray;
RAY_init_from_tuples(&ray, &origin, &direction);
RAY_Intersections *xs = RAY_new_intersections();
CYLINDER_local_intersect(xs, (SHAPE_Shape *)c, &ray);
TEST_ASSERT_EQUAL(0, xs->count);
RAY_delete_intersections(xs);
CYLINDER_delete(c);
}
void test_ray_misses_cylinder(void) {
helper_ray_misses_cylinder(1, 0, 0, 0, 1, 0);
helper_ray_misses_cylinder(0, 0, 0, 0, 1, 0);
helper_ray_misses_cylinder(0, 0, -5, 1, 1, 1);
}
void helper_ray_hits_cylinder(double ox, double oy, double oz, double dx, double dy, double dz, double t0, double t1) {
CYLINDER_Cylinder *c = CYLINDER_new();
TUPLES_Vector direction;
TUPLES_Point origin;
TUPLES_init_vector(&direction, dx, dy, dz);
TUPLES_normalize(&direction);
TUPLES_init_point(&origin, ox, oy, oz);
RAY_Ray ray;
RAY_init_from_tuples(&ray, &origin, &direction);
RAY_Intersections *xs = RAY_new_intersections();
CYLINDER_local_intersect(xs, (SHAPE_Shape *)c, &ray);
TEST_ASSERT_EQUAL(2, xs->count);
TEST_ASSERT_EQUAL_DOUBLE(t0, xs->xs[0].t);
TEST_ASSERT_EQUAL_DOUBLE(t1, xs->xs[1].t);
RAY_delete_intersections(xs);
CYLINDER_delete(c);
}
void test_ray_hits_cylinder(void) {
helper_ray_hits_cylinder(1, 0, -5, 0, 0, 1, 5, 5);
helper_ray_hits_cylinder(0, 0, -5, 0, 0, 1, 4, 6);
helper_ray_hits_cylinder(0.5, 0, -5, 0.1, 1, 1, 6.80798, 7.08872);
}
void helper_normal_vector_on_cylinder(double px, double py, double pz, double nx, double ny, double nz) {
CYLINDER_Cylinder *c = CYLINDER_new();
TUPLES_Point p;
TUPLES_init_point(&p, px, py, pz);
TUPLES_Vector got, expected;
CYLINDER_local_normal_at(&got, (SHAPE_Shape *)c, &p, NULL);
TUPLES_init_vector(&expected, nx, ny, nz);
test_tuples(&got, &expected);
CYLINDER_delete(c);
}
void test_normal_vector_on_cylinder(void) {
helper_normal_vector_on_cylinder(1, 0, 0, 1, 0, 0);
helper_normal_vector_on_cylinder(0, 5, -1, 0, 0, -1);
helper_normal_vector_on_cylinder(0, -2, 1, 0, 0, 1);
helper_normal_vector_on_cylinder(-1, 1, 0, -1, 0, 0);
}
void test_default_cylinder_min_max(void) {
CYLINDER_Cylinder *c = CYLINDER_new();
TEST_ASSERT_EQUAL_DOUBLE(-INFINITY, c->minimum);
TEST_ASSERT_EQUAL_DOUBLE(INFINITY, c->maximum);
CYLINDER_delete(c);
}
void helper_intersect_constrained_cylinder(double px, double py, double pz, double dx, double dy, double dz, unsigned int count) {
CYLINDER_Cylinder *c = CYLINDER_new();
c->maximum = 2;
c->minimum = 1;
TUPLES_Vector direction;
TUPLES_init_vector(&direction, dx, dy, dz);
TUPLES_normalize(&direction);
TUPLES_Point p;
TUPLES_init_point(&p, px, py, pz);
RAY_Ray ray;
RAY_init_from_tuples(&ray, &p, &direction);
RAY_Intersections *xs = RAY_new_intersections();
CYLINDER_local_intersect(xs, (SHAPE_Shape *)c, &ray);
TEST_ASSERT_EQUAL(count, xs->count);
RAY_delete_intersections(xs);
CYLINDER_delete(c);
}
void test_intersect_constrained_cylinder(void) {
helper_intersect_constrained_cylinder(0, 1.5, 0, 0.1, 1, 0, 0);
helper_intersect_constrained_cylinder(0, 3, -5, 0, 0, 1, 0);
helper_intersect_constrained_cylinder(0, 0, -5, 0, 0, 1, 0);
helper_intersect_constrained_cylinder(0, 2, -5, 0, 0, 1, 0);
helper_intersect_constrained_cylinder(0, 1, -5, 0, 0, 1, 0);
helper_intersect_constrained_cylinder(0, 1.5, -2, 0, 0, 1, 2);
}
void test_default_closed_value_for_cylinder(void) {
CYLINDER_Cylinder *c = CYLINDER_new();
TEST_ASSERT_FALSE(c->closed);
CYLINDER_delete(c);
}
void helper_intersect_caps_of_closed_cylinder(double px, double py, double pz, double dx, double dy, double dz, unsigned int count) {
CYLINDER_Cylinder *c = CYLINDER_new();
c->minimum = 1;
c->maximum = 2;
c->closed = true;
TUPLES_Vector direction;
TUPLES_init_vector(&direction, dx, dy, dz);
TUPLES_normalize(&direction);
TUPLES_Point p;
TUPLES_init_point(&p, px, py, pz);
RAY_Ray ray;
RAY_init_from_tuples(&ray, &p, &direction);
RAY_Intersections *xs = RAY_new_intersections();
CYLINDER_local_intersect(xs, (SHAPE_Shape *)c, &ray);
TEST_ASSERT_EQUAL(count, xs->count);
RAY_delete_intersections(xs);
CYLINDER_delete(c);
}
void test_intersect_caps_of_closed_cylinder(void) {
helper_intersect_caps_of_closed_cylinder(0, 3, 0, 0, -1, 0, 2);
helper_intersect_caps_of_closed_cylinder(0, 3, -2, 0, -1, 2, 2);
helper_intersect_caps_of_closed_cylinder(0, 4, -2, 0, -1, 1, 2);
helper_intersect_caps_of_closed_cylinder(0, 0, -2, 0, 1, 2, 2);
helper_intersect_caps_of_closed_cylinder(0, -1, -2, 0, 1, 1, 2);
}
void helper_test_normal_vector_on_cylinder_end_caps(double px, double py, double pz, double nx, double ny, double nz) {
CYLINDER_Cylinder *c = CYLINDER_new();
c->minimum = 1;
c->maximum = 2;
c->closed = true;
TUPLES_Point p;
TUPLES_init_point(&p, px, py, pz);
TUPLES_Vector expected, got;
TUPLES_init_vector(&expected, nx, ny, nz);
CYLINDER_local_normal_at(&got, (SHAPE_Shape *)c, &p, NULL);
test_tuples(&expected, &got);
CYLINDER_delete(c);
}
void test_normal_vector_on_cylinder_end_caps(void) {
helper_test_normal_vector_on_cylinder_end_caps(0, 1, 0, 0, -1, 0);
helper_test_normal_vector_on_cylinder_end_caps(0.5, 1, 0, 0, -1, 0);
helper_test_normal_vector_on_cylinder_end_caps(0, 1, 0.5, 0, -1, 0);
helper_test_normal_vector_on_cylinder_end_caps(0, 2, 0, 0, 1, 0);
helper_test_normal_vector_on_cylinder_end_caps(0.5, 2, 0, 0, 1, 0);
helper_test_normal_vector_on_cylinder_end_caps(0, 2, 0.5, 0, 1, 0);
}
void test_unbounded_cylinder_bounding_box(void) {
CYLINDER_Cylinder *c = CYLINDER_new();
BOUND_Box box;
c->vtable->bounds_of((SHAPE_Shape *)c, &box);
TUPLES_Point min_expected, max_expected;
TUPLES_init_point(&min_expected, -1, -INFINITY, -1);
TUPLES_init_point(&max_expected, 1, INFINITY, 1);
TEST_ASSERT_TRUE(TUPLES_is_equal(&min_expected, &box.min));
TEST_ASSERT_TRUE(TUPLES_is_equal(&max_expected, &box.max));
CYLINDER_delete(c);
}
void test_bounded_cylinder_bounding_box(void) {
CYLINDER_Cylinder *c = CYLINDER_new();
c->minimum = -5;
c->maximum = 3;
BOUND_Box box;
c->vtable->bounds_of((SHAPE_Shape *)c, &box);
TUPLES_Point min_expected, max_expected;
TUPLES_init_point(&min_expected, -1, -5, -1);
TUPLES_init_point(&max_expected, 1, 3, 1);
TEST_ASSERT_TRUE(TUPLES_is_equal(&min_expected, &box.min));
TEST_ASSERT_TRUE(TUPLES_is_equal(&max_expected, &box.max));
CYLINDER_delete(c);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_ray_misses_cylinder);
RUN_TEST(test_ray_hits_cylinder);
RUN_TEST(test_normal_vector_on_cylinder);
RUN_TEST(test_default_cylinder_min_max);
RUN_TEST(test_intersect_constrained_cylinder);
RUN_TEST(test_default_closed_value_for_cylinder);
RUN_TEST(test_intersect_caps_of_closed_cylinder);
RUN_TEST(test_normal_vector_on_cylinder_end_caps);
RUN_TEST(test_bounded_cylinder_bounding_box);
RUN_TEST(test_unbounded_cylinder_bounding_box);
return UNITY_END();
}