ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/fvect.c
Revision: 2.19
Committed: Sat Jun 29 21:03:44 2013 UTC (10 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad4R2, rad4R2P1
Changes since 2.18: +21 -1 lines
Log Message:
Fixed problem with acos(1) returning NaN

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: fvect.c,v 2.18 2013/04/03 00:22:12 greg Exp $";
3 #endif
4 /*
5 * fvect.c - routines for floating-point vector calculations
6 */
7
8 #include "copyright.h"
9
10 #define _USE_MATH_DEFINES
11 #include <math.h>
12 #include "fvect.h"
13
14 double
15 Acos(double x) /* insurance for touchy math library */
16 {
17 if (x <= -1.+FTINY*FTINY)
18 return(M_PI);
19 if (x >= 1.-FTINY*FTINY)
20 return(.0);
21 return(acos(x));
22 }
23
24 double
25 Asin(double x) /* insurance for touchy math library */
26 {
27 if (x <= -1.+FTINY*FTINY)
28 return(-M_PI/2.);
29 if (x >= 1.-FTINY*FTINY)
30 return(M_PI/2);
31 return(asin(x));
32 }
33
34 double
35 fdot( /* return the dot product of two vectors */
36 const FVECT v1,
37 const FVECT v2
38 )
39 {
40 return(DOT(v1,v2));
41 }
42
43
44 double
45 dist2( /* return square of distance between points */
46 const FVECT p1,
47 const FVECT p2
48 )
49 {
50 FVECT delta;
51
52 VSUB(delta, p2, p1);
53
54 return(DOT(delta, delta));
55 }
56
57
58 double
59 dist2line( /* return square of distance to line */
60 const FVECT p, /* the point */
61 const FVECT ep1,
62 const FVECT ep2 /* points on the line */
63 )
64 {
65 double d, d1, d2;
66
67 d = dist2(ep1, ep2);
68 d1 = dist2(ep1, p);
69 d2 = d + d1 - dist2(ep2, p);
70
71 return(d1 - 0.25*d2*d2/d);
72 }
73
74
75 double
76 dist2lseg( /* return square of distance to line segment */
77 const FVECT p, /* the point */
78 const FVECT ep1,
79 const FVECT ep2 /* the end points */
80 )
81 {
82 double d, d1, d2;
83
84 d = dist2(ep1, ep2);
85 d1 = dist2(ep1, p);
86 d2 = dist2(ep2, p);
87
88 if (d2 > d1) { /* check if past endpoints */
89 if (d2 - d1 > d)
90 return(d1);
91 } else {
92 if (d1 - d2 > d)
93 return(d2);
94 }
95 d2 = d + d1 - d2;
96
97 return(d1 - 0.25*d2*d2/d); /* distance to line */
98 }
99
100
101 void
102 fcross( /* vres = v1 X v2 */
103 FVECT vres,
104 const FVECT v1,
105 const FVECT v2
106 )
107 {
108 VCROSS(vres, v1, v2);
109 }
110
111
112 void
113 fvsum( /* vres = v0 + f*v1 */
114 FVECT vres,
115 const FVECT v0,
116 const FVECT v1,
117 double f
118 )
119 {
120 VSUM(vres, v0, v1, f);
121 }
122
123
124 double
125 normalize( /* normalize a vector, return old magnitude */
126 FVECT v
127 )
128 {
129 double len, d;
130
131 d = DOT(v, v);
132
133 if (d == 0.0)
134 return(0.0);
135
136 if ((d <= 1.0+FTINY) & (d >= 1.0-FTINY)) {
137 len = 0.5 + 0.5*d; /* first order approximation */
138 d = 2.0 - len;
139 } else {
140 len = sqrt(d);
141 d = 1.0/len;
142 }
143 v[0] *= d;
144 v[1] *= d;
145 v[2] *= d;
146
147 return(len);
148 }
149
150
151 int
152 closestapproach( /* closest approach of two rays */
153 RREAL t[2], /* returned distances along each ray */
154 const FVECT rorg0, /* first origin */
155 const FVECT rdir0, /* first direction (normalized) */
156 const FVECT rorg1, /* second origin */
157 const FVECT rdir1 /* second direction (normalized) */
158 )
159 {
160 double dotprod = DOT(rdir0, rdir1);
161 double denom = 1. - dotprod*dotprod;
162 double o1o2_d1;
163 FVECT o0o1;
164
165 if (denom <= FTINY) { /* check if lines are parallel */
166 t[0] = t[1] = 0.0;
167 return(0);
168 }
169 VSUB(o0o1, rorg0, rorg1);
170 o1o2_d1 = DOT(o0o1, rdir1);
171 t[0] = (o1o2_d1*dotprod - DOT(o0o1,rdir0)) / denom;
172 t[1] = o1o2_d1 + t[0]*dotprod;
173 return(1);
174 }
175
176
177 void
178 spinvector( /* rotate vector around normal */
179 FVECT vres, /* returned vector (same magnitude as vorig) */
180 const FVECT vorig, /* original vector */
181 const FVECT vnorm, /* normalized vector for rotation */
182 double theta /* right-hand radians */
183 )
184 {
185 double sint, cost, normprod;
186 FVECT vperp;
187 int i;
188
189 if (theta == 0.0) {
190 if (vres != vorig)
191 VCOPY(vres, vorig);
192 return;
193 }
194 cost = cos(theta);
195 sint = sin(theta);
196 normprod = DOT(vorig, vnorm)*(1.-cost);
197 VCROSS(vperp, vnorm, vorig);
198 for (i = 0; i < 3; i++)
199 vres[i] = vorig[i]*cost + vnorm[i]*normprod + vperp[i]*sint;
200 }
201
202 double
203 geodesic( /* rotate vector on great circle towards target */
204 FVECT vres, /* returned vector (same magnitude as vorig) */
205 const FVECT vorig, /* original vector */
206 const FVECT vtarg, /* vector we are rotating towards */
207 double t, /* amount along arc directed towards vtarg */
208 int meas /* distance measure (radians, absolute, relative) */
209 )
210 {
211 FVECT normtarg;
212 double volen, dotprod, sintr, cost;
213 int i;
214
215 VCOPY(normtarg, vtarg); /* in case vtarg==vres */
216 if (vres != vorig)
217 VCOPY(vres, vorig);
218 if (t == 0.0)
219 return(VLEN(vres)); /* no rotation requested */
220 if ((volen = normalize(vres)) == 0.0)
221 return(0.0);
222 if (normalize(normtarg) == 0.0)
223 return(0.0); /* target vector is zero */
224 dotprod = DOT(vres, normtarg);
225 /* check for colinear */
226 if (dotprod >= 1.0-FTINY*FTINY) {
227 if (meas != GEOD_REL)
228 return(0.0);
229 vres[0] *= volen; vres[1] *= volen; vres[2] *= volen;
230 return(volen);
231 }
232 if (dotprod <= -1.0+FTINY*FTINY)
233 return(0.0);
234 if (meas == GEOD_ABS)
235 t /= volen;
236 else if (meas == GEOD_REL)
237 t *= acos(dotprod);
238 cost = cos(t);
239 sintr = sin(t) / sqrt(1. - dotprod*dotprod);
240 for (i = 0; i < 3; i++)
241 vres[i] = volen*( cost*vres[i] +
242 sintr*(normtarg[i] - dotprod*vres[i]) );
243
244 return(volen); /* return vector length */
245 }