BRL-CAD
g_bot_include.c
Go to the documentation of this file.
1 /* G _ B O T _ I N C L U D E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1999-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup primitives */
21 /** @{ */
22 /** @file primitives/bot/g_bot_include.c
23  *
24  * This file contains all the routines for "g_bot.c" that contain
25  * references to "tri_specific" structs. This file is included in
26  * "g_bot.c" twice. Each time the macro TRI_TYPE is defined to reflect
27  * the desired version of the "tri_specific" structure:
28  *
29  * TRI_TYPE == float -> use the "tri_float_specific" struct
30  * TRI_TYPE == double -> use the original "tri_specific" struct
31  *
32  */
33 
34 
35 /**
36  * This function is called with pointers to 3 points, and is used to
37  * prepare BOT faces. ap, bp, cp point to vect_t points.
38  *
39  * Returns 0 if the 3 points didn't form a plane (e.g., collinear, etc.).
40  * Returns # pts (3) if a valid plane resulted.
41  */
42 int
43 XGLUE(rt_botface_w_normals_, TRI_TYPE)(struct soltab *stp,
44  struct bot_specific *bot,
45  fastf_t *ap,
46  fastf_t *bp,
47  fastf_t *cp,
48  fastf_t *vertex_normals, /* array of nine values (three unit normals vectors) */
49  size_t face_no,
50  const struct bn_tol *tol)
51 {
52  register XGLUE(tri_specific_, TRI_TYPE) *trip;
53  vect_t work;
54  fastf_t m1, m2, m3, m4;
55  vect_t BA_N, CA_N;
56  size_t i;
57 
58  BU_GET(trip, XGLUE(tri_specific_, TRI_TYPE));
59  VMOVE(trip->tri_A, ap);
60  VSUB2(trip->tri_BA, bp, ap);
61  VSUB2(trip->tri_CA, cp, ap);
62  VCROSS(trip->tri_wn, trip->tri_BA, trip->tri_CA);
63  trip->tri_surfno = face_no;
64 
65  VMOVE(BA_N, trip->tri_BA);
66  VMOVE(CA_N, trip->tri_CA);
67  VUNITIZE(BA_N);
68  VUNITIZE(CA_N);
69 
70  /* Check to see if this plane is a line or pnt */
71  m1 = MAGSQ(trip->tri_BA);
72  m2 = MAGSQ(trip->tri_CA);
73  VSUB2(work, bp, cp);
74  m3 = MAGSQ(work);
75  m4 = fabs(VDOT(BA_N, CA_N));
76  if (m1 < tol->dist_sq
77  || m2 < tol->dist_sq
78  || m3 < tol->dist_sq
79  || m4 >= tol->para)
80  {
81  BU_PUT(trip, XGLUE(tri_specific_, TRI_TYPE));
82 
83  if (RT_G_DEBUG & DEBUG_SHOOT) {
84  bu_log("%s: degenerate facet #%zu\n",
85  stp->st_name, face_no);
86  bu_log("\t(%g %g %g) (%g %g %g) (%g %g %g)\n",
87  V3ARGS(ap), V3ARGS(bp), V3ARGS(cp));
88  }
89  return 0; /* BAD */
90  }
91 
92  if ((bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot->bot_flags & RT_BOT_USE_NORMALS) && vertex_normals) {
93  trip->tri_normals = (NORM_TYPE *)bu_malloc(9 * sizeof(NORM_TYPE), "trip->tri_normals");
94  for (i = 0; i < 3; i++) {
95  size_t j;
96 
97  for (j = 0; j < 3; j++) {
98  trip->tri_normals[i*3+j] = vertex_normals[i*3+j] * NORMAL_SCALE;
99  }
100  }
101  } else {
102  trip->tri_normals = (NORM_TYPE *)NULL;
103  }
104 
105  /* wn is a normal of not necessarily unit length.
106  * N is an outward pointing unit normal.
107  * We depend on the points being given in CCW order here.
108  */
109  VMOVE(trip->tri_N, trip->tri_wn);
110  VUNITIZE(trip->tri_N);
111  if (bot->bot_orientation == RT_BOT_CW)
112  VREVERSE(trip->tri_N, trip->tri_N);
113 
114  /* Add this face onto the linked list for this solid */
115  trip->tri_forw = (XGLUE(tri_specific_, TRI_TYPE) *)bot->bot_facelist;
116  bot->bot_facelist = (void *)trip;
117  return 3; /* OK */
118 }
119 
120 
121 /*
122  * Do the prep to support pieces for a BOT/ARS
123  */
124 void
125 XGLUE(rt_bot_prep_pieces_, TRI_TYPE)(struct bot_specific *bot,
126  struct soltab *stp,
127  size_t ntri,
128  const struct bn_tol *tol)
129 {
130  struct bound_rpp *minmax = (struct bound_rpp *)NULL;
131  XGLUE(tri_specific_, TRI_TYPE) **fap;
132  register XGLUE(tri_specific_, TRI_TYPE) *trip;
133  point_t b, c;
134  point_t d, e, f;
135  vect_t offset;
136  fastf_t los;
137  size_t surfno;
138  long num_rpps;
139  size_t tri_per_piece, tpp_m1;
140 
141  tri_per_piece = bot->bot_tri_per_piece = rt_bot_tri_per_piece;
142 
143  num_rpps = ntri / tri_per_piece;
144  if (ntri % tri_per_piece) num_rpps++;
145 
146  stp->st_npieces = num_rpps;
147 
148  fap = (XGLUE(tri_specific_, TRI_TYPE) **)
149  bu_malloc(sizeof(XGLUE(tri_specific_, TRI_TYPE) *) * ntri,
150  "bot_facearray");
151  bot->bot_facearray = (void **)fap;
152 
153  stp->st_piece_rpps = (struct bound_rpp *)
154  bu_malloc(sizeof(struct bound_rpp) * num_rpps,
155  "st_piece_rpps");
156 
157 
158  tpp_m1 = tri_per_piece - 1;
159  trip = (XGLUE(tri_specific_, TRI_TYPE) *)bot->bot_facelist;
160  minmax = &stp->st_piece_rpps[num_rpps-1];
161  minmax->min[X] = minmax->max[X] = trip->tri_A[X];
162  minmax->min[Y] = minmax->max[Y] = trip->tri_A[Y];
163  minmax->min[Z] = minmax->max[Z] = trip->tri_A[Z];
164  for (surfno=ntri-1; trip; trip = trip->tri_forw, surfno--) {
165 
166  if ((surfno % tri_per_piece) == tpp_m1) {
167  /* top most surfno in a piece group */
168  /* first surf for this piece */
169  minmax = &stp->st_piece_rpps[surfno / tri_per_piece];
170 
171  minmax->min[X] = minmax->max[X] = trip->tri_A[X];
172  minmax->min[Y] = minmax->max[Y] = trip->tri_A[Y];
173  minmax->min[Z] = minmax->max[Z] = trip->tri_A[Z];
174  } else {
175  VMINMAX(minmax->min, minmax->max, trip->tri_A);
176  }
177 
178  fap[surfno] = trip;
179 
180  if (bot->bot_mode == RT_BOT_PLATE || bot->bot_mode == RT_BOT_PLATE_NOCOS) {
181  if (BU_BITTEST(bot->bot_facemode, surfno)) {
182  /* Append full thickness on both sides */
183  los = bot->bot_thickness[surfno];
184  } else {
185  /* Center thickness. Append 1/2 thickness on both sides */
186  los = bot->bot_thickness[surfno] * 0.51;
187  }
188  } else {
189  /* Prevent the RPP from being 0 thickness */
190  los = tol->dist; /* typ 0.0005mm */
191  if (los < SMALL_FASTF)
192  los = SMALL_FASTF;
193  }
194 
195  VADD2(b, trip->tri_BA, trip->tri_A);
196  VADD2(c, trip->tri_CA, trip->tri_A);
197  VMINMAX(minmax->min, minmax->max, b);
198  VMINMAX(minmax->min, minmax->max, c);
199 
200  /* Offset face in +los */
201  VSCALE(offset, trip->tri_N, los);
202  VADD2(d, trip->tri_A, offset);
203  VADD2(e, b, offset);
204  VADD2(f, c, offset);
205  VMINMAX(minmax->min, minmax->max, d);
206  VMINMAX(minmax->min, minmax->max, e);
207  VMINMAX(minmax->min, minmax->max, f);
208 
209  /* Offset face in -los */
210  VSCALE(offset, trip->tri_N, -los);
211  VADD2(d, trip->tri_A, offset);
212  VADD2(e, b, offset);
213  VADD2(f, c, offset);
214  VMINMAX(minmax->min, minmax->max, d);
215  VMINMAX(minmax->min, minmax->max, e);
216  VMINMAX(minmax->min, minmax->max, f);
217 
218  VMINMAX(stp->st_min, stp->st_max, minmax->min);
219  VMINMAX(stp->st_min, stp->st_max, minmax->max);
220 
221  }
222 
223 }
224 
225 
226 /**
227  * Given a pointer to a GED database record, and a transformation
228  * matrix, determine if this is a valid BOT, and if so, precompute
229  * various terms of the formula.
230  *
231  * Returns -
232  * 0 BOT is OK
233  * !0 Error in description
234  *
235  * Implicit return -
236  * A struct bot_specific is created, and its address is stored in
237  * stp->st_specific for use by bot_shot().
238  */
239 int
240 XGLUE(rt_bot_prep_, TRI_TYPE)(struct soltab *stp, struct rt_bot_internal *bot_ip, struct rt_i *rtip)
241 {
242  register struct bot_specific *bot;
243  const struct bn_tol *tol = &rtip->rti_tol;
244  size_t tri_index, i;
245  fastf_t dx, dy, dz;
246  fastf_t f;
247  size_t ntri = 0;
248  fastf_t los = tol->dist;
249 
250  if (los < SMALL_FASTF)
251  los = SMALL_FASTF;
252 
253  RT_BOT_CK_MAGIC(bot_ip);
254 
255  BU_GET(bot, struct bot_specific);
256  stp->st_specific = (void *)bot;
257  bot->bot_mode = bot_ip->mode;
258  bot->bot_orientation = bot_ip->orientation;
259  bot->bot_flags = bot_ip->bot_flags;
260  if (bot_ip->thickness) {
261  bot->bot_thickness = (fastf_t *)bu_calloc(bot_ip->num_faces, sizeof(fastf_t), "bot_thickness");
262  for (tri_index = 0; tri_index < bot_ip->num_faces; tri_index++)
263  bot->bot_thickness[tri_index] = bot_ip->thickness[tri_index];
264  }
265  if (bot_ip->face_mode)
266  bot->bot_facemode = bu_bitv_dup(bot_ip->face_mode);
267  bot->bot_facelist = (XGLUE(tri_specific_, TRI_TYPE) *)NULL;
268 
269  for (tri_index = 0; tri_index < bot_ip->num_faces; tri_index++) {
270  point_t p1, p2, p3;
271  long default_normal=-1;
272  size_t pt1, pt2, pt3;
273 
274  pt1 = bot_ip->faces[tri_index*3];
275  pt2 = bot_ip->faces[tri_index*3 + 1];
276  pt3 = bot_ip->faces[tri_index*3 + 2];
277  if (pt1 >= bot_ip->num_vertices
278  || pt2 >= bot_ip->num_vertices
279  || pt3 >= bot_ip->num_vertices)
280  {
281  bu_log("face number %zu of bot(%s) references a non-existent vertex\n",
282  tri_index, stp->st_name);
283  return -1;
284  }
285 
286  VMOVE(p1, &bot_ip->vertices[pt1*3]);
287  VMOVE(p2, &bot_ip->vertices[pt2*3]);
288  VMOVE(p3, &bot_ip->vertices[pt3*3]);
289 
290  if ((bot_ip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot_ip->bot_flags & RT_BOT_USE_NORMALS)
291  && (bot_ip->num_normals > 0) && (bot_ip->num_face_normals > tri_index)) {
292  for (i = 0; i < 3; i++) {
293  size_t idx;
294 
295  idx = bot_ip->face_normals[tri_index*3 + i];
296  if (idx < bot_ip->num_normals) {
297  default_normal = idx;
298  }
299  }
300  if (default_normal < 0) {
301  if (rt_botface(stp, bot, p1, p2, p3, tri_index, tol) > 0)
302  ntri++;
303  } else {
304  fastf_t normals[9];
305 
306  for (i = 0; i < 3; i++) {
307  size_t idx;
308 
309  idx = bot_ip->face_normals[tri_index*3 + i];
310  if (idx > bot_ip->num_normals) {
311  VMOVE(&normals[i*3], &bot_ip->normals[default_normal*3]);
312  } else {
313  VMOVE(&normals[i*3], &bot_ip->normals[idx*3]);
314  }
315  }
316  if (rt_botface_w_normals(stp, bot, p1, p2, p3, normals, tri_index, tol) > 0)
317  ntri++;
318  }
319  } else {
320  if (rt_botface(stp, bot, p1, p2, p3, tri_index, tol) > 0)
321  ntri++;
322  }
323  }
324 
325  if (bot->bot_facelist == (XGLUE(tri_specific_, TRI_TYPE) *)0) {
326  bu_log("bot(%s): no faces\n", stp->st_name);
327  return -1; /* BAD */
328  }
329 
330  bot->bot_ntri = ntri;
331 
332  if (rt_bot_minpieces > 0 && bot_ip->num_faces > rt_bot_minpieces) {
333  rt_bot_prep_pieces(bot, stp, ntri, tol);
334  }
335 
336  /* zero thickness will get missed by the raytracer */
337  if (NEAR_EQUAL(stp->st_min[X], stp->st_max[X], los)) {
338  stp->st_min[X] -= los;
339  stp->st_max[X] += los;
340  }
341  if (NEAR_EQUAL(stp->st_min[Y], stp->st_max[Y], los)) {
342  stp->st_min[Y] -= los;
343  stp->st_max[Y] += los;
344  }
345  if (NEAR_EQUAL(stp->st_min[Z], stp->st_max[Z], los)) {
346  stp->st_min[Z] -= los;
347  stp->st_max[Z] += los;
348  }
349 
350  VADD2SCALE(stp->st_center, stp->st_max, stp->st_min, 0.5);
351 
352  dx = (stp->st_max[X] - stp->st_min[X])/2;
353  f = dx;
354  dy = (stp->st_max[Y] - stp->st_min[Y])/2;
355  if (dy > f) f = dy;
356  dz = (stp->st_max[Z] - stp->st_min[Z])/2;
357  if (dz > f) f = dz;
358  stp->st_aradius = f;
359  stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
360 
361  /*
362  * Support for solid 'pieces'
363  *
364  * Each piece can represent a number of triangles. This is
365  * encoded in bot->bot_tri_per_piece.
366  *
367  * These array allocations can't be made until the number of
368  * triangles are known.
369  *
370  * If the number of triangles is too small, don't bother making
371  * pieces, the overhead isn't worth it.
372  *
373  * To disable BoT pieces, on the RT command line specify:
374  * -c "set rt_bot_minpieces=0"
375  */
376 
377  return 0;
378 }
379 
380 
381 static int
382 XGLUE(rt_bot_plate_segs_, TRI_TYPE)(struct hit *hits,
383  size_t nhits,
384  struct soltab *stp,
385  struct xray *rp,
386  struct application *ap,
387  struct seg *seghead,
388  struct bot_specific *bot)
389 {
390  register struct seg *segp;
391  register size_t i;
392  register fastf_t los;
393  size_t surfno;
394  static const int IN = 0;
395  static const int OUT = 1;
396 
397  if (rp) RT_CK_RAY(rp);
398 
399  for (i = 0; i < nhits; i++) {
400  XGLUE(tri_specific_, TRI_TYPE) *trip=(XGLUE(tri_specific_, TRI_TYPE) *)hits[i].hit_private;
401 
402  surfno = hits[i].hit_surfno;
403 
404  los = 0.0;
405  if (LIKELY(bot->bot_thickness != NULL)) {
406  if (bot->bot_mode == RT_BOT_PLATE_NOCOS) {
407  los = bot->bot_thickness[surfno];
408  } else {
409  los = bot->bot_thickness[surfno] / hits[i].hit_vpriv[X];
410  if (los < 0.0)
411  los = -los;
412  }
413  }
414 
415  if (LIKELY(bot->bot_facemode != NULL) && BU_BITTEST(bot->bot_facemode, hits[i].hit_surfno)) {
416 
417  /* append thickness to hit point */
418  RT_GET_SEG(segp, ap->a_resource);
419  segp->seg_stp = stp;
420 
421  /* set in hit */
422  segp->seg_in = hits[i];
423  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
424 
425  /* set out hit */
426  segp->seg_out.hit_surfno = surfno;
427  segp->seg_out.hit_dist = segp->seg_in.hit_dist + los;
428  VMOVE(segp->seg_out.hit_vpriv, hits[i].hit_vpriv);
429  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
430  segp->seg_out.hit_private = segp->seg_in.hit_private;
431  segp->seg_out.hit_rayp = &ap->a_ray;
432 
433  BU_LIST_INSERT(&(seghead->l), &(segp->l));
434  } else {
435  /* center thickness about hit point */
436  RT_GET_SEG(segp, ap->a_resource);
437  segp->seg_stp = stp;
438 
439  /* set in hit */
440  segp->seg_in.hit_surfno = surfno;
441  VMOVE(segp->seg_in.hit_vpriv, hits[i].hit_vpriv);
442  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
443  segp->seg_in.hit_private = hits[i].hit_private;
444  segp->seg_in.hit_dist = hits[i].hit_dist - (los*0.5);
445  segp->seg_in.hit_rayp = &ap->a_ray;
446 
447  /* set out hit */
448  segp->seg_out.hit_surfno = surfno;
449  segp->seg_out.hit_dist = segp->seg_in.hit_dist + los;
450  VMOVE(segp->seg_out.hit_vpriv, hits[i].hit_vpriv);
451  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
452  segp->seg_out.hit_private = hits[i].hit_private;
453  segp->seg_out.hit_rayp = &ap->a_ray;
454 
455  BU_LIST_INSERT(&(seghead->l), &(segp->l));
456  }
457  }
458  /* Every hit turns into two, and makes a seg. No leftovers */
459  return nhits*2;
460 }
461 
462 
463 static int
464 XGLUE(rt_bot_unoriented_segs_, TRI_TYPE)(struct hit *hits,
465  size_t nhits,
466  struct soltab *stp,
467  struct xray *rp,
468  struct application *ap,
469  struct seg *seghead)
470 {
471  register struct seg *segp;
472  register size_t i, j;
473 
474  /*
475  * RT_BOT_SOLID, RT_BOT_UNORIENTED.
476  */
477  fastf_t rm_dist = 0.0;
478  int removed = 0;
479  static const int IN = 0;
480  static const int OUT = 1;
481 
482  if (nhits == 1) {
483  XGLUE(tri_specific_, TRI_TYPE) *trip=(XGLUE(tri_specific_, TRI_TYPE) *)hits[0].hit_private;
484 
485  /* make a zero length partition */
486  RT_GET_SEG(segp, ap->a_resource);
487  segp->seg_stp = stp;
488 
489  /* set in hit */
490  segp->seg_in = hits[0];
491  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
492 
493  /* set out hit */
494  segp->seg_out = hits[0];
495  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
496 
497  BU_LIST_INSERT(&(seghead->l), &(segp->l));
498  return 1;
499  }
500 
501  /* Remove duplicate hits */
502  for (i = 0; i < nhits - 1; i++) {
503  fastf_t dist;
504 
505  dist = hits[i].hit_dist - hits[i+1].hit_dist;
506  if (NEAR_ZERO(dist, ap->a_rt_i->rti_tol.dist)) {
507  removed++;
508  rm_dist = hits[i+1].hit_dist;
509  for (j = i; j < nhits - 1; j++)
510  hits[j] = hits[j+1];
511  nhits--;
512  i--;
513  }
514  }
515 
516 
517  if (nhits == 1)
518  return 0;
519 
520  if (nhits&1 && removed) {
521  /* If we have an odd number of hits and have removed a
522  * duplicate, then it was likely on an edge, so remove the one
523  * we left.
524  */
525  for (i = 0; i < nhits; i++) {
526  if (ZERO(hits[i].hit_dist - rm_dist)) {
527  for (j = i; j < nhits - 1; j++)
528  hits[j] = hits[j+1];
529  nhits--;
530  i--;
531  break;
532  }
533  }
534  }
535 
536  for (i = 0; i < (nhits&~1); i += 2) {
537  XGLUE(tri_specific_, TRI_TYPE) *trip;
538 
539  RT_GET_SEG(segp, ap->a_resource);
540  segp->seg_stp = stp;
541 
542  /* set in hit */
543  segp->seg_in = hits[i];
544  trip = (XGLUE(tri_specific_, TRI_TYPE) *)hits[i].hit_private;
545  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
546 
547  /* set out hit */
548  segp->seg_out = hits[i+1];
549  trip = (XGLUE(tri_specific_, TRI_TYPE) *)hits[i+1].hit_private;
550  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
551 
552  BU_LIST_INSERT(&(seghead->l), &(segp->l));
553  }
554  if (nhits&1) {
555  if (RT_G_DEBUG & DEBUG_SHOOT) {
556  bu_log("rt_bot_unoriented_segs(%s): WARNING: odd number of hits (%zu), last hit ignored\n",
557  stp->st_name, nhits);
558  bu_log("\tray = -p %g %g %g -d %g %g %g\n",
559  V3ARGS(rp->r_pt), V3ARGS(rp->r_dir));
560  }
561  nhits--;
562  }
563  return nhits;
564 }
565 
566 
567 /**
568  * Given an array of hits, make segments out of them. Exactly how
569  * this is to be done depends on the mode of the BoT.
570  */
571 HIDDEN int
572 XGLUE(rt_bot_makesegs_, TRI_TYPE)(struct hit *hits, size_t nhits, struct soltab *stp,
573  struct xray *rp, struct application *ap,
574  struct seg *seghead, struct rt_piecestate *psp)
575 {
576  struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
577  register struct seg *segp;
578  register ssize_t i;
579  static const int IN = 0;
580  static const int OUT = 1;
581  /* TODO: review the use of a signed tmp var. Var i was changed to be signed in
582  * r44239 as a bug in another project was segfaulting. */
583  ssize_t snhits = (ssize_t)nhits;
584 
585  RT_CK_SOLTAB(stp);
586 
587  if (bot->bot_mode == RT_BOT_SURFACE) {
588  for (i = 0; i < snhits; i++) {
589  XGLUE(tri_specific_, TRI_TYPE) *trip=(XGLUE(tri_specific_, TRI_TYPE) *)hits[i].hit_private;
590 
591  RT_GET_SEG(segp, ap->a_resource);
592  segp->seg_stp = stp;
593 
594  /* set in hit */
595  segp->seg_in = hits[i];
596  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
597 
598  /* set out hit */
599  segp->seg_out = hits[i];
600  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
601  BU_LIST_INSERT(&(seghead->l), &(segp->l));
602  }
603  /* Every hit turns into two, and makes a seg. No leftovers */
604  return snhits*2;
605  }
606 
607  BU_ASSERT(bot->bot_mode == RT_BOT_SOLID);
608 
609  if (bot->bot_orientation == RT_BOT_UNORIENTED) {
610  return rt_bot_unoriented_segs(hits, snhits, stp, rp, ap, seghead, bot);
611  }
612 
613  /*
614  * RT_BOT_SOLID, RT_BOT_ORIENTED.
615  *
616  * From this point on, process very similar to a polysolid
617  */
618 
619  /* Remove duplicate hits */
620  {
621  register ssize_t j, k, l;
622 
623  for (i = 0; i < snhits-1; i++) {
624  fastf_t dist;
625  fastf_t dn;
626 
627  dn = hits[i].hit_vpriv[X];
628 
629  k = i + 1;
630  dist = hits[i].hit_dist - hits[k].hit_dist;
631 
632  /* count number of hits at this distance */
633  while (NEAR_ZERO(dist, ap->a_rt_i->rti_tol.dist)) {
634  k++;
635  if (k > snhits - 1)
636  break;
637  dist = hits[i].hit_dist - hits[k].hit_dist;
638  }
639 
640  if ((k - i) == 2 && dn * hits[i+1].hit_vpriv[X] > 0) {
641  /* a pair of hits at the same distance and both are exits or entrances,
642  * likely an edge hit, remove one */
643  for (j = i; j < snhits - 1; j++)
644  hits[j] = hits[j+1];
645  if (psp) {
646  psp->htab.end--;
647  }
648  snhits--;
649  i--;
650  continue;
651  } else if ((k - i) > 2) {
652  ssize_t keep1 = -1, keep2 = -1;
653  ssize_t enters = 0, exits = 0;
654  int reorder = 0;
655  int reorder_failed = 0;
656 
657  /* more than two hits at the same distance, likely a vertex hit
658  * try to keep just two, one entrance and one exit.
659  * unless they are all entrances or all exits, then just keep one */
660 
661  /* first check if we need to do anything */
662  for (j = 0; j < k; j++) {
663  if (hits[j].hit_vpriv[X] > 0)
664  exits++;
665  else
666  enters++;
667  }
668 
669  if (k%2) {
670  if (exits == (enters - 1)) {
671  reorder = 1;
672  }
673  } else {
674  if (exits == enters) {
675  reorder = 1;
676  }
677  }
678 
679  if (reorder) {
680  struct hit tmp_hit;
681  int changed = 0;
682 
683  for (j = i; j < k; j++) {
684 
685  if (j%2) {
686  if (hits[j].hit_vpriv[X] > 0) {
687  continue;
688  }
689  /* should be an exit here */
690  l = j+1;
691  while (l < k) {
692  if (hits[l].hit_vpriv[X] > 0) {
693  /* swap with this exit */
694  tmp_hit = hits[j];
695  hits[j] = hits[l];
696  hits[l] = tmp_hit;
697  changed = 1;
698  break;
699  }
700  l++;
701  }
702  if (hits[j].hit_vpriv[X] < 0) {
703  reorder_failed = 1;
704  break;
705  }
706  } else {
707  if (hits[j].hit_vpriv[X] < 0) {
708  continue;
709  }
710  /* should be an entrance here */
711  l = j+1;
712  while (l < k) {
713  if (hits[l].hit_vpriv[X] < 0) {
714  /* swap with this entrance */
715  tmp_hit = hits[j];
716  hits[j] = hits[l];
717  hits[l] = tmp_hit;
718  changed = 1;
719  break;
720  }
721  l++;
722  }
723  if (hits[j].hit_vpriv[X] > 0) {
724  reorder_failed = 1;
725  break;
726  }
727  }
728  }
729  if (changed) {
730  /* if we have re-ordered these hits, make sure they are really
731  * at the same distance.
732  */
733  for (j = i + 1; j < k; j++) {
734  hits[j].hit_dist = hits[i].hit_dist;
735  }
736  }
737  }
738  if (!reorder || reorder_failed) {
739 
740  exits = 0;
741  enters = 0;
742  if (i == 0) {
743  dn = 1.0;
744  } else {
745  dn = hits[i-1].hit_vpriv[X];
746  }
747  for (j = i; j < k; j++) {
748  if (hits[j].hit_vpriv[X] > 0)
749  exits++;
750  else
751  enters++;
752  if (dn * hits[j].hit_vpriv[X] < 0) {
753  if (keep1 == -1) {
754  keep1 = j;
755  dn = hits[j].hit_vpriv[X];
756  } else if (keep2 == -1) {
757  keep2 = j;
758  dn = hits[j].hit_vpriv[X];
759  break;
760  }
761  }
762  }
763 
764  if (keep2 == -1) {
765  /* did not find two keepers, perhaps they were
766  * all entrances or all exits.
767  */
768  if (exits == k - i || enters == k - i) {
769  /* eliminate all but one entrance or exit */
770  for (j = k - 1; j > i; j--) {
771  /* delete this hit */
772  for (l=j; l<snhits-1; l++)
773  hits[l] = hits[l+1];
774  if (psp) {
775  psp->htab.end--;
776  }
777  snhits--;
778  }
779  i--;
780  }
781  } else {
782  /* found an entrance and an exit to keep */
783  for (j = k - 1; j >= i; j--) {
784  if (j != keep1 && j != keep2) {
785  /* delete this hit */
786  for (l=j; l<snhits-1; l++)
787  hits[l] = hits[l+1];
788  if (psp) {
789  psp->htab.end--;
790  }
791  snhits--;
792  }
793  }
794  i--;
795  }
796  }
797  }
798  }
799 
800  /*
801  * Handle cases where there are multiple adjacent entrances or
802  * exits along the shotline. Using the FILO approach where we
803  * keep the "First In" from multiple entrances and the "Last
804  * Out" for multiple exits.
805  *
806  * Many of these cases were being generated when the shot ray
807  * grazed a surface. Grazing shots should USUALLY be treated
808  * as non-hits (and is the case for other primitives). With
809  * BoTs, however, these can cause multiple entrances and exits
810  * when adjacent surfaces are hit.
811  *
812  * Example #1: CROSS-SECTION OF CONVEX SOLID
813  *
814  * --------------
815  * | |
816  * |entrance |exit
817  * ray--> ------------ ------------
818  * |entrance |exit
819  * | |
820  *
821  * For this grazing hit, LOS(X) was being shown as:
822  * --------------
823  * | |
824  * |entrance |exit
825  * ray--> XXXXXXXXXXXX XXXXXXXXXXXXX
826  * |entrance |exit
827  * | |
828  *
829  * Using a FILO approach, now LOS(X) shows as:
830  * --------------
831  * | |
832  * |entrance |exit
833  * ray--> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
834  * |entrance |exit
835  * | |
836  *
837  */
838  for (i = 0; i < snhits-1; i++) {
839  if (hits[i].hit_vpriv[X] < 0.0) { /* entering */
840  k = i + 1;
841  while ((k < snhits) && (hits[k].hit_vpriv[X] < 0.0)) {
842  for (j = i; j < snhits-1; j++)
843  hits[j] = hits[j+1];
844  snhits--;
845  }
846  } else if (hits[i].hit_vpriv[X] > 0.0) { /* exiting */
847  k = i + 1;
848  while ((k < snhits) && (hits[k].hit_vpriv[X] > 0.0)) {
849  for (j = i + 1; j < snhits - 1; j++)
850  hits[j] = hits[j+1];
851  snhits--;
852  }
853  }
854  }
855 
856  /*
857  * Note that we could try to use a LIFO approach so that we
858  * more consistently count all grazing hits as a miss, but
859  * there's an increased chance of slipping through a crack
860  * with BoTs without a change to check mesh neighbors:
861  *
862  * Using a LIFO approach, the above LOS(X) would have been:
863  *
864  * --------------
865  * | |
866  * |entrance |exit
867  * ray--> -----------XXXXXXXXXXXXXX------------
868  * |entrance |exit
869  * | |
870  *
871  * Example #2: CROSS-SECTION OF CONCAVE SOLID
872  *
873  * ray--> ------------ ------------
874  * |entrance |exit |entrance |exit
875  * | | | |
876  * --------------
877  *
878  * Using LIFO, we would report a miss for the concave case,
879  * but with FILO this will return two hit segments.
880  *
881  * ray--> XXXXXXXXXXXX XXXXXXXXXXXX
882  * |entrance |exit |entrance |exit
883  * | | | |
884  * --------------
885  */
886  }
887 
888  /* if first hit is an exit, it is likely due to the "piece" for
889  * the corresponding entrance not being processed (this is OK, but
890  * we need to eliminate the stray exit hit)
891  */
892  while (snhits > 0 && hits[0].hit_vpriv[X] > 0.0) {
893  ssize_t j;
894 
895  for (j = 1; j < snhits; j++) {
896  hits[j-1] = hits[j];
897  }
898  snhits--;
899  }
900 
901  /* similar for trailing entrance hits */
902  while (snhits > 0 && hits[snhits-1].hit_vpriv[X] < 0.0) {
903  snhits--;
904  }
905 
906  if ((snhits&1)) {
907  /*
908  * If this condition exists, it is almost certainly due to the
909  * dn==0 check above. Thus, we will make the last surface
910  * rather thin. This at least makes the presence of this
911  * solid known. There may be something better we can do.
912  */
913 
914  if (snhits > 2) {
915  fastf_t dot1, dot2;
916  ssize_t j;
917 
918  /* likely an extra hit, look for consecutive entrances or
919  * exits.
920  */
921 
922  dot2 = 1.0;
923  i = 0;
924  while (i<snhits) {
925  dot1 = dot2;
926  dot2 = hits[i].hit_vpriv[X];
927  if (dot1 > 0.0 && dot2 > 0.0) {
928  /* two consecutive exits, manufacture an entrance
929  * at same distance as second exit.
930  */
931  /* XXX This consumes an extra hit structure in the array */
932  if (psp) {
933  /* using pieces */
934  (void)rt_htbl_get(&psp->htab); /* make sure space exists in the hit array */
935  hits = psp->htab.hits;
936  } else if (snhits + 1 >= MAXHITS) {
937  /* not using pieces */
938  bu_log("rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep);
939  i++;
940  continue;
941  }
942  for (j = snhits; j > i; j--)
943  hits[j] = hits[j-1]; /* struct copy */
944 
945  hits[i].hit_vpriv[X] = -hits[i].hit_vpriv[X];
946  dot2 = hits[i].hit_vpriv[X];
947  snhits++;
948  bu_log("\t\tadding fictitious entry at %f (%s)\n", hits[i].hit_dist, stp->st_name);
949  bu_log("\t\t\tray = (%g %g %g) -> (%g %g %g)\n", V3ARGS(ap->a_ray.r_pt), V3ARGS(ap->a_ray.r_dir));
950  } else if (dot1 < 0.0 && dot2 < 0.0) {
951  /* two consecutive entrances, manufacture an exit
952  * between them.
953  */
954  /* XXX This consumes an extra hit structure in the
955  * array.
956  */
957 
958  if (psp) {
959  /* using pieces */
960  (void)rt_htbl_get(&psp->htab); /* make sure space exists in the hit array */
961  hits = psp->htab.hits;
962  } else if (snhits + 1 >= MAXHITS) {
963  /* not using pieces */
964  bu_log("rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep);
965  i++;
966  continue;
967  }
968  for (j = snhits; j > i; j--)
969  hits[j] = hits[j-1]; /* struct copy */
970 
971  hits[i] = hits[i-1]; /* struct copy */
972  hits[i].hit_vpriv[X] = -hits[i].hit_vpriv[X];
973  dot2 = hits[i].hit_vpriv[X];
974  snhits++;
975  bu_log("\t\tadding fictitious exit at %f (%s)\n", hits[i].hit_dist, stp->st_name);
976  bu_log("\t\t\tray = (%g %g %g) -> (%g %g %g)\n", V3ARGS(ap->a_ray.r_pt), V3ARGS(ap->a_ray.r_dir));
977  }
978  i++;
979  }
980  }
981  }
982 
983  if ((snhits&1)) {
984  /* XXX This consumes an extra hit structure in the array */
985  if (psp) {
986  (void)rt_htbl_get(&psp->htab); /* make sure space exists in the hit array */
987  hits = psp->htab.hits;
988  }
989  if (!psp && (snhits + 1 >= MAXHITS)) {
990  bu_log("rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep);
991  snhits--;
992  } else {
993  hits[snhits] = hits[snhits-1]; /* struct copy */
994  hits[snhits].hit_vpriv[X] = -hits[snhits].hit_vpriv[X];
995  snhits++;
996  }
997  }
998 
999  /* snhits is even, build segments */
1000  for (i = 0; i < snhits; i += 2) {
1001  XGLUE(tri_specific_, TRI_TYPE) *trip;
1002 
1003  RT_GET_SEG(segp, ap->a_resource);
1004  segp->seg_stp = stp;
1005  segp->seg_in = hits[i]; /* struct copy */
1006  trip = (XGLUE(tri_specific_, TRI_TYPE) *)hits[i].hit_private;
1007  BOT_UNORIENTED_NORM(ap, &segp->seg_in, IN);
1008  segp->seg_out = hits[i+1]; /* struct copy */
1009  trip = (XGLUE(tri_specific_, TRI_TYPE) *)hits[i+1].hit_private;
1010  BOT_UNORIENTED_NORM(ap, &segp->seg_out, OUT);
1011  BU_LIST_INSERT(&(seghead->l), &(segp->l));
1012  }
1013 
1014  return snhits; /* HIT */
1015 }
1016 
1017 
1018 /**
1019  * Intersect a ray with a bot. If an intersection occurs, a struct
1020  * seg will be acquired and filled in.
1021  *
1022  * Notes for rt_bot_norm(): hit_private contains pointer to the
1023  * tri_specific structure. hit_vpriv[X] contains dot product of ray
1024  * direction and unit normal from tri_specific.
1025  *
1026  * Returns -
1027  * 0 MISS
1028  * >0 HIT
1029  */
1030 int
1031 XGLUE(rt_bot_shot_, TRI_TYPE)(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
1032 {
1033  struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
1034  register XGLUE(tri_specific_, TRI_TYPE) *trip = (XGLUE(tri_specific_, TRI_TYPE) *)bot->bot_facelist;
1035  struct hit hits[MAXHITS];
1036  register struct hit *hp;
1037  size_t nhits;
1038  fastf_t toldist, dn_plus_tol;
1039 
1040  nhits = 0;
1041  hp = &hits[0];
1042  if (bot->bot_orientation != RT_BOT_UNORIENTED && bot->bot_mode == RT_BOT_SOLID) {
1043  toldist = stp->st_aradius / 10.0e+6;
1044  } else {
1045  toldist = 0.0;
1046  }
1047 
1048  /* consider each face */
1049  for (; trip; trip = trip->tri_forw) {
1050  fastf_t dn; /* Direction dot Normal */
1051  fastf_t abs_dn;
1052  fastf_t k;
1053  fastf_t alpha, beta;
1054  vect_t wxb; /* vertex - ray_start */
1055  vect_t xp; /* wxb cross ray_dir */
1056 
1057  /*
1058  * Ray Direction dot N. (N is outward-pointing normal) wn
1059  * points inwards, and is not unit length.
1060  */
1061  dn = VDOT(trip->tri_wn, rp->r_dir);
1062 
1063  /*
1064  * If ray lies directly along the face, (i.e., dot product is
1065  * zero), drop this face.
1066  */
1067  abs_dn = dn >= 0.0 ? dn : (-dn);
1068  if (abs_dn < BOT_MIN_DN) {
1069  continue;
1070  }
1071  VSUB2(wxb, trip->tri_A, rp->r_pt);
1072  VCROSS(xp, wxb, rp->r_dir);
1073 
1074  dn_plus_tol = toldist + abs_dn;
1075 
1076  /* Check for exceeding along the one side */
1077  alpha = VDOT(trip->tri_CA, xp);
1078  if (dn < 0.0) alpha = -alpha;
1079  if (alpha < -toldist || alpha > dn_plus_tol) {
1080  continue;
1081  }
1082 
1083  /* Check for exceeding along the other side */
1084  beta = VDOT(trip->tri_BA, xp);
1085  if (dn > 0.0) beta = -beta;
1086  if (beta < -toldist || beta > dn_plus_tol) {
1087  continue;
1088  }
1089  if (alpha+beta > dn_plus_tol) {
1090  continue;
1091  }
1092  k = VDOT(wxb, trip->tri_wn) / dn;
1093  /* HIT is within planar face */
1094  hp->hit_magic = RT_HIT_MAGIC;
1095  hp->hit_dist = k;
1096  hp->hit_private = (void *)trip;
1097  hp->hit_vpriv[X] = VDOT(trip->tri_N, rp->r_dir);
1098  hp->hit_vpriv[Y] = alpha / abs_dn;
1099  hp->hit_vpriv[Z] = beta / abs_dn;
1100  hp->hit_surfno = trip->tri_surfno;
1101  hp->hit_rayp = &ap->a_ray;
1102  if (++nhits >= MAXHITS) {
1103  bu_log("rt_bot_shot(%s): too many hits (%zu)\n", stp->st_name, nhits);
1104  break;
1105  }
1106  hp++;
1107  }
1108  if (nhits == 0)
1109  return 0; /* MISS */
1110 
1111  /* Sort hits, Near to Far */
1112  rt_hitsort(hits, nhits);
1113 
1114  /* build segments */
1115  return rt_bot_makesegs(hits, nhits, stp, rp, ap, seghead, NULL);
1116 }
1117 
1118 
1119 /**
1120  * Intersect a ray with a list of "pieces" of a BoT.
1121  *
1122  * This routine may be invoked many times for a single ray, as the ray
1123  * traverses from one space partitioning cell to the next.
1124  *
1125  * Plate-mode (2 hit) segments will be returned immediately in
1126  * seghead.
1127  *
1128  * Generally the hits are stashed between invocations in psp.
1129  */
1130 int
1131 XGLUE(rt_bot_piece_shot_, TRI_TYPE)(struct rt_piecestate *psp, struct rt_piecelist *plp,
1132  double dist_corr, struct xray *rp, struct application *ap, struct seg *seghead)
1133 {
1134  struct resource *resp;
1135  long *sol_piece_subscr_p;
1136  struct soltab *stp;
1137  long piecenum;
1138  register struct hit *hp;
1139  struct bot_specific *bot;
1140  const int debug_shoot = RT_G_DEBUG & DEBUG_SHOOT;
1141  int starting_hits;
1142  fastf_t toldist, dn_plus_tol;
1143  size_t trinum;
1144 
1145  RT_CK_PIECELIST(plp);
1146  stp = plp->stp;
1147 
1148  RT_CK_APPLICATION(ap);
1149  resp = ap->a_resource;
1150  RT_CK_RESOURCE(resp);
1151 
1152  RT_CK_SOLTAB(stp);
1153  bot = (struct bot_specific *)stp->st_specific;
1154 
1155  RT_CK_PIECESTATE(psp);
1156  starting_hits = psp->htab.end;
1157 
1158  if (bot->bot_orientation != RT_BOT_UNORIENTED &&
1159  bot->bot_mode == RT_BOT_SOLID) {
1160 
1161  toldist = psp->stp->st_aradius / 10.0e+6;
1162  } else {
1163  toldist = 0.0;
1164  }
1165 
1166  if (debug_shoot) {
1167  bu_log("In rt_bot_piece_shot(), looking at %zu pieces\n", plp->npieces);
1168  }
1169  sol_piece_subscr_p = &(plp->pieces[plp->npieces-1]);
1170  for (; sol_piece_subscr_p >= plp->pieces; sol_piece_subscr_p--) {
1171  fastf_t dn; /* Direction dot Normal */
1172  fastf_t abs_dn;
1173  fastf_t k;
1174  fastf_t alpha, beta;
1175  vect_t wxb; /* vertex - ray_start */
1176  vect_t xp; /* wxb cross ray_dir */
1177  size_t face_array_index;
1178  size_t tris_in_piece;
1179 
1180  piecenum = *sol_piece_subscr_p;
1181 
1182  if (BU_BITTEST(psp->shot, piecenum)) {
1183  if (debug_shoot)
1184  bu_log("%s piece %ld already shot\n",
1185  stp->st_name, piecenum);
1186 
1187  resp->re_piece_ndup++;
1188  continue; /* this piece already shot */
1189  }
1190 
1191  /* Shoot a ray */
1192  BU_BITSET(psp->shot, piecenum);
1193  if (debug_shoot)
1194  bu_log("%s piece %ld ...\n", stp->st_name, piecenum);
1195 
1196  /* Now intersect with each piece, which means intersecting with
1197  * each triangle that makes up the piece.
1198  */
1199  face_array_index = piecenum*bot->bot_tri_per_piece;
1200  tris_in_piece = bot->bot_ntri - face_array_index;
1201  if (tris_in_piece > bot->bot_tri_per_piece) {
1202  tris_in_piece = bot->bot_tri_per_piece;
1203  }
1204  for (trinum = 0; trinum < tris_in_piece; trinum++) {
1205  register XGLUE(tri_specific_, TRI_TYPE) *trip = (XGLUE(tri_specific_, TRI_TYPE) *)bot->bot_facearray[face_array_index+trinum];
1206  fastf_t dN, abs_dN;
1207  /*
1208  * Ray Direction dot N. (N is outward-pointing normal) wn
1209  * points inwards, and is not unit length. Therefore, wn
1210  * is not a good choice for this test
1211  */
1212  dn = VDOT(trip->tri_wn, rp->r_dir);
1213  dN = VDOT(trip->tri_N, rp->r_dir);
1214 
1215  /*
1216  * If ray lies directly along the face, (i.e., dot product
1217  * is zero), drop this face.
1218  */
1219  abs_dN = dN >= 0.0 ? dN : (-dN);
1220  abs_dn = dn >= 0.0 ? dn : (-dn);
1221  if (abs_dN < BOT_MIN_DN) {
1222  continue;
1223  }
1224  VSUB2(wxb, trip->tri_A, rp->r_pt);
1225  VCROSS(xp, wxb, rp->r_dir);
1226 
1227  dn_plus_tol = toldist + abs_dn;
1228 
1229  /* Check for exceeding along the one side */
1230  alpha = VDOT(trip->tri_CA, xp);
1231  if (dn < 0.0) alpha = -alpha;
1232  if (alpha < -toldist || alpha > dn_plus_tol) {
1233  continue;
1234  }
1235 
1236  /* Check for exceeding along the other side */
1237  beta = VDOT(trip->tri_BA, xp);
1238  if (dn > 0.0) beta = -beta;
1239  if (beta < -toldist || beta > dn_plus_tol) {
1240  continue;
1241  }
1242  if (alpha+beta > dn_plus_tol) {
1243  continue;
1244  }
1245  k = VDOT(wxb, trip->tri_wn) / dn;
1246 
1247  /* HIT is within planar face */
1248  hp = rt_htbl_get(&psp->htab);
1249  hp->hit_magic = RT_HIT_MAGIC;
1250  hp->hit_dist = k + dist_corr;
1251  hp->hit_private = (void *)trip;
1252  hp->hit_vpriv[X] = VDOT(trip->tri_N, rp->r_dir);
1253  hp->hit_vpriv[Y] = alpha / abs_dn;
1254  hp->hit_vpriv[Z] = beta / abs_dn;
1255  hp->hit_surfno = trip->tri_surfno;
1256  hp->hit_rayp = &ap->a_ray;
1257  if (debug_shoot)
1258  bu_log("%s piece %ld surfno %d ... HIT %g\n",
1259  stp->st_name, piecenum, trip->tri_surfno, hp->hit_dist);
1260  } /* for (trinum...) */
1261  } /* for (;sol_piece_subscr_p...) */
1262 
1263  if (psp->htab.end > 0 &&
1264  (bot->bot_mode == RT_BOT_PLATE ||
1265  bot->bot_mode == RT_BOT_PLATE_NOCOS)) {
1266  /*
1267  * Each of these hits is really two, resulting in an instant
1268  * seg. Saving an odd number of these will confuse a_onehit
1269  * processing.
1270  */
1271  rt_hitsort(psp->htab.hits, psp->htab.end);
1272  return rt_bot_makesegs(psp->htab.hits, psp->htab.end,
1273  stp, rp, ap, seghead, psp);
1274  }
1275  return psp->htab.end - starting_hits;
1276 }
1277 
1278 
1279 /**
1280  * Given ONE ray distance, return the normal and entry/exit point.
1281  */
1282 void
1283 XGLUE(rt_bot_norm_, TRI_TYPE)(struct bot_specific *bot, struct hit *hitp, struct soltab *stp, struct xray *rp)
1284 {
1285  vect_t old_norm;
1286  XGLUE(tri_specific_, TRI_TYPE) *trip=(XGLUE(tri_specific_, TRI_TYPE) *)hitp->hit_private;
1287 
1288  if (stp) RT_CK_SOLTAB(stp);
1289 
1290  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
1291  VMOVE(old_norm, hitp->hit_normal);
1292 
1293  if ((bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot->bot_flags & RT_BOT_USE_NORMALS) && trip->tri_normals) {
1294  fastf_t old_ray_dot_norm, new_ray_dot_norm;
1295  fastf_t u, v, w; /*barycentric coords of hit point */
1296  size_t i;
1297 
1298  old_ray_dot_norm = VDOT(hitp->hit_normal, rp->r_dir);
1299 
1300  v = hitp->hit_vpriv[Y];
1301  if (v < 0.0) v = 0.0;
1302  if (v > 1.0) v = 1.0;
1303 
1304  w = hitp->hit_vpriv[Z];
1305  if (w < 0.0) w = 0.0;
1306  if (w > 1.0) w = 1.0;
1307 
1308  u = 1.0 - v - w;
1309  if (u < 0.0) u = 0.0;
1310  VSETALL(hitp->hit_normal, 0.0);
1311 
1312  for (i = X; i <= Z; i++) {
1313  hitp->hit_normal[i] = u*trip->tri_normals[i]*ONE_OVER_SCALE + v*trip->tri_normals[i+3]*ONE_OVER_SCALE + w*trip->tri_normals[i+6]*ONE_OVER_SCALE;
1314  }
1315  VUNITIZE(hitp->hit_normal);
1316 
1317  if (bot->bot_mode == RT_BOT_PLATE || bot->bot_mode == RT_BOT_PLATE_NOCOS) {
1318  if (VDOT(old_norm, hitp->hit_normal) < 0.0) {
1319  VREVERSE(hitp->hit_normal, hitp->hit_normal);
1320  }
1321  }
1322 
1323  new_ray_dot_norm = VDOT(hitp->hit_normal, rp->r_dir);
1324 
1325  if ((old_ray_dot_norm < 0.0 && new_ray_dot_norm > 0.0) ||
1326  (old_ray_dot_norm > 0.0 && new_ray_dot_norm < 0.0)) {
1327  /* surface normal interpolation has produced an
1328  * incompatible normal direction clamp the normal to 90
1329  * degrees to the ray direction
1330  */
1331 
1332  vect_t tmp;
1333 
1334  VCROSS(tmp, rp->r_dir, hitp->hit_normal);
1335  VCROSS(hitp->hit_normal, tmp, rp->r_dir);
1336  }
1337 
1338  VUNITIZE(hitp->hit_normal);
1339  }
1340 }
1341 
1342 
1343 void
1344 XGLUE(rt_bot_free_, TRI_TYPE)(struct bot_specific *bot)
1345 {
1346  register XGLUE(tri_specific_, TRI_TYPE) *tri, *ptr;
1347 
1348  if (bot->bot_facearray) {
1349  bu_free((char *)bot->bot_facearray, "bot_facearray");
1350  bot->bot_facearray = NULL;
1351  }
1352  if (bot->bot_thickness) {
1353  bu_free((char *)bot->bot_thickness, "bot_thickness");
1354  bot->bot_thickness = NULL;
1355  }
1356  if (bot->bot_facemode) {
1357  bu_free((char *)bot->bot_facemode, "bot_facemode");
1358  bot->bot_facemode = NULL;
1359  }
1360 
1361  ptr = (XGLUE(tri_specific_, TRI_TYPE) *)bot->bot_facelist;
1362  while (ptr) {
1363  tri = ptr->tri_forw;
1364  if (ptr) {
1365  if (ptr->tri_normals) {
1366  bu_free((char *)ptr->tri_normals, "bot tri_specific normals");
1367  }
1368  BU_PUT(ptr, XGLUE(tri_specific_, TRI_TYPE));
1369  }
1370  ptr = tri;
1371  }
1372  bot->bot_facelist = NULL;
1373  BU_PUT(bot, struct bot_specific);
1374 }
1375 
1376 
1377 /** @} */
1378 
1379 /*
1380  * Local Variables:
1381  * mode: C
1382  * tab-width: 8
1383  * indent-tabs-mode: t
1384  * c-file-style: "stroustrup"
1385  * End:
1386  * ex: shiftwidth=4 tabstop=8
1387  */
ptrdiff_t ssize_t
Definition: common.h:119
char * d_namep
pointer to name string
Definition: raytrace.h:859
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
uint32_t hit_magic
Definition: raytrace.h:249
struct bu_bitv * shot
Definition: raytrace.h:1381
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
struct hit seg_in
IN information.
Definition: raytrace.h:370
#define IN
Definition: tgc.c:84
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
void * hit_private
PRIVATE handle for xxx_shot()
Definition: raytrace.h:254
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
#define LIKELY(expression)
Definition: common.h:261
#define RT_CK_PIECELIST(_p)
Definition: raytrace.h:1410
double dist
>= 0
Definition: tol.h:73
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
double dist_sq
dist * dist
Definition: tol.h:74
void rt_hitsort(struct hit h[], int nh)
Definition: raytrace.h:368
int rt_bot_makesegs(struct hit *hits, size_t nhits, struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead, struct rt_piecestate *psp)
Definition: bot.c:320
Definition: raytrace.h:248
#define SMALL_FASTF
Definition: defines.h:342
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
#define DEBUG_SHOOT
3 Info about rt_shootray() processing
Definition: raytrace.h:84
int XGLUE(rt_botface_w_normals_, TRI_TYPE)
Definition: g_bot_include.c:43
#define RT_CK_RAY(_p)
Definition: raytrace.h:224
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
struct soltab * stp
Definition: raytrace.h:1380
#define BU_ASSERT(_equation)
Definition: defines.h:216
point_t min
Definition: raytrace.h:415
#define HIDDEN
Definition: common.h:86
#define BU_BITSET(_bv, bit)
Definition: bitv.h:183
#define OUT
Definition: tgc.c:83
struct bu_list l
Definition: raytrace.h:369
size_t rt_bot_minpieces
Definition: globals.c:83
#define BOT_UNORIENTED_NORM(_ap, _hitp, _out)
Definition: bot.c:58
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
if(share_geom)
Definition: nmg_mod.c:3829
Definition: color.c:49
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
#define NORMAL_SCALE
Definition: bot.c:121
long * pieces
pieces[npieces], piece indices
Definition: raytrace.h:1407
long re_piece_ndup
ft_piece_shot() calls skipped for already-ft_shot() solids
Definition: raytrace.h:1471
#define RT_G_DEBUG
Definition: raytrace.h:1718
vect_t hit_vpriv
PRIVATE vector for xxx_*()
Definition: raytrace.h:253
#define BU_BITTEST(_bv, bit)
Definition: bitv.h:168
struct bound_rpp * st_piece_rpps
bounding RPP of each piece of this solid
Definition: raytrace.h:446
struct hit * rt_htbl_get(struct rt_htbl *b)
Definition: htbl.c:82
size_t rt_botface(struct soltab *stp, struct bot_specific *bot, fastf_t *ap, fastf_t *bp, fastf_t *cp, size_t face_no, const struct bn_tol *tol)
Definition: bot.c:160
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
fastf_t st_bradius
Radius of BOUNDING sphere.
Definition: raytrace.h:434
struct rt_htbl htab
accumulating hits here
Definition: raytrace.h:1384
#define V3ARGS(a)
Definition: color.c:56
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
unsigned char * bp
Definition: rot.c:56
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
point_t hit_point
DEPRECATED: Intersection point, use VJOIN1 hit_dist.
Definition: raytrace.h:251
point_t st_max
max X, Y, Z of bounding RPP
Definition: raytrace.h:438
struct hit seg_out
OUT information.
Definition: raytrace.h:371
struct xray * hit_rayp
pointer to defining ray
Definition: raytrace.h:256
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
Support for uniform tolerances.
Definition: tol.h:71
#define TRI_TYPE
Definition: bot.c:119
struct bu_bitv * bu_bitv_dup(const struct bu_bitv *bv)
ustring alpha
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
point_t max
Definition: raytrace.h:416
#define ZERO(val)
Definition: units.c:38
size_t end
index of first available location
Definition: raytrace.h:1363
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
point_t st_min
min X, Y, Z of bounding RPP
Definition: raytrace.h:437
size_t npieces
number of pieces in pieces[] array
Definition: raytrace.h:1406
#define RT_CK_RESOURCE(_p)
Definition: raytrace.h:1490
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
void rt_bot_prep_pieces(struct bot_specific *bot, struct soltab *stp, size_t ntri, const struct bn_tol *tol)
Definition: bot.c:176
#define ONE_OVER_SCALE
Definition: bot.c:122
#define MAXHITS
Definition: bot.c:54
Definition: color.c:51
#define RT_CK_PIECESTATE(_p)
Definition: raytrace.h:1387
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
struct hit * hits
hits[blen] data storage area
Definition: raytrace.h:1365
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
struct soltab * stp
ref back to solid
Definition: raytrace.h:1408
#define NORM_TYPE
Definition: bot.c:120
size_t rt_bot_tri_per_piece
Definition: globals.c:88
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
double fastf_t
Definition: defines.h:300
HIDDEN int rt_bot_unoriented_segs(struct hit *hits, size_t nhits, struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead, struct bot_specific *bot)
Definition: bot.c:299
size_t rt_botface_w_normals(struct soltab *stp, struct bot_specific *bot, fastf_t *ap, fastf_t *bp, fastf_t *cp, fastf_t *vertex_normals, size_t face_no, const struct bn_tol *tol)
Definition: bot.c:139
Definition: color.c:50
#define BOT_MIN_DN
Definition: bot.c:56
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
long st_npieces
pieces used by this solid
Definition: raytrace.h:444
#define RT_HIT_MAGIC
Definition: magic.h:161