| 1 | greg | 1.1 | #ifndef lint | 
| 2 | greg | 2.18 | static const char       RCSid[] = "$Id: mkillum2.c,v 2.17 2004/09/19 08:42:22 greg Exp $"; | 
| 3 | greg | 1.1 | #endif | 
| 4 |  |  | /* | 
| 5 | greg | 1.4 | * Routines to do the actual calculation for mkillum | 
| 6 | greg | 1.1 | */ | 
| 7 |  |  |  | 
| 8 | schorsch | 2.11 | #include <string.h> | 
| 9 |  |  |  | 
| 10 | greg | 1.1 | #include  "mkillum.h" | 
| 11 |  |  | #include  "face.h" | 
| 12 |  |  | #include  "cone.h" | 
| 13 | greg | 1.2 | #include  "random.h" | 
| 14 | greg | 1.1 |  | 
| 15 | greg | 2.13 |  | 
| 16 | greg | 2.16 | static void mkaxes(FVECT u, FVECT v, FVECT n); | 
| 17 |  |  | static void rounddir(FVECT dv, double alt, double azi); | 
| 18 |  |  | static void flatdir(FVECT dv, double alt, double azi); | 
| 19 |  |  |  | 
| 20 |  |  |  | 
| 21 | greg | 2.18 | static COLORV * distarr = NULL;         /* distribution array */ | 
| 22 |  |  | static int      distsiz = 0; | 
| 23 |  |  |  | 
| 24 |  |  |  | 
| 25 |  |  | static void | 
| 26 |  |  | newdist(                        /* allocate & clear distribution array */ | 
| 27 |  |  | int siz | 
| 28 |  |  | ) | 
| 29 |  |  | { | 
| 30 |  |  | if (siz == 0) { | 
| 31 |  |  | if (distsiz > 0) | 
| 32 |  |  | free((void *)distarr); | 
| 33 |  |  | distarr = NULL; | 
| 34 |  |  | distsiz = 0; | 
| 35 |  |  | return; | 
| 36 |  |  | } | 
| 37 |  |  | if (distsiz < siz) { | 
| 38 |  |  | free((void *)distarr); | 
| 39 |  |  | distarr = (COLORV *)malloc(sizeof(COLORV)*3*siz); | 
| 40 |  |  | if (distarr == NULL) | 
| 41 |  |  | error(SYSTEM, "Out of memory in distalloc"); | 
| 42 |  |  | distsiz = siz; | 
| 43 |  |  | } | 
| 44 |  |  | memset(distarr, '\0', sizeof(COLORV)*3*siz); | 
| 45 |  |  | } | 
| 46 |  |  |  | 
| 47 |  |  |  | 
| 48 |  |  | static int | 
| 49 |  |  | process_ray(RAY *r, int rv) | 
| 50 |  |  | { | 
| 51 |  |  | COLORV  *colp; | 
| 52 |  |  |  | 
| 53 |  |  | if (rv == 0) | 
| 54 |  |  | return(0); | 
| 55 |  |  | if (rv < 0) | 
| 56 |  |  | error(USER, "Ray tracing process died"); | 
| 57 |  |  | if (r->rno >= distsiz) | 
| 58 |  |  | error(INTERNAL, "Bad returned index in process_ray"); | 
| 59 |  |  | colp = &distarr[r->rno * 3]; | 
| 60 |  |  | addcolor(colp, r->rcol); | 
| 61 |  |  | return(1); | 
| 62 |  |  | } | 
| 63 |  |  |  | 
| 64 |  |  |  | 
| 65 | greg | 2.16 | static void | 
| 66 | greg | 2.18 | raysamp(        /* queue a ray sample */ | 
| 67 |  |  | int  ndx, | 
| 68 |  |  | FVECT  org, | 
| 69 |  |  | FVECT  dir | 
| 70 | greg | 2.16 | ) | 
| 71 |  |  | { | 
| 72 | greg | 2.18 | RAY     myRay; | 
| 73 |  |  | int     rv; | 
| 74 |  |  |  | 
| 75 |  |  | if ((ndx < 0) | (ndx >= distsiz)) | 
| 76 |  |  | error(INTERNAL, "Bad index in raysamp"); | 
| 77 |  |  | VCOPY(myRay.rorg, org); | 
| 78 |  |  | VCOPY(myRay.rdir, dir); | 
| 79 |  |  | myRay.rmax = .0; | 
| 80 |  |  | rayorigin(&myRay, PRIMARY, NULL, NULL); | 
| 81 |  |  | myRay.rno = ndx; | 
| 82 |  |  | /* queue ray, check result */ | 
| 83 |  |  | process_ray(&myRay, ray_pqueue(&myRay)); | 
| 84 |  |  | } | 
| 85 |  |  |  | 
| 86 |  |  |  | 
| 87 |  |  | static void | 
| 88 |  |  | rayclean()                      /* finish all pending rays */ | 
| 89 |  |  | { | 
| 90 |  |  | RAY     myRay; | 
| 91 |  |  |  | 
| 92 |  |  | while (process_ray(&myRay, ray_presult(&myRay, 0))) | 
| 93 | greg | 2.16 | ; | 
| 94 |  |  | } | 
| 95 | schorsch | 2.12 |  | 
| 96 |  |  |  | 
| 97 |  |  | int /* XXX type conflict with otypes.h */ | 
| 98 | greg | 2.18 | my_default(     /* default illum action */ | 
| 99 | schorsch | 2.12 | OBJREC  *ob, | 
| 100 |  |  | struct illum_args  *il, | 
| 101 |  |  | char  *nm | 
| 102 |  |  | ) | 
| 103 | greg | 1.1 | { | 
| 104 | greg | 1.2 | sprintf(errmsg, "(%s): cannot make illum for %s \"%s\"", | 
| 105 |  |  | nm, ofun[ob->otype].funame, ob->oname); | 
| 106 |  |  | error(WARNING, errmsg); | 
| 107 | greg | 2.2 | printobj(il->altmat, ob); | 
| 108 | greg | 2.13 | return(1); | 
| 109 | greg | 1.2 | } | 
| 110 |  |  |  | 
| 111 |  |  |  | 
| 112 | greg | 2.13 | int | 
| 113 | greg | 2.18 | my_face(                /* make an illum face */ | 
| 114 | schorsch | 2.12 | OBJREC  *ob, | 
| 115 |  |  | struct illum_args  *il, | 
| 116 |  |  | char  *nm | 
| 117 |  |  | ) | 
| 118 | greg | 1.2 | { | 
| 119 | greg | 1.3 | #define MAXMISS         (5*n*il->nsamps) | 
| 120 | greg | 1.10 | int  dim[3]; | 
| 121 |  |  | int  n, nalt, nazi, h; | 
| 122 |  |  | double  sp[2], r1, r2; | 
| 123 | greg | 1.4 | FVECT  dn, org, dir; | 
| 124 | greg | 1.3 | FVECT  u, v; | 
| 125 |  |  | double  ur[2], vr[2]; | 
| 126 |  |  | int  nmisses; | 
| 127 |  |  | register FACE  *fa; | 
| 128 |  |  | register int  i, j; | 
| 129 |  |  | /* get/check arguments */ | 
| 130 |  |  | fa = getface(ob); | 
| 131 |  |  | if (fa->area == 0.0) { | 
| 132 |  |  | freeface(ob); | 
| 133 | greg | 2.18 | return(o_default(ob, il, nm)); | 
| 134 | greg | 1.3 | } | 
| 135 |  |  | /* set up sampling */ | 
| 136 | greg | 1.11 | if (il->sampdens <= 0) | 
| 137 |  |  | nalt = nazi = 1; | 
| 138 |  |  | else { | 
| 139 |  |  | n = PI * il->sampdens; | 
| 140 |  |  | nalt = sqrt(n/PI) + .5; | 
| 141 |  |  | nazi = PI*nalt + .5; | 
| 142 |  |  | } | 
| 143 | greg | 1.3 | n = nalt*nazi; | 
| 144 | greg | 2.18 | newdist(n); | 
| 145 | greg | 2.3 | /* take first edge longer than sqrt(area) */ | 
| 146 | greg | 2.4 | for (j = fa->nv-1, i = 0; i < fa->nv; j = i++) { | 
| 147 |  |  | u[0] = VERTEX(fa,i)[0] - VERTEX(fa,j)[0]; | 
| 148 |  |  | u[1] = VERTEX(fa,i)[1] - VERTEX(fa,j)[1]; | 
| 149 |  |  | u[2] = VERTEX(fa,i)[2] - VERTEX(fa,j)[2]; | 
| 150 | greg | 2.5 | if ((r1 = DOT(u,u)) >= fa->area-FTINY) | 
| 151 | greg | 2.3 | break; | 
| 152 |  |  | } | 
| 153 |  |  | if (i < fa->nv) {       /* got one! -- let's align our axes */ | 
| 154 | greg | 2.5 | r2 = 1.0/sqrt(r1); | 
| 155 |  |  | u[0] *= r2; u[1] *= r2; u[2] *= r2; | 
| 156 | greg | 2.3 | fcross(v, fa->norm, u); | 
| 157 |  |  | } else                  /* oh well, we'll just have to wing it */ | 
| 158 |  |  | mkaxes(u, v, fa->norm); | 
| 159 |  |  | /* now, find limits in (u,v) coordinates */ | 
| 160 | greg | 1.3 | ur[0] = vr[0] = FHUGE; | 
| 161 |  |  | ur[1] = vr[1] = -FHUGE; | 
| 162 |  |  | for (i = 0; i < fa->nv; i++) { | 
| 163 |  |  | r1 = DOT(VERTEX(fa,i),u); | 
| 164 |  |  | if (r1 < ur[0]) ur[0] = r1; | 
| 165 |  |  | if (r1 > ur[1]) ur[1] = r1; | 
| 166 |  |  | r2 = DOT(VERTEX(fa,i),v); | 
| 167 |  |  | if (r2 < vr[0]) vr[0] = r2; | 
| 168 |  |  | if (r2 > vr[1]) vr[1] = r2; | 
| 169 |  |  | } | 
| 170 |  |  | dim[0] = random(); | 
| 171 |  |  | /* sample polygon */ | 
| 172 |  |  | nmisses = 0; | 
| 173 |  |  | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 174 |  |  | for (dim[2] = 0; dim[2] < nazi; dim[2]++) | 
| 175 |  |  | for (i = 0; i < il->nsamps; i++) { | 
| 176 |  |  | /* random direction */ | 
| 177 | greg | 1.10 | h = ilhash(dim, 3) + i; | 
| 178 | greg | 1.11 | multisamp(sp, 2, urand(h)); | 
| 179 | greg | 1.10 | r1 = (dim[1] + sp[0])/nalt; | 
| 180 | greg | 1.13 | r2 = (dim[2] + sp[1] - .5)/nazi; | 
| 181 | greg | 1.3 | flatdir(dn, r1, r2); | 
| 182 |  |  | for (j = 0; j < 3; j++) | 
| 183 | greg | 1.5 | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*fa->norm[j]; | 
| 184 | greg | 1.3 | /* random location */ | 
| 185 |  |  | do { | 
| 186 | greg | 1.11 | multisamp(sp, 2, urand(h+4862+nmisses)); | 
| 187 | greg | 1.10 | r1 = ur[0] + (ur[1]-ur[0]) * sp[0]; | 
| 188 |  |  | r2 = vr[0] + (vr[1]-vr[0]) * sp[1]; | 
| 189 | greg | 1.3 | for (j = 0; j < 3; j++) | 
| 190 |  |  | org[j] = r1*u[j] + r2*v[j] | 
| 191 |  |  | + fa->offset*fa->norm[j]; | 
| 192 |  |  | } while (!inface(org, fa) && nmisses++ < MAXMISS); | 
| 193 |  |  | if (nmisses > MAXMISS) { | 
| 194 |  |  | objerror(ob, WARNING, "bad aspect"); | 
| 195 | greg | 2.18 | rayclean(); | 
| 196 | greg | 1.3 | freeface(ob); | 
| 197 | greg | 2.9 | free((void *)distarr); | 
| 198 | greg | 2.18 | return(o_default(ob, il, nm)); | 
| 199 | greg | 1.3 | } | 
| 200 |  |  | for (j = 0; j < 3; j++) | 
| 201 |  |  | org[j] += .001*fa->norm[j]; | 
| 202 |  |  | /* send sample */ | 
| 203 | greg | 2.18 | raysamp(dim[1]*nazi+dim[2], org, dir); | 
| 204 | greg | 1.3 | } | 
| 205 | greg | 2.18 | rayclean(); | 
| 206 | greg | 1.11 | /* write out the face and its distribution */ | 
| 207 | greg | 1.12 | if (average(il, distarr, nalt*nazi)) { | 
| 208 |  |  | if (il->sampdens > 0) | 
| 209 |  |  | flatout(il, distarr, nalt, nazi, u, v, fa->norm); | 
| 210 |  |  | illumout(il, ob); | 
| 211 | greg | 2.2 | } else | 
| 212 | greg | 1.12 | printobj(il->altmat, ob); | 
| 213 | greg | 1.3 | /* clean up */ | 
| 214 |  |  | freeface(ob); | 
| 215 | greg | 2.15 | return(0); | 
| 216 | greg | 1.3 | #undef MAXMISS | 
| 217 | greg | 1.2 | } | 
| 218 |  |  |  | 
| 219 |  |  |  | 
| 220 | greg | 2.13 | int | 
| 221 | greg | 2.18 | my_sphere(      /* make an illum sphere */ | 
| 222 | schorsch | 2.12 | register OBJREC  *ob, | 
| 223 |  |  | struct illum_args  *il, | 
| 224 |  |  | char  *nm | 
| 225 |  |  | ) | 
| 226 | greg | 1.2 | { | 
| 227 | greg | 1.10 | int  dim[3]; | 
| 228 | greg | 1.2 | int  n, nalt, nazi; | 
| 229 | greg | 1.10 | double  sp[4], r1, r2, r3; | 
| 230 | greg | 1.4 | FVECT  org, dir; | 
| 231 | greg | 1.2 | FVECT  u, v; | 
| 232 |  |  | register int  i, j; | 
| 233 |  |  | /* check arguments */ | 
| 234 |  |  | if (ob->oargs.nfargs != 4) | 
| 235 |  |  | objerror(ob, USER, "bad # of arguments"); | 
| 236 |  |  | /* set up sampling */ | 
| 237 | greg | 1.11 | if (il->sampdens <= 0) | 
| 238 |  |  | nalt = nazi = 1; | 
| 239 |  |  | else { | 
| 240 |  |  | n = 4.*PI * il->sampdens; | 
| 241 | greg | 2.7 | nalt = sqrt(2./PI*n) + .5; | 
| 242 |  |  | nazi = PI/2.*nalt + .5; | 
| 243 | greg | 1.11 | } | 
| 244 | greg | 1.2 | n = nalt*nazi; | 
| 245 | greg | 2.18 | newdist(n); | 
| 246 | greg | 1.2 | dim[0] = random(); | 
| 247 |  |  | /* sample sphere */ | 
| 248 |  |  | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 249 | greg | 1.8 | for (dim[2] = 0; dim[2] < nazi; dim[2]++) | 
| 250 | greg | 1.2 | for (i = 0; i < il->nsamps; i++) { | 
| 251 | greg | 1.10 | /* next sample point */ | 
| 252 | greg | 1.11 | multisamp(sp, 4, urand(ilhash(dim,3)+i)); | 
| 253 | greg | 1.2 | /* random direction */ | 
| 254 | greg | 1.10 | r1 = (dim[1] + sp[0])/nalt; | 
| 255 | greg | 1.13 | r2 = (dim[2] + sp[1] - .5)/nazi; | 
| 256 | greg | 1.2 | rounddir(dir, r1, r2); | 
| 257 |  |  | /* random location */ | 
| 258 | greg | 1.8 | mkaxes(u, v, dir);          /* yuck! */ | 
| 259 | greg | 1.10 | r3 = sqrt(sp[2]); | 
| 260 |  |  | r2 = 2.*PI*sp[3]; | 
| 261 | greg | 1.5 | r1 = r3*ob->oargs.farg[3]*cos(r2); | 
| 262 |  |  | r2 = r3*ob->oargs.farg[3]*sin(r2); | 
| 263 |  |  | r3 = ob->oargs.farg[3]*sqrt(1.01-r3*r3); | 
| 264 |  |  | for (j = 0; j < 3; j++) { | 
| 265 |  |  | org[j] = ob->oargs.farg[j] + r1*u[j] + r2*v[j] + | 
| 266 |  |  | r3*dir[j]; | 
| 267 |  |  | dir[j] = -dir[j]; | 
| 268 |  |  | } | 
| 269 | greg | 1.2 | /* send sample */ | 
| 270 | greg | 2.18 | raysamp(dim[1]*nazi+dim[2], org, dir); | 
| 271 | greg | 1.2 | } | 
| 272 | greg | 2.18 | rayclean(); | 
| 273 | greg | 1.11 | /* write out the sphere and its distribution */ | 
| 274 | greg | 1.12 | if (average(il, distarr, nalt*nazi)) { | 
| 275 |  |  | if (il->sampdens > 0) | 
| 276 |  |  | roundout(il, distarr, nalt, nazi); | 
| 277 |  |  | else | 
| 278 |  |  | objerror(ob, WARNING, "diffuse distribution"); | 
| 279 |  |  | illumout(il, ob); | 
| 280 | greg | 2.2 | } else | 
| 281 | greg | 1.12 | printobj(il->altmat, ob); | 
| 282 | greg | 1.2 | /* clean up */ | 
| 283 | greg | 2.13 | return(1); | 
| 284 | greg | 1.2 | } | 
| 285 |  |  |  | 
| 286 |  |  |  | 
| 287 | greg | 2.13 | int | 
| 288 | greg | 2.18 | my_ring(                /* make an illum ring */ | 
| 289 | schorsch | 2.12 | OBJREC  *ob, | 
| 290 |  |  | struct illum_args  *il, | 
| 291 |  |  | char  *nm | 
| 292 |  |  | ) | 
| 293 | greg | 1.2 | { | 
| 294 | greg | 1.10 | int  dim[3]; | 
| 295 | greg | 1.3 | int  n, nalt, nazi; | 
| 296 | greg | 1.10 | double  sp[4], r1, r2, r3; | 
| 297 | greg | 1.4 | FVECT  dn, org, dir; | 
| 298 | greg | 1.3 | FVECT  u, v; | 
| 299 |  |  | register CONE  *co; | 
| 300 |  |  | register int  i, j; | 
| 301 |  |  | /* get/check arguments */ | 
| 302 |  |  | co = getcone(ob, 0); | 
| 303 |  |  | /* set up sampling */ | 
| 304 | greg | 1.11 | if (il->sampdens <= 0) | 
| 305 |  |  | nalt = nazi = 1; | 
| 306 |  |  | else { | 
| 307 |  |  | n = PI * il->sampdens; | 
| 308 |  |  | nalt = sqrt(n/PI) + .5; | 
| 309 |  |  | nazi = PI*nalt + .5; | 
| 310 |  |  | } | 
| 311 | greg | 1.3 | n = nalt*nazi; | 
| 312 | greg | 2.18 | newdist(n); | 
| 313 | greg | 1.3 | mkaxes(u, v, co->ad); | 
| 314 |  |  | dim[0] = random(); | 
| 315 |  |  | /* sample disk */ | 
| 316 |  |  | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 317 |  |  | for (dim[2] = 0; dim[2] < nazi; dim[2]++) | 
| 318 |  |  | for (i = 0; i < il->nsamps; i++) { | 
| 319 | greg | 1.10 | /* next sample point */ | 
| 320 | greg | 1.11 | multisamp(sp, 4, urand(ilhash(dim,3)+i)); | 
| 321 | greg | 1.3 | /* random direction */ | 
| 322 | greg | 1.10 | r1 = (dim[1] + sp[0])/nalt; | 
| 323 | greg | 1.13 | r2 = (dim[2] + sp[1] - .5)/nazi; | 
| 324 | greg | 1.3 | flatdir(dn, r1, r2); | 
| 325 |  |  | for (j = 0; j < 3; j++) | 
| 326 | greg | 1.5 | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j]; | 
| 327 | greg | 1.3 | /* random location */ | 
| 328 | greg | 1.5 | r3 = sqrt(CO_R0(co)*CO_R0(co) + | 
| 329 | greg | 1.10 | sp[2]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co))); | 
| 330 |  |  | r2 = 2.*PI*sp[3]; | 
| 331 | greg | 1.5 | r1 = r3*cos(r2); | 
| 332 |  |  | r2 = r3*sin(r2); | 
| 333 | greg | 1.3 | for (j = 0; j < 3; j++) | 
| 334 | greg | 2.6 | org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j] + | 
| 335 | greg | 1.5 | .001*co->ad[j]; | 
| 336 | greg | 1.3 |  | 
| 337 |  |  | /* send sample */ | 
| 338 | greg | 2.18 | raysamp(dim[1]*nazi+dim[2], org, dir); | 
| 339 | greg | 1.3 | } | 
| 340 | greg | 2.18 | rayclean(); | 
| 341 | greg | 1.11 | /* write out the ring and its distribution */ | 
| 342 | greg | 1.12 | if (average(il, distarr, nalt*nazi)) { | 
| 343 |  |  | if (il->sampdens > 0) | 
| 344 |  |  | flatout(il, distarr, nalt, nazi, u, v, co->ad); | 
| 345 |  |  | illumout(il, ob); | 
| 346 | greg | 2.2 | } else | 
| 347 | greg | 1.12 | printobj(il->altmat, ob); | 
| 348 | greg | 1.3 | /* clean up */ | 
| 349 |  |  | freecone(ob); | 
| 350 | greg | 2.13 | return(1); | 
| 351 | greg | 1.2 | } | 
| 352 |  |  |  | 
| 353 |  |  |  | 
| 354 | greg | 2.16 | static void | 
| 355 | schorsch | 2.12 | mkaxes(                 /* compute u and v to go with n */ | 
| 356 |  |  | FVECT  u, | 
| 357 |  |  | FVECT  v, | 
| 358 |  |  | FVECT  n | 
| 359 |  |  | ) | 
| 360 | greg | 1.4 | { | 
| 361 |  |  | register int  i; | 
| 362 |  |  |  | 
| 363 |  |  | v[0] = v[1] = v[2] = 0.0; | 
| 364 |  |  | for (i = 0; i < 3; i++) | 
| 365 |  |  | if (n[i] < 0.6 && n[i] > -0.6) | 
| 366 |  |  | break; | 
| 367 |  |  | v[i] = 1.0; | 
| 368 |  |  | fcross(u, v, n); | 
| 369 |  |  | normalize(u); | 
| 370 |  |  | fcross(v, n, u); | 
| 371 |  |  | } | 
| 372 |  |  |  | 
| 373 |  |  |  | 
| 374 | greg | 2.16 | static void | 
| 375 | schorsch | 2.12 | rounddir(               /* compute uniform spherical direction */ | 
| 376 |  |  | register FVECT  dv, | 
| 377 |  |  | double  alt, | 
| 378 |  |  | double  azi | 
| 379 |  |  | ) | 
| 380 | greg | 1.4 | { | 
| 381 |  |  | double  d1, d2; | 
| 382 |  |  |  | 
| 383 |  |  | dv[2] = 1. - 2.*alt; | 
| 384 |  |  | d1 = sqrt(1. - dv[2]*dv[2]); | 
| 385 |  |  | d2 = 2.*PI * azi; | 
| 386 |  |  | dv[0] = d1*cos(d2); | 
| 387 |  |  | dv[1] = d1*sin(d2); | 
| 388 |  |  | } | 
| 389 |  |  |  | 
| 390 |  |  |  | 
| 391 | greg | 2.16 | static void | 
| 392 | schorsch | 2.12 | flatdir(                /* compute uniform hemispherical direction */ | 
| 393 |  |  | register FVECT  dv, | 
| 394 |  |  | double  alt, | 
| 395 |  |  | double  azi | 
| 396 |  |  | ) | 
| 397 | greg | 1.4 | { | 
| 398 |  |  | double  d1, d2; | 
| 399 |  |  |  | 
| 400 |  |  | d1 = sqrt(alt); | 
| 401 |  |  | d2 = 2.*PI * azi; | 
| 402 |  |  | dv[0] = d1*cos(d2); | 
| 403 |  |  | dv[1] = d1*sin(d2); | 
| 404 | greg | 1.6 | dv[2] = sqrt(1. - alt); | 
| 405 | greg | 1.1 | } |