129 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <assert.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include "cone.h"
 | |
| #include "exceptions.h"
 | |
| 
 | |
| void CONE_bounds_of(const SHAPE_Shape *shape, BOUND_Box *box) {
 | |
|   assert(shape);
 | |
|   assert(box);
 | |
|   CONE_Cone *cone = (CONE_Cone *)shape;
 | |
| 
 | |
|   double a = fabs(cone->minimum);
 | |
|   double b = fabs(cone->maximum);
 | |
|   double limit = (a > b) ? a : b;
 | |
| 
 | |
|   BOUND_init(box);
 | |
|   BOUND_add_point(box, -limit, cone->minimum, -limit);
 | |
|   BOUND_add_point(box, limit, cone->maximum, limit);
 | |
| }
 | |
| 
 | |
| const SHAPE_vtable CONE_vtable = {&CONE_local_intersect, &CYLINDER_delete_shape, &CONE_local_normal_at, &SHAPE_default_shape_contains, &CONE_bounds_of, NULL};
 | |
| 
 | |
| CONE_Cone *CONE_new() {
 | |
|   CONE_Cone *cone = malloc(sizeof(CONE_Cone));
 | |
|   if (!cone) {
 | |
|     Throw(E_MALLOC_FAILED);
 | |
|   }
 | |
|   CONE_init(cone);
 | |
|   return cone;
 | |
| }
 | |
| 
 | |
| void CONE_init(CONE_Cone *cone) {
 | |
|   assert(cone);
 | |
|   SHAPE_init(&cone->shape, &CONE_vtable);
 | |
|   cone->minimum = -INFINITY;
 | |
|   cone->maximum = INFINITY;
 | |
|   cone->closed = false;
 | |
| }
 | |
| 
 | |
| void CONE_local_normal_at(TUPLES_Vector *local_normal, SHAPE_Shape *shape, const TUPLES_Point *local_point, const RAY_Xs *hit) {
 | |
|   assert(local_normal);
 | |
|   assert(shape);
 | |
|   assert(local_point);
 | |
|   UNUSED(hit);
 | |
| 
 | |
|   CONE_Cone *cone = (CONE_Cone *)shape;
 | |
|   double dist = pow(local_point->x, 2) + pow(local_point->z, 2);
 | |
|   if (dist < 1 && local_point->y >= cone->maximum - EPSILON) {
 | |
|     TUPLES_init_vector(local_normal, 0, 1, 0);
 | |
|   } else if (dist < 1 && local_point->y <= cone->minimum + EPSILON) {
 | |
|     TUPLES_init_vector(local_normal, 0, -1, 0);
 | |
|   } else {
 | |
|     double y = sqrt(pow(local_point->x, 2) + pow(local_point->z, 2));
 | |
|     if (local_point->y > 0) {
 | |
|       y = -y;
 | |
|     }
 | |
|     TUPLES_init_vector(local_normal, local_point->x, y, local_point->z);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void intersect_caps(RAY_Intersections *intersections, CONE_Cone *cone, const RAY_Ray *local_ray) {
 | |
|   // if not closed, no need to check
 | |
|   if (!cone->closed || double_equal(0.0, local_ray->direction.y)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // check bottom cap
 | |
|   double t = (cone->minimum - local_ray->origin.y) / local_ray->direction.y;
 | |
|   if (CYLINDER_check_cap(local_ray, t, cone->minimum)) {
 | |
|     RAY_add_intersection(intersections, t, cone);
 | |
|   }
 | |
| 
 | |
|   // check top cap
 | |
|   t = (cone->maximum - local_ray->origin.y) / local_ray->direction.y;
 | |
|   if (CYLINDER_check_cap(local_ray, t, cone->maximum)) {
 | |
|     RAY_add_intersection(intersections, t, cone);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CONE_local_intersect(RAY_Intersections *intersections, SHAPE_Shape *shape, const RAY_Ray *local_ray) {
 | |
|   assert(intersections);
 | |
|   assert(shape);
 | |
|   assert(local_ray);
 | |
|   CONE_Cone *cone = (CONE_Cone *)shape;
 | |
| 
 | |
|   double a = pow(local_ray->direction.x, 2) - pow(local_ray->direction.y, 2) + pow(local_ray->direction.z, 2);
 | |
| 
 | |
|   double b =
 | |
|       2 * local_ray->origin.x * local_ray->direction.x - 2 * local_ray->origin.y * local_ray->direction.y + 2 * local_ray->origin.z * local_ray->direction.z;
 | |
| 
 | |
|   if (double_equal(0, a) && double_equal(0, b)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   double c = pow(local_ray->origin.x, 2) - pow(local_ray->origin.y, 2) + pow(local_ray->origin.z, 2);
 | |
|   if (double_equal(0, a)) {
 | |
|     double t = -c / (2 * b);
 | |
|     RAY_add_intersection(intersections, t, shape);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   double disc = pow(b, 2) - 4 * a * c;
 | |
| 
 | |
|   if (disc < 0) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   double t0 = (-b - sqrt(disc)) / (2 * a);
 | |
|   double t1 = (-b + sqrt(disc)) / (2 * a);
 | |
| 
 | |
|   if (t0 > t1) {
 | |
|     double tmp = t1;
 | |
|     t1 = t0;
 | |
|     t0 = tmp;
 | |
|   }
 | |
| 
 | |
|   double y0 = local_ray->origin.y + t0 * local_ray->direction.y;
 | |
|   if (cone->minimum < y0 && y0 < cone->maximum) {
 | |
|     RAY_add_intersection(intersections, t0, cone);
 | |
|   }
 | |
| 
 | |
|   double y1 = local_ray->origin.y + t1 * local_ray->direction.y;
 | |
|   if (cone->minimum < y1 && y1 < cone->maximum) {
 | |
|     RAY_add_intersection(intersections, t1, cone);
 | |
|   }
 | |
| 
 | |
|   intersect_caps(intersections, cone, local_ray);
 | |
| }
 |