BRL-CAD
ebm.c
Go to the documentation of this file.
1 /* E B M . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1988-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/ebm/ebm.c
23  *
24  * Intersect a ray with an Extruded Bitmap, where the bitmap is taken
25  * from a bw(5) file.
26  *
27  */
28 
29 #include "common.h"
30 
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <ctype.h>
34 #include <math.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "bio.h"
38 
39 #include "tcl.h"
40 #include "bu/parallel.h"
41 #include "vmath.h"
42 #include "db.h"
43 #include "nmg.h"
44 #include "rtgeom.h"
45 #include "raytrace.h"
46 #include "../fixpt.h"
47 
48 
50  struct rt_ebm_internal ebm_i;
51  vect_t ebm_xnorm; /* local +X norm in model coords */
52  vect_t ebm_ynorm;
53  vect_t ebm_znorm;
54  vect_t ebm_cellsize;/* ideal coords: size of each cell */
55  vect_t ebm_origin; /* local coords of grid origin (0, 0, 0) for now */
56  vect_t ebm_large; /* local coords of XYZ max */
57  mat_t ebm_mat; /* model to ideal space */
58 };
59 
60 
61 #define RT_EBM_NULL ((struct rt_ebm_specific *)0)
62 
63 #define RT_EBM_O(m) bu_offsetof(struct rt_ebm_internal, m)
64 
65 const struct bu_structparse rt_ebm_parse[] = {
66  {"%s", RT_EBM_NAME_LEN, "file", bu_offsetof(struct rt_ebm_internal, file), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
67  {"%d", 1, "w", RT_EBM_O(xdim), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
68  {"%d", 1, "n", RT_EBM_O(ydim), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
69  {"%f", 1, "d", RT_EBM_O(tallness), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
70  {"%f", 16, "mat", bu_offsetof(struct rt_ebm_internal, mat), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
71  {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
72 };
73 
74 
76  int x_cell;
77  int y_cell;
78 };
79 
80 
81 extern int rt_ebm_dda(struct xray *rp, struct soltab *stp,
82  struct application *ap, struct seg *seghead);
83 extern int rt_seg_planeclip(struct seg *out_hd, struct seg *in_hd,
84  vect_t out_norm, fastf_t in, fastf_t out,
85  struct xray *rp, struct application *ap);
86 
87 /*
88  * Codes to represent surface normals. In a bitmap, there are only 4
89  * possible normals. With this code, reverse the sign to reverse the
90  * direction. As always, the normal is expected to point outwards.
91  */
92 #define NORM_ZPOS 3
93 #define NORM_YPOS 2
94 #define NORM_XPOS 1
95 #define NORM_XNEG (-1)
96 #define NORM_YNEG (-2)
97 #define NORM_ZNEG (-3)
98 
99 /*
100  * Regular bit addressing is used: (0..W-1, 0..N-1), but the bitmap is
101  * stored with two cells of zeros all around, so permissible
102  * subscripts run (-2..W+1, -2..N+1). This eliminates special-case
103  * code for the boundary conditions.
104  */
105 #define BIT_XWIDEN 2
106 #define BIT_YWIDEN 2
107 #define BIT(_eip, _xx, _yy) \
108  ((unsigned char *)((_eip)->mp->apbuf))[ ((_yy)+BIT_YWIDEN)*((_eip)->xdim + BIT_XWIDEN*2)+(_xx)+BIT_XWIDEN ]
109 
110 
111 /**
112  * Computes centroid of an extruded bitmap
113  */
114 void
115 rt_ebm_centroid(point_t *cent, const struct rt_db_internal *ip)
116 {
117  struct rt_ebm_internal *eip;
118  register unsigned int x, y;
119  unsigned long int xsum, ysum, totalcells;
120  fastf_t avgx, avgy, avgz;
121  point_t bmcentroid;
122 
123  RT_CK_DB_INTERNAL(ip);
124  eip = (struct rt_ebm_internal *)ip->idb_ptr;
125  RT_EBM_CK_MAGIC(eip);
126 
127  bu_log("WARNING: EBM centroids have not been verified\n");
128 
129  xsum = 0;
130  ysum = 0;
131  totalcells = 0;
132  for (y = 0; y < eip->ydim; y++) {
133  for (x = 0; x < eip->xdim; x++) {
134  if (BIT(eip, x, y) == 1) {
135  xsum += x;
136  ysum += y;
137  totalcells++;
138  }
139  }
140  }
141  avgx = (fastf_t)xsum / totalcells + 0.5;
142  avgy = (fastf_t)ysum / totalcells + 0.5;
143  avgz = eip->tallness / 2;
144  VSET(bmcentroid, avgx, avgy, avgz);
145  MAT4X3VEC(*cent, eip->mat, bmcentroid);
146 }
147 
148 
149 /**
150  * Take a segment chain, in sorted order (ascending hit_dist), and
151  * clip to the range (in, out) along the normal "out_norm". For the
152  * particular ray "rp", find the parametric distances:
153  *
154  * kmin is the minimum permissible parameter, "in" units away
155  * kmax is the maximum permissible parameter, "out" units away
156  *
157  * Returns -
158  * 1 OK: trimmed segment chain, still in sorted order
159  * 0 ERROR
160  */
161 int
162 rt_seg_planeclip(struct seg *out_hd, struct seg *in_hd, fastf_t *out_norm, fastf_t in, fastf_t out, struct xray *rp, struct application *ap)
163 {
164  fastf_t norm_dist_min, norm_dist_max;
165  fastf_t slant_factor;
166  fastf_t kmin, kmax;
167  vect_t in_norm;
168  register struct seg *curr;
169  int out_norm_code;
170  int count;
171 
172  norm_dist_min = in - VDOT(rp->r_pt, out_norm);
173  slant_factor = VDOT(rp->r_dir, out_norm); /* always abs < 1 */
174  if (ZERO(slant_factor)) {
175  if (norm_dist_min < 0.0) {
176  bu_log("rt_seg_planeclip ERROR -- ray parallel to baseplane, outside \n");
177  /* XXX Free segp chain */
178  return 0;
179  }
180  kmin = -INFINITY;
181  } else
182  kmin = norm_dist_min / slant_factor;
183 
184  VREVERSE(in_norm, out_norm);
185  norm_dist_max = out - VDOT(rp->r_pt, in_norm);
186  slant_factor = VDOT(rp->r_dir, in_norm); /* always abs < 1 */
187  if (ZERO(slant_factor)) {
188  if (norm_dist_max < 0.0) {
189  bu_log("rt_seg_planeclip ERROR -- ray parallel to baseplane, outside \n");
190  /* XXX Free segp chain */
191  return 0;
192  }
193  kmax = INFINITY;
194  } else
195  kmax = norm_dist_max / slant_factor;
196 
197  if (kmin > kmax) {
198  /* If r_dir[Z] < 0, will need to swap min & max */
199  slant_factor = kmax;
200  kmax = kmin;
201  kmin = slant_factor;
202  out_norm_code = NORM_ZPOS;
203  } else {
204  out_norm_code = NORM_ZNEG;
205  }
206  if (RT_G_DEBUG&DEBUG_EBM)bu_log("kmin=%g, kmax=%g, out_norm_code=%d\n", kmin, kmax, out_norm_code);
207 
208  count = 0;
209  while (BU_LIST_WHILE(curr, seg, &(in_hd->l))) {
210  BU_LIST_DEQUEUE(&(curr->l));
211  if (RT_G_DEBUG&DEBUG_EBM)bu_log(" rt_seg_planeclip seg(%g, %g)\n", curr->seg_in.hit_dist, curr->seg_out.hit_dist);
212  if (curr->seg_out.hit_dist <= kmin) {
213  if (RT_G_DEBUG&DEBUG_EBM)bu_log("seg_out %g <= kmin %g, freeing\n", curr->seg_out.hit_dist, kmin);
214  RT_FREE_SEG(curr, ap->a_resource);
215  continue;
216  }
217  if (curr->seg_in.hit_dist >= kmax) {
218  if (RT_G_DEBUG&DEBUG_EBM)bu_log("seg_in %g >= kmax %g, freeing\n", curr->seg_in.hit_dist, kmax);
219  RT_FREE_SEG(curr, ap->a_resource);
220  continue;
221  }
222  if (curr->seg_in.hit_dist <= kmin) {
223  if (RT_G_DEBUG&DEBUG_EBM)bu_log("seg_in = kmin %g\n", kmin);
224  curr->seg_in.hit_dist = kmin;
225  curr->seg_in.hit_surfno = out_norm_code;
226  }
227  if (curr->seg_out.hit_dist >= kmax) {
228  if (RT_G_DEBUG&DEBUG_EBM)bu_log("seg_out= kmax %g\n", kmax);
229  curr->seg_out.hit_dist = kmax;
230  curr->seg_out.hit_surfno = (-out_norm_code);
231  }
232  BU_LIST_INSERT(&(out_hd->l), &(curr->l));
233  count += 2;
234  }
235  return count;
236 }
237 
238 
239 static int rt_ebm_normtab[3] = { NORM_XPOS, NORM_YPOS, NORM_ZPOS };
240 
241 
242 /**
243  * Step through the 2-D array, in local coordinates ("ideal space").
244  */
245 int
246 rt_ebm_dda(register struct xray *rp, struct soltab *stp, struct application *ap, struct seg *seghead)
247 {
248  register struct rt_ebm_specific *ebmp =
249  (struct rt_ebm_specific *)stp->st_specific;
250  vect_t invdir;
251  double t0; /* in point of cell */
252  double t1; /* out point of cell */
253  double tmax; /* out point of entire grid */
254  vect_t t; /* next t value for XYZ cell plane intersect */
255  vect_t delta; /* spacing of XYZ cell planes along ray */
256  size_t igrid[3]; /* Grid cell coordinates of cell (integerized) */
257  vect_t P; /* hit point */
258  int inside; /* inside/outside a solid flag */
259  int in_index;
260  int out_index;
261  int j;
262 
263  /* Compute the inverse of the direction cosines */
264  if (!ZERO(rp->r_dir[X])) {
265  invdir[X] = 1.0/rp->r_dir[X];
266  } else {
267  invdir[X] = INFINITY;
268  rp->r_dir[X] = 0.0;
269  }
270  if (!ZERO(rp->r_dir[Y])) {
271  invdir[Y] = 1.0/rp->r_dir[Y];
272  } else {
273  invdir[Y] = INFINITY;
274  rp->r_dir[Y] = 0.0;
275  }
276  if (!ZERO(rp->r_dir[Z])) {
277  invdir[Z] = 1.0/rp->r_dir[Z];
278  } else {
279  invdir[Z] = INFINITY;
280  rp->r_dir[Z] = 0.0;
281  }
282 
283  /* intersect ray with ideal grid rpp */
284  VSETALL(P, 0);
285  if (! rt_in_rpp(rp, invdir, P, ebmp->ebm_large))
286  return 0; /* MISS */
287 
288  VJOIN1(P, rp->r_pt, rp->r_min, rp->r_dir);
289  /* P is hit point (on RPP?) */
290 
291  if (RT_G_DEBUG&DEBUG_EBM)VPRINT("ebm_origin", ebmp->ebm_origin);
292  if (RT_G_DEBUG&DEBUG_EBM)VPRINT("r_pt", rp->r_pt);
293  if (RT_G_DEBUG&DEBUG_EBM)VPRINT("P", P);
294  if (RT_G_DEBUG&DEBUG_EBM)VPRINT("cellsize", ebmp->ebm_cellsize);
295  t0 = rp->r_min;
296  tmax = rp->r_max;
297  if (RT_G_DEBUG&DEBUG_EBM)bu_log("[shoot: r_min=%g, r_max=%g]\n", rp->r_min, rp->r_max);
298 
299  /* find grid cell where ray first hits ideal space bounding RPP */
300  igrid[X] = (P[X] - ebmp->ebm_origin[X]) / ebmp->ebm_cellsize[X];
301  igrid[Y] = (P[Y] - ebmp->ebm_origin[Y]) / ebmp->ebm_cellsize[Y];
302  if (igrid[X] >= ebmp->ebm_i.xdim) {
303  igrid[X] = ebmp->ebm_i.xdim-1;
304  }
305  if (igrid[Y] >= ebmp->ebm_i.ydim) {
306  igrid[Y] = ebmp->ebm_i.ydim-1;
307  }
308  if (RT_G_DEBUG&DEBUG_EBM)bu_log("g[X] = %zu, g[Y] = %zu\n", igrid[X], igrid[Y]);
309 
310  if (ZERO(rp->r_dir[X]) && ZERO(rp->r_dir[Y])) {
311  register struct seg *segp;
312 
313  /* Ray is traveling exactly along Z axis. Just check the one
314  * cell hit. Depend on higher level to clip ray to Z extent.
315  */
316  if (RT_G_DEBUG&DEBUG_EBM)bu_log("ray on local Z axis\n");
317  if (BIT(&ebmp->ebm_i, igrid[X], igrid[Y]) == 0)
318  return 0; /* MISS */
319  RT_GET_SEG(segp, ap->a_resource);
320  segp->seg_stp = stp;
321  segp->seg_in.hit_dist = 0;
322  segp->seg_out.hit_dist = INFINITY;
323 
324  segp->seg_in.hit_vpriv[X] =
325  (double) igrid[X] / ebmp->ebm_i.xdim;
326  segp->seg_in.hit_vpriv[Y] =
327  (double) igrid[Y] / ebmp->ebm_i.ydim;
328 
329  segp->seg_out.hit_vpriv[X] =
330  (double) igrid[X] / ebmp->ebm_i.xdim;
331  segp->seg_out.hit_vpriv[Y] =
332  (double) igrid[Y] / ebmp->ebm_i.ydim;
333 
334  if (rp->r_dir[Z] < 0) {
335  segp->seg_in.hit_surfno = NORM_ZPOS;
336  segp->seg_out.hit_surfno = NORM_ZNEG;
337  } else {
338  segp->seg_in.hit_surfno = NORM_ZNEG;
339  segp->seg_out.hit_surfno = NORM_ZPOS;
340  }
341  BU_LIST_INSERT(&(seghead->l), &(segp->l));
342  return 2; /* HIT */
343  }
344 
345  /* X setup */
346  if (ZERO(rp->r_dir[X])) {
347  t[X] = INFINITY;
348  delta[X] = 0;
349  } else {
350  j = igrid[X];
351  if (rp->r_dir[X] < 0) j++;
352  t[X] = (ebmp->ebm_origin[X] + j*ebmp->ebm_cellsize[X] -
353  rp->r_pt[X]) * invdir[X];
354  delta[X] = ebmp->ebm_cellsize[X] * fabs(invdir[X]);
355  }
356  /* Y setup */
357  if (ZERO(rp->r_dir[Y])) {
358  t[Y] = INFINITY;
359  delta[Y] = 0;
360  } else {
361  j = igrid[Y];
362  if (rp->r_dir[Y] < 0) j++;
363  t[Y] = (ebmp->ebm_origin[Y] + j*ebmp->ebm_cellsize[Y] -
364  rp->r_pt[Y]) * invdir[Y];
365  delta[Y] = ebmp->ebm_cellsize[Y] * fabs(invdir[Y]);
366  }
367 
368  /* The delta[] elements *must* be positive, as t must increase */
369  if (RT_G_DEBUG&DEBUG_EBM)bu_log("t[X] = %g, delta[X] = %g\n", t[X], delta[X]);
370  if (RT_G_DEBUG&DEBUG_EBM)bu_log("t[Y] = %g, delta[Y] = %g\n", t[Y], delta[Y]);
371 
372  /* Find face of entry into first cell -- max initial t value */
373  if (ZERO(t[X] - INFINITY)) {
374  in_index = Y;
375  t0 = t[Y];
376  } else if (ZERO(t[Y] - INFINITY)) {
377  in_index = X;
378  t0 = t[X];
379  } else if (t[X] >= t[Y]) {
380  in_index = X;
381  t0 = t[X];
382  } else {
383  in_index = Y;
384  t0 = t[Y];
385  }
386  if (RT_G_DEBUG&DEBUG_EBM)bu_log("Entry index is %s, t0=%g\n", in_index==X ? "X" : "Y", t0);
387 
388  /* Advance to next exits */
389  t[X] += delta[X];
390  t[Y] += delta[Y];
391 
392  /* Ensure that next exit is after first entrance */
393  if (t[X] < t0) {
394  bu_log("*** advancing t[X]\n");
395  t[X] += delta[X];
396  }
397  if (t[Y] < t0) {
398  bu_log("*** advancing t[Y]\n");
399  t[Y] += delta[Y];
400  }
401  if (RT_G_DEBUG&DEBUG_EBM)bu_log("Exit t[X]=%g, t[Y]=%g\n", t[X], t[Y]);
402 
403  inside = 0;
404 
405  while (t0 < tmax) {
406  int val;
407  struct seg *segp;
408 
409  /* find minimum exit t value */
410  out_index = t[X] < t[Y] ? X : Y;
411 
412  t1 = t[out_index];
413 
414  /* Ray passes through cell igrid[XY] from t0 to t1 */
415  val = BIT(&ebmp->ebm_i, igrid[X], igrid[Y]);
416  if (RT_G_DEBUG&DEBUG_EBM)bu_log("igrid [%zu %zu] from %g to %g, val=%d\n",
417  igrid[X], igrid[Y],
418  t0, t1, val);
419  if (RT_G_DEBUG&DEBUG_EBM)bu_log("Exit index is %s, t[X]=%g, t[Y]=%g\n",
420  out_index==X ? "X" : "Y", t[X], t[Y]);
421 
422 
423  if (t1 <= t0) bu_log("ERROR ebm t1=%g < t0=%g\n", t1, t0);
424  if (!inside) {
425  if (val > 0) {
426  /* Handle the transition from vacuum to solid */
427  /* Start of segment (entering a full voxel) */
428  inside = 1;
429 
430  RT_GET_SEG(segp, ap->a_resource);
431  segp->seg_stp = stp;
432  segp->seg_in.hit_dist = t0;
433 
434  segp->seg_in.hit_vpriv[X] =
435  (double) igrid[X] / ebmp->ebm_i.xdim;
436  segp->seg_in.hit_vpriv[Y] =
437  (double) igrid[Y] / ebmp->ebm_i.ydim;
438 
439  /* Compute entry normal */
440  if (rp->r_dir[in_index] < 0) {
441  /* Go left, entry norm goes right */
442  segp->seg_in.hit_surfno =
443  rt_ebm_normtab[in_index];
444  } else {
445  /* go right, entry norm goes left */
446  segp->seg_in.hit_surfno =
447  (-rt_ebm_normtab[in_index]);
448  }
449  BU_LIST_INSERT(&(seghead->l), &(segp->l));
450 
451  if (RT_G_DEBUG&DEBUG_EBM) bu_log("START t=%g, surfno=%d\n",
452  t0, segp->seg_in.hit_surfno);
453  } else {
454  /* Do nothing, marching through void */
455  }
456  } else {
457  register struct seg *tail;
458  if (val > 0) {
459  /* Do nothing, marching through solid */
460  } else {
461  /* End of segment (now in an empty voxel) */
462  /* Handle transition from solid to vacuum */
463  inside = 0;
464 
465  tail = BU_LIST_LAST(seg, &(seghead->l));
466  tail->seg_out.hit_dist = t0;
467 
468  tail->seg_out.hit_vpriv[X] =
469  (double) igrid[X] / ebmp->ebm_i.xdim;
470  tail->seg_out.hit_vpriv[Y] =
471  (double) igrid[Y] / ebmp->ebm_i.ydim;
472 
473  /* Compute exit normal */
474  if (rp->r_dir[in_index] < 0) {
475  /* Go left, exit normal goes left */
476  tail->seg_out.hit_surfno =
477  (-rt_ebm_normtab[in_index]);
478  } else {
479  /* go right, exit norm goes right */
480  tail->seg_out.hit_surfno =
481  rt_ebm_normtab[in_index];
482  }
483  if (RT_G_DEBUG&DEBUG_EBM) bu_log("END t=%g, surfno=%d\n",
484  t0, tail->seg_out.hit_surfno);
485  }
486  }
487 
488  /* Take next step */
489  t0 = t1;
490  in_index = out_index;
491  t[out_index] += delta[out_index];
492  if (rp->r_dir[out_index] > 0) {
493  igrid[out_index]++;
494  } else {
495  igrid[out_index]--;
496  }
497  }
498 
499  if (inside) {
500  register struct seg *tail;
501 
502  /* Close off the final segment */
503  tail = BU_LIST_LAST(seg, &(seghead->l));
504  tail->seg_out.hit_dist = tmax;
505  VSETALL(tail->seg_out.hit_vpriv, 0.0);
506 
507  /* Compute exit normal. Previous out_index is now in_index */
508  if (rp->r_dir[in_index] < 0) {
509  /* Go left, exit normal goes left */
510  tail->seg_out.hit_surfno = (-rt_ebm_normtab[in_index]);
511  } else {
512  /* go right, exit norm goes right */
513  tail->seg_out.hit_surfno = rt_ebm_normtab[in_index];
514  }
515  if (RT_G_DEBUG&DEBUG_EBM) bu_log("closed END t=%g, surfno=%d\n",
516  tmax, tail->seg_out.hit_surfno);
517  }
518 
519  if (BU_LIST_IS_EMPTY(&(seghead->l)))
520  return 0;
521  return 2;
522 }
523 
524 
525 /**
526  * Read in the information from the string solid record. Then, as a
527  * service to the application, read in the bitmap and set up some of
528  * the associated internal variables.
529  */
530 int
531 rt_ebm_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
532 {
533  union record *rp;
534  register struct rt_ebm_internal *eip;
535  struct bu_vls str = BU_VLS_INIT_ZERO;
536  int nbytes;
537  mat_t tmat;
538  struct bu_mapped_file *mp;
539 
540  BU_CK_EXTERNAL(ep);
541  rp = (union record *)ep->ext_buf;
542  if (rp->u_id != DBID_STRSOL) {
543  bu_log("rt_ebm_import4: defective strsol record\n");
544  return -1;
545  }
546 
547  RT_CK_DB_INTERNAL(ip);
548  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
549  ip->idb_type = ID_EBM;
550  ip->idb_meth = &OBJ[ID_EBM];
551  BU_ALLOC(ip->idb_ptr, struct rt_ebm_internal);
552 
553  eip = (struct rt_ebm_internal *)ip->idb_ptr;
554  eip->magic = RT_EBM_INTERNAL_MAGIC;
555 
556  /* Provide default orientation info */
557  MAT_IDN(eip->mat);
558 
559  bu_vls_strcpy(&str, rp->ss.ss_args);
560  if (bu_struct_parse(&str, rt_ebm_parse, (char *)eip, NULL) < 0) {
561  bu_vls_free(&str);
562  bu_free((char *)eip, "rt_ebm_import4: eip");
563  ip->idb_type = ID_NULL;
564  ip->idb_ptr = (void *)NULL;
565  return -2;
566  }
567  bu_vls_free(&str);
568 
569  /* Check for reasonable values */
570  if (eip->file[0] == '\0' || eip->xdim < 1 ||
571  eip->ydim < 1 || eip->mat[15] <= 0.0 ||
572  eip->tallness <= 0.0) {
573  bu_struct_print("Unreasonable EBM parameters", rt_ebm_parse,
574  (char *)eip);
575  bu_free((char *)eip, "rt_ebm_import4: eip");
576  ip->idb_type = ID_NULL;
577  ip->idb_ptr = (void *)NULL;
578  return -1;
579  }
580 
581  /* Apply any modeling transforms to get final matrix */
582  if (mat == NULL) mat = bn_mat_identity;
583  bn_mat_mul(tmat, mat, eip->mat);
584  MAT_COPY(eip->mat, tmat);
585 
586  /* Get bit map from .bw(5) file */
587  mp = bu_open_mapped_file_with_path(dbip->dbi_filepath, eip->file, "ebm");
588  if (!mp) {
589  bu_log("rt_ebm_import4() unable to open '%s'\n", eip->file);
590  bu_free((char *)eip, "rt_ebm_import4: eip");
591  fail:
592  ip->idb_type = ID_NULL;
593  ip->idb_ptr = (void *)NULL;
594  return -1;
595  }
596  eip->mp = mp;
597  if (mp->buflen < (size_t)(eip->xdim*eip->ydim)) {
598  bu_log("rt_ebm_import4() file '%s' is too short %zu < %u\n",
599  eip->file, mp->buflen, eip->xdim*eip->ydim);
600  goto fail;
601  }
602 
603  nbytes = (eip->xdim+BIT_XWIDEN*2)*(eip->ydim+BIT_YWIDEN*2);
604 
605  /* If first use of this file, prepare in-memory buffer */
606  if (!mp->apbuf) {
607  size_t y;
608  unsigned char *cp;
609 
610  /* Prevent a multi-processor race */
612  if (mp->apbuf) {
613  /* someone else beat us, nothing more to do */
615  return 0;
616  }
617  mp->apbuf = (void *)bu_calloc(
618  1, nbytes, "rt_ebm_import4 bitmap");
619  mp->apbuflen = nbytes;
620 
622 
623  /* Because of in-memory padding, read each scanline separately */
624  cp = (unsigned char *)mp->buf;
625  for (y = 0; y < eip->ydim; y++) {
626  /* BIT() addresses into mp->apbuf */
627  memcpy(&BIT(eip, 0, y), cp, eip->xdim);
628  cp += eip->xdim;
629  }
630  }
631  return 0;
632 }
633 
634 
635 /**
636  * The name will be added by the caller.
637  */
638 int
639 rt_ebm_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
640 {
641  struct rt_ebm_internal *eip;
642  struct rt_ebm_internal ebm; /* scaled version */
643  union record *rec;
644  struct bu_vls str = BU_VLS_INIT_ZERO;
645 
646  if (dbip) RT_CK_DBI(dbip);
647 
648  RT_CK_DB_INTERNAL(ip);
649  if (ip->idb_type != ID_EBM) return -1;
650  eip = (struct rt_ebm_internal *)ip->idb_ptr;
651  RT_EBM_CK_MAGIC(eip);
652  ebm = *eip; /* struct copy */
653 
654  /* Apply scale factor */
655  ebm.mat[15] /= local2mm;
656 
657  BU_CK_EXTERNAL(ep);
658  ep->ext_nbytes = sizeof(union record)*DB_SS_NGRAN;
659  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "ebm external");
660  rec = (union record *)ep->ext_buf;
661 
662  bu_vls_struct_print(&str, rt_ebm_parse, (char *)&ebm);
663 
664  rec->ss.ss_id = DBID_STRSOL;
665  bu_strlcpy(rec->ss.ss_keyword, "ebm", sizeof(rec->ss.ss_keyword));
666  bu_strlcpy(rec->ss.ss_args, bu_vls_addr(&str), DB_SS_LEN);
667  bu_vls_free(&str);
668 
669  return 0;
670 }
671 
672 
673 /**
674  * Read in the information from the string solid record. Then, as a
675  * service to the application, read in the bitmap and set up some of
676  * the associated internal variables.
677  */
678 int
679 rt_ebm_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
680 {
681  register struct rt_ebm_internal *eip;
682  struct bu_vls str = BU_VLS_INIT_ZERO;
683  int nbytes;
684  mat_t tmat;
685  struct bu_mapped_file *mp;
686 
687  BU_CK_EXTERNAL(ep);
688  RT_CK_DB_INTERNAL(ip);
689 
690  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
691  ip->idb_type = ID_EBM;
692  ip->idb_meth = &OBJ[ID_EBM];
693  BU_ALLOC(ip->idb_ptr, struct rt_ebm_internal);
694 
695  eip = (struct rt_ebm_internal *)ip->idb_ptr;
696  eip->magic = RT_EBM_INTERNAL_MAGIC;
697 
698  /* Provide default orientation info */
699  MAT_IDN(eip->mat);
700 
701  bu_vls_strcpy(&str, (const char *)ep->ext_buf);
702  if (bu_struct_parse(&str, rt_ebm_parse, (char *)eip, NULL) < 0) {
703  bu_vls_free(&str);
704  bu_free((char *)eip, "rt_ebm_import4: eip");
705  ip->idb_type = ID_NULL;
706  ip->idb_ptr = (void *)NULL;
707  return -2;
708  }
709  bu_vls_free(&str);
710 
711  /* Check for reasonable values */
712  if (eip->file[0] == '\0' || eip->xdim < 1 ||
713  eip->ydim < 1 || eip->mat[15] <= 0.0 ||
714  eip->tallness <= 0.0) {
715  bu_struct_print("Unreasonable EBM parameters", rt_ebm_parse,
716  (char *)eip);
717  bu_free((char *)eip, "rt_ebm_import4: eip");
718  ip->idb_type = ID_NULL;
719  ip->idb_ptr = (void *)NULL;
720  return -1;
721  }
722 
723  /* Apply any modeling transforms to get final matrix */
724  if (mat == NULL) mat = bn_mat_identity;
725  bn_mat_mul(tmat, mat, eip->mat);
726  MAT_COPY(eip->mat, tmat);
727 
728  /* Get bit map from .bw(5) file */
729  mp = bu_open_mapped_file_with_path(dbip->dbi_filepath, eip->file, "ebm");
730  if (!mp) {
731  bu_log("rt_ebm_import4() unable to open '%s'\n", eip->file);
732  bu_free((char *)eip, "rt_ebm_import4: eip");
733  fail:
734  ip->idb_type = ID_NULL;
735  ip->idb_ptr = (void *)NULL;
736  return -1;
737  }
738  eip->mp = mp;
739  if (mp->buflen < (size_t)(eip->xdim*eip->ydim)) {
740  bu_log("rt_ebm_import4() file '%s' is too short %zu < %u\n",
741  eip->file, mp->buflen, eip->xdim*eip->ydim);
742  goto fail;
743  }
744 
745  nbytes = (eip->xdim+BIT_XWIDEN*2)*(eip->ydim+BIT_YWIDEN*2);
746 
747  /* If first use of this file, prepare in-memory buffer */
748  if (!mp->apbuf) {
749  size_t y;
750  unsigned char *cp;
751 
752  /* Prevent a multi-processor race */
754  if (mp->apbuf) {
755  /* someone else beat us, nothing more to do */
757  return 0;
758  }
759  mp->apbuf = (void *)bu_calloc(
760  1, nbytes, "rt_ebm_import4 bitmap");
761  mp->apbuflen = nbytes;
762 
764 
765  /* Because of in-memory padding, read each scanline separately */
766  cp = (unsigned char *)mp->buf;
767  for (y = 0; y < eip->ydim; y++) {
768  /* BIT() addresses into mp->apbuf */
769  memcpy(&BIT(eip, 0, y), cp, eip->xdim);
770  cp += eip->xdim;
771  }
772  }
773  return 0;
774 }
775 
776 
777 /**
778  * The name will be added by the caller.
779  */
780 int
781 rt_ebm_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
782 {
783  struct rt_ebm_internal *eip;
784  struct rt_ebm_internal ebm; /* scaled version */
785  struct bu_vls str = BU_VLS_INIT_ZERO;
786 
787  if (dbip) RT_CK_DBI(dbip);
788 
789  RT_CK_DB_INTERNAL(ip);
790  if (ip->idb_type != ID_EBM) return -1;
791  eip = (struct rt_ebm_internal *)ip->idb_ptr;
792  RT_EBM_CK_MAGIC(eip);
793  ebm = *eip; /* struct copy */
794 
795  /* Apply scale factor */
796  ebm.mat[15] /= local2mm;
797 
798  BU_CK_EXTERNAL(ep);
799 
800  bu_vls_struct_print(&str, rt_ebm_parse, (char *)&ebm);
801 
802  ep->ext_nbytes = bu_vls_strlen(&str) + 1;
803  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "ebm external");
804 
805  bu_strlcpy((char *)ep->ext_buf, bu_vls_addr(&str), ep->ext_nbytes);
806  bu_vls_free(&str);
807 
808  return 0;
809 }
810 
811 
812 /**
813  * Make human-readable formatted presentation of this solid. First
814  * line describes type of solid. Additional lines are indented one
815  * tab, and give parameter values.
816  */
817 int
818 rt_ebm_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
819 {
820  register struct rt_ebm_internal *eip =
821  (struct rt_ebm_internal *)ip->idb_ptr;
822  int i;
823  struct bu_vls substr = BU_VLS_INIT_ZERO;
824 
825  RT_EBM_CK_MAGIC(eip);
826 
827  bu_vls_strcat(str, "extruded bitmap (EBM)\n\t");
828 
829  if (!verbose)
830  return 0;
831 
832  bu_vls_printf(&substr, " file=\"%s\" w=%u n=%u depth=%g\n mat=",
833  eip->file, eip->xdim, eip->ydim, INTCLAMP(eip->tallness*mm2local));
834  bu_vls_vlscat(str, &substr);
835  for (i = 0; i < 15; i++) {
836  bu_vls_trunc(&substr, 0);
837  bu_vls_printf(&substr, "%g, ", INTCLAMP(eip->mat[i]));
838  bu_vls_vlscat(str, &substr);
839  }
840  bu_vls_trunc(&substr, 0);
841  bu_vls_printf(&substr, "%g\n", INTCLAMP(eip->mat[15]));
842  bu_vls_vlscat(str, &substr);
843 
844  bu_vls_free(&substr);
845 
846  return 0;
847 }
848 
849 
850 /**
851  * Free the storage associated with the rt_db_internal version of this
852  * solid.
853  */
854 void
856 {
857  register struct rt_ebm_internal *eip;
858 
859  RT_CK_DB_INTERNAL(ip);
860 
861  eip = (struct rt_ebm_internal *)ip->idb_ptr;
862  RT_EBM_CK_MAGIC(eip);
863 
864  if (eip->mp) {
865  BU_CK_MAPPED_FILE(eip->mp);
866  bu_close_mapped_file(eip->mp);
867  }
868 
869  eip->magic = 0; /* sanity */
870  eip->mp = (struct bu_mapped_file *)0;
871  bu_free((char *)eip, "ebm ifree");
872  ip->idb_ptr = ((void *)0); /* sanity */
873  ip->idb_type = ID_NULL; /* sanity */
874 }
875 
876 
877 /**
878  * Calculate bounding RPP for ebm
879  */
880 int
881 rt_ebm_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol))
882 {
883  register struct rt_ebm_internal *eip;
884  vect_t v1, localspace;
885 
886  RT_CK_DB_INTERNAL(ip);
887  eip = (struct rt_ebm_internal *)ip->idb_ptr;
888  RT_EBM_CK_MAGIC(eip);
889 
890  /* Find bounding RPP of rotated local RPP */
891  VSETALL(v1, 0);
892  VSET(localspace, eip->xdim, eip->ydim, eip->tallness);
893  bn_rotate_bbox((*min), (*max), eip->mat, v1, localspace);
894  return 0;
895 }
896 
897 
898 /**
899  * Returns -
900  * 0 OK
901  * !0 Failure
902  *
903  * Implicit return -
904  * A struct rt_ebm_specific is created, and its address is stored
905  * in stp->st_specific for use by rt_ebm_shot().
906  */
907 int
908 rt_ebm_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
909 {
910  struct rt_ebm_internal *eip;
911  register struct rt_ebm_specific *ebmp;
912  vect_t norm;
913  vect_t radvec;
914  vect_t diam;
915 
916  if (rtip) RT_CK_RTI(rtip);
917 
918  eip = (struct rt_ebm_internal *)ip->idb_ptr;
919  RT_EBM_CK_MAGIC(eip);
920 
921  BU_GET(ebmp, struct rt_ebm_specific);
922  ebmp->ebm_i = *eip; /* struct copy */
923 
924  /* "steal" the bitmap storage */
925  eip->mp = (struct bu_mapped_file *)0; /* "steal" the mapped file */
926 
927  /* build Xform matrix from model(world) to ideal(local) space */
928  bn_mat_inv(ebmp->ebm_mat, eip->mat);
929 
930  /* Pre-compute the necessary normals. Rotate only. */
931  VSET(norm, 1, 0, 0);
932  MAT3X3VEC(ebmp->ebm_xnorm, eip->mat, norm);
933  VSET(norm, 0, 1, 0);
934  MAT3X3VEC(ebmp->ebm_ynorm, eip->mat, norm);
935  VSET(norm, 0, 0, 1);
936  MAT3X3VEC(ebmp->ebm_znorm, eip->mat, norm);
937 
938  stp->st_specific = (void *)ebmp;
939 
940  /* Find bounding RPP of rotated local RPP */
941  rt_ebm_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol);
942  VSET(ebmp->ebm_large, ebmp->ebm_i.xdim, ebmp->ebm_i.ydim, ebmp->ebm_i.tallness);
943 
944  /* for now, EBM origin in ideal coordinates is at origin */
945  VSETALL(ebmp->ebm_origin, 0);
946  VADD2(ebmp->ebm_large, ebmp->ebm_large, ebmp->ebm_origin);
947 
948  /* for now, EBM cell size in ideal coordinates is one unit/cell */
949  VSETALL(ebmp->ebm_cellsize, 1);
950 
951  VSUB2(diam, stp->st_max, stp->st_min);
952  VADD2SCALE(stp->st_center, stp->st_min, stp->st_max, 0.5);
953  VSCALE(radvec, diam, 0.5);
954  stp->st_aradius = stp->st_bradius = MAGNITUDE(radvec);
955 
956  return 0; /* OK */
957 }
958 
959 
960 void
961 rt_ebm_print(register const struct soltab *stp)
962 {
963  register const struct rt_ebm_specific *ebmp =
964  (struct rt_ebm_specific *)stp->st_specific;
965 
966  bu_log("ebm file = %s\n", ebmp->ebm_i.file);
967  bu_log("dimensions = (%u, %u, %g)\n",
968  ebmp->ebm_i.xdim, ebmp->ebm_i.ydim,
969  ebmp->ebm_i.tallness);
970  VPRINT("model cellsize", ebmp->ebm_cellsize);
971  VPRINT("model grid origin", ebmp->ebm_origin);
972 }
973 
974 
975 /**
976  * Intersect a ray with an extruded bitmap. If intersection occurs, a
977  * pointer to a sorted linked list of "struct seg"s will be returned.
978  *
979  * Returns -
980  * 0 MISS
981  * >0 HIT
982  */
983 int
984 rt_ebm_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
985 {
986  register struct rt_ebm_specific *ebmp =
987  (struct rt_ebm_specific *)stp->st_specific;
988  vect_t norm;
989  struct xray ideal_ray;
990  struct seg myhead;
991  int i;
992 
993  BU_LIST_INIT(&(myhead.l));
994 
995  /* Transform actual ray into ideal space at origin in X-Y plane */
996  MAT4X3PNT(ideal_ray.r_pt, ebmp->ebm_mat, rp->r_pt);
997  MAT4X3VEC(ideal_ray.r_dir, ebmp->ebm_mat, rp->r_dir);
998 
999  if (rt_ebm_dda(&ideal_ray, stp, ap, &myhead) <= 0)
1000  return 0;
1001 
1002  VSET(norm, 0, 0, -1); /* letters grow in +z, which is "inside" the halfspace */
1003  i = rt_seg_planeclip(seghead, &myhead, norm, 0.0, ebmp->ebm_i.tallness,
1004  &ideal_ray, ap);
1005  return i;
1006 }
1007 
1008 
1009 /**
1010  * Given one ray distance, return the normal and entry/exit point.
1011  * This is mostly a matter of translating the stored code into the
1012  * proper normal.
1013  */
1014 void
1015 rt_ebm_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
1016 {
1017  register struct rt_ebm_specific *ebmp =
1018  (struct rt_ebm_specific *)stp->st_specific;
1019 
1020  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
1021 
1022  switch (hitp->hit_surfno) {
1023  case NORM_XPOS:
1024  VMOVE(hitp->hit_normal, ebmp->ebm_xnorm);
1025  break;
1026  case NORM_XNEG:
1027  VREVERSE(hitp->hit_normal, ebmp->ebm_xnorm);
1028  break;
1029 
1030  case NORM_YPOS:
1031  VMOVE(hitp->hit_normal, ebmp->ebm_ynorm);
1032  break;
1033  case NORM_YNEG:
1034  VREVERSE(hitp->hit_normal, ebmp->ebm_ynorm);
1035  break;
1036 
1037  case NORM_ZPOS:
1038  VMOVE(hitp->hit_normal, ebmp->ebm_znorm);
1039  break;
1040  case NORM_ZNEG:
1041  VREVERSE(hitp->hit_normal, ebmp->ebm_znorm);
1042  break;
1043 
1044  default:
1045  bu_log("ebm_norm(%s): surfno=%d bad\n",
1046  stp->st_name, hitp->hit_surfno);
1047  VSETALL(hitp->hit_normal, 0);
1048  break;
1049  }
1050 }
1051 
1052 
1053 /**
1054  * Everything has sharp edges. This makes things easy.
1055  */
1056 void
1057 rt_ebm_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
1058 {
1059  struct rt_ebm_specific *ebmp = (struct rt_ebm_specific *)stp->st_specific;
1060  if (!ebmp) return;
1061 
1062  bn_vec_ortho(cvp->crv_pdir, hitp->hit_normal);
1063  cvp->crv_c1 = cvp->crv_c2 = 0;
1064 }
1065 
1066 
1067 /**
1068  * Map the hit point in 2-D into the range 0..1 untransformed X
1069  * becomes U, and Y becomes V.
1070  */
1071 void
1072 rt_ebm_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
1073 {
1074  if (ap) RT_CK_APPLICATION(ap);
1075  if (stp) RT_CK_SOLTAB(stp);
1076 
1077  uvp->uv_u = hitp->hit_vpriv[X];
1078  uvp->uv_v = hitp->hit_vpriv[Y];
1079 
1080  /* XXX should compute this based upon footprint of ray in ebm space */
1081  uvp->uv_du = 0.0;
1082  uvp->uv_dv = 0.0;
1083 }
1084 
1085 
1086 void
1087 rt_ebm_free(struct soltab *stp)
1088 {
1089  register struct rt_ebm_specific *ebmp =
1090  (struct rt_ebm_specific *)stp->st_specific;
1091 
1092  BU_CK_MAPPED_FILE(ebmp->ebm_i.mp);
1093  bu_close_mapped_file(ebmp->ebm_i.mp);
1094 
1095  BU_PUT(ebmp, struct rt_ebm_specific);
1096 }
1097 
1098 
1099 /* either x1==x2, or y1==y2 */
1100 void
1101 rt_ebm_plate(int x_1, int y_1, int x_2, int y_2, double t, register fastf_t *mat, register struct bu_list *vhead)
1102 {
1103  point_t s, p;
1104  point_t srot, prot;
1105 
1106  BU_CK_LIST_HEAD(vhead);
1107  VSET(s, x_1, y_1, 0.0);
1108  MAT4X3PNT(srot, mat, s);
1109  RT_ADD_VLIST(vhead, srot, BN_VLIST_LINE_MOVE);
1110 
1111  VSET(p, x_1, y_1, t);
1112  MAT4X3PNT(prot, mat, p);
1113  RT_ADD_VLIST(vhead, prot, BN_VLIST_LINE_DRAW);
1114 
1115  VSET(p, x_2, y_2, t);
1116  MAT4X3PNT(prot, mat, p);
1117  RT_ADD_VLIST(vhead, prot, BN_VLIST_LINE_DRAW);
1118 
1119  p[Z] = 0;
1120  MAT4X3PNT(prot, mat, p);
1121  RT_ADD_VLIST(vhead, prot, BN_VLIST_LINE_DRAW);
1122 
1123  RT_ADD_VLIST(vhead, srot, BN_VLIST_LINE_DRAW);
1124 }
1125 
1126 
1127 int
1128 rt_ebm_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info))
1129 {
1130  register struct rt_ebm_internal *eip;
1131  size_t x, y;
1132  register int following;
1133  register int base;
1134 
1135  BU_CK_LIST_HEAD(vhead);
1136  RT_CK_DB_INTERNAL(ip);
1137  eip = (struct rt_ebm_internal *)ip->idb_ptr;
1138  RT_EBM_CK_MAGIC(eip);
1139 
1140  /* Find vertical lines */
1141  base = 0; /* lint */
1142  for (x = 0; x <= eip->xdim; x++) {
1143  following = 0;
1144  for (y = 0; y <= eip->ydim; y++) {
1145  if (following) {
1146  if ((BIT(eip, x-1, y) == 0) != (BIT(eip, x, y) == 0))
1147  continue;
1148  rt_ebm_plate(x, base, x, y, eip->tallness,
1149  eip->mat, vhead);
1150  following = 0;
1151  } else {
1152  if ((BIT(eip, x-1, y) == 0) == (BIT(eip, x, y) == 0))
1153  continue;
1154  following = 1;
1155  base = y;
1156  }
1157  }
1158  }
1159 
1160  /* Find horizontal lines */
1161  for (y = 0; y <= eip->ydim; y++) {
1162  following = 0;
1163  for (x = 0; x <= eip->xdim; x++) {
1164  if (following) {
1165  if ((BIT(eip, x, y-1) == 0) != (BIT(eip, x, y) == 0))
1166  continue;
1167  rt_ebm_plate(base, y, x, y, eip->tallness,
1168  eip->mat, vhead);
1169  following = 0;
1170  } else {
1171  if ((BIT(eip, x, y-1) == 0) == (BIT(eip, x, y) == 0))
1172  continue;
1173  following = 1;
1174  base = x;
1175  }
1176  }
1177  }
1178  return 0;
1179 }
1180 
1181 
1182 struct ebm_edge
1183 {
1184  struct bu_list l;
1185  int x1, y1;
1186  int x2, y2;
1187  int left; /* 1=>material to left, 0=>material to right */
1188  struct vertex *v; /* vertex at x1, y1 */
1189 };
1190 
1191 
1192 /* either x1==x2, or y1==y2 */
1193 static void
1194 rt_ebm_edge(int x_1, int y_1, int x_2, int y_2, int left, struct ebm_edge *edges)
1195 {
1196  struct ebm_edge *new_edge;
1197 
1198  BU_ALLOC(new_edge, struct ebm_edge);
1199 
1200  /* make all edges go from lower values to larger */
1201  if (y_1 < y_2 || x_1 < x_2) {
1202  new_edge->x1 = x_1;
1203  new_edge->y1 = y_1;
1204  new_edge->x2 = x_2;
1205  new_edge->y2 = y_2;
1206  new_edge->left = left;
1207  } else {
1208  new_edge->x1 = x_2;
1209  new_edge->y1 = y_2;
1210  new_edge->x2 = x_1;
1211  new_edge->y2 = y_1;
1212  new_edge->left = (!left);
1213  }
1214  new_edge->v = (struct vertex *)NULL;
1215  BU_LIST_APPEND(&edges->l, &new_edge->l);
1216 }
1217 
1218 
1219 static int
1220 rt_ebm_sort_edges(struct ebm_edge *edges)
1221 {
1222  struct ebm_edge loops;
1223  int vertical;
1224  int done;
1225  int from_x, from_y, to_x, to_y;
1226  int start_x, start_y;
1227  int max_loop_length = 0;
1228  int loop_length;
1229 
1230  /* create another list to hold the edges as they are sorted */
1231  BU_LIST_INIT(&loops.l);
1232 
1233  while (BU_LIST_NON_EMPTY(&edges->l)) {
1234  struct ebm_edge *start, *next;
1235 
1236  /* look for a vertical edge starting in lower left (smallest x and y) */
1237  start = (struct ebm_edge *)NULL;
1238  next = BU_LIST_FIRST(ebm_edge, &edges->l);
1239  while (BU_LIST_NOT_HEAD(&next->l, &edges->l)) {
1240  if (next->x1 != next->x2) {
1241  next = BU_LIST_PNEXT(ebm_edge, &next->l);
1242  continue; /* not a vertical edge */
1243  }
1244 
1245  if (!start)
1246  start = next;
1247  else if (next->x1 < start->x1 || next->y1 < start->y1)
1248  start = next;
1249 
1250  next = BU_LIST_PNEXT(ebm_edge, &next->l);
1251  }
1252 
1253  if (!start)
1254  bu_bomb("rt_ebm_tess: rt_ebm_sort_edges: no vertical edges left!\n");
1255 
1256  /* put starting edge on the loop list */
1257  BU_LIST_DEQUEUE(&start->l);
1258  BU_LIST_INSERT(&loops.l, &start->l);
1259 
1260  next = (struct ebm_edge *)NULL;
1261  vertical = 0; /* look for horizontal edge */
1262  done = 0;
1263  to_x = start->x2;
1264  to_y = start->y2;
1265  from_x = start->x1;
1266  from_y = start->y1;
1267  start_x = from_x;
1268  start_y = from_y;
1269  loop_length = 1;
1270  while (!done) {
1271  struct ebm_edge *e, *e_poss[2];
1272  int poss;
1273 
1274  /* now find an edge that starts where this one stops (at to_x, to_y) */
1275  poss = 0;
1276  for (BU_LIST_FOR(e, ebm_edge, &edges->l)) {
1277  if ((vertical && e->y1 == e->y2) ||
1278  (!vertical && e->x1 == e->x2))
1279  continue;
1280 
1281  if ((e->x1 == to_x && e->y1 == to_y) ||
1282  (e->x2 == to_x && e->y2 == to_y))
1283  e_poss[poss++] = e;
1284  if (poss > 2)
1285  bu_bomb("rt_ebm_tess: rt_ebm_sort_edges: too many edges at one point\n");
1286  }
1287 
1288  if (poss == 0)
1289  bu_bomb("rt_ebm_tess: rt_ebm_sort_edges: no edge to continue loop\n");
1290  if (poss == 1) {
1291  next = e_poss[0];
1292  } else {
1293  /* must choose between two possibilities */
1294  if (vertical) {
1295  if (to_x < from_x) {
1296  if (e_poss[0]->y1 > to_y || e_poss[0]->y2 > to_y)
1297  next = e_poss[0];
1298  else
1299  next = e_poss[1];
1300  } else {
1301  if (e_poss[0]->y1 < to_y || e_poss[0]->y2 < to_y)
1302  next = e_poss[0];
1303  else
1304  next = e_poss[1];
1305  }
1306  } else {
1307  if (to_y < from_y) {
1308  if (e_poss[0]->x1 < to_x || e_poss[0]->x2 < to_x)
1309  next = e_poss[0];
1310  else
1311  next = e_poss[1];
1312  } else {
1313  if (e_poss[0]->x1 > to_x || e_poss[0]->x2 > to_x)
1314  next = e_poss[0];
1315  else
1316  next = e_poss[1];
1317  }
1318  }
1319  }
1320 
1321  if (next->x2 == to_x && next->y2 == to_y) {
1322  /* reverse direction of edge */
1323  next->x2 = next->x1;
1324  next->y2 = next->y1;
1325  next->x1 = to_x;
1326  next->y1 = to_y;
1327  next->left = (!next->left);
1328  }
1329  to_x = next->x2;
1330  to_y = next->y2;
1331  from_x = next->x1;
1332  from_y = next->y1;
1333  loop_length++;
1334 
1335  BU_LIST_DEQUEUE(&next->l);
1336  BU_LIST_INSERT(&loops.l, &next->l);
1337 
1338  if (to_x == start_x && to_y == start_y) {
1339  if (loop_length > max_loop_length)
1340  max_loop_length = loop_length;
1341  done = 1; /* complete loop */
1342  }
1343 
1344  if (vertical)
1345  vertical = 0;
1346  else
1347  vertical = 1;
1348  }
1349  }
1350 
1351  /* move sorted list back to "edges" */
1352  BU_LIST_INSERT_LIST(&edges->l, &loops.l);
1353 
1354  return max_loop_length;
1355 }
1356 
1357 
1358 int
1359 rt_ebm_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
1360 {
1361  struct rt_ebm_internal *eip;
1362  struct shell *s;
1363  struct faceuse *fu=(struct faceuse*)NULL;
1364  struct vertex ***vertp; /* dynam array of ptrs to pointers */
1365  struct vertex **loop_verts;
1366  struct ebm_edge edges; /* list of edges */
1367  struct ebm_edge *e, *start_loop;
1368  size_t i;
1369  size_t start, x, y, left;
1370  size_t max_loop_length;
1371  size_t loop_length;
1372  vect_t height, h;
1373 
1374  BN_CK_TOL(tol);
1375  NMG_CK_MODEL(m);
1376 
1377  RT_CK_DB_INTERNAL(ip);
1378  eip = (struct rt_ebm_internal *)ip->idb_ptr;
1379  RT_EBM_CK_MAGIC(eip);
1380 
1381  BU_LIST_INIT(&edges.l);
1382 
1383  x = 0;
1384  while (x <= eip->xdim) {
1385  y = 0;
1386  while (y <= eip->ydim) {
1387  if ((BIT(eip, x-1, y) == 0) != (BIT(eip, x, y) == 0)) {
1388  /* a vertical edge starts here */
1389  start = y;
1390  left = (BIT(eip, x, y) != 0);
1391 
1392  /* find other end */
1393  while ((BIT(eip, x-1, y) == 0) != (BIT(eip, x, y) == 0) &&
1394  (BIT(eip, x, y) != 0) == left)
1395  y++;
1396  rt_ebm_edge(x, start, x, y, left, &edges);
1397  } else {
1398  y++;
1399  }
1400  }
1401  x++;
1402  }
1403 
1404  y = 0;
1405  while (y <= eip->ydim) {
1406  x = 0;
1407  while (x <= eip->xdim) {
1408  if ((BIT(eip, x, y-1) ==0 ) != (BIT(eip, x, y) == 0)) {
1409  /* a horizontal edge starts here */
1410  start = x;
1411  left = (BIT(eip, x, y-1) != 0);
1412 
1413  /* find other end */
1414  while ((BIT(eip, x, y-1) == 0) != (BIT(eip, x, y) == 0) &&
1415  (BIT(eip, x, y-1) != 0) == left)
1416  x++;
1417  rt_ebm_edge(start, y, x, y, left, &edges);
1418  } else
1419  x++;
1420  }
1421  y++;
1422  }
1423 
1424  /* Sort edges into loops */
1425  max_loop_length = rt_ebm_sort_edges(&edges);
1426 
1427  /* Make NMG structures */
1428 
1429  /* make region, shell, vertex */
1430  *r = nmg_mrsv(m);
1431  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
1432 
1433 
1434  vertp = (struct vertex ***)bu_calloc(max_loop_length, sizeof(struct vertex **) ,
1435  "rt_ebm_tess: vertp");
1436  loop_verts = (struct vertex **)bu_calloc(max_loop_length, sizeof(struct vertex *),
1437  "rt_ebm_tess: loop_verts");
1438 
1439  e = BU_LIST_FIRST(ebm_edge, &edges.l);
1440  while (BU_LIST_NOT_HEAD(&e->l, &edges.l)) {
1441  start_loop = e;
1442  loop_length = 0;
1443  vertp[loop_length++] = &start_loop->v;
1444 
1445  e = BU_LIST_PNEXT(ebm_edge, &start_loop->l);
1446  while (BU_LIST_NOT_HEAD(&e->l, &edges.l)) {
1447  vertp[loop_length++] = &e->v;
1448  if (e->x2 == start_loop->x1 && e->y2 == start_loop->y1) {
1449  struct faceuse *fu1;
1450  struct ebm_edge *e1;
1451  point_t pt_ebm, pt_model;
1452  int done = 0;
1453 
1454  if (e->left) {
1455  /* make a face */
1456  fu1 = nmg_cmface(s, vertp, loop_length);
1457  NMG_CK_FACEUSE(fu1);
1458 
1459  /* assign geometry to the vertices used in this face */
1460  e1 = start_loop;
1461  while (!done) {
1462  if (e1->v) {
1463  VSET(pt_ebm, e1->x1, e1->y1, 0.0);
1464  MAT4X3PNT(pt_model, eip->mat, pt_ebm);
1465  nmg_vertex_gv(e1->v, pt_model);
1466  }
1467  if (e1 == e)
1468  done = 1;
1469  else
1470  e1 = BU_LIST_PNEXT(ebm_edge, &e1->l);
1471  }
1472 
1473  /* assign face geometry */
1474  if (nmg_fu_planeeqn(fu1, tol))
1475  goto fail;
1476 
1477  if (!fu)
1478  fu = fu1;
1479  } else {
1480  /* make a hole */
1481  for (i = 0; i < loop_length; i++) {
1482  if (*vertp[loop_length-i-1])
1483  loop_verts[i] = (*vertp[loop_length-i-1]);
1484  else
1485  loop_verts[i] = (struct vertex *)NULL;
1486  }
1487 
1488  (void) nmg_add_loop_to_face(s, fu, loop_verts ,
1489  loop_length, OT_OPPOSITE);
1490 
1491  /* Assign geometry to new vertices */
1492  done = 0;
1493  e1 = start_loop;
1494  i = loop_length - 1;
1495  while (!done) {
1496  if (!loop_verts[i]->vg_p) {
1497  VSET(pt_ebm, e1->x1, e1->y1, 0.0);
1498  MAT4X3PNT(pt_model, eip->mat, pt_ebm);
1499  nmg_vertex_gv(loop_verts[i], pt_model);
1500  e1->v = loop_verts[i];
1501  }
1502  if (e1 == e) {
1503  done = 1;
1504  } else {
1505  e1 = BU_LIST_PNEXT(ebm_edge, &e1->l);
1506  i--;
1507  }
1508  }
1509  }
1510  break;
1511  }
1512  e = BU_LIST_PNEXT(ebm_edge, &e->l);
1513  }
1514  e = BU_LIST_PNEXT(ebm_edge, &e->l);
1515  }
1516 
1517  /* all faces should merge into one */
1518  nmg_shell_coplanar_face_merge(s, tol, 1);
1519 
1520  fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
1521  NMG_CK_FACEUSE(fu);
1522 
1523  VSET(h, 0.0, 0.0, eip->tallness);
1524  MAT4X3VEC(height, eip->mat, h);
1525 
1526  nmg_extrude_face(fu, height, tol);
1527 
1528  nmg_region_a(*r, tol);
1529 
1530  (void)nmg_mark_edges_real(&s->l.magic);
1531 
1532  bu_free((char *)vertp, "rt_ebm_tess: vertp");
1533  bu_free((char *)loop_verts, "rt_ebm_tess: loop_verts");
1534  while (BU_LIST_NON_EMPTY(&edges.l)) {
1535  e = BU_LIST_FIRST(ebm_edge, &edges.l);
1536  BU_LIST_DEQUEUE(&e->l);
1537  bu_free((char *)e, "rt_ebm_tess: e");
1538  }
1539  return 0;
1540 
1541 fail:
1542  bu_free((char *)vertp, "rt_ebm_tess: vertp");
1543  bu_free((char *)loop_verts, "rt_ebm_tess: loop_verts");
1544  while (BU_LIST_NON_EMPTY(&edges.l)) {
1545  e = BU_LIST_FIRST(ebm_edge, &edges.l);
1546  BU_LIST_DEQUEUE(&e->l);
1547  bu_free((char *)e, "rt_ebm_tess: e");
1548  }
1549 
1550  return -1;
1551 }
1552 
1553 
1554 /**
1555  * Routine to format the parameters of an EBM for "db get"
1556  *
1557  * Legal requested parameters are:
1558  * "F" or "file" - bitmap file to extrude
1559  * "W" - number of cells in X direction
1560  * "N" - number of cells in Y direction
1561  * "H" - height of each cell (mm)
1562  * "M" - matrix to transform EBM solid into model coordinates
1563  *
1564  * no parameters requested returns all
1565  */
1566 int
1567 rt_ebm_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
1568 {
1569  register struct rt_ebm_internal *ebm=(struct rt_ebm_internal *)intern->idb_ptr;
1570  int i;
1571 
1572  RT_EBM_CK_MAGIC(ebm);
1573 
1574  if (attr == (char *)NULL) {
1575  bu_vls_strcpy(logstr, "ebm");
1576  bu_vls_printf(logstr, " F %s W %u N %u H %.25g",
1577  ebm->file, ebm->xdim, ebm->ydim, ebm->tallness);
1578  bu_vls_printf(logstr, " M {");
1579  for (i = 0; i < 16; i++)
1580  bu_vls_printf(logstr, " %.25g", ebm->mat[i]);
1581  bu_vls_printf(logstr, " }");
1582  } else if (BU_STR_EQUAL(attr, "F") || BU_STR_EQUAL(attr, "file")) {
1583  bu_vls_printf(logstr, "%s", ebm->file);
1584  } else if (BU_STR_EQUAL(attr, "W")) {
1585  bu_vls_printf(logstr, "%u", ebm->xdim);
1586  } else if (BU_STR_EQUAL(attr, "N")) {
1587  bu_vls_printf(logstr, "%u", ebm->ydim);
1588  } else if (BU_STR_EQUAL(attr, "H")) {
1589  bu_vls_printf(logstr, "%.25g", ebm->tallness);
1590  } else if (BU_STR_EQUAL(attr, "M")) {
1591  for (i = 0; i < 16; i++)
1592  bu_vls_printf(logstr, "%.25g ", ebm->mat[i]);
1593  } else {
1594  bu_vls_printf(logstr, "ERROR: Unknown attribute, choices are F, W, N, or H\n");
1595  return BRLCAD_ERROR;
1596  }
1597 
1598  return BRLCAD_OK;
1599 }
1600 
1601 
1602 /**
1603  * Routine to adjust the parameters of an EBM
1604  *
1605  * Legal parameters are:
1606  * "F" or "file" - bitmap file to extrude
1607  * "W" - number of cells in X direction
1608  * "N" - number of cells in Y direction
1609  * "H" - height of each cell (mm)
1610  * "M" - matrix to transform EBM solid into model coordinates
1611  */
1612 int
1613 rt_ebm_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv)
1614 {
1615  struct rt_ebm_internal *ebm;
1616 
1617  RT_CK_DB_INTERNAL(intern);
1618 
1619  ebm = (struct rt_ebm_internal *)intern->idb_ptr;
1620  RT_EBM_CK_MAGIC(ebm);
1621 
1622  while (argc >= 2) {
1623  if (BU_STR_EQUAL(argv[0], "F") || BU_STR_EQUAL(argv[0], "file")) {
1624  if (strlen(argv[1]) >= RT_EBM_NAME_LEN) {
1625  bu_vls_printf(logstr, "ERROR: File name too long");
1626  return BRLCAD_ERROR;
1627  }
1628  bu_strlcpy(ebm->file, argv[1], RT_EBM_NAME_LEN);
1629  } else if (BU_STR_EQUAL(argv[0], "W")) {
1630  ebm->xdim = atoi(argv[1]);
1631  } else if (BU_STR_EQUAL(argv[0], "N")) {
1632  ebm->ydim = atoi(argv[1]);
1633  } else if (BU_STR_EQUAL(argv[0], "H")) {
1634  ebm->tallness = atof(argv[1]);
1635  } else if (BU_STR_EQUAL(argv[0], "M")) {
1636  int len = 16;
1637  fastf_t array[16];
1638  fastf_t *ar_ptr;
1639 
1640  /*XXX needs list_to_fastf_array function */
1641  ar_ptr = array;
1642 
1643  if (tcl_list_to_fastf_array(brlcad_interp, argv[1], &ar_ptr, &len) != len) {
1644  bu_vls_printf(logstr, "ERROR: incorrect number of coefficients for matrix\n");
1645  return BRLCAD_ERROR;
1646  }
1647  MAT_COPY(ebm->mat, array);
1648  } else {
1649  bu_vls_printf(logstr, "ERROR: illegal argument, choices are F, W, N, or H\n");
1650  return BRLCAD_ERROR;
1651  }
1652  argc -= 2;
1653  argv += 2;
1654  }
1655  return BRLCAD_OK;
1656 }
1657 
1658 
1659 int
1660 rt_ebm_form(struct bu_vls *logstr, const struct rt_functab *ftp)
1661 {
1662  RT_CK_FUNCTAB(ftp);
1663 
1664  bu_vls_printf(logstr, "F %%s W %%d N %%d H %%f M { %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f %%f }");
1665 
1666  return TCL_OK;
1667 
1668 }
1669 
1670 
1671 /**
1672  * Routine to make a new EBM solid. The only purpose of this routine
1673  * is to initialize the matrix and height to legal values.
1674  */
1675 void
1676 rt_ebm_make(const struct rt_functab *ftp, struct rt_db_internal *intern)
1677 {
1678  struct rt_ebm_internal *ebm;
1679 
1680  intern->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1681  intern->idb_type = ID_EBM;
1682  BU_ASSERT(&OBJ[intern->idb_type] == ftp);
1683 
1684  intern->idb_meth = ftp;
1685  BU_ALLOC(ebm, struct rt_ebm_internal);
1686 
1687  intern->idb_ptr = (void *)ebm;
1688  ebm->magic = RT_EBM_INTERNAL_MAGIC;
1689  MAT_IDN(ebm->mat);
1690  ebm->tallness = 1.0;
1691 }
1692 
1693 
1694 int
1695 rt_ebm_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
1696 {
1697  if (!ps) return 0;
1698  if (ip) RT_CK_DB_INTERNAL(ip);
1699 
1700  return 0; /* OK */
1701 }
1702 
1703 
1704 /*
1705  * Computes the surface area of the ebm.
1706  *
1707  * The vertices are numbered from left to right, front to back.
1708  * This method calculates the position of all the 8 vertices of each cell and
1709  * then calculates the area of the top and bottom faces, then any other
1710  * necessary faces.
1711  */
1712 void
1713 rt_ebm_surf_area(fastf_t *area, const struct rt_db_internal *ip)
1714 {
1715  struct rt_ebm_internal *eip;
1716  unsigned int x, y;
1717  point_t x0, x1, x2, x3, x4, x5, x6, x7;
1718  point_t _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7;
1719  vect_t d3_0, d2_1, d7_4, d6_5;
1720  vect_t d6_0, d4_2, d4_1, d5_0, d5_3, d7_1, d7_2, d6_3, _cross;
1721  fastf_t _x, _y, det, _area = 0.0;
1722 
1723  if (area == NULL || ip == NULL) {
1724  return;
1725  }
1726  RT_CK_DB_INTERNAL(ip);
1727  eip = (struct rt_ebm_internal *)ip->idb_ptr;
1728  RT_EBM_CK_MAGIC(eip);
1729 
1730  det = fabs(bn_mat_determinant(eip->mat));
1731  if (EQUAL(det, 0.0)) {
1732  *area = -1.0;
1733  return;
1734  }
1735 
1736  for (y = 0; y < eip->ydim; y++) {
1737  for (x = 0; x < eip->xdim; x++) {
1738  if (BIT(eip, x, y) != 0) {
1739  _x = (fastf_t)x;
1740  _y = (fastf_t)y;
1741  VSET(_x0, _x - 0.5, _y - 0.5, 0.0);
1742  VSET(_x1, _x + 0.5, _y - 0.5, 0.0);
1743  VSET(_x2, _x - 0.5, _y + 0.5, 0.0);
1744  VSET(_x3, _x + 0.5, _y + 0.5, 0.0);
1745  VSET(_x4, _x - 0.5, _y - 0.5, eip->tallness);
1746  VSET(_x5, _x + 0.5, _y - 0.5, eip->tallness);
1747  VSET(_x6, _x - 0.5, _y + 0.5, eip->tallness);
1748  VSET(_x7, _x + 0.5, _y + 0.5, eip->tallness);
1749  MAT4X3PNT(x0, eip->mat, _x0);
1750  MAT4X3PNT(x1, eip->mat, _x1);
1751  MAT4X3PNT(x2, eip->mat, _x2);
1752  MAT4X3PNT(x3, eip->mat, _x3);
1753  MAT4X3PNT(x4, eip->mat, _x4);
1754  MAT4X3PNT(x5, eip->mat, _x5);
1755  MAT4X3PNT(x6, eip->mat, _x6);
1756  MAT4X3PNT(x7, eip->mat, _x7);
1757 
1758  VSUB2(d3_0, x3, x0);
1759  VSUB2(d2_1, x2, x1);
1760  VSUB2(d7_4, x7, x4);
1761  VSUB2(d6_5, x6, x5);
1762 
1763  VCROSS(_cross, d3_0, d2_1);
1764  _area += 0.5 * MAGNITUDE(_cross);
1765  VCROSS(_cross, d7_4, d6_5);
1766  _area += 0.5 * MAGNITUDE(_cross);
1767 
1768  if (BIT(eip, x + 1, y) == 0) {
1769  VSUB2(d5_3, x5, x3);
1770  VSUB2(d7_1, x7, x1);
1771  VCROSS(_cross, d5_3, d7_1);
1772  _area += 0.5 * MAGNITUDE(_cross);
1773  }
1774  if (BIT(eip, x - 1, y) == 0) {
1775  VSUB2(d6_0, x6, x0);
1776  VSUB2(d4_2, x4, x2);
1777  VCROSS(_cross, d6_0, d4_2);
1778  _area += 0.5 * MAGNITUDE(_cross);
1779  }
1780  if (BIT(eip, x, y + 1) == 0) {
1781  VSUB2(d7_2, x7, x2);
1782  VSUB2(d6_3, x6, x3);
1783  VCROSS(_cross, d7_2, d6_3);
1784  _area += 0.5 * MAGNITUDE(_cross);
1785  }
1786  if (BIT(eip, x, y - 1) == 0) {
1787  VSUB2(d4_1, x4, x1);
1788  VSUB2(d5_0, x5, x0);
1789  VCROSS(_cross, d4_1, d5_0);
1790  _area += 0.5 * MAGNITUDE(_cross);
1791  }
1792  }
1793  }
1794  }
1795  *area = _area;
1796 }
1797 
1798 
1799 /** @} */
1800 /*
1801  * Local Variables:
1802  * mode: C
1803  * tab-width: 8
1804  * indent-tabs-mode: t
1805  * c-file-style: "stroustrup"
1806  * End:
1807  * ex: shiftwidth=4 tabstop=8
1808  */
Definition: db_flip.c:35
void rt_ebm_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
Definition: ebm.c:1057
int rt_ebm_form(struct bu_vls *logstr, const struct rt_functab *ftp)
Definition: ebm.c:1660
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
Definition: raytrace.h:800
#define RT_CK_FUNCTAB(_p)
Definition: raytrace.h:2242
int y_cell
Definition: ebm.c:77
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
void rt_ebm_ifree(struct rt_db_internal *ip)
Definition: ebm.c:855
struct hit seg_in
IN information.
Definition: raytrace.h:370
int rt_ebm_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
Definition: ebm.c:1567
Definition: list.h:118
int nmg_fu_planeeqn(struct faceuse *fu, const struct bn_tol *tol)
Definition: nmg_mod.c:1311
fastf_t bn_mat_determinant(const mat_t m)
Definition: mat.c:1117
#define BU_LIST_LAST(structure, hp)
Definition: list.h:306
void rt_ebm_make(const struct rt_functab *ftp, struct rt_db_internal *intern)
Definition: ebm.c:1676
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
#define RT_FREE_SEG(p, res)
Definition: raytrace.h:389
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
vect_t crv_pdir
Principle direction.
Definition: raytrace.h:307
const mat_t bn_mat_identity
Matrix and vector functionality.
Definition: mat.c:46
fastf_t uv_u
Range 0..1.
Definition: raytrace.h:341
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
if lu s
Definition: nmg_mod.c:3860
void bn_rotate_bbox(point_t omin, point_t omax, const mat_t mat, const point_t imin, const point_t imax)
Transform a bounding box (RPP) by the given 4x4 matrix. There are 8 corners to the bounding RPP...
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define BU_LIST_IS_EMPTY(hp)
Definition: list.h:295
#define BIT_YWIDEN
Definition: ebm.c:106
void rt_ebm_free(struct soltab *stp)
Definition: ebm.c:1087
Definition: pc.h:108
mat_t ebm_mat
Definition: ebm.c:57
Definition: raytrace.h:368
#define NORM_XNEG
Definition: ebm.c:95
int rt_ebm_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: ebm.c:781
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
int rt_ebm_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: ebm.c:679
#define NORM_YPOS
Definition: ebm.c:93
char ** dbi_filepath
search path for aux file opens (convenience var)
Definition: raytrace.h:810
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
#define NORM_ZPOS
Definition: ebm.c:92
#define ID_NULL
Unused.
Definition: raytrace.h:458
int rt_ebm_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: ebm.c:818
Header file for the BRL-CAD common definitions.
#define BU_LIST_APPEND(old, new)
Definition: list.h:197
vect_t ebm_xnorm
Definition: ebm.c:51
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
#define RT_EBM_INTERNAL_MAGIC
Definition: magic.h:89
#define BU_ASSERT(_equation)
Definition: defines.h:216
int rt_in_rpp(struct xray *rp, const fastf_t *invdir, const fastf_t *min, const fastf_t *max)
int rt_seg_planeclip(struct seg *out_hd, struct seg *in_hd, vect_t out_norm, fastf_t in, fastf_t out, struct xray *rp, struct application *ap)
#define BU_LIST_NON_EMPTY(hp)
Definition: list.h:296
struct bu_list l
Definition: ebm.c:1184
struct bu_list l
Definition: raytrace.h:369
void bu_struct_print(const char *title, const struct bu_structparse *parsetab, const char *base)
Definition: parse.c:1221
const struct bu_structparse rt_ebm_parse[]
Definition: ebm.c:65
if(share_geom)
Definition: nmg_mod.c:3829
int rt_ebm_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
Definition: ebm.c:984
size_t apbuflen
Definition: mapped_file.h:90
int idb_major_type
Definition: raytrace.h:192
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
void rt_ebm_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: ebm.c:115
Definition: color.c:49
int rt_ebm_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: ebm.c:1695
vect_t ebm_origin
Definition: ebm.c:55
int x2
Definition: ebm.c:1186
void rt_ebm_plate(int x_1, int y_1, int x_2, int y_2, double t, register fastf_t *mat, register struct bu_list *vhead)
Definition: ebm.c:1101
#define RT_G_DEBUG
Definition: raytrace.h:1718
int rt_ebm_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: ebm.c:881
vect_t hit_vpriv
PRIVATE vector for xxx_*()
Definition: raytrace.h:253
#define RT_ADD_VLIST(hd, pnt, draw)
Definition: raytrace.h:1865
#define ID_EBM
Extruded bitmap solid.
Definition: raytrace.h:470
Definition: ebm.c:1182
int nmg_extrude_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
Definition: nmg_extrude.c:179
#define BIT_XWIDEN
Definition: ebm.c:105
void nmg_shell_coplanar_face_merge(struct shell *s, const struct bn_tol *tol, const int simplify)
Definition: nmg_mod.c:93
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
#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
fastf_t st_bradius
Radius of BOUNDING sphere.
Definition: raytrace.h:434
fastf_t crv_c2
curvature in other direction
Definition: raytrace.h:309
int rt_ebm_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: ebm.c:531
struct vertex * v
Definition: ebm.c:1188
#define BN_VLIST_LINE_MOVE
Definition: vlist.h:82
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
fastf_t uv_dv
delta in v
Definition: raytrace.h:344
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
void bn_mat_inv(mat_t output, const mat_t input)
int rt_ebm_dda(struct xray *rp, struct soltab *stp, struct application *ap, struct seg *seghead)
#define BRLCAD_OK
Definition: defines.h:71
int x1
Definition: ebm.c:1185
void rt_ebm_surf_area(fastf_t *area, const struct rt_db_internal *ip)
Definition: ebm.c:1713
uint8_t * ext_buf
Definition: parse.h:216
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
int rt_ebm_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *info)
Definition: ebm.c:1128
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
#define BU_CK_MAPPED_FILE(_mf)
Definition: mapped_file.h:101
struct faceuse * nmg_add_loop_to_face(struct shell *s, struct faceuse *fu, struct vertex **verts, int n, int dir)
Definition: nmg_mod.c:1211
struct hit seg_out
OUT information.
Definition: raytrace.h:371
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
vect_t ebm_ynorm
Definition: ebm.c:52
fastf_t r_max
exit dist from bounding sphere
Definition: raytrace.h:221
size_t bu_vls_strlen(const struct bu_vls *vp)
Definition: vls.c:189
#define DEBUG_EBM
26 Extruded bit-map solids
Definition: raytrace.h:113
#define BU_LIST_PNEXT(structure, p)
Definition: list.h:422
int y2
Definition: ebm.c:1186
#define NORM_XPOS
Definition: ebm.c:94
#define UNUSED(parameter)
Definition: common.h:239
#define NORM_ZNEG
Definition: ebm.c:97
int nmg_mark_edges_real(const uint32_t *magic_p)
Definition: nmg_misc.c:846
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
goto out
Definition: nmg_mod.c:3846
void bn_mat_mul(mat_t o, const mat_t a, const mat_t b)
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
void bu_vls_struct_print(struct bu_vls *vls, const struct bu_structparse *sdp, const char *base)
#define BU_LIST_WHILE(p, structure, hp)
Definition: list.h:410
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
void rt_ebm_print(register const struct soltab *stp)
Definition: ebm.c:961
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
#define bu_offsetof(_t, _m)
Definition: parse.h:64
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
vect_t ebm_cellsize
Definition: ebm.c:54
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
fastf_t r_min
entry dist to bounding sphere
Definition: raytrace.h:220
#define ZERO(val)
Definition: units.c:38
#define BU_LIST_INIT(_hp)
Definition: list.h:148
#define NORM_YNEG
Definition: ebm.c:96
void * idb_ptr
Definition: raytrace.h:195
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
int x_cell
Definition: ebm.c:76
point_t st_min
min X, Y, Z of bounding RPP
Definition: raytrace.h:437
const struct rt_functab OBJ[]
Definition: table.c:159
#define BIT(_eip, _xx, _yy)
Definition: ebm.c:107
void bn_vec_ortho(vect_t out, const vect_t in)
int rt_ebm_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: ebm.c:639
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
void rt_ebm_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
Definition: ebm.c:1015
fastf_t uv_du
delta in u
Definition: raytrace.h:343
int rt_ebm_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: ebm.c:908
void bu_close_mapped_file(struct bu_mapped_file *mp)
Definition: mappedfile.c:339
int tcl_list_to_fastf_array(Tcl_Interp *interp, const char *char_list, fastf_t **array, int *array_len)
Definition: tcl.c:829
int left
Definition: ebm.c:1187
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
int rt_ebm_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: ebm.c:1359
Definition: color.c:51
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
vect_t ebm_znorm
Definition: ebm.c:53
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
#define RT_SEM_MODEL
Definition: raytrace.h:1733
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
#define RT_EBM_O(m)
Definition: ebm.c:63
#define BU_CK_LIST_HEAD(_p)
Definition: list.h:142
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
struct faceuse * nmg_cmface(struct shell *s, struct vertex ***verts, int n)
Definition: nmg_mod.c:979
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
struct rt_ebm_internal ebm_i
Definition: ebm.c:50
#define BU_LIST_DEQUEUE(cur)
Definition: list.h:209
size_t ext_nbytes
Definition: parse.h:210
void bu_vls_vlscat(struct bu_vls *dest, const struct bu_vls *src)
Definition: vls.c:415
vect_t ebm_large
Definition: ebm.c:56
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
#define BU_LIST_INSERT_LIST(dest_hp, src_hp)
Definition: list.h:270
Definition: vls.h:56
#define BRLCAD_ERROR
Definition: defines.h:72
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
int y1
Definition: ebm.c:1185
HIDDEN const point_t delta
Definition: sh_prj.c:618
void rt_ebm_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
Definition: ebm.c:1072
double fastf_t
Definition: defines.h:300
#define VPRINT(a, b)
Definition: raytrace.h:1881
#define BU_LIST_NOT_HEAD(p, hp)
Definition: list.h:324
Tcl_Interp * brlcad_interp
Definition: tcl.c:41
struct bu_mapped_file * bu_open_mapped_file_with_path(char *const *path, const char *name, const char *appl)
Definition: mappedfile.c:430
Definition: color.c:50
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
fastf_t uv_v
Range 0..1.
Definition: raytrace.h:342
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
int rt_ebm_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv)
Definition: ebm.c:1613
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
void nmg_region_a(struct nmgregion *r, const struct bn_tol *tol)
Definition: nmg_mk.c:2557