BRL-CAD
bbox.c
Go to the documentation of this file.
1 /* B B O X . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1995-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 librt */
21 /** @{ */
22 /** @file librt/bbox.c
23  *
24  * Routines related to creating and processing bounding boxes.
25  *
26  */
27 /** @} */
28 
29 #include "common.h"
30 
31 #include <string.h>
32 
33 #include "vmath.h"
34 #include "raytrace.h"
35 
36 
37 int
38 rt_bound_tree(const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
39 {
40  vect_t r_min, r_max; /* rpp for right side of tree */
41 
42  RT_CK_TREE(tp);
43 
44  switch (tp->tr_op) {
45 
46  case OP_SOLID:
47  {
48  const struct soltab *stp;
49 
50  stp = tp->tr_a.tu_stp;
51  RT_CK_SOLTAB(stp);
52  if (stp->st_aradius <= 0) {
53  bu_log("rt_bound_tree: encountered dead solid '%s'\n",
54  stp->st_dp->d_namep);
55  return -1; /* ERROR */
56  }
57 
58  if (stp->st_aradius >= INFINITY) {
59  VSETALL(tree_min, -INFINITY);
60  VSETALL(tree_max, INFINITY);
61  return 0;
62  }
63  VMOVE(tree_min, stp->st_min);
64  VMOVE(tree_max, stp->st_max);
65  return 0;
66  }
67 
68  default:
69  bu_log("rt_bound_tree(%p): unknown op=x%x\n",
70  (void *)tp, tp->tr_op);
71  return -1;
72 
73  case OP_XOR:
74  case OP_UNION:
75  /* BINARY type -- expand to contain both */
76  if (rt_bound_tree(tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
77  rt_bound_tree(tp->tr_b.tb_right, r_min, r_max) < 0)
78  return -1;
79  VMIN(tree_min, r_min);
80  VMAX(tree_max, r_max);
81  break;
82  case OP_INTERSECT:
83  /* BINARY type -- find common area only */
84  if (rt_bound_tree(tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
85  rt_bound_tree(tp->tr_b.tb_right, r_min, r_max) < 0)
86  return -1;
87  /* min = largest min, max = smallest max */
88  VMAX(tree_min, r_min);
89  VMIN(tree_max, r_max);
90  break;
91  case OP_SUBTRACT:
92  /* BINARY type -- just use left tree */
93  if (rt_bound_tree(tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
94  rt_bound_tree(tp->tr_b.tb_right, r_min, r_max) < 0)
95  return -1;
96  /* Discard right rpp */
97  break;
98  case OP_NOP:
99  /* Implies that this tree has nothing in it */
100  break;
101  }
102  return 0;
103 }
104 
105 
106 /**
107  * Return a pointer to the corresponding region structure of the given
108  * region's name (reg_name), or REGION_NULL if it does not exist.
109  *
110  * If the full path of a region is specified, then that one is
111  * returned. However, if only the database node name of the region is
112  * specified and that region has been referenced multiple time in the
113  * tree, then this routine will simply return the first one.
114  */
115 HIDDEN struct region *
116 _rt_getregion(struct rt_i *rtip, const char *reg_name)
117 {
118  struct region *regp;
119  char *reg_base = (char *)bu_calloc(strlen(reg_name), sizeof(char), "rt_getregion reg_base");
120  bu_basename(reg_base, reg_name);
121 
122  RT_CK_RTI(rtip);
123  for (BU_LIST_FOR(regp, region, &(rtip->HeadRegion))) {
124  char *cp;
125  /* First, check for a match of the full path */
126  if (*reg_base == regp->reg_name[0] &&
127  BU_STR_EQUAL(reg_base, regp->reg_name)) {
128  bu_free(reg_base, "reg_base free");
129  return regp;
130  }
131  /* Second, check for a match of the database node name */
132  cp = (char *)bu_calloc(strlen(regp->reg_name), sizeof(char), "rt_getregion cp");
133  bu_basename(cp, regp->reg_name);
134  if (*cp == *reg_name && BU_STR_EQUAL(cp, reg_name)) {
135  bu_free(reg_base, "reg_base free");
136  bu_free(cp, "cp free");
137  return regp;
138  }
139  bu_free(cp, "cp free");
140  }
141  bu_free(reg_base, "reg_base free");
142 
143  return REGION_NULL;
144 }
145 
146 
147 int
148 rt_rpp_region(struct rt_i *rtip, const char *reg_name, fastf_t *min_rpp, fastf_t *max_rpp)
149 {
150  struct region *regp;
151 
152  RT_CHECK_RTI(rtip);
153 
154  regp = _rt_getregion(rtip, reg_name);
155  if (regp == REGION_NULL) return 0;
156  if (rt_bound_tree(regp->reg_treetop, min_rpp, max_rpp) < 0)
157  return 0;
158  return 1;
159 }
160 
161 
162 int
163 rt_in_rpp(struct xray *rp,
164  register const fastf_t *invdir, /* inverses of rp->r_dir[] */
165  register const fastf_t *min,
166  register const fastf_t *max)
167 {
168  register const fastf_t *pt = &rp->r_pt[0];
169  register fastf_t sv;
170 #define st sv /* reuse the register */
171  register fastf_t rmin = -MAX_FASTF;
172  register fastf_t rmax = MAX_FASTF;
173 
174  /* Start with infinite ray, and trim it down */
175 
176  /* X axis */
177  if (*invdir < -SMALL_FASTF) {
178  /* Heading towards smaller numbers */
179  /* if (*min > *pt) miss */
180  if (rmax > (sv = (*min - *pt) * *invdir))
181  rmax = sv;
182  if (rmin < (st = (*max - *pt) * *invdir))
183  rmin = st;
184  } else if (*invdir > SMALL_FASTF) {
185  /* Heading towards larger numbers */
186  /* if (*max < *pt) miss */
187  if (rmax > (st = (*max - *pt) * *invdir))
188  rmax = st;
189  if (rmin < ((sv = (*min - *pt) * *invdir)))
190  rmin = sv;
191  } else {
192  /*
193  * Direction cosines along this axis is NEAR 0,
194  * which implies that the ray is perpendicular to the axis,
195  * so merely check position against the boundaries.
196  */
197  if ((*min > *pt) || (*max < *pt))
198  return 0; /* MISS */
199  }
200 
201  /* Y axis */
202  pt++; invdir++; max++; min++;
203  if (*invdir < -SMALL_FASTF) {
204  if (rmax > (sv = (*min - *pt) * *invdir))
205  rmax = sv;
206  if (rmin < (st = (*max - *pt) * *invdir))
207  rmin = st;
208  } else if (*invdir > SMALL_FASTF) {
209  if (rmax > (st = (*max - *pt) * *invdir))
210  rmax = st;
211  if (rmin < ((sv = (*min - *pt) * *invdir)))
212  rmin = sv;
213  } else {
214  if ((*min > *pt) || (*max < *pt))
215  return 0; /* MISS */
216  }
217 
218  /* Z axis */
219  pt++; invdir++; max++; min++;
220  if (*invdir < -SMALL_FASTF) {
221  if (rmax > (sv = (*min - *pt) * *invdir))
222  rmax = sv;
223  if (rmin < (st = (*max - *pt) * *invdir))
224  rmin = st;
225  } else if (*invdir > SMALL_FASTF) {
226  if (rmax > (st = (*max - *pt) * *invdir))
227  rmax = st;
228  if (rmin < ((sv = (*min - *pt) * *invdir)))
229  rmin = sv;
230  } else {
231  if ((*min > *pt) || (*max < *pt))
232  return 0; /* MISS */
233  }
234 
235  /* If equal, RPP is actually a plane */
236  if (rmin > rmax)
237  return 0; /* MISS */
238 
239  /* HIT. Only now do rp->r_min and rp->r_max have to be written */
240  rp->r_min = rmin;
241  rp->r_max = rmax;
242  return 1; /* HIT */
243 }
244 
245 
246 /**
247  * Traverse the passed tree using rt_db_internals to show the way
248  * This function supports rt_bound_internal and is internal to librt
249  *
250  * Returns -
251  * 0 success
252  * -1 failure (tree_min and tree_max may have been altered)
253  */
254 int
255 rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
256 {
257  vect_t r_min, r_max; /* rpp for right side of tree */
258 
259  RT_CK_TREE(tp);
260 
261  switch (tp->tr_op) {
262 
263  case OP_SOLID:
264  {
265  const struct soltab *stp;
266 
267  stp = tp->tr_a.tu_stp;
268  RT_CK_SOLTAB(stp);
269  if (stp->st_aradius <= 0) {
270  bu_log("rt_traverse_tree: encountered dead solid '%s'\n",
271  stp->st_dp->d_namep);
272  return -1; /* ERROR */
273  }
274 
275  if (stp->st_aradius >= INFINITY) {
276  VSETALL(tree_min, -INFINITY);
277  VSETALL(tree_max, INFINITY);
278  return 0;
279  }
280  VMOVE(tree_min, stp->st_min);
281  VMOVE(tree_max, stp->st_max);
282  return 0;
283  }
284 
285  default:
286  bu_log("rt_traverse_tree(%p): unknown op=x%x\n", (void *)tp, (tp->tr_op));
287  return -1;
288 
289  case OP_XOR:
290  case OP_UNION:
291  /* BINARY type -- expand to contain both */
292  if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
293  rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
294  return -1;
295  VMIN(tree_min, r_min);
296  VMAX(tree_max, r_max);
297  break;
298  case OP_INTERSECT:
299  /* BINARY type -- find common area only */
300  if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
301  rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
302  return -1;
303  /* min = largest min, max = smallest max */
304  VMAX(tree_min, r_min);
305  VMIN(tree_max, r_max);
306  break;
307  case OP_SUBTRACT:
308  /* BINARY type -- just use left tree */
309  if (rt_traverse_tree(rtip, tp->tr_b.tb_left, tree_min, tree_max) < 0 ||
310  rt_traverse_tree(rtip, tp->tr_b.tb_right, r_min, r_max) < 0)
311  return -1;
312  /* Discard right rpp */
313  break;
314 
315  /* This case is especially for handling rt_db_internal formats which generally contain a "unloaded"
316  * tree with tp->tr_op = OP_DB_LEAF
317  */
318  case OP_DB_LEAF:
319  {
320  const struct soltab *stp;
321 
322  if (rtip == NULL) {
323  bu_log("rt_traverse_tree: A valid rtip was not passed for calculating bounds of '%s'\n",
324  tp->tr_l.tl_name);
325  return -1;
326  }
327 
328  /* Good to go */
329 
330  /* Attempt to get a solid pointer, will fail for combs */
331  stp = rt_find_solid(rtip, tp->tr_l.tl_name);
332  if (stp == NULL) {
333 
334  /* It was a comb! get an internal format and repeat the whole thing that got us here
335  * in the 1st place
336  */
337  struct rt_db_internal intern;
338  struct directory *dp;
339  struct rt_comb_internal *combp;
340 
341  /* Get the directory pointer */
342  if ((dp=db_lookup(rtip->rti_dbip, tp->tr_l.tl_name, LOOKUP_QUIET)) == RT_DIR_NULL) {
343  bu_log("rt_traverse_tree: db_lookup(%s) failed", tp->tr_l.tl_name);
344  return -1;
345  }
346 
347  /* Why does recursion work with the internal format ?
348  * The internal format does have the boolean op for a comb in the tr_a.tu_op field
349  * in the root node, even though it has no prims at the leaves.
350  * So recursive calls to load the prim further down the tree, will return the correct bb
351  * as we are going through the proper switch case in each step down the tree
352  */
353  if (!rt_db_lookup_internal(rtip->rti_dbip, tp->tr_l.tl_name, &dp, &intern, LOOKUP_NOISY,
354  &rt_uniresource)) {
355  bu_log("rt_traverse_tree: rt_db_lookup_internal(%s) failed to get the internal form",
356  tp->tr_l.tl_name);
357  return -1;
358  }
359 
360  /* The passed rt_db_internal should be a comb, prepare a rt_comb_internal */
361  if (intern.idb_minor_type == ID_COMBINATION) {
362  combp = (struct rt_comb_internal *)intern.idb_ptr;
363  } else {
364  /* if it's not a comb, then something else is cooking */
365  bu_log("rt_traverse_tree: WARNING : rt_db_lookup_internal(%s) got the internal form of a \
366  primitive when it should not, the bounds may not be correct", tp->tr_l.tl_name);
367  return -1;
368  }
369 
370  RT_CK_COMB(combp);
371  /* further down the rabbit hole */
372  if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
373  bu_log("rt_traverse_tree: rt_bound_tree() failed\n");
374  return -1;
375  }
376  } else {
377  /* Got a solid pointer, get bounds and return */
378  RT_CK_SOLTAB(stp);
379  if (stp->st_aradius <= 0) {
380  bu_log("rt_traverse_tree: encountered dead solid '%s'\n",
381  stp->st_dp->d_namep);
382  return -1; /* ERROR */
383  }
384 
385  if (stp->st_aradius >= INFINITY) {
386  VSETALL(tree_min, -INFINITY);
387  VSETALL(tree_max, INFINITY);
388  return 0;
389  }
390 
391  VMOVE(tree_min, stp->st_min);
392  VMOVE(tree_max, stp->st_max);
393  }
394 
395  return 0;
396  }
397 
398  case OP_NOP:
399  /* Implies that this tree has nothing in it */
400  break;
401  }
402  return 0;
403 }
404 
405 
406 int
407 rt_bound_internal(struct db_i *dbip, struct directory *dp,
408  point_t rpp_min, point_t rpp_max)
409 {
410  struct rt_i *rtip;
411  struct rt_db_internal intern;
412  struct rt_comb_internal *combp;
413  vect_t tree_min, tree_max;
414  union tree *tp;
415 
416  /* Initialize RPP bounds */
417  VSETALL(rpp_min, MAX_FASTF);
418  VREVERSE(rpp_max, rpp_min);
419 
420  if ((rtip=rt_new_rti(dbip)) == RTI_NULL) {
421  bu_log("rt_bound_internal: rt_new_rti() failure while getting bb for %s\n", dp->d_namep);
422  return -1;
423  }
424 
425  /* Call rt_gettree() to get the bounds for primitives, else soltab ptr is null */
426  if (rt_gettree(rtip, dp->d_namep) < 0) {
427  bu_log("rt_bound_internal: rt_gettree('%s') failed\n", dp->d_namep);
428  rt_free_rti(rtip);
429  return -1;
430  }
431 
432 
433  if (!rt_db_lookup_internal(dbip, dp->d_namep, &dp, &intern, LOOKUP_NOISY, &rt_uniresource)) {
434  bu_exit(1, "rt_bound_internal: rt_db_lookup_internal(%s) failed to get the internal form", dp->d_namep);
435  rt_free_rti(rtip);
436  return -1;
437  }
438 
439  /* If passed rt_db_internal is a combination(a group or a region) then further calls needed */
440  if (intern.idb_minor_type == ID_COMBINATION) {
441  combp = (struct rt_comb_internal *)intern.idb_ptr;
442  } else {
443  /* A primitive was passed, construct a struct rt_comb_internal with a single leaf node */
444  BU_ALLOC(combp, struct rt_comb_internal);
445  RT_COMB_INTERNAL_INIT(combp);
446  combp->region_flag = 0;
447 
449  RT_TREE_INIT(tp);
450  tp->tr_l.tl_op = OP_SOLID;
451  tp->tr_l.tl_name = "dummy";
452  tp->tr_l.tl_mat = (matp_t)NULL;
453  tp->tr_a.tu_stp = rt_find_solid(rtip, dp->d_namep);
454  combp->tree = tp;
455  }
456 
457  RT_CK_COMB(combp);
458  if (rt_traverse_tree(rtip, combp->tree, tree_min, tree_max)) {
459  bu_log("rt_bound_internal: rt_bound_tree() failed\n");
460  rt_db_free_internal(&intern);
461  rt_free_rti(rtip);
462  return -1;
463  }
464 
465 
466  VMOVE(rpp_min, tree_min);
467  VMOVE(rpp_max, tree_max);
468 
469  /* Check if the model bounds look correct e.g. if they are all 0, then it's not correct */
470  if ((NEAR_ZERO(rpp_min[0], SMALL_FASTF) || rpp_min[0] <= -INFINITY || rpp_min[0] >= INFINITY) &&
471  (NEAR_ZERO(rpp_min[1], SMALL_FASTF) || rpp_min[1] <= -INFINITY || rpp_min[1] >= INFINITY) &&
472  (NEAR_ZERO(rpp_min[2], SMALL_FASTF) || rpp_min[2] <= -INFINITY || rpp_min[2] >= INFINITY) &&
473  (NEAR_ZERO(rpp_max[0], SMALL_FASTF) || rpp_max[0] <= -INFINITY || rpp_max[0] >= INFINITY) &&
474  (NEAR_ZERO(rpp_max[1], SMALL_FASTF) || rpp_max[1] <= -INFINITY || rpp_max[1] >= INFINITY) &&
475  (NEAR_ZERO(rpp_max[2], SMALL_FASTF) || rpp_max[2] <= -INFINITY || rpp_max[2] >= INFINITY)
476  ) {
477  bu_log("rt_bound_internal: Warning : The returned bounds of the model may not be correct\n");
478  }
479 
480  rt_db_free_internal(&intern);
481  rt_free_rti(rtip);
482  return 0;
483 }
484 
485 
486 /*
487  * Local Variables:
488  * mode: C
489  * tab-width: 8
490  * indent-tabs-mode: t
491  * c-file-style: "stroustrup"
492  * End:
493  * ex: shiftwidth=4 tabstop=8
494  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
Definition: raytrace.h:800
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
char region_flag
!0 ==> this COMB is a REGION
Definition: raytrace.h:939
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
int rt_bound_internal(struct db_i *dbip, struct directory *dp, point_t rpp_min, point_t rpp_max)
Definition: bbox.c:407
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
#define OP_NOP
Leaf with no effect.
Definition: raytrace.h:1132
void rt_free_rti(struct rt_i *rtip)
Definition: prep.c:156
#define VSETALL(a, s)
Definition: color.c:54
#define OP_XOR
Binary: L xor R, not both.
Definition: raytrace.h:1130
struct bu_list HeadRegion
ptr of list of regions in model
Definition: raytrace.h:1778
Definition: raytrace.h:215
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
#define st
#define RT_CK_COMB(_p)
Definition: raytrace.h:955
#define SMALL_FASTF
Definition: defines.h:342
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
Header file for the BRL-CAD common definitions.
const char * reg_name
Identifying string.
Definition: raytrace.h:539
#define ID_COMBINATION
Combination Record.
Definition: raytrace.h:499
#define MAX_FASTF
Definition: defines.h:340
#define HIDDEN
Definition: common.h:86
#define RT_TREE_INIT(_p)
Definition: raytrace.h:1189
#define RTI_NULL
Definition: raytrace.h:1830
union tree * tb_left
Definition: raytrace.h:1149
struct soltab * tu_stp
Definition: raytrace.h:1156
#define OP_SUBTRACT
Binary: L subtract R.
Definition: raytrace.h:1129
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define OP_INTERSECT
Binary: L intersect R.
Definition: raytrace.h:1128
void bu_exit(int status, const char *fmt,...) _BU_ATTR_NORETURN _BU_ATTR_PRINTF23
Definition: bomb.c:195
#define OP_DB_LEAF
Leaf of combination, db fmt.
Definition: raytrace.h:1139
struct soltab * rt_find_solid(const struct rt_i *rtip, const char *name)
Definition: tree.c:989
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define RT_CHECK_RTI(_p)
Definition: raytrace.h:1832
#define LOOKUP_QUIET
Definition: raytrace.h:893
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
point_t st_max
max X, Y, Z of bounding RPP
Definition: raytrace.h:438
matp_t tl_mat
xform matp, NULL ==> identity
Definition: raytrace.h:1173
fastf_t r_max
exit dist from bounding sphere
Definition: raytrace.h:221
char * tl_name
Name of this leaf (bu_strdup'ed)
Definition: raytrace.h:1174
struct tree::tree_node tr_b
int rt_bound_tree(const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
Definition: bbox.c:38
int rt_db_lookup_internal(struct db_i *dbip, const char *obj_name, struct directory **dpp, struct rt_db_internal *ip, int noisy, struct resource *resp)
Definition: dir.c:240
struct rt_i * rt_new_rti(struct db_i *dbip)
Definition: prep.c:58
int rt_gettree(struct rt_i *rtip, const char *node)
Definition: tree.c:869
int rt_rpp_region(struct rt_i *rtip, const char *reg_name, fastf_t *min_rpp, fastf_t *max_rpp)
Definition: bbox.c:148
void bu_basename(char *basename, const char *path)
Definition: basename.c:30
fastf_t r_min
entry dist to bounding sphere
Definition: raytrace.h:220
struct tree::tree_db_leaf tr_l
union tree * tb_right
Definition: raytrace.h:1150
void * idb_ptr
Definition: raytrace.h:195
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
struct db_i * rti_dbip
prt to Database instance struct
Definition: raytrace.h:1774
#define RT_GET_TREE(_tp, _res)
Definition: raytrace.h:1210
#define RT_COMB_INTERNAL_INIT(_p)
Definition: raytrace.h:960
union tree * tree
Leading to tree_db_leaf leaves.
Definition: raytrace.h:938
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
#define REGION_NULL
Definition: raytrace.h:558
int rt_in_rpp(struct xray *rp, register const fastf_t *invdir, register const fastf_t *min, register const fastf_t *max)
Definition: bbox.c:163
int rt_traverse_tree(struct rt_i *rtip, const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
Definition: bbox.c:255
union tree * reg_treetop
Pointer to boolean tree.
Definition: raytrace.h:540
int idb_minor_type
ID_xxx.
Definition: raytrace.h:193
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define RT_CK_TREE(_p)
Definition: raytrace.h:1182
#define OP_SOLID
Leaf: tr_stp -> solid.
Definition: raytrace.h:1126
int tl_op
leaf, OP_DB_LEAF
Definition: raytrace.h:1172
double fastf_t
Definition: defines.h:300
#define OP_UNION
Binary: L union R.
Definition: raytrace.h:1127
HIDDEN struct region * _rt_getregion(struct rt_i *rtip, const char *reg_name)
Definition: bbox.c:116
struct tree::tree_leaf tr_a
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126