Tachyon (current)  Current Main Branch
cylinder.c
Go to the documentation of this file.
1 /*
2  * cylinder.c - This file contains the functions for dealing with cylinders.
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: cylinder.c,v 1.30 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "macros.h"
19 #include "vector.h"
20 #include "intersect.h"
21 #include "util.h"
22 
23 #define CYLINDER_PRIVATE
24 #include "cylinder.h"
25 
26 static object_methods cylinder_methods = {
27  (void (*)(const void *, void *))(cylinder_intersect),
28  (void (*)(const void *, const void *, const void *, void *))(cylinder_normal),
30  free
31 };
32 
33 static object_methods fcylinder_methods = {
34  (void (*)(const void *, void *))(fcylinder_intersect),
35  (void (*)(const void *, const void *, const void *, void *))(cylinder_normal),
37  free
38 };
39 
40 
41 object * newcylinder(void * tex, vector ctr, vector axis, flt rad) {
42  cylinder * c;
43 
44  c=(cylinder *) malloc(sizeof(cylinder));
45  memset(c, 0, sizeof(cylinder));
46  c->methods = &cylinder_methods;
47 
48  c->tex=(texture *) tex;
49  c->ctr=ctr;
50  c->axis=axis;
51  c->rad=rad;
52  return (object *) c;
53 }
54 
55 static int cylinder_bbox(void * obj, vector * min, vector * max) {
56  return 0; /* infinite / unbounded object */
57 }
58 
59 static void cylinder_intersect(const cylinder * cyl, ray * ry) {
60  vector rc, n, D, O;
61  flt t, s, tin, tout, ln, d;
62 
63  rc.x = ry->o.x - cyl->ctr.x;
64  rc.y = ry->o.y - cyl->ctr.y;
65  rc.z = ry->o.z - cyl->ctr.z;
66 
67  VCross(&ry->d, &cyl->axis, &n);
68 
69  ln=SQRT(n.x*n.x + n.y*n.y + n.z*n.z); /* finish length calculation */
70 
71  if (ln == 0.0) { /* ray is parallel to the cylinder.. */
72  VDOT(d, rc, cyl->axis);
73  D.x = rc.x - d * cyl->axis.x;
74  D.y = rc.y - d * cyl->axis.y;
75  D.z = rc.z - d * cyl->axis.z;
76  VDOT(d, D, D);
77  d = SQRT(d);
78  tin = -FHUGE;
79  tout = FHUGE;
80  /* if (d <= cyl->rad) then ray is inside cylinder.. else outside */
81  }
82 
83  n.x /= ln;
84  n.y /= ln;
85  n.z /= ln;
86 
87  VDOT(d, rc, n);
88  d = FABS(d);
89 
90  if (d <= cyl->rad) { /* ray intersects cylinder.. */
91  VCross(&rc, &cyl->axis, &O);
92  VDOT(t, O, n);
93  t = - t / ln;
94  VCross(&n, &cyl->axis, &O);
95 
96  ln = SQRT(O.x*O.x + O.y*O.y + O.z*O.z);
97  O.x /= ln;
98  O.y /= ln;
99  O.z /= ln;
100 
101  VDOT(s, ry->d, O);
102  s = FABS(SQRT(cyl->rad*cyl->rad - d*d) / s);
103  tin = t - s;
104  ry->add_intersection(tin, (object *) cyl, ry);
105  tout = t + s;
106  ry->add_intersection(tout, (object *) cyl, ry);
107  }
108 }
109 
110 static void cylinder_normal(const cylinder * cyl, const vector * pnt, const ray * incident, vector * N) {
111  vector a, b;
112  flt t, invlen, invlen2;
113 
114  a.x = pnt->x - cyl->ctr.x;
115  a.y = pnt->y - cyl->ctr.y;
116  a.z = pnt->z - cyl->ctr.z;
117 
118  b=cyl->axis;
119 
120  invlen = 1.0 / SQRT(b.x*b.x + b.y*b.y + b.z*b.z);
121  b.x *= invlen;
122  b.y *= invlen;
123  b.z *= invlen;
124 
125  VDOT(t, a, b);
126 
127  N->x = pnt->x - (b.x * t + cyl->ctr.x);
128  N->y = pnt->y - (b.y * t + cyl->ctr.y);
129  N->z = pnt->z - (b.z * t + cyl->ctr.z);
130 
131  invlen2 = 1.0 / SQRT(N->x*N->x + N->y*N->y + N->z*N->z);
132  N->x *= invlen2;
133  N->y *= invlen2;
134  N->z *= invlen2;
135 
136  /* Flip surface normal to point toward the viewer if necessary */
137  if (VDot(N, &(incident->d)) > 0.0) {
138  N->x=-N->x;
139  N->y=-N->y;
140  N->z=-N->z;
141  }
142 }
143 
144 object * newfcylinder(void * tex, vector ctr, vector axis, flt rad) {
145  cylinder * c;
146 
147  c=(cylinder *) malloc(sizeof(cylinder));
148  memset(c, 0, sizeof(cylinder));
149  c->methods = &fcylinder_methods;
150 
151  c->tex=(texture *) tex;
152  c->ctr=ctr;
153  c->axis=axis;
154  c->rad=rad;
155 
156  return (object *) c;
157 }
158 
159 static int fcylinder_bbox(void * obj, vector * min, vector * max) {
160  cylinder * c = (cylinder *) obj;
161  vector mintmp, maxtmp;
162 
163  mintmp.x = c->ctr.x;
164  mintmp.y = c->ctr.y;
165  mintmp.z = c->ctr.z;
166  maxtmp.x = c->ctr.x + c->axis.x;
167  maxtmp.y = c->ctr.y + c->axis.y;
168  maxtmp.z = c->ctr.z + c->axis.z;
169 
170  min->x = MYMIN(mintmp.x, maxtmp.x);
171  min->y = MYMIN(mintmp.y, maxtmp.y);
172  min->z = MYMIN(mintmp.z, maxtmp.z);
173  min->x -= c->rad;
174  min->y -= c->rad;
175  min->z -= c->rad;
176 
177  max->x = MYMAX(mintmp.x, maxtmp.x);
178  max->y = MYMAX(mintmp.y, maxtmp.y);
179  max->z = MYMAX(mintmp.z, maxtmp.z);
180  max->x += c->rad;
181  max->y += c->rad;
182  max->z += c->rad;
183 
184  return 1;
185 }
186 
187 
188 static void fcylinder_intersect(const cylinder * cyl, ray * ry) {
189  vector rc, n, O, hit, tmp2, ctmp4;
190  flt t, s, tin, tout, ln, d, tmp, tmp3;
191 
192  rc.x = ry->o.x - cyl->ctr.x;
193  rc.y = ry->o.y - cyl->ctr.y;
194  rc.z = ry->o.z - cyl->ctr.z;
195 
196  VCross(&ry->d, &cyl->axis, &n);
197 
198  ln=SQRT(n.x*n.x + n.y*n.y + n.z*n.z); /* finish length calculation */
199 
200  if (ln == 0.0) { /* ray is parallel to the cylinder.. */
201  return; /* in this case, we want to miss or go through the "hole" */
202  }
203 
204  n.x /= ln;
205  n.y /= ln;
206  n.z /= ln;
207 
208  VDOT(d, rc, n);
209  d = FABS(d);
210 
211  if (d <= cyl->rad) { /* ray intersects cylinder.. */
212  VCross(&rc, &cyl->axis, &O);
213  VDOT(t, O, n);
214  t = - t / ln;
215  VCross(&n, &cyl->axis, &O);
216 
217  ln = SQRT(O.x*O.x + O.y*O.y + O.z*O.z);
218  O.x /= ln;
219  O.y /= ln;
220  O.z /= ln;
221 
222  VDOT(s, ry->d, O);
223  s = FABS(SQRT(cyl->rad*cyl->rad - d*d) / s);
224  tin = t - s;
225 
226  RAYPNT(hit, (*ry), tin);
227 
228  ctmp4=cyl->axis;
229  VNorm(&ctmp4);
230 
231  tmp2.x = hit.x - cyl->ctr.x;
232  tmp2.y = hit.y - cyl->ctr.y;
233  tmp2.z = hit.z - cyl->ctr.z;
234 
235  VDOT(tmp, tmp2, ctmp4);
236  VDOT(tmp3, cyl->axis, cyl->axis);
237 
238  if ((tmp > 0.0) && (tmp < SQRT(tmp3)))
239  ry->add_intersection(tin, (object *) cyl, ry);
240  tout = t + s;
241 
242  RAYPNT(hit, (*ry), tout);
243 
244  tmp2.x = hit.x - cyl->ctr.x;
245  tmp2.y = hit.y - cyl->ctr.y;
246  tmp2.z = hit.z - cyl->ctr.z;
247 
248  VDOT(tmp, tmp2, ctmp4);
249  VDOT(tmp3, cyl->axis, cyl->axis);
250 
251  if ((tmp > 0.0) && (tmp < SQRT(tmp3)))
252  ry->add_intersection(tout, (object *) cyl, ry);
253  }
254 }
255 
static void fcylinder_intersect(const cylinder *cyl, ray *ry)
Definition: cylinder.c:188
void VNorm(apivector *)
flt VDot(apivector *a, apivector *b)
static void cylinder_normal(const cylinder *cyl, const vector *pnt, const ray *incident, vector *N)
Definition: cylinder.c:110
double flt
generic floating point number, using double
Definition: tachyon.h:47
static object_methods cylinder_methods
Definition: cylinder.c:26
void VCross(apivector *a, apivector *b, apivector *c)
static int fcylinder_bbox(void *obj, vector *min, vector *max)
Definition: cylinder.c:159
#define VDOT(return, a, b)
Definition: macros.h:15
static void cylinder_intersect(const cylinder *cyl, ray *ry)
Definition: cylinder.c:59
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define RAYPNT(c, a, b)
Definition: macros.h:18
#define MYMIN(a, b)
Definition: macros.h:13
#define SQRT(x)
Definition: util.h:31
object * newcylinder(void *tex, vector ctr, vector axis, flt rad)
Definition: cylinder.c:41
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
object * newfcylinder(void *tex, vector ctr, vector axis, flt rad)
Definition: cylinder.c:144
static object_methods fcylinder_methods
Definition: cylinder.c:33
static int cylinder_bbox(void *obj, vector *min, vector *max)
Definition: cylinder.c:55
#define FABS(x)
Definition: util.h:28
#define MYMAX(a, b)
Definition: macros.h:12