g_dsp.c

Go to the documentation of this file.
00001 #define FULL_DSP_DEBUGGING 1
00002 
00003 /** @addtogroup g_  */
00004 
00005 /*@{*/
00006 /** @file g_dsp.c
00007  *      Intersect a ray with a displacement map.
00008  *
00009  *  The bounding box planes (in dsp coordinates) are numbered 0 .. 5
00010  *
00011  *  For purposes of the "struct hit" surface number, the "non-elevation"
00012  *  surfaces are numbered 0 .. 7 where:
00013  *
00014  *           Plane #    Name  plane dist
00015  *      --------------------------------------------------
00016  *              0       XMIN (dist = 0)
00017  *              1       XMAX (dist = xsiz)
00018  *              2       YMIN (dist = 0)
00019  *              3       YMAX (dist = ysiz)
00020  *              4       ZMIN (dist = 0)
00021  *              5       ZMAX (dsp_max)
00022  *
00023  *              6       ZMID (dsp_min)
00024  *              7       ZTOP (computed)
00025  *
00026  *  if the "struct hit" surfno surface is ZMAX, then
00027  *      hit_vpriv[X,Y] holds the cell that was hit.
00028  *      hit_vpriv[Z] is 0 if this was an in-hit.  1 if an out-hit
00029  *
00030  *
00031  *  Authors -
00032  *      Lee A. Butler
00033  *
00034  *  Source -
00035  *      SECAD/VLD Computing Consortium, Bldg 394
00036  *      The U. S. Army Ballistic Research Laboratory
00037  *      Aberdeen Proving Ground, Maryland  21005-5066
00038  *
00039  */
00040 
00041 #ifndef lint
00042 static const char RCSdsp[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_dsp.c,v 14.12 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00043 #endif
00044 
00045 #include "common.h"
00046 
00047 #include <stddef.h>
00048 #include <stdio.h>
00049 #include <string.h>
00050 #include <math.h>
00051 #include <setjmp.h>
00052 
00053 #include "machine.h"
00054 #include "vmath.h"
00055 #include "db.h"
00056 #include "nmg.h"
00057 #include "raytrace.h"
00058 #include "rtgeom.h"
00059 #include "./debug.h"
00060 #include "plot3.h"
00061 
00062 #define ORDERED_ISECT 1
00063 /* #define FULL_DSP_DEBUGGING 1 */
00064 
00065 #define DIM_BB_CHILDREN 4
00066 #define NUM_BB_CHILDREN (DIM_BB_CHILDREN*DIM_BB_CHILDREN)
00067 
00068 struct dsp_rpp {
00069     unsigned short dsp_min[3];
00070     unsigned short dsp_max[3];
00071 };
00072 
00073 /* This structure contains a bounding box for a portion of the DSP
00074  * along with information about sub-bounding boxes, and what layer
00075  * (resolution) of the DSP this box bounds
00076  */
00077 struct dsp_bb {
00078     long        magic;
00079     struct dsp_rpp      dspb_rpp;       /* our bounding box */
00080     /*
00081      * the next two elements indicate the number and locations of
00082      * sub-bounding rpps.
00083      *
00084      * dsp_b_ch_dim is typically DIM_BB_CHILDREN,DIM_BB_CHILDREN
00085      * except for "border" areas of the array
00086      */
00087     unsigned short      dspb_subcell_size;/* XXX This is not yet computed */
00088     unsigned short      dspb_ch_dim[2]; /* dimensions of children[] */
00089     struct dsp_bb       *dspb_children[NUM_BB_CHILDREN];
00090 };
00091 #define MAGIC_dsp_bb 234
00092 #define DSP_BB_CK(_p) BU_CKMAG(_p, MAGIC_dsp_bb, "dsp_bb")
00093 /*
00094  * This structure provides a handle to all of the bounding boxes for the DSP
00095  * at a particular resolution.
00096  */
00097 #define LAYER(l, x,y) l->p[l->dim[1]*y+x]
00098 struct dsp_bb_layer {
00099     int dim[2];         /* the dimensions of the array at element p */
00100     struct dsp_bb *p;   /* array of dsp_bb's for this level */
00101 };
00102 
00103 
00104 
00105 extern int rt_retrieve_binunif(struct rt_db_internal *intern,
00106                                const struct db_i        *dbip,
00107                                const char *name);
00108 
00109 extern void rt_binunif_ifree( struct rt_db_internal     *ip );
00110 
00111 
00112 #define dlog if (RT_G_DEBUG & DEBUG_HF) bu_log
00113 
00114 
00115 #define BBOX_PLANES     7       /* 2 tops & 5 other sides */
00116 #define XMIN 0
00117 #define XMAX 1
00118 #define YMIN 2
00119 #define YMAX 3
00120 #define ZMIN 4
00121 #define ZMAX 5
00122 #define ZMID 6
00123 #define ZTOP 7
00124 
00125 
00126 
00127 /* per-solid ray tracing form of solid, including precomputed terms
00128  *
00129  * The dsp_i element MUST BE FIRST so that we can cast a pointer to
00130  *  a dsp_specific to a rt_dsp_intermal.
00131  */
00132 struct dsp_specific {
00133     struct rt_dsp_internal dsp_i;       /* MUST BE FIRST */
00134     double              dsp_pl_dist[BBOX_PLANES];
00135     int         xsiz;
00136     int         ysiz;
00137     int         layers;
00138     struct dsp_bb_layer *layer;
00139     struct dsp_bb *bb_array;
00140 };
00141 
00142 
00143 
00144 /* access to the array */
00145 #ifdef FULL_DSP_DEBUGGING
00146 #define DSP(_p,_x,_y) dsp_val(_p, _x, _y, __FILE__, __LINE__)
00147 unsigned short
00148 dsp_val(struct rt_dsp_internal *dsp_i, unsigned x, unsigned y, char *file, int line)
00149 {
00150     RT_DSP_CK_MAGIC(dsp_i);
00151 
00152     if (x >= dsp_i->dsp_xcnt || y >= dsp_i->dsp_ycnt) {
00153         bu_log("%s:%d xy: %u,%u cnt: %u,%u\n",
00154                file, line, x, y, dsp_i->dsp_xcnt, dsp_i->dsp_ycnt);
00155         bu_bomb("");
00156     }
00157 
00158     return dsp_i->dsp_buf[ y * dsp_i->dsp_xcnt + x ];
00159 }
00160 #else
00161 # define DSP(_p,_x,_y) ( \
00162         ( \
00163          (unsigned short *) \
00164           ((_p)->dsp_buf) \
00165         )[ \
00166              (_y) * ((struct rt_dsp_internal *)_p)->dsp_xcnt + (_x) ] )
00167 #endif
00168 
00169 # define XCNT(_p) (((struct rt_dsp_internal *)_p)->dsp_xcnt)
00170 # define YCNT(_p) (((struct rt_dsp_internal *)_p)->dsp_ycnt)
00171 # define XSIZ(_p) (_p->dsp_i.dsp_xcnt - 1)
00172 # define YSIZ(_p) (_p->dsp_i.dsp_ycnt - 1)
00173 
00174 
00175 
00176 
00177 struct bbox_isect {
00178     double      in_dist;
00179     double      out_dist;
00180     int in_surf;
00181     int out_surf;
00182 };
00183 
00184 
00185 /* per-ray ray tracing information
00186  *
00187  */
00188 struct isect_stuff {
00189     struct dsp_specific *dsp;
00190     struct bu_list      seglist;        /* list of segments */
00191     struct xray         r;              /* solid space ray */
00192     vect_t              inv_dir;        /* inverses of ray direction */
00193     struct application  *ap;
00194     struct soltab       *stp;
00195     struct bn_tol       *tol;
00196 
00197     struct bbox_isect   bbox;
00198     struct bbox_isect   minbox;
00199 
00200     int                 num_segs;
00201     int                 dmin, dmax;     /* for dsp_in_rpp , {X,Y,Z}MIN/MAX */
00202 };
00203 
00204 
00205 
00206 
00207 /* plane equations (minus offset distances) for bounding RPP */
00208 static const vect_t     dsp_pl[BBOX_PLANES] = {
00209     {-1.0, 0.0, 0.0},
00210     { 1.0, 0.0, 0.0},
00211 
00212     {0.0, -1.0, 0.0},
00213     {0.0,  1.0, 0.0},
00214 
00215     {0.0, 0.0, -1.0},
00216     {0.0, 0.0,  1.0},
00217     {0.0, 0.0,  1.0},
00218 };
00219 
00220 /*
00221  * This function computes the DSP mtos matrix from the stom matrix
00222  * whenever the stom matrix is parsed using a bu_structparse.
00223  */
00224 static void
00225 hook_mtos_from_stom(
00226                     const struct bu_structparse *ip,
00227                     const char                  *sp_name,
00228                     genptr_t                    base,
00229                     char                        *p)
00230 {
00231     struct rt_dsp_internal *dsp_ip = (struct rt_dsp_internal *)base;
00232 
00233     bn_mat_inv(dsp_ip->dsp_mtos, dsp_ip->dsp_stom);
00234 }
00235 static void
00236 hook_file(
00237           const struct bu_structparse   *ip,
00238           const char                    *sp_name,
00239           genptr_t                      base,
00240           char                  *p)
00241 {
00242     struct rt_dsp_internal *dsp_ip = (struct rt_dsp_internal *)base;
00243 
00244     dsp_ip->dsp_datasrc = RT_DSP_SRC_V4_FILE;
00245     dsp_ip->dsp_bip = (struct rt_db_internal *)NULL;
00246 }
00247 
00248 #define DSP_O(m) bu_offsetof(struct rt_dsp_internal, m)
00249 #define DSP_AO(a) bu_offsetofarray(struct rt_dsp_internal, a)
00250 
00251 /*
00252  *      These are only used when editing a v4 database
00253  */
00254 const struct bu_structparse rt_dsp_parse[] = {
00255     {"%S",      1, "file", DSP_O(dsp_name), hook_file },
00256     {"%i",      1, "sm", DSP_O(dsp_smooth), BU_STRUCTPARSE_FUNC_NULL },
00257     {"%d",      1, "w", DSP_O(dsp_xcnt), BU_STRUCTPARSE_FUNC_NULL },
00258     {"%d",      1, "n", DSP_O(dsp_ycnt), BU_STRUCTPARSE_FUNC_NULL },
00259     {"%f",     16, "stom", DSP_AO(dsp_stom), hook_mtos_from_stom },
00260     {"",        0, (char *)0, 0,        BU_STRUCTPARSE_FUNC_NULL }
00261 };
00262 
00263 const struct bu_structparse rt_dsp_ptab[] = {
00264     {"%S",      1, "file", DSP_O(dsp_name), BU_STRUCTPARSE_FUNC_NULL },
00265     {"%i",      1, "sm", DSP_O(dsp_smooth), BU_STRUCTPARSE_FUNC_NULL },
00266     {"%d",      1, "w", DSP_O(dsp_xcnt), BU_STRUCTPARSE_FUNC_NULL },
00267     {"%d",      1, "n", DSP_O(dsp_ycnt), BU_STRUCTPARSE_FUNC_NULL },
00268     {"%f",     16, "stom", DSP_AO(dsp_stom), BU_STRUCTPARSE_FUNC_NULL },
00269     {"",        0, (char *)0, 0,        BU_STRUCTPARSE_FUNC_NULL }
00270 };
00271 
00272 /*
00273  *      This one is used by the rt_dsp_tclget()
00274  */
00275 
00276 
00277 static int plot_file_num=0;
00278 
00279 
00280 /**
00281  *      P L O T _ R P P
00282  *
00283  * Plot an RPP to a file in the given color
00284  */
00285 static void
00286 plot_rpp(FILE *fp, struct bound_rpp *rpp, int r, int g, int b)
00287 {
00288     pl_color(fp, r, g, b);
00289 
00290     pd_3move(fp, rpp->min[X], rpp->min[Y], rpp->min[Z]);
00291     pd_3cont(fp, rpp->max[X], rpp->min[Y], rpp->min[Z]);
00292     pd_3cont(fp, rpp->max[X], rpp->max[Y], rpp->min[Z]);
00293     pd_3cont(fp, rpp->min[X], rpp->max[Y], rpp->min[Z]);
00294     pd_3cont(fp, rpp->min[X], rpp->min[Y], rpp->min[Z]);
00295 
00296     pd_3cont(fp, rpp->min[X], rpp->min[Y], rpp->max[Z]);
00297     pd_3cont(fp, rpp->max[X], rpp->min[Y], rpp->max[Z]);
00298     pd_3cont(fp, rpp->max[X], rpp->max[Y], rpp->max[Z]);
00299     pd_3cont(fp, rpp->min[X], rpp->max[Y], rpp->max[Z]);
00300     pd_3cont(fp, rpp->min[X], rpp->min[Y], rpp->max[Z]);
00301 }
00302 
00303 
00304 /**     P L O T _ D S P _ B B
00305  *
00306  *  Plot a dsp_bb structure
00307  */
00308 static void
00309 plot_dsp_bb(FILE *fp, struct dsp_bb *dsp_bb,
00310             struct dsp_specific *dsp,
00311             int r, int g, int b, int blather)
00312 {
00313     fastf_t *stom = &dsp->dsp_i.dsp_stom[0];
00314     struct bound_rpp rpp;
00315     point_t pt;
00316 
00317     DSP_BB_CK(dsp_bb);
00318 
00319     VMOVE(pt, dsp_bb->dspb_rpp.dsp_min); /* int->float conversion */
00320     MAT4X3PNT(rpp.min, stom, pt);
00321 
00322     VMOVE(pt, dsp_bb->dspb_rpp.dsp_max); /* int->float conversion */
00323     MAT4X3PNT(rpp.max, stom, pt);
00324 
00325     if (blather)
00326         bu_log(" (%g %g %g) (%g %g %g)\n",
00327                V3ARGS(rpp.min), V3ARGS(rpp.max) );
00328 
00329     plot_rpp(fp, &rpp, r, g, b);
00330 }
00331 /*
00332  * drawing support for isect_ray_dsp_bb()
00333  */
00334 static FILE *
00335 draw_dsp_bb(int *plotnum,
00336             struct dsp_bb *dsp_bb,
00337             struct dsp_specific *dsp,
00338             int r, int g, int b)
00339 {
00340     char buf[64];
00341     FILE *fp;
00342     struct dsp_bb bb;
00343 
00344     sprintf(buf, "dsp_bb%03d.pl", (*plotnum)++);
00345     if ( (fp=fopen(buf, "w")) == (FILE *)NULL) {
00346         perror(buf);
00347         bu_bomb("");
00348     }
00349 
00350     bu_log("plotting %s", buf);
00351     bb = *dsp_bb; /* struct copy */
00352     bb.dspb_rpp.dsp_min[Z] = 0.0;
00353     plot_dsp_bb(fp, &bb, dsp, r, g, b, 1);
00354 
00355     return fp;
00356 }
00357 
00358 #define PLOT_LAYERS
00359 #ifdef PLOT_LAYERS
00360 /**     P L O T _ L A Y E R S
00361  *
00362  *
00363  *  Plot the bounding box layers for a dsp
00364  */
00365 static void
00366 plot_layers(struct dsp_specific *dsp_sp)
00367 {
00368     FILE *fp;
00369     int l, x, y, n;
00370     char buf[32];
00371     static int colors[7][3] = {
00372         {255, 0, 0},
00373         {0, 255, 0},
00374         {0, 0, 255},
00375         {255, 255, 0},
00376         {255, 0, 255},
00377         {0, 255, 255},
00378         {255, 255, 255}
00379     };
00380     int r, g, b, c;
00381     struct dsp_bb *d_bb;
00382 
00383     for (l=0 ; l < dsp_sp->layers ; l++) {
00384         bu_semaphore_acquire( BU_SEM_SYSCALL);
00385         sprintf(buf, "Dsp_layer%d.pl", l);
00386         fp=fopen(buf, "w");
00387         bu_semaphore_release( BU_SEM_SYSCALL);
00388         if ( fp == (FILE *)NULL ) {
00389             bu_log("%s:%d error opening %s\n", __FILE__, __LINE__,
00390                    buf);
00391             return;
00392         } else
00393             bu_log("plotting \"%s\" dim:%d,%d\n", buf,
00394                    dsp_sp->layer[l].dim[X],
00395                    dsp_sp->layer[l].dim[Y]);
00396         c = l % 6;
00397         r = colors[c][0];
00398         g = colors[c][1];
00399         b = colors[c][2];
00400 
00401         for (y=0 ; y < dsp_sp->layer[l].dim[Y] ; y+= 2 ) {
00402             for (x=0 ; x < dsp_sp->layer[l].dim[X] ; x+= 2 ) {
00403                 n = y * dsp_sp->layer[l].dim[X] + x;
00404                 d_bb = &dsp_sp->layer[l].p[n];
00405                 plot_dsp_bb(fp, d_bb, dsp_sp, r, g, b, 0);
00406 
00407 #if 0
00408                 if (RT_G_DEBUG & DEBUG_HF)
00409                     bu_log("\t%d,%d ch_dim:%d,%d  min:(%d %d %d)  max:(%d %d %d)\n",
00410                            x, y,
00411                            d_bb->dspb_ch_dim[X],
00412                            d_bb->dspb_ch_dim[Y],
00413                            V3ARGS(d_bb->dspb_rpp.dsp_min),
00414                            V3ARGS(d_bb->dspb_rpp.dsp_max));
00415 #endif
00416             }
00417         }
00418         fclose(fp);
00419     }
00420 }
00421 #endif
00422 
00423 /**     P L O T _ C E L L _ T O P
00424  *
00425  *      Plot the results of intersecting a ray with the top of a cell
00426  *
00427  */
00428 static void
00429 plot_cell_top(struct isect_stuff *isect,
00430               struct dsp_bb *dsp_bb,
00431               point_t A,
00432               point_t B,
00433               point_t C,
00434               point_t D,
00435               struct hit hitlist[],
00436               int hitflags,
00437               int style)        /* plot diagonal */
00438 {
00439     fastf_t *stom = &isect->dsp->dsp_i.dsp_stom[0];
00440     char buf[64];
00441     static int plotcnt = 0;
00442     static int cnt = 0;
00443     FILE *fp;
00444     point_t p1, p2, p3, p4;
00445     int i;
00446     int in_seg;
00447     static unsigned char colors[4][3] = {
00448         {255, 255, 128},
00449         {255, 128, 255},
00450         {128, 255, 128},
00451         {128, 255, 255},
00452     };
00453 
00454     DSP_BB_CK(dsp_bb);
00455 
00456     bu_semaphore_acquire( BU_SEM_SYSCALL);
00457     if (style)
00458         sprintf(buf, "dsp_cell_isect%04d.pl", cnt++);
00459     else
00460         sprintf(buf, "dsp_cell_top%04d.pl", plotcnt++);
00461 
00462     fp=fopen(buf, "w");
00463 
00464     bu_semaphore_release( BU_SEM_SYSCALL);
00465 
00466     if ( fp == (FILE *)NULL) {
00467         bu_log("error opening \"%s\"\n", buf);
00468         return;
00469     } else {
00470         bu_log("plotting %s flags 0x%x\n\t", buf, hitflags);
00471     }
00472 
00473     plot_dsp_bb(fp, dsp_bb, isect->dsp, 128, 128, 128, 1);
00474 
00475     /* plot the triangulation */
00476     pl_color(fp, 255, 255, 255);
00477     MAT4X3PNT(p1, stom, A);
00478     MAT4X3PNT(p2, stom, B);
00479     MAT4X3PNT(p3, stom, C);
00480     MAT4X3PNT(p4, stom, D);
00481 
00482     pdv_3move(fp, p1);
00483     if (style) {
00484         pdv_3cont(fp, p2);
00485         pdv_3cont(fp, p4);
00486         pdv_3cont(fp, p1);
00487         pdv_3cont(fp, p3);
00488         pdv_3cont(fp, p4);
00489     } else {
00490         pdv_3cont(fp, p2);
00491         pdv_3cont(fp, p4);
00492         pdv_3cont(fp, p3);
00493         pdv_3cont(fp, p1);
00494     }
00495 
00496     /* plot the hit points */
00497 
00498     for (in_seg = 0, i = 0 ; i < 4 ; i++ ) {
00499         if (hitflags & (1<<i)) {
00500             if (in_seg) {
00501                 in_seg = 0;
00502                 MAT4X3PNT(p1, stom, hitlist[i].hit_point);
00503                 pdv_3cont(fp, p1);
00504             } else {
00505                 in_seg = 1;
00506                 pl_color(fp, colors[i][0], colors[i][1], colors[i][2]);
00507                 MAT4X3PNT(p1, stom, hitlist[i].hit_point);
00508                 pdv_3move(fp, p1);
00509             }
00510         }
00511     }
00512     fclose(fp);
00513 }
00514 
00515 /**     D S P _ P R I N T _ V 4
00516  */
00517 static void
00518 dsp_print_v4(struct bu_vls *vls, const struct rt_dsp_internal *dsp_ip)
00519 {
00520     point_t pt, v;
00521     RT_DSP_CK_MAGIC(dsp_ip);
00522     BU_CK_VLS(&dsp_ip->dsp_name);
00523     BU_CK_VLS(vls);
00524 
00525     bu_vls_printf( vls, "Displacement Map\n  file='%s' w=%d n=%d sm=%d",
00526                    bu_vls_addr(&dsp_ip->dsp_name),
00527                    dsp_ip->dsp_xcnt,
00528                    dsp_ip->dsp_ycnt,
00529                    dsp_ip->dsp_smooth);
00530 
00531     VSETALL(pt, 0.0);
00532 
00533     MAT4X3PNT(v, dsp_ip->dsp_stom, pt);
00534 
00535     bu_vls_printf( vls, " (origin at %g %g %g)mm\n", V3INTCLAMPARGS(v));
00536 
00537     bu_vls_printf( vls, "  stom=\n");
00538     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n",
00539                    V4INTCLAMPARGS(dsp_ip->dsp_stom) );
00540 
00541     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n",
00542                    V4INTCLAMPARGS( &dsp_ip->dsp_stom[4]) );
00543 
00544     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n",
00545                    V4INTCLAMPARGS( &dsp_ip->dsp_stom[8]) );
00546 
00547     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n",
00548                    V4INTCLAMPARGS( &dsp_ip->dsp_stom[12]) );
00549 }
00550 
00551 /**     D S P _ P R I N T _ V 5
00552  */
00553 static void
00554 dsp_print_v5(struct bu_vls *vls,
00555              const struct rt_dsp_internal *dsp_ip)
00556 {
00557     point_t pt, v;
00558 
00559     BU_CK_VLS(vls);
00560 
00561     RT_DSP_CK_MAGIC(dsp_ip);
00562     BU_CK_VLS(&dsp_ip->dsp_name);
00563 
00564 
00565     bu_vls_printf( vls, "Displacement Map\n" );
00566 
00567     switch (dsp_ip->dsp_datasrc) {
00568     case RT_DSP_SRC_V4_FILE:
00569                         bu_vls_printf( vls, "  Error Error Error");
00570                         break;
00571     case RT_DSP_SRC_FILE:
00572                         bu_vls_printf( vls, "  file");
00573                         break;
00574     case RT_DSP_SRC_OBJ:
00575                         bu_vls_printf( vls, "  obj");
00576                         break;
00577     default:
00578                         bu_vls_printf( vls, "unk src type'%c'", dsp_ip->dsp_datasrc);
00579                         break;
00580     }
00581 
00582     bu_vls_printf( vls, "='%s'\n  w=%d n=%d sm=%d ",
00583                                                                          bu_vls_addr(&dsp_ip->dsp_name),
00584                                                                          dsp_ip->dsp_xcnt,
00585                                                                          dsp_ip->dsp_ycnt,
00586                                                                          dsp_ip->dsp_smooth);
00587 
00588     switch (dsp_ip->dsp_cuttype) {
00589     case DSP_CUT_DIR_ADAPT:
00590                         bu_vls_printf( vls, "cut=ad" ); break;
00591     case DSP_CUT_DIR_llUR:
00592                         bu_vls_printf( vls, "cut=lR" ); break;
00593     case DSP_CUT_DIR_ULlr:
00594                         bu_vls_printf( vls, "cut=Lr" ); break;
00595     default:
00596                         bu_vls_printf( vls, "cut bogus('%c'/%d)",
00597                                                                                  dsp_ip->dsp_cuttype,
00598                                                                                  dsp_ip->dsp_cuttype ); break;
00599     }
00600 
00601 
00602     VSETALL(pt, 0.0);
00603 
00604     MAT4X3PNT(v, dsp_ip->dsp_stom, pt);
00605 
00606     bu_vls_printf( vls, " (origin at %g %g %g)mm\n", V3INTCLAMPARGS(v));
00607 
00608     bu_vls_printf( vls, "  stom=\n");
00609     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n", V4INTCLAMPARGS(dsp_ip->dsp_stom) );
00610     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n", V4INTCLAMPARGS( &dsp_ip->dsp_stom[4]) );
00611     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n", V4INTCLAMPARGS( &dsp_ip->dsp_stom[8]) );
00612     bu_vls_printf( vls, "  %8.3f %8.3f %8.3f %8.3f\n", V4INTCLAMPARGS( &dsp_ip->dsp_stom[12]) );
00613 }
00614 
00615 /**
00616  *                      R T _ D S P _ P R I N T
00617  */
00618 void
00619 rt_dsp_print(register const struct soltab *stp)
00620 {
00621         register const struct dsp_specific *dsp =
00622                 (struct dsp_specific *)stp->st_specific;
00623         struct bu_vls vls;
00624 
00625 
00626         RT_DSP_CK_MAGIC(dsp);
00627         BU_CK_VLS(&dsp->dsp_i.dsp_name);
00628 
00629         bu_vls_init( &vls );
00630         BU_CK_VLS(&vls);
00631 
00632         bu_vls_printf(&vls, "\n---------db version: %d----------\n",
00633                                                                 stp->st_rtip->rti_dbip->dbi_version );
00634 
00635         switch (stp->st_rtip->rti_dbip->dbi_version) {
00636         case 4:
00637                 BU_CK_VLS(&vls);
00638                 dsp_print_v4(&vls, &(dsp->dsp_i) );
00639                 break;
00640         case 5:
00641                 BU_CK_VLS(&vls);
00642                 dsp_print_v5(&vls, &(dsp->dsp_i) );
00643                 break;
00644         }
00645 
00646         bu_log("%s", bu_vls_addr( &vls));
00647 
00648         if (BU_VLS_IS_INITIALIZED( &vls )) bu_vls_free( &vls );
00649 
00650 }
00651 
00652 
00653 /**
00654  *      compute bounding boxes for each cell, then compute bounding boxes
00655  *      for collections of bounding boxes
00656  */
00657 static void
00658 dsp_layers(struct dsp_specific *dsp, unsigned short *d_min, unsigned short *d_max)
00659 {
00660         int idx, i, j, k, curr_layer, x, y, xs, ys, xv, yv, tot;
00661         unsigned short dsp_min, dsp_max, cell_min, cell_max;
00662         unsigned short elev;
00663         struct dsp_bb *dsp_bb;
00664         struct dsp_rpp *t;
00665         struct dsp_bb_layer *curr, *prev;
00666         unsigned short subcell_size;
00667 
00668         /* First we compute the total number of struct dsp_bb's we will need */
00669         xs = dsp->xsiz;
00670         ys = dsp->ysiz;
00671         tot = xs * ys;
00672         /*    bu_log("layer %d   %dx%d\n", 0, xs, ys); */
00673         dsp->layers = 1;
00674         while ( xs > 1 || ys > 1 ) {
00675                 xv = xs / DIM_BB_CHILDREN;
00676                 yv = ys / DIM_BB_CHILDREN;
00677                 if (xs % DIM_BB_CHILDREN) xv++;
00678                 if (ys % DIM_BB_CHILDREN) yv++;
00679 
00680 #ifdef FULL_DSP_DEBUGGING
00681                 if (RT_G_DEBUG & DEBUG_HF)
00682             bu_log("layer %d   %dx%d\n", dsp->layers, xv, yv);
00683 #endif
00684                 tot += xv * yv;
00685 
00686                 if (xv > 0) xs = xv;
00687                 else xs = 1;
00688 
00689                 if (yv > 0) ys = yv;
00690                 else ys = 1;
00691                 dsp->layers++;
00692         }
00693 
00694 
00695 #ifdef FULL_DSP_DEBUGGING
00696         if (RT_G_DEBUG & DEBUG_HF)
00697                 bu_log("%d layers total\n", dsp->layers);
00698 #endif
00699 
00700         /* allocate the struct dsp_bb's we will need */
00701         dsp->layer = bu_malloc(dsp->layers * sizeof(struct dsp_bb_layer),
00702                                                                                                  "dsp_bb_layers array");
00703         dsp->bb_array = bu_malloc(tot * sizeof(struct dsp_bb), "dsp_bb array");
00704 
00705         /* now we fill in the "lowest" layer of struct dsp_bb's from the
00706          * raw data
00707          */
00708         dsp->layer[0].dim[X] = dsp->xsiz;
00709         dsp->layer[0].dim[Y] = dsp->ysiz;
00710         dsp->layer[0].p = dsp->bb_array;
00711 
00712         xs = dsp->xsiz;
00713         ys = dsp->ysiz;
00714 
00715         dsp_min = 0xffff;
00716         dsp_max = 0;
00717 
00718         for (y=0 ; y < YSIZ(dsp) ; y++) {
00719 
00720                 cell_min = 0xffff;
00721                 cell_max = 0;
00722 
00723                 for (x=0 ; x < XSIZ(dsp) ; x++) {
00724 
00725 #if 0
00726             if (RT_G_DEBUG & DEBUG_HF)
00727                                 bu_log("filling %d,%d\n", x, y);
00728 #endif
00729             elev = DSP(&dsp->dsp_i, x, y);
00730             cell_min = cell_max = elev;
00731 
00732             elev = DSP(&dsp->dsp_i, x+1, y);
00733             V_MIN(cell_min, elev);
00734             V_MAX(cell_max, elev);
00735 
00736             elev = DSP(&dsp->dsp_i, x, y+1);
00737             V_MIN(cell_min, elev);
00738             V_MAX(cell_max, elev);
00739 
00740             elev = DSP(&dsp->dsp_i, x+1, y+1);
00741             V_MIN(cell_min, elev);
00742             V_MAX(cell_max, elev);
00743 
00744             /* factor the cell min/max into the overall min/max */
00745             V_MIN(dsp_min, cell_min);
00746             V_MAX(dsp_max, cell_max);
00747 
00748             /* fill in the dsp_rpp cell min/max */
00749             i = y*XSIZ(dsp) + x;
00750             dsp_bb = &dsp->layer[0].p[i];
00751             VSET(dsp_bb->dspb_rpp.dsp_min, x, y, cell_min);
00752             VSET(dsp_bb->dspb_rpp.dsp_max, x+1, y+1, cell_max);
00753 
00754             dsp_bb->dspb_subcell_size = 0;
00755 
00756             /* There are no "children" of a layer 0 element */
00757             dsp_bb->dspb_ch_dim[X] = 0;
00758             dsp_bb->dspb_ch_dim[Y] = 0;
00759             for (k=0 ; k < NUM_BB_CHILDREN ; k++ ) {
00760                                 dsp_bb->dspb_children[k] =
00761                                         (struct dsp_bb *)NULL;
00762             }
00763             dsp_bb->magic = MAGIC_dsp_bb;
00764 #if 0
00765             dlog("cell %d,%d min: %d,%d,%d  max: %d,%d,%d\n",
00766                                          x, y, V3ARGS(dsp_bb->dspb_rpp.dsp_min),
00767                                          V3ARGS(dsp_bb->dspb_rpp.dsp_max) );
00768 #endif
00769 
00770             /* XXX should we compute the triangle orientation and
00771              * save it here too?
00772              */
00773                 }
00774         }
00775 
00776         *d_min = dsp_min;
00777         *d_max = dsp_max;
00778 
00779 
00780         if (RT_G_DEBUG & DEBUG_HF)
00781                 bu_log("layer 0 filled\n");
00782 
00783         subcell_size = 1;
00784 
00785         /* now we compute successive layers from the initial layer */
00786         for (curr_layer = 1 ; curr_layer < dsp->layers ; curr_layer++ ) {
00787                 /* compute the number of cells in each direction for this layer */
00788 
00789                 xs = dsp->layer[curr_layer-1].dim[X];
00790                 if (xs % DIM_BB_CHILDREN)
00791             dsp->layer[curr_layer].dim[X] =
00792                                 xs / DIM_BB_CHILDREN + 1;
00793                 else
00794             dsp->layer[curr_layer].dim[X] =
00795                                 xs / DIM_BB_CHILDREN;
00796 
00797                 ys = dsp->layer[curr_layer-1].dim[Y];
00798                 if (ys % DIM_BB_CHILDREN)
00799             dsp->layer[curr_layer].dim[Y] =
00800                                 ys / DIM_BB_CHILDREN + 1;
00801                 else
00802             dsp->layer[curr_layer].dim[Y] =
00803                                 ys / DIM_BB_CHILDREN;
00804 
00805                 /* set the start of the array for this layer */
00806                 dsp->layer[curr_layer].p =
00807             &dsp->layer[curr_layer-1].p[dsp->layer[curr_layer-1].dim[X] *       dsp->layer[curr_layer-1].dim[Y] ];
00808 
00809                 curr = &dsp->layer[curr_layer];
00810                 prev = &dsp->layer[curr_layer-1];
00811 
00812                 if (RT_G_DEBUG & DEBUG_HF)
00813             bu_log("layer %d  subcell size %d\n", curr_layer, subcell_size);
00814 
00815                 /* walk the grid and fill in the values for this layer */
00816                 for (y=0 ; y < curr->dim[Y] ; y++ ) {
00817             for (x=0 ; x < curr->dim[X] ; x++ ) {
00818                                 int n, xp, yp;
00819                                 /* x,y are in the coordinates in the current
00820                                  * layer.  xp,yp are the coordinates of the
00821                                  * same area in the previous (lower) layer.
00822                                  */
00823                                 xp = x * DIM_BB_CHILDREN;
00824                                 yp = y * DIM_BB_CHILDREN;
00825 
00826                                 /* initialize the current dsp_bb cell */
00827                                 dsp_bb = &curr->p[y*curr->dim[X]+x];
00828                                 dsp_bb->magic = MAGIC_dsp_bb;
00829                                 n = (int)pow( (double)DIM_BB_CHILDREN, (double)curr_layer);
00830                                 VSET(dsp_bb->dspb_rpp.dsp_min,
00831                                                  x * n, y * n, 0x0ffff);
00832                                 VSET(dsp_bb->dspb_rpp.dsp_max,
00833                                                  x * n, y * n, 0);
00834 
00835                                 /* record the dimensions of our children */
00836                                 dsp_bb->dspb_subcell_size = subcell_size;
00837 
00838 
00839                                 tot = 0;
00840 #if 0
00841                                 dlog("  cell %d,%d  (%d,%d-%d,%d)\n", x, y,
00842                                                  dsp_bb->dspb_rpp.dsp_min[X],
00843                                                  dsp_bb->dspb_rpp.dsp_min[Y],
00844                                                  (x+1) * n, (y+1)*n);
00845 #endif
00846                                 i=0;
00847                                 for (j=0 ; j<DIM_BB_CHILDREN && (yp+j)<prev->dim[Y] ; j++) {
00848                                         for (i=0 ; i<DIM_BB_CHILDREN && (xp+i)<prev->dim[X]; i++) {
00849 
00850                                                 idx = (yp+j) * prev->dim[X] + xp+i;
00851 
00852                                                 t = &prev->p[ idx ].dspb_rpp;
00853 
00854                                                 VMINMAX(dsp_bb->dspb_rpp.dsp_min,
00855                                                                                 dsp_bb->dspb_rpp.dsp_max, t->dsp_min);
00856                                                 VMINMAX(dsp_bb->dspb_rpp.dsp_min,
00857                                                                                 dsp_bb->dspb_rpp.dsp_max, t->dsp_max);
00858 
00859                                                 dsp_bb->dspb_children[tot++] = &prev->p[ idx ];
00860 
00861 #if 0
00862                                                 dlog("\t\tsubcell %d,%d min: %d,%d,%d  max: %d,%d,%d\n",
00863                                                                  xp+i, yp+j, V3ARGS(t->dsp_min), V3ARGS(t->dsp_max) );
00864 
00865                                                 if (RT_G_DEBUG & DEBUG_HF)
00866                                                         if (i+1 >= DIM_BB_CHILDREN || xp+i+1 >= prev->dim[X])
00867                                                                 bu_log("\n");
00868 #endif
00869                                         }
00870                                 }
00871 #if 0
00872                                 dlog("\t\txy: %d,%d, ij:%d,%d min:%d,%d,%d max:%d,%d,%d\n",
00873                                                  x, y, i, j,
00874                                                  V3ARGS(dsp_bb->dspb_rpp.dsp_min),
00875                                                  V3ARGS(dsp_bb->dspb_rpp.dsp_max) );
00876 #endif
00877 
00878                                 dsp_bb->dspb_ch_dim[X] = i;
00879                                 dsp_bb->dspb_ch_dim[Y] = j;
00880             }
00881                 }
00882                 subcell_size *= DIM_BB_CHILDREN;
00883         }
00884 
00885 #ifdef PLOT_LAYERS
00886         if (RT_G_DEBUG & DEBUG_HF) {
00887                 plot_layers(dsp);
00888                 bu_log("_  x:%d y:%d min %d max %d\n",
00889                                          XCNT(dsp), YCNT(dsp), dsp_min, dsp_max);
00890         }
00891 #endif
00892 }
00893 
00894 
00895 /**
00896  *                      R T _ D S P _ P R E P
00897  *
00898  *  Given a pointer to a GED database record, and a transformation matrix,
00899  *  determine if this is a valid DSP, and if so, precompute various
00900  *  terms of the formula.
00901  *
00902  *  Returns -
00903  *      0       DSP is OK
00904  *      !0      Error in description
00905  *
00906  *  Implicit return -
00907  *      A struct dsp_specific is created, and it's address is stored in
00908  *      stp->st_specific for use by dsp_shot().
00909  */
00910 int
00911 rt_dsp_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00912 {
00913         struct rt_dsp_internal          *dsp_ip;
00914         register struct dsp_specific    *dsp;
00915         unsigned short dsp_min, dsp_max;
00916         point_t pt, bbpt;
00917         vect_t work;
00918         fastf_t f;
00919 
00920         if (RT_G_DEBUG & DEBUG_HF)
00921                 bu_log("rt_dsp_prep()\n");
00922 
00923         RT_CK_DB_INTERNAL(ip);
00924         dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
00925         RT_DSP_CK_MAGIC(dsp_ip);
00926         BU_CK_VLS(&dsp_ip->dsp_name);
00927 
00928         switch (dsp_ip->dsp_datasrc) {
00929         case RT_DSP_SRC_V4_FILE:
00930         case RT_DSP_SRC_FILE:
00931                 BU_CK_MAPPED_FILE(dsp_ip->dsp_mp);
00932 
00933                 /* we do this here and now because we will need it for the
00934                  * dsp_specific structure in a few lines
00935                  */
00936                 bu_semaphore_acquire( RT_SEM_MODEL);
00937                 ++dsp_ip->dsp_mp->uses;
00938                 bu_semaphore_release( RT_SEM_MODEL);
00939                 break;
00940         case RT_DSP_SRC_OBJ:
00941                 RT_CK_DB_INTERNAL(dsp_ip->dsp_bip);
00942                 RT_CK_BINUNIF(dsp_ip->dsp_bip->idb_ptr);
00943                 break;
00944         }
00945 
00946 
00947         BU_GETSTRUCT( dsp, dsp_specific );
00948         stp->st_specific = (genptr_t) dsp;
00949 
00950         /* this works ok, because the mapped file keeps track of the number of
00951          * uses.  However, the binunif interface does not.  We'll
00952          * have to copy the data for that one.
00953          */
00954         dsp->dsp_i = *dsp_ip;           /* struct copy */
00955 
00956         /* this keeps the binary internal object from being freed */
00957         dsp_ip->dsp_bip = (struct rt_db_internal *)NULL;
00958 
00959 
00960         dsp->xsiz = dsp_ip->dsp_xcnt-1; /* size is # cells or values-1 */
00961         dsp->ysiz = dsp_ip->dsp_ycnt-1; /* size is # cells or values-1 */
00962 
00963 
00964         /* compute the multi-resolution bounding boxes */
00965         dsp_layers(dsp, &dsp_min, &dsp_max);
00966 
00967 
00968         /* record the distance to each of the bounding planes */
00969         dsp->dsp_pl_dist[XMIN] = 0.0;
00970         dsp->dsp_pl_dist[XMAX] = (fastf_t)dsp->xsiz;
00971         dsp->dsp_pl_dist[YMIN] = 0.0;
00972         dsp->dsp_pl_dist[YMAX] = (fastf_t)dsp->ysiz;
00973         dsp->dsp_pl_dist[ZMIN] = 0.0;
00974         dsp->dsp_pl_dist[ZMAX] = (fastf_t)dsp_max;
00975         dsp->dsp_pl_dist[ZMID] = (fastf_t)dsp_min;
00976 
00977         /* compute enlarged bounding box and spere */
00978 
00979 #define BBOX_PT(_x, _y, _z) \
00980         VSET(pt, (fastf_t)_x, (fastf_t)_y, (fastf_t)_z); \
00981         MAT4X3PNT(bbpt, dsp_ip->dsp_stom, pt); \
00982         VMINMAX( stp->st_min, stp->st_max, bbpt)
00983 
00984         BBOX_PT(-.1,                -.1,                        -.1);
00985         BBOX_PT(dsp_ip->dsp_xcnt+.1, -.1,                       -.1);
00986         BBOX_PT(dsp_ip->dsp_xcnt+.1, dsp_ip->dsp_ycnt+.1, -1);
00987         BBOX_PT(-.1,                dsp_ip->dsp_ycnt+.1, -1);
00988         BBOX_PT(-.1,                -.1,                        dsp_max+.1);
00989         BBOX_PT(dsp_ip->dsp_xcnt+.1, -.1,                       dsp_max+.1);
00990         BBOX_PT(dsp_ip->dsp_xcnt+.1, dsp_ip->dsp_ycnt+.1, dsp_max+.1);
00991         BBOX_PT(-.1,                dsp_ip->dsp_ycnt+.1, dsp_max+.1);
00992 
00993 #undef BBOX_PT
00994 
00995         VADD2SCALE( stp->st_center, stp->st_min, stp->st_max, 0.5 );
00996         VSUB2SCALE( work, stp->st_max, stp->st_min, 0.5 );
00997 
00998         f = work[X];
00999         if (work[Y] > f )  f = work[Y];
01000         if (work[Z] > f )  f = work[Z];
01001         stp->st_aradius = f;
01002         stp->st_bradius = MAGNITUDE(work);
01003 
01004         if (RT_G_DEBUG & DEBUG_HF) {
01005                 bu_log("  model space bbox (%g %g %g) (%g %g %g)\n",
01006                                          V3ARGS(stp->st_min),
01007                                          V3ARGS(stp->st_max));
01008         }
01009 
01010 
01011         switch (dsp_ip->dsp_datasrc) {
01012         case RT_DSP_SRC_V4_FILE:
01013         case RT_DSP_SRC_FILE:
01014                 BU_CK_MAPPED_FILE(dsp->dsp_i.dsp_mp);
01015                 break;
01016         case RT_DSP_SRC_OBJ:
01017                 RT_CK_DB_INTERNAL(dsp->dsp_i.dsp_bip);
01018                 RT_CK_BINUNIF(dsp->dsp_i.dsp_bip->idb_ptr);
01019                 break;
01020         }
01021 
01022         return 0;
01023 }
01024 
01025 static void
01026 plot_seg(struct isect_stuff *isect,
01027                                  struct hit *in_hit,
01028                                  struct hit *out_hit,
01029                                  const point_t bbmin,/* The bounding box of what you are adding ... */
01030                                  const point_t bbmax,/* ... */
01031                                  int r, int g, int b)/* ... this is strictly for debug plot purposes */
01032 {
01033         fastf_t *stom = &isect->dsp->dsp_i.dsp_stom[0];
01034         struct bound_rpp rpp;
01035         char fname[32];
01036         FILE *fp;
01037         static int segnum =0;
01038 
01039         /* plot the bounding box and the seg */
01040         bu_semaphore_acquire( BU_SEM_SYSCALL);
01041         sprintf(fname, "dsp_seg%04d.pl", segnum++);
01042         fp=fopen(fname, "w");
01043         bu_semaphore_release( BU_SEM_SYSCALL);
01044 
01045         if (fp != (FILE *)NULL) {
01046                 bu_log("plotting %s\n", fname);
01047 
01048                 MAT4X3PNT(rpp.min, stom, bbmin);
01049                 MAT4X3PNT(rpp.max, stom, bbmax);
01050                 plot_rpp(fp, &rpp, r/2, g/2, b/2);
01051 
01052                 /* re-use the rpp for the points for the segment */
01053                 MAT4X3PNT(rpp.min, stom, in_hit->hit_point);
01054                 MAT4X3PNT(rpp.max, stom, out_hit->hit_point);
01055 
01056                 pl_color(fp, r, g, b);
01057                 pdv_3line(fp, rpp.min, rpp.max);
01058 
01059                 bu_semaphore_acquire( BU_SEM_SYSCALL);
01060                 fclose(fp);
01061                 bu_semaphore_release( BU_SEM_SYSCALL);
01062         }
01063 }
01064 
01065 /**     A D D _ S E G
01066  *
01067  *  Add a segment to the list of intersections in DSP space
01068  *
01069  *      Return:
01070  *      0       continue to intersect
01071  *      1       All intersections computed, terminate intersection processing
01072  */
01073 #define ADD_SEG(isect, in, out, min, max, r, g, b) \
01074         add_seg(isect, in, out, min, max, r, g, b, __LINE__)
01075 
01076 
01077 static int
01078 add_seg(struct isect_stuff *isect,
01079         struct hit *in_hit,
01080         struct hit *out_hit,
01081         const point_t bbmin,/* The bounding box of what you are adding ... */
01082         const point_t bbmax,/* ... */
01083         int r, int g, int b,/* ... this is strictly for debug plot purposes */
01084         int line)
01085 
01086 {
01087     struct seg *seg;
01088     double tt = isect->tol->dist;
01089     double delta;
01090 #ifndef ORDERED_ISECT
01091     struct bu_list *spot;
01092 #endif
01093 
01094     dlog("add_seg %g %g line %d vpriv:%g %g\n", in_hit->hit_dist, out_hit->hit_dist, line, in_hit->hit_vpriv[X], in_hit->hit_vpriv[Y]);
01095 
01096     tt *= tt;
01097 
01098 #ifdef ORDERED_ISECT
01099     if (BU_LIST_NON_EMPTY(&isect->seglist) ) {
01100         /* if the new in-distance equals the old out distance
01101          * we just extend the old segment
01102          */
01103         seg = BU_LIST_LAST(seg, &isect->seglist);
01104         if ( fabs(seg->seg_out.hit_dist - in_hit->hit_dist) <= tt) {
01105 
01106 #if 0
01107             seg->seg_out = *out_hit; /* struct copy  most expensive line */
01108             seg->seg_out.hit_magic = RT_HIT_MAGIC;
01109 #else
01110             seg->seg_out.hit_dist = out_hit->hit_dist;
01111             seg->seg_out.hit_surfno = out_hit->hit_surfno;
01112             VMOVE(seg->seg_out.hit_normal, out_hit->hit_normal);
01113 #endif
01114             if (out_hit->hit_surfno == ZTOP) {
01115                 seg->seg_out.hit_vpriv[X] = out_hit->hit_vpriv[X];
01116                 seg->seg_out.hit_vpriv[Y] = out_hit->hit_vpriv[Y];
01117             }
01118             seg->seg_out.hit_vpriv[Z] = 1.0; /* flag as out-hit */
01119 
01120             if (RT_G_DEBUG & DEBUG_HF) {
01121                 bu_log("extending previous seg to %g\n", out_hit->hit_dist);
01122                 plot_seg(isect, in_hit, out_hit, bbmin, bbmax, r, g, b);
01123             }
01124             return 0;
01125         }
01126     }
01127 #else
01128     /* insert the segment in the list by in-hit distance */
01129     dlog("searching for insertion point for seg w in/out dist %g %g\n",
01130                in_hit->hit_dist, out_hit->hit_dist);
01131 
01132     for ( BU_LIST_FOR(seg, seg, &isect->seglist) ) {
01133         dlog("checking %g->%g seg\n", seg->seg_in.hit_dist,
01134              seg->seg_out.hit_dist);
01135         /* found the spot for this one */
01136         if ( fabs(seg->seg_out.hit_dist - in_hit->hit_dist) <= tt ) {
01137             seg->seg_out = *out_hit; /* struct copy */
01138             seg->seg_out.hit_magic = RT_HIT_MAGIC;
01139             seg->seg_out.hit_vpriv[Z] = 1.0; /* flag as out-hit */
01140 
01141             if (RT_G_DEBUG & DEBUG_HF) {
01142                 bu_log("extending previous seg to %g\n",
01143                        out_hit->hit_dist);
01144                 plot_seg(isect, in_hit, out_hit, bbmin, bbmax, r, g, b);
01145             }
01146             return 0;
01147         }
01148         if (in_hit->hit_dist < seg->seg_in.hit_dist) {
01149             spot = &seg->l;
01150             dlog("insert before this one\n");
01151             goto found_spot;
01152         }
01153     }
01154     spot = &isect->seglist;
01155     seg = BU_LIST_LAST(seg, &isect->seglist);
01156     dlog("insert at end\n");
01157  found_spot:
01158 #endif
01159 
01160 
01161     /* if both points are on the "floor" of the DSP, then we
01162      * don't have a hit segment
01163      */
01164     if (NEAR_ZERO(in_hit->hit_point[Z], isect->tol->dist) &&
01165         NEAR_ZERO(out_hit->hit_point[Z], isect->tol->dist) ) {
01166         return 0;
01167     }
01168 
01169     /* throw away any zero length segments,
01170      * mostly to avoid seeing inside-out segments
01171      */
01172     delta = out_hit->hit_dist - in_hit->hit_dist;
01173 
01174     if (delta == 0.0) {
01175         return 0;
01176     }
01177 
01178     /* if the segment is inside-out, we need to say something about it */
01179     if (delta < 0.0 && !NEAR_ZERO(delta, isect->tol->dist)) {
01180         bu_log(" %s:%dDSP:  Adding inside-out seg in:%g out:%g\n",
01181                __FILE__, __LINE__,
01182                in_hit->hit_dist, out_hit->hit_dist);
01183 
01184         VPRINT("\tin_pt", in_hit->hit_point);
01185         VPRINT("\tout_pt", out_hit->hit_point);
01186     }
01187 
01188 
01189 
01190 
01191     RT_GET_SEG(seg, isect->ap->a_resource);
01192 
01193 #if 0
01194     seg->seg_in = *in_hit; /* struct copy */
01195     seg->seg_in.hit_magic = RT_HIT_MAGIC;
01196     seg->seg_out = *out_hit; /* struct copy */
01197     seg->seg_out.hit_magic = RT_HIT_MAGIC;
01198 
01199 #else
01200     seg->seg_in.hit_dist    = in_hit->hit_dist;
01201     seg->seg_out.hit_dist   = out_hit->hit_dist;
01202 
01203     seg->seg_in.hit_surfno  = in_hit->hit_surfno;
01204     seg->seg_out.hit_surfno = out_hit->hit_surfno;
01205 
01206     VMOVE(seg->seg_in.hit_normal, in_hit->hit_normal);
01207     VMOVE(seg->seg_out.hit_normal, out_hit->hit_normal);
01208 
01209 #endif
01210     if (in_hit->hit_surfno >= ZMAX) {
01211         seg->seg_in.hit_vpriv[X] = in_hit->hit_vpriv[X];
01212         seg->seg_in.hit_vpriv[Y] = in_hit->hit_vpriv[Y];
01213     }
01214 
01215     if (out_hit->hit_surfno >= ZMAX) {
01216         seg->seg_out.hit_vpriv[X] = out_hit->hit_vpriv[X];
01217         seg->seg_out.hit_vpriv[Y] = out_hit->hit_vpriv[Y];
01218     }
01219 
01220     seg->seg_in.hit_vpriv[Z] = 0.0; /* flag as in-hit */
01221     seg->seg_out.hit_vpriv[Z] = 1.0; /* flag as out-hit */
01222 
01223     seg->seg_stp = isect->stp;
01224 
01225 #ifdef FULL_DSP_DEBUGGING
01226     if (VDOT(seg->seg_in.hit_normal, isect->r.r_dir) > 0 ) {
01227         bu_log("----------------------------------------------------------\n");
01228         bu_log("pixel %d,%d bogus seg in, inward normal\nN: %g %g %g\nd: %g %g %g\n",
01229                isect->ap->a_x, isect->ap->a_y,
01230                V3ARGS(seg->seg_in.hit_normal), V3ARGS(isect->r.r_dir) );
01231         bu_bomb("");
01232     }
01233     if (VDOT(seg->seg_out.hit_normal, isect->r.r_dir) < 0 ) {
01234         bu_log("----------------------------------------------------------\n");
01235         bu_log("pixel %d,%d bogus seg out, inward normal\nN: %g %g %g\nd: %g %g %g\n",
01236                isect->ap->a_x, isect->ap->a_y,
01237                V3ARGS(seg->seg_out.hit_normal), V3ARGS(isect->r.r_dir) );
01238         bu_bomb("");
01239     }
01240 #endif
01241 
01242 #ifdef ORDERED_ISECT
01243     BU_LIST_INSERT(&isect->seglist, &seg->l);
01244 #else
01245     BU_LIST_INSERT(spot, &seg->l);
01246 #endif
01247 
01248 
01249 
01250 
01251     if (RT_G_DEBUG & DEBUG_HF)
01252         plot_seg(isect, in_hit, out_hit, bbmin, bbmax, r, g, b);
01253 
01254 
01255     if (seg->seg_in.hit_dist > 0.0 || seg->seg_out.hit_dist > 0.0) {
01256         return (++isect->num_segs > isect->ap->a_onehit);
01257     }
01258     return 0;
01259 }
01260 
01261 
01262 /**     I S E C T _ R A Y _ T R I A N G L E
01263  *
01264  * Side Effects:
01265  *      dist and P may be set
01266  *
01267  * Return:
01268  *      1       Ray intersects triangle
01269  *      0       Ray misses triangle
01270  *      -1      Ray/plane parallel
01271  */
01272 static int
01273 isect_ray_triangle(struct isect_stuff *isect,
01274                    point_t A,
01275                    point_t B,
01276                    point_t C,
01277                    struct hit *hitp,
01278                    double alphabbeta[])
01279 {
01280     point_t P;          /* plane intercept point */
01281     vect_t AB, AC, AP;
01282     plane_t N;          /* Normal for plane of triangle */
01283     double NdotDir;
01284     double alpha, beta; /* barycentric distances */
01285     double hitdist;     /* distance to ray/trianlge intercept */
01286     double toldist;     /* distance tolerance from isect->tol */
01287 
01288 #ifdef FULL_DSP_DEBUGGING
01289     if (RT_G_DEBUG & DEBUG_HF) {
01290         fastf_t *stom = &isect->dsp->dsp_i.dsp_stom[0];
01291 
01292         MAT4X3PNT(P, stom, A);
01293         bu_log("isect_ray_triangle...\n  A %g %g %g  (%g %g %g)\n",
01294                V3ARGS(A), V3ARGS(P));
01295 
01296         MAT4X3PNT(P, stom, B);
01297         bu_log("  B %g %g %g  (%g %g %g)\n",
01298                V3ARGS(B), V3ARGS(P));
01299 
01300         MAT4X3PNT(P, stom, C);
01301         bu_log("  C %g %g %g  (%g %g %g)\n",
01302                V3ARGS(C), V3ARGS(P));
01303 
01304     }
01305 #endif
01306     VSUB2(AB, B, A);
01307     VSUB2(AC, C, A);
01308 
01309     /* Compute the plane equation of the triangle */
01310     VCROSS(N, AB, AC);
01311     VUNITIZE(N);
01312     N[H] = VDOT(N, A);
01313 
01314 
01315     /* intersect ray with plane */
01316     NdotDir = VDOT(N, isect->r.r_dir);
01317     if ( BN_VECT_ARE_PERP(NdotDir, isect->tol) ) {
01318         /* Ray perpendicular to plane of triangle */
01319         return -1;
01320     }
01321 
01322     /* dist to plane icept */
01323     hitdist = (N[H]-VDOT(N, isect->r.r_pt)) / NdotDir;
01324 
01325     VJOIN1(P, isect->r.r_pt, hitdist, isect->r.r_dir);
01326 
01327 #ifdef FULL_DSP_DEBUGGING
01328     if (RT_G_DEBUG & DEBUG_HF) {
01329         FILE *fp;
01330         char buf[32];
01331         static int plotnum = 0;
01332         fastf_t *stom = &isect->dsp->dsp_i.dsp_stom[0];
01333         point_t p1, p2;
01334 
01335         bu_semaphore_acquire( BU_SEM_SYSCALL);
01336         sprintf(buf, "dsp_tri%03d.pl", plotnum++);
01337         fp=fopen(buf, "w");
01338         bu_semaphore_release( BU_SEM_SYSCALL);
01339 
01340         if ( fp == (FILE *)NULL) {
01341             bu_log("%s:%d error opening \"%s\"\n", __FILE__, __LINE__, buf);
01342             bu_bomb("");
01343         } else
01344             bu_log("  plotting %s\n", buf);
01345 
01346 
01347         pl_color(fp, 255, 255, 255);
01348         MAT4X3PNT(p1, stom, A); pdv_3move(fp, p1);
01349         MAT4X3PNT(p2, stom, B); pdv_3cont(fp, p2);
01350         MAT4X3PNT(p2, stom, C); pdv_3cont(fp, p2);
01351         pdv_3cont(fp, p1);
01352 
01353         /* plot the ray */
01354         pl_color(fp, 255, 255, 0);
01355         MAT4X3PNT(p1, stom, P);
01356         MAT4X3PNT(p2, stom, isect->r.r_pt);
01357         pdv_3line(fp, p1, p2);
01358 
01359         bu_semaphore_acquire( BU_SEM_SYSCALL);
01360         fclose(fp);
01361         bu_semaphore_release( BU_SEM_SYSCALL);
01362 
01363         bu_log("  dist:%g plane point: %g %g %g\n", hitdist, V3ARGS(p2));
01364     }
01365 #endif
01366     /* We project the system into the XY plane at this point to determine
01367      * if the ray_plane_isect_pt is within the bounds of the triangle
01368      *
01369      * The general idea here is to project the vector AP onto both sides of the
01370      * triangle.  The distances along each side can be used to determine if
01371      * we are inside/outside the triangle.
01372      *
01373      *    VSUB2(AP, P, A);
01374      *    alpha = VDOT(AP, AB);
01375      *    beta = VDOT(AP, AC);
01376      *
01377      *            C
01378      *            |
01379      *            |
01380      *            |
01381      *----        |--- P
01382      *  |         |   /
01383      *  |         |  / |
01384      * alpha      | /  |
01385      *  |         |/   |
01386      *----        A---------B
01387      *
01388      *              b
01389      *            |-e--|
01390      *              t
01391      *              a
01392      *
01393      *  To save on computation, we do this calculation in 2D.
01394      *
01395      * See: "Graphics Gems",  Andrew S. Glassner ed.  PP390-393 for details
01396      */
01397 
01398     toldist = isect->tol->dist;
01399 
01400 
01401     VSUB2(AP, P, A);
01402 #ifdef FULL_DSP_DEBUGGING
01403     if (RT_G_DEBUG & DEBUG_HF) {
01404         VPRINT("  AP", AP);
01405         VPRINT("  AB", AB);
01406         VPRINT("  AC", AC);
01407     }
01408 #endif
01409     /*  Oridnarily, in 2D we would say:
01410      *
01411      *    beta = AB[X] * AP[X] + AB[Y] * AP[Y];
01412      *    alpha = AC[X] * AP[X] + AC[Y] * AP[Y];
01413      *
01414      *  However, in this case, we know that AB and AC will always be
01415      *  axis-aligned, so we can short-cut.
01416      *  XXX consider: we know that AB and AC
01417      *  will be unit length, so only the sign counts.
01418      */
01419 
01420     if (AB[X] == 0) {
01421         beta = AB[Y] * AP[Y];
01422     } else {
01423         beta = AB[X] * AP[X];
01424     }
01425 
01426     if (AC[X] == 0) {
01427         alpha = AC[Y] * AP[Y];
01428     } else {
01429         alpha = AC[X] * AP[X];
01430     }
01431 
01432     /* return 1 if we hit the triangle */
01433     alphabbeta[0] = alpha;
01434     alphabbeta[1] = beta;
01435 
01436 #ifdef FULL_DSP_DEBUGGING
01437     if (alpha < -toldist ) {
01438         dlog("alpha < 0\n");
01439         return 0;
01440     }
01441     if (beta < -toldist ) {
01442         dlog("beta < 0\n");
01443         return 0;
01444     }
01445     if ( (alpha+beta) > (1.0 + toldist) ) {
01446         dlog("alpha+beta > 1\n");
01447         return 0;
01448     }
01449 #else
01450     if (alpha < -toldist || beta < -toldist || (alpha+beta) > (1.0 + toldist))
01451         return 0;
01452 #endif
01453 
01454     hitp->hit_dist = hitdist;
01455     VMOVE(hitp->hit_normal, N);
01456     VMOVE(hitp->hit_point, P);
01457     return 1;
01458 }
01459 
01460 /**     P E R M U T E _ C E L L
01461  *
01462  *      For adaptive diagonal selection or for Upper-Left to lower right
01463  *      cell cut, we must permute the verticies of the cell before handing
01464  *      them to the intersection algorithm.  That's what this function does.
01465  */
01466 static int
01467 permute_cell(point_t A,
01468              point_t B,
01469              point_t C,
01470              point_t D,
01471              struct dsp_specific *dsp,
01472              struct dsp_rpp *dsp_rpp)
01473 {
01474     int x, y;
01475 
01476 
01477 #ifdef FULL_DSP_DEBUGGING
01478     if (RT_G_DEBUG & DEBUG_HF) {
01479         VPRINT("\tA", A);
01480         VPRINT("\tB", B);
01481         VPRINT("\tC", C);
01482         VPRINT("\tD", D);
01483     }
01484 #endif
01485 
01486     switch (dsp->dsp_i.dsp_cuttype) {
01487     case DSP_CUT_DIR_llUR:
01488         return  DSP_CUT_DIR_llUR;
01489         break;
01490 
01491     case DSP_CUT_DIR_ADAPT: {
01492         int lo[2], hi[2];
01493         point_t tmp;
01494         double h1, h2, h3, h4;
01495         double cAD, cBC;  /* curvature in direction AD, and BC */
01496 
01497         if (RT_G_DEBUG & DEBUG_HF)
01498             bu_log("cell %d,%d adaptive triangulation... ",
01499                    dsp_rpp->dsp_min[X],
01500                    dsp_rpp->dsp_min[Y]);
01501 
01502         /*
01503          *  We look at the points in the diagonal next cells to determine
01504          *  the curvature along each diagonal of this cell.  This cell is
01505          *  divided into two triangles by cutting across the cell in the
01506          *  direction of least curvature.
01507          *
01508          *      *  *  *  *
01509          *       \      /
01510          *        \C  D/
01511          *      *  *--*  *
01512          *         |\/|
01513          *         |/\|
01514          *      *  *--*  *
01515          *        /A  B\
01516          *       /      \
01517          *      *  *  *  *
01518          */
01519 
01520         lo[X] = dsp_rpp->dsp_min[X] - 1;
01521         lo[Y] = dsp_rpp->dsp_min[Y] - 1;
01522         hi[X] = dsp_rpp->dsp_max[X] + 1;
01523         hi[Y] = dsp_rpp->dsp_max[Y] + 1;
01524 
01525         /* a little bounds checking */
01526         if (lo[X] < 0) lo[X] = 0;
01527         if (lo[Y] < 0) lo[Y] = 0;
01528         if (hi[X] > dsp->xsiz)
01529             hi[X] = dsp->xsiz;
01530 
01531         if (hi[Y] > dsp->ysiz)
01532             hi[Y] = dsp->ysiz;
01533 
01534         /* compute curvature along the A->D direction */
01535         h1 = DSP(&dsp->dsp_i, lo[X], lo[Y]);
01536         h2 = A[Z];
01537         h3 = D[Z];
01538         h4 = DSP(&dsp->dsp_i, hi[X], hi[Y]);
01539 
01540         cAD = fabs(h3 + h1 - 2*h2 ) + fabs( h4 + h2 - 2*h3 );
01541 
01542 
01543         /* compute curvature along the B->C direction */
01544         h1 = DSP(&dsp->dsp_i, hi[X], lo[Y]);
01545         h2 = B[Z];
01546         h3 = C[Z];
01547         h4 = DSP(&dsp->dsp_i, lo[X], hi[Y]);
01548 
01549         cBC = fabs(h3 + h1 - 2*h2 ) + fabs( h4 + h2 - 2*h3 );
01550 
01551         if ( cAD < cBC ) {
01552             /* A-D cut is fine, no need to permute */
01553             if (RT_G_DEBUG & DEBUG_HF)
01554                 bu_log("A-D cut\n");
01555 
01556             return  DSP_CUT_DIR_llUR;
01557 
01558         }
01559 
01560         /* prefer the B-C cut */
01561         VMOVE(tmp, A);
01562         VMOVE(A, B);
01563         VMOVE(B, D);
01564         VMOVE(D, C);
01565         VMOVE(C, tmp);
01566         if (RT_G_DEBUG & DEBUG_HF)
01567             bu_log("B-C cut\n");
01568 
01569         return  DSP_CUT_DIR_ULlr;
01570 
01571         break;
01572     }
01573     case DSP_CUT_DIR_ULlr:
01574         /* assign the values for the corner points
01575          *
01576          *  D----C
01577          *  |    |
01578          *  |    |
01579          *  |    |
01580          *  B----A
01581          */
01582         x = dsp_rpp->dsp_min[X];
01583         y = dsp_rpp->dsp_min[Y];
01584         VSET(B, x, y, DSP(&dsp->dsp_i, x, y) );
01585 
01586         x = dsp_rpp->dsp_max[X];
01587         VSET(A, x, y, DSP(&dsp->dsp_i, x, y) );
01588 
01589         y = dsp_rpp->dsp_max[Y];
01590         VSET(C, x, y, DSP(&dsp->dsp_i, x, y) );
01591 
01592         x = dsp_rpp->dsp_min[X];
01593         VSET(D, x, y, DSP(&dsp->dsp_i, x, y) );
01594 
01595         return DSP_CUT_DIR_ULlr;
01596         break;
01597     }
01598     bu_log("%s:%d Unknown DSP cut direction: %d\n",
01599            __FILE__, __LINE__, dsp->dsp_i.dsp_cuttype);
01600     bu_bomb("");
01601     /* not reached */
01602     return -1;
01603 }
01604 
01605 /**
01606  *      C H E C K _ B B _ E L E V A T I O N
01607  *
01608  *      determine if a point P is above/below the slope line on the
01609  *      bounding box.  eg:
01610  *
01611  *      Bounding box side view:
01612  *
01613  *      +-------+
01614  *      |       |
01615  *      |       *       Determine if P ( or Q ) is above the
01616  *      |      /|       diagonal from the two * points at the corners
01617  *      | P.  / |       of the bounding box.
01618  *      |    /  |
01619  *      |   /   |
01620  *      |  /  . |
01621  *      | /   Q |
01622  *      |/      |
01623  *      *       |
01624  *      |       |
01625  *      +-------+
01626  *
01627  *      Return
01628  *              0 if pt above line (such as P in diagram)
01629  *              1 if pt at/below line (such as Q in diagram)
01630  */
01631 static int
01632 check_bbpt_hit_elev(int i,      /* indicates face of cell */
01633                     point_t A,
01634                     point_t B,
01635                     point_t C,
01636                     point_t D,
01637                     point_t P)
01638 {
01639     double slope = 0.0;
01640     double delta = 0.0;
01641     double origin = 0.0;
01642 
01643 #ifdef FULL_DSP_DEBUGGING
01644     dlog("check_bbpt_hit_elev(");
01645 #endif
01646     switch (i) {
01647     case XMIN:
01648         /* the minimal YZ plane.  Top view:     *   *
01649          *                                      |
01650          *                                      *   *
01651          */
01652 #ifdef FULL_DSP_DEBUGGING
01653         dlog("XMIN)\n");
01654 #endif
01655         slope = C[Z] - A[Z];
01656         delta = P[Y] - A[Y];
01657         origin = A[Z];
01658         break;
01659     case XMAX:
01660         /* the maximal YZ plane.   Top view:    *   *
01661          *                                          |
01662          *                                      *   *
01663          */
01664 #ifdef FULL_DSP_DEBUGGING
01665         dlog("XMAX)\n");
01666 #endif
01667         slope = D[Z] - B[Z];
01668         delta = P[Y] - B[Y];
01669         origin = B[Z];
01670         break;
01671     case YMIN:
01672         /* the minimal XZ plane.   Top view:    *   *
01673          *
01674          *                                      * - *
01675          */
01676 #ifdef FULL_DSP_DEBUGGING
01677         dlog("YMIN)\n");
01678 #endif
01679         slope = B[Z] - A[Z];
01680         delta = P[X] - A[X];
01681         origin = A[Z];
01682         break;
01683     case YMAX:
01684         /* the maximal XZ plane.   Top view:    * - *
01685          *
01686          *                                      *   *
01687          */
01688 #ifdef FULL_DSP_DEBUGGING
01689         dlog("YMAX)\n");
01690 #endif
01691         slope = D[Z] - C[Z];
01692         delta = P[X] - C[X];
01693         origin = C[Z];
01694         break;
01695     case ZMIN:
01696 #ifdef FULL_DSP_DEBUGGING
01697         dlog("ZMIN)\n");
01698 #endif
01699         return 1;
01700         break;
01701     case ZMAX:
01702 #ifdef FULL_DSP_DEBUGGING
01703         dlog("ZMAX)\n");
01704 #endif
01705         return 0;
01706         break;
01707     default:
01708         bu_log("%s:%d Coding error, bad face %d\n", __FILE__, __LINE__, i);
01709         bu_bomb("");
01710         break;
01711     }
01712 
01713     if ( (origin + slope * delta) < P[Z] ) return 0;
01714 
01715     return 1;
01716 }
01717 
01718 /*
01719  *      I S E C T _ R A Y _ C E L L _ T O P
01720  *
01721  *  Return
01722  *      0       continue intesection calculations
01723  *      1       Terminate intesection computation
01724  */
01725 static int
01726 isect_ray_cell_top(struct isect_stuff *isect, struct dsp_bb *dsp_bb)
01727 {
01728     point_t A, B, C, D, P;
01729     int x, y;
01730     double ab_first[2], ab_second[2];
01731     struct hit hits[4]; /* list of hits that are valid */
01732     struct hit *hitp;
01733     int hitf = 0;       /* bit flags for valid hits in hits */
01734     int cond, i;
01735     int hitcount = 0;
01736     point_t bbmin, bbmax;
01737     double dot, dot2;
01738 
01739 
01740     dlog("isect_ray_cell_top\n");
01741     DSP_BB_CK(dsp_bb);
01742 
01743     /* assign the values for the corner points
01744      *
01745      *  C----D
01746      *  |    |
01747      *  |    |
01748      *  |    |
01749      *  A----B
01750      */
01751     x = dsp_bb->dspb_rpp.dsp_min[X];
01752     y = dsp_bb->dspb_rpp.dsp_min[Y];
01753     VSET(A, x, y, DSP(&isect->dsp->dsp_i, x, y) );
01754 
01755     x = dsp_bb->dspb_rpp.dsp_max[X];
01756     VSET(B, x, y, DSP(&isect->dsp->dsp_i, x, y) );
01757 
01758     y = dsp_bb->dspb_rpp.dsp_max[Y];
01759     VSET(D, x, y, DSP(&isect->dsp->dsp_i, x, y) );
01760 
01761     x = dsp_bb->dspb_rpp.dsp_min[X];
01762     VSET(C, x, y, DSP(&isect->dsp->dsp_i, x, y) );
01763 
01764 
01765 #ifdef DEBUG_FULL
01766     if (RT_G_DEBUG & DEBUG_HF) {
01767         point_t p1, p2;
01768 
01769         VJOIN1(p1, isect->r.r_pt, isect->r.r_min, isect->r.r_dir);
01770         VMOVE(hits[0].hit_point, p1);
01771         hits[0].hit_dist = isect->r.r_min;
01772 
01773         VJOIN1(p2, isect->r.r_pt, isect->r.r_max, isect->r.r_dir);
01774         VMOVE(hits[1].hit_point, p2);
01775         hits[1].hit_dist = isect->r.r_max;
01776 
01777         plot_cell_top(isect, dsp_bb, A, B, C, D, hits, 3, 0);
01778     }
01779 #endif
01780 
01781 
01782     /* first order of business is to discard any "fake" hits on the
01783      * bounding box, and fill in any "real" hits in our list
01784      */
01785     VJOIN1(P, isect->r.r_pt, isect->r.r_min, isect->r.r_dir);
01786     if ( check_bbpt_hit_elev(isect->dmin, A, B, C, D, P) ) {
01787         hits[0].hit_dist = isect->r.r_min;
01788         VMOVE(hits[0].hit_point, P);
01789         VMOVE(hits[0].hit_normal, dsp_pl[isect->dmin]);
01790         /* vpriv */
01791         hits[0].hit_vpriv[X] = dsp_bb->dspb_rpp.dsp_min[X];
01792         hits[0].hit_vpriv[Y] = dsp_bb->dspb_rpp.dsp_min[Y];
01793         /* private */
01794         hits[0].hit_surfno = isect->dmin;
01795 
01796         hitcount++;
01797 
01798         hitf = 1;
01799         if (RT_G_DEBUG & DEBUG_HF) {
01800             dot = VDOT(hits[0].hit_normal, isect->r.r_dir);
01801             bu_log("hit ray/bb min  Normal: %g %g %g %s\n",
01802                    V3ARGS(hits[0].hit_normal),
01803                    ((dot > 0.0) ? "outbound" : "inbound"));
01804         }
01805     } else {
01806         dlog("miss ray/bb min\n");
01807     }
01808 
01809 
01810     /* make sure the point P is below the cell top */
01811     VJOIN1(P, isect->r.r_pt, isect->r.r_max, isect->r.r_dir);
01812     if (check_bbpt_hit_elev(isect->dmax, A, B, C, D, P) ) {
01813         /* P is at or below the top surface */
01814         hits[3].hit_dist = isect->r.r_max;
01815         VMOVE(hits[3].hit_point, P);
01816         VMOVE(hits[3].hit_normal, dsp_pl[isect->dmax]);
01817         /* vpriv */
01818         hits[3].hit_vpriv[X] = dsp_bb->dspb_rpp.dsp_min[X];
01819         hits[3].hit_vpriv[Y] = dsp_bb->dspb_rpp.dsp_min[Y];
01820         /* private */
01821         hits[3].hit_surfno = isect->dmax;
01822 
01823         hitcount++;
01824 
01825         hitf |= 8;
01826         if (RT_G_DEBUG & DEBUG_HF) {
01827             dot = VDOT(hits[3].hit_normal, isect->r.r_dir);
01828             bu_log("hit ray/bb max  Normal: %g %g %g  %s\n",
01829                    V3ARGS(hits[3].hit_normal),
01830                    ((dot > 0.0) ? "outbound" : "inbound"));
01831         }
01832     } else {
01833         dlog("miss ray/bb max\n");
01834     }
01835 
01836 
01837 
01838     (void)permute_cell(A, B, C, D, isect->dsp, &dsp_bb->dspb_rpp);
01839 
01840     if ((cond=isect_ray_triangle(isect, B, D, A, &hits[1], ab_first)) > 0.0){
01841         /* hit triangle */
01842 
01843         /* record cell */
01844         hits[1].hit_vpriv[X] = dsp_bb->dspb_rpp.dsp_min[X];
01845         hits[1].hit_vpriv[Y] = dsp_bb->dspb_rpp.dsp_min[Y];
01846         hits[1].hit_surfno = ZTOP; /* indicate we hit the top */
01847 
01848         hitcount++;
01849         hitf |= 2;
01850         dlog("  hit triangle 1 (alpha: %g beta:%g alpha+beta: %g) vpriv %g %g\n",
01851              ab_first[0], ab_first[1], ab_first[0] + ab_first[1],
01852              hits[1].hit_vpriv[X], hits[1].hit_vpriv[Y]);
01853     } else {
01854         dlog("  miss triangle 1 (alpha: %g beta:%g a+b: %g) cond:%d\n",
01855              ab_first[0], ab_first[1], ab_first[0] + ab_first[1], cond);
01856     }
01857     if ((cond=isect_ray_triangle(isect, C, A, D, &hits[2], ab_second)) > 0.0) {
01858         /* hit triangle */
01859 
01860         /* record cell */
01861         hits[2].hit_vpriv[X] = dsp_bb->dspb_rpp.dsp_min[X];
01862         hits[2].hit_vpriv[Y] = dsp_bb->dspb_rpp.dsp_min[Y];
01863         hits[2].hit_surfno = ZTOP; /* indicate we hit the top */
01864 
01865         hitcount++;
01866 
01867         hitf |= 4;
01868         dlog("  hit triangle 2 (alpha: %g beta:%g alpha+beta: %g) vpriv %g %g\n",
01869              ab_second[0], ab_second[1], ab_second[0] + ab_second[1],
01870              hits[2].hit_vpriv[X], hits[2].hit_vpriv[Y]);
01871 
01872         if (hitf & 2) {
01873             /* if this hit occurs before the hit on the other triangle
01874              * swap the order
01875              */
01876             if (hits[1].hit_dist > hits[2].hit_dist) {
01877                 struct hit tmp;
01878                 tmp = hits[1]; /* struct copy */
01879                 hits[1] = hits[2]; /* struct copy */
01880                 hits[2] = tmp; /* struct copy */
01881                 dlog("re-ordered triangle hits\n");
01882 
01883             } else
01884                 dlog("triangle hits in order\n");
01885         }
01886 
01887 
01888     } else {
01889         dlog("  miss triangle 2 (alpha: %g beta:%g alpha+beta: %g) cond:%d\n",
01890              ab_second[0], ab_second[1], ab_second[0] + ab_second[1], cond);
01891     }
01892 
01893     if (RT_G_DEBUG & DEBUG_HF) {
01894         bu_log("hitcount: %d flags: 0x%0x\n", hitcount, hitf);
01895 
01896         plot_cell_top(isect, dsp_bb, A, B, C, D, hits, hitf, 1);
01897         for (i=0 ; i < 4 ; i++) {
01898             if (hitf & (1<<i)) {
01899                 double v = VDOT(isect->r.r_dir, hits[i].hit_normal);
01900 
01901                 bu_log("%d dist:%g N:%g %g %g ",
01902                        i, hits[i].hit_dist, V3ARGS(hits[i].hit_normal));
01903 
01904                 if (v > 0.0) bu_log("outbound\n");
01905                 else if (v < 0.0)  bu_log("inbound\n");
01906                 else bu_log("perp\n");
01907             }
01908         }
01909         bu_log("assembling segs\n");
01910     }
01911 
01912 
01913     /* fill out the segment structures */
01914 
01915     hitp = 0;
01916     for (i = 0 ; i < 4 ; i++ ) {
01917         if (hitf & (1<<i)) {
01918             if (hitp) {
01919 
01920                 dot2 = VDOT(isect->r.r_dir, hits[i].hit_normal);
01921 
01922                 /* if we have two entry points then pick the first one */
01923                 if ( dot2 < 0.0 ) {
01924                     dlog("dot2(%g) < 0.0\n", dot2);
01925                     if (hitp->hit_dist > hits[i].hit_dist) {
01926                         dlog("skipping duplicate entry point at dist %g\n",
01927                              hitp->hit_dist);
01928 
01929                         hitp = &hits[i];
01930                     } else {
01931                         dlog("skipping duplicate entry point at dist %g\n",
01932                              hits[i].hit_dist);
01933                     }
01934 
01935                     continue;
01936                 }
01937 
01938                 /* create seg with hits[i].hit_point); as out point */
01939                 if (RT_G_DEBUG & DEBUG_HF) {
01940                     /* int/float conv */
01941                     VMOVE(bbmin, dsp_bb->dspb_rpp.dsp_min);
01942                     VMOVE(bbmax, dsp_bb->dspb_rpp.dsp_max);
01943                 }
01944 
01945                 if (ADD_SEG(isect, hitp, &hits[i], bbmin, bbmax,255, 255, 255))
01946                     return 1;
01947 
01948                 hitp = 0;
01949             } else {
01950                 dot = VDOT(isect->r.r_dir, hits[i].hit_normal);
01951                 if (dot >= 0.0)
01952                     continue;
01953 
01954                 /* remember hits[i].hit_point); as in point */
01955                 if (RT_G_DEBUG & DEBUG_HF) {
01956                     bu_log("in-hit at dist %g\n", hits[i].hit_dist);
01957                 }
01958                 hitp = &hits[i];
01959             }
01960         }
01961     }
01962 
01963     if (hitp && hitcount > 1) {
01964         point_t p1, p2;
01965 
01966         bu_log("----------------ERROR incomplete segment-------------\n");
01967         bu_log("  pixel %d %d\n", isect->ap->a_x, isect->ap->a_y);
01968 
01969         VJOIN1(p1, isect->r.r_pt, isect->r.r_min, isect->r.r_dir);
01970         VMOVE(hits[0].hit_point, p1);
01971         hits[0].hit_dist = isect->r.r_min;
01972 
01973         VJOIN1(p2, isect->r.r_pt, isect->r.r_max, isect->r.r_dir);
01974         VMOVE(hits[1].hit_point, p2);
01975         hits[1].hit_dist = isect->r.r_max;
01976 
01977         if (RT_G_DEBUG & DEBUG_HF)
01978             plot_cell_top(isect, dsp_bb, A, B, C, D, hits, 3, 0);
01979     }
01980     return 0;
01981 }
01982 
01983 /**
01984  *                      D S P _ I N _ R P P
01985  *
01986  *  Compute the intersections of a ray with a rectangular parallelpiped (RPP)
01987  *  that has faces parallel to the coordinate planes
01988  *
01989  *  The algorithm here was developed by Gary Kuehl for GIFT.
01990  *  A good description of the approach used can be found in
01991  *  "??" by XYZZY and Barsky,
01992  *  ACM Transactions on Graphics, Vol 3 No 1, January 1984.
01993  *
01994  * Note -
01995  *  The computation of entry and exit distance is mandatory, as the final
01996  *  test catches the majority of misses.
01997  *
01998  * Note -
01999  *  A hit is returned if the intersect is behind the start point.
02000  *
02001  *  Returns -
02002  *       0  if ray does not hit RPP,
02003  *      !0  if ray hits RPP.
02004  *
02005  *  Implicit return -
02006  *      rp->r_min = dist from start of ray to point at which ray ENTERS solid
02007  *      rp->r_max = dist from start of ray to point at which ray LEAVES solid
02008  *      isect->dmin
02009  *      isect->dmax
02010  */
02011 int
02012 dsp_in_rpp(struct isect_stuff *isect,
02013            register const fastf_t *min,
02014            register const fastf_t *max)
02015 {
02016     struct xray         *rp = &isect->r;
02017     /* inverses of rp->r_dir[] */
02018     register const fastf_t *invdir = isect->inv_dir;
02019     register const fastf_t      *pt = &rp->r_pt[0];
02020     register fastf_t    sv;
02021     register fastf_t    rmin = -INFINITY;
02022     register fastf_t    rmax =  INFINITY;
02023     int dmin = -1;
02024     int dmax = -1;
02025 
02026     /* Start with infinite ray, and trim it down */
02027 
02028     /* X axis */
02029     if( *invdir < 0.0 )  {
02030         /* Heading towards smaller numbers */
02031         /* if( *min > *pt )  miss */
02032         if(rmax > (sv = (*min - *pt) * *invdir) ) {
02033             rmax = sv;
02034             dmax = XMIN;
02035         }
02036         if( rmin < (sv = (*max - *pt) * *invdir) ) {
02037             rmin = sv;
02038             dmin = XMAX;
02039         }
02040     }  else if( *invdir > 0.0 )  {
02041         /* Heading towards larger numbers */
02042         /* if( *max < *pt )  miss */
02043         if (rmax > (sv = (*max - *pt) * *invdir) ) {
02044             rmax = sv;
02045             dmax = XMAX;
02046         }
02047         if( rmin < ((sv = (*min - *pt) * *invdir)) ) {
02048             rmin = sv;
02049             dmin = XMIN;
02050         }
02051     }  else  {
02052         /*
02053          *  Direction cosines along this axis is NEAR 0,
02054          *  which implies that the ray is perpendicular to the axis,
02055          *  so merely check position against the boundaries.
02056          */
02057         if( (*min > *pt) || (*max < *pt) )
02058             return(0);  /* MISS */
02059     }
02060 
02061     /* Y axis */
02062     pt++; invdir++; max++; min++;
02063     if( *invdir < 0.0 )  {
02064         if (rmax > (sv = (*min - *pt) * *invdir) ) {
02065             /* towards smaller */
02066             rmax = sv;
02067             dmax = YMIN;
02068         }
02069         if (rmin < (sv = (*max - *pt) * *invdir) ) {
02070             rmin = sv;
02071             dmin = YMAX;
02072         }
02073     }  else if( *invdir > 0.0 )  {
02074         /* towards larger */
02075         if(rmax > (sv = (*max - *pt) * *invdir) ) {
02076             rmax = sv;
02077             dmax = YMAX;
02078         }
02079         if( rmin < ((sv = (*min - *pt) * *invdir)) ) {
02080             rmin = sv;
02081             dmin = YMIN;
02082         }
02083     }  else  {
02084         if( (*min > *pt) || (*max < *pt) )
02085             return(0);  /* MISS */
02086     }
02087 
02088     /* Z axis */
02089     pt++; invdir++; max++; min++;
02090     if( *invdir < 0.0 )  {
02091         /* towards smaller */
02092         if(rmax > (sv = (*min - *pt) * *invdir) ) {
02093             rmax = sv;
02094             dmax = ZMIN;
02095         }
02096         if( rmin < (sv = (*max - *pt) * *invdir) ) {
02097             rmin = sv;
02098             dmin = ZMAX;
02099         }
02100     }  else if( *invdir > 0.0 )  {
02101         /* towards larger */
02102         if(rmax > (sv = (*max - *pt) * *invdir) ) {
02103             rmax = sv;
02104             dmax = ZMAX;
02105         }
02106         if( rmin < ((sv = (*min - *pt) * *invdir)) ) {
02107             rmin = sv;
02108             dmin = ZMIN;
02109         }
02110     }  else  {
02111         if( (*min > *pt) || (*max < *pt) )
02112             return(0);  /* MISS */
02113     }
02114 
02115     /* If equal, RPP is actually a plane */
02116     if( rmin > rmax )
02117         return(0);      /* MISS */
02118 
02119     /* HIT.  Only now do rp->r_min and rp->r_max have to be written */
02120     rp->r_min = rmin;
02121     rp->r_max = rmax;
02122 
02123     isect->dmin = dmin;
02124     isect->dmax = dmax;
02125     return(1);          /* HIT */
02126 }
02127 #ifdef ORDERED_ISECT
02128 static int
02129 isect_ray_dsp_bb(struct isect_stuff *isect, struct dsp_bb *dsp_bb);
02130 
02131 /**
02132  *      R E C U R S E _ D S P _ B B
02133  *
02134  *  Return
02135  *      0       continue intesection calculations
02136  *      1       Terminate intesection computation
02137  */
02138 static int
02139 recurse_dsp_bb(struct isect_stuff *isect,
02140                struct dsp_bb *dsp_bb,
02141                point_t minpt, /* entry point of dsp_bb */
02142                point_t maxpt, /* exit point of dsp_bb */
02143                point_t bbmin, /* min point of bb (Z=0) */
02144                point_t bbmax) /* max point of bb */
02145 {
02146     double      tDX;            /* dist along ray to span 1 cell in X dir */
02147     double      tDY;            /* dist along ray to span 1 cell in Y dir */
02148     double      tX, tY;         /* dist from hit pt. to next cell boundary */
02149     double      curr_dist;
02150     short       cX, cY;         /* coordinates of current cell */
02151     short       cs;             /* cell X,Y dimension */
02152     short       stepX, stepY;   /* dist to step in child array for each dir */
02153     short       stepPX, stepPY;
02154     double      out_dist;
02155     struct dsp_bb **p;
02156     fastf_t *stom = &isect->dsp->dsp_i.dsp_stom[0];
02157     point_t pt, v;
02158     int loop = 0;
02159 
02160     DSP_BB_CK(dsp_bb);
02161 
02162     /* compute the size of a cell in each direction */
02163     cs = dsp_bb->dspb_subcell_size;
02164 
02165     /* compute current cell */
02166     cX = (minpt[X] - bbmin[X]) / cs;
02167     cY = (minpt[Y] - bbmin[Y]) / cs;
02168 
02169     /* a little bounds checking because a hit on XMAX or YMAX looks like
02170      * it should be in the next cell outside the box
02171      */
02172     if (cX >= dsp_bb->dspb_ch_dim[X]) cX = dsp_bb->dspb_ch_dim[X] - 1;
02173     if (cY >= dsp_bb->dspb_ch_dim[Y]) cY = dsp_bb->dspb_ch_dim[Y] - 1;
02174 
02175 #ifdef FULL_DSP_DEBUGGING
02176     dlog("recurse_dsp_bb  cell size: %d  current cell: %d %d\n",
02177          cs, cX, cY);
02178     dlog("dspb_ch_dim x:%d  y:%d\n",
02179          dsp_bb->dspb_ch_dim[X], dsp_bb->dspb_ch_dim[Y]);
02180 #endif
02181 
02182     tX = tY = curr_dist = isect->r.r_min;
02183 
02184     if (isect->r.r_dir[X] < 0.0) {
02185         stepPX = stepX = -1;
02186         /* tDX is the distance along the ray we have to travel
02187          * to traverse a cell (travel a unit distance) along the
02188          * X axis of the grid
02189          */
02190         tDX = -cs / isect->r.r_dir[X];
02191 
02192         /* tX is the distance along the ray to the first cell
02193          * boundary in the X direction beyond our hit point (minpt)
02194          */
02195         tX += ( (bbmin[X] + (cX * cs)) - minpt[X]) / isect->r.r_dir[X];
02196     } else {
02197         stepPX = stepX = 1;
02198         tDX = cs / isect->r.r_dir[X];
02199 
02200         if (isect->r.r_dir[X] > 0.0)
02201             tX += ((bbmin[X] + ((cX+1) * cs)) - minpt[X]) / isect->r.r_dir[X];
02202         else
02203             tX = MAX_FASTF; /* infinite distance to next X boundary */
02204     }
02205 
02206     if (isect->r.r_dir[Y] < 0) {
02207         /* distance in dspb_children we have to move to step in Y dir */
02208         stepY = -1;
02209         stepPY = -dsp_bb->dspb_ch_dim[X];
02210         tDY = -cs / isect->r.r_dir[Y];
02211         tY += ( (bbmin[Y] + (cY * cs)) - minpt[Y]) / isect->r.r_dir[Y];
02212     } else {
02213         stepY = 1;
02214         stepPY = dsp_bb->dspb_ch_dim[X];
02215         tDY = cs / isect->r.r_dir[Y];
02216 
02217         if (isect->r.r_dir[Y] > 0.0)
02218             tY += ((bbmin[Y] + ((cY+1) * cs)) - minpt[Y]) / isect->r.r_dir[Y];
02219         else
02220             tY = MAX_FASTF;
02221     }
02222 
02223     /* factor in the tolerance to the out-distance */
02224     out_dist = isect->r.r_max - isect->tol->dist;
02225 
02226     p = &dsp_bb->dspb_children[dsp_bb->dspb_ch_dim[X] * cY + cX];
02227 #ifdef FULL_DSP_DEBUGGING
02228     dlog("tX:%g tY:%g\n", tX, tY);
02229 
02230 #endif
02231 
02232     do {
02233         /* intersect with the current cell */
02234         if (RT_G_DEBUG & DEBUG_HF) {
02235             if (loop)
02236                 bu_log("\nisect sub-cell %d %d  in dist:%g ",
02237                        cX, cY, curr_dist, out_dist);
02238             else {
02239                 bu_log("isect sub-cell %d %d  in dist:%g ",
02240                        cX, cY, curr_dist, out_dist);
02241                 loop = 1;
02242             }
02243             VJOIN1(pt, isect->r.r_pt, curr_dist, isect->r.r_dir);
02244             MAT4X3PNT(v, stom, pt);
02245             bu_log("pt %g %g %g\n", V3ARGS(v));
02246         }
02247 
02248         /* get pointer to the current child cell.  Note the extra level
02249          * of indirection.  We want to march p through dspb_children using
02250          * pointer addition, but dspb_children contains pointers.  We need
02251          * to be sure to increment the offset in the array, not the child
02252          * pointer.
02253          */
02254 
02255         if (RT_G_DEBUG & DEBUG_HF)
02256             bu_log_indent_delta(4);
02257 
02258         if (isect_ray_dsp_bb(isect, *p)) return 1;
02259 
02260         if (RT_G_DEBUG & DEBUG_HF)
02261             bu_log_indent_delta(-4);
02262 
02263         /* figure out which cell is next */
02264         if (tX < tY) {
02265             cX += stepX;  /* track cell offset for debugging */
02266             p += stepPX;
02267 #ifdef FULL_DSP_DEBUGGING
02268             dlog("stepping X to %d because %g < %g\n", cX, tX, tY);
02269 #endif
02270             curr_dist = tX;
02271             tX += tDX;
02272         } else {
02273             cY += stepY;  /* track cell offset for debugging */
02274             p += stepPY;
02275 #ifdef FULL_DSP_DEBUGGING
02276             dlog("stepping Y to %d because %g >= %g\n", cY, tX, tY);
02277 #endif
02278             curr_dist = tY;
02279             tY += tDY;
02280         }
02281 #ifdef FULL_DSP_DEBUGGING
02282         dlog("curr_dist %g, out_dist %g\n", curr_dist, out_dist);
02283 #endif
02284     } while ( curr_dist < out_dist &&
02285               cX < dsp_bb->dspb_ch_dim[X] && cX >= 0 &&
02286               cY < dsp_bb->dspb_ch_dim[Y] && cY >= 0 );
02287 
02288     return 0;
02289 }
02290 #endif
02291 
02292 /**
02293  *      I S E C T _ R A Y _ D S P _ B B
02294  *
02295  *  Intersect a ray with a DSP bounding box.  This is the primary child of
02296  *  rt_dsp_shot()
02297  *
02298  *  Return
02299  *      0       continue intesection calculations
02300  *      1       Terminate intesection computation
02301  */
02302 static int
02303 isect_ray_dsp_bb(struct isect_stuff *isect, struct dsp_bb *dsp_bb)
02304 {
02305     point_t bbmin, bbmax;
02306     point_t minpt, maxpt;
02307     double min_z;
02308     /* the rest of these support debugging output */
02309     FILE *fp;
02310     static int plotnum;
02311     fastf_t *stom;
02312     point_t pt;
02313     struct xray *r = &isect->r; /* Does this buy us anything? */
02314 
02315     if (dsp_bb) {
02316         DSP_BB_CK(dsp_bb);
02317     } else {
02318         bu_log("%s:%d null ptr pixel %d %d\n",
02319                __FILE__, __LINE__, isect->ap->a_x,  isect->ap->a_y);
02320         bu_bomb("");
02321     }
02322 
02323     if (RT_G_DEBUG & DEBUG_HF) {
02324         bu_log("\nisect_ray_dsp_bb( (%d,%d,%d) (%d,%d,%d))\n",
02325                V3ARGS(dsp_bb->dspb_rpp.dsp_min),
02326                V3ARGS(dsp_bb->dspb_rpp.dsp_max));
02327     }
02328 
02329     /* check to see if we miss the RPP for this area entirely */
02330     VMOVE(bbmax, dsp_bb->dspb_rpp.dsp_max);
02331     VSET(bbmin,
02332          dsp_bb->dspb_rpp.dsp_min[X],
02333          dsp_bb->dspb_rpp.dsp_min[Y], 0.0);
02334 
02335 
02336     if ( ! dsp_in_rpp(isect, bbmin, bbmax) ) {
02337         /* missed it all, just return */
02338 
02339         if (RT_G_DEBUG & DEBUG_HF) {
02340             bu_log("missed... ");
02341             fclose(draw_dsp_bb(&plotnum, dsp_bb, isect->dsp, 0, 150, 0));
02342         }
02343 
02344         return 0;
02345     }
02346 
02347     /* At this point we know that we've hit the overall bounding box */
02348 
02349     VJOIN1(minpt, r->r_pt, r->r_min, r->r_dir);
02350     VJOIN1(maxpt, r->r_pt, r->r_max, r->r_dir);
02351     /* We could do the following:
02352      *
02353      * however, we only need the Z values now, and benchmarking show
02354      * that this is an expensive
02355      */
02356     if (RT_G_DEBUG & DEBUG_HF) {
02357 
02358         stom = &isect->dsp->dsp_i.dsp_stom[0];
02359 
02360         bu_log("hit b-box ");
02361         fp = draw_dsp_bb(&plotnum, dsp_bb, isect->dsp, 200, 200, 100);
02362 
02363         pl_color(fp, 150, 150, 255);
02364         MAT4X3PNT(pt, stom, minpt);
02365         pdv_3move(fp, pt);
02366         MAT4X3PNT(pt, stom, maxpt);
02367         pdv_3cont(fp, pt);
02368 
02369         fclose(fp);
02370     }
02371 
02372 
02373     /* if both hits are UNDER the top of the "foundation" pillar, we can
02374      * just add a segment for that range and return
02375      */
02376     min_z = dsp_bb->dspb_rpp.dsp_min[Z];
02377 
02378     if (minpt[Z] < min_z && maxpt[Z] < min_z) {
02379         /* add hit segment */
02380         struct hit seg_in, seg_out;
02381 
02382         seg_in.hit_magic = RT_HIT_MAGIC;
02383         seg_in.hit_dist = r->r_min;
02384         VMOVE(seg_in.hit_point, minpt);
02385         VMOVE(seg_in.hit_normal, dsp_pl[isect->dmin]);
02386         /* hit_priv   */
02387         /* hit_private */
02388         seg_in.hit_surfno = isect->dmin;
02389         /* hit_rayp */
02390 
02391         seg_out.hit_dist = r->r_max;
02392 
02393         VMOVE(seg_out.hit_point, maxpt);
02394         VMOVE(seg_out.hit_normal, dsp_pl[isect->dmax]);
02395         /* hit_priv   */
02396         /* hit_private */
02397         seg_out.hit_surfno = isect->dmax;
02398         /* hit_rayp */
02399 
02400         if (RT_G_DEBUG & DEBUG_HF) {
02401             /* we need these for debug output
02402              * VMOVE(seg_in.hit_point, minpt);
02403              * VMOVE(seg_out.hit_point, maxpt);
02404              */
02405             /* create a special bounding box for plotting purposes */
02406             VMOVE(bbmax,  dsp_bb->dspb_rpp.dsp_max);
02407             VMOVE(bbmin,  dsp_bb->dspb_rpp.dsp_min);
02408             bbmax[Z] = bbmin[Z];
02409             bbmin[Z] = 0.0;
02410         }
02411 
02412         /* outta here */
02413         return (ADD_SEG(isect, &seg_in, &seg_out, bbmin, bbmax, 0, 255, 255));
02414     }
02415 
02416 
02417     /* We've hit something where we might be going through the
02418      * boundary.  We've got to intersect the children
02419      */
02420     if (dsp_bb->dspb_ch_dim[0]) {
02421 #ifdef ORDERED_ISECT
02422         return (recurse_dsp_bb(isect, dsp_bb, minpt, maxpt, bbmin, bbmax));
02423 #else
02424         int i;
02425         /* there are children, so we recurse */
02426         i = dsp_bb->dspb_ch_dim[X] * dsp_bb->dspb_ch_dim[Y] - 1;
02427         if (RT_G_DEBUG & DEBUG_HF)
02428             bu_log_indent_delta(4);
02429 
02430         for ( ; i >= 0 ; i--)
02431             isect_ray_dsp_bb(isect, dsp_bb->dspb_children[i]);
02432 
02433         if (RT_G_DEBUG & DEBUG_HF)
02434             bu_log_indent_delta(-4);
02435 
02436         return 0;
02437 
02438 #endif
02439     }
02440 
02441     /***********************************************************************
02442      *
02443      *   This section is for level 0 intersections only
02444      *
02445      ***********************************************************************/
02446 
02447     /* intersect the DSP grid surface geometry */
02448 
02449     /* Check for a hit on the triangulated zone on top.
02450      * This gives us intersections on the triangulated top, and the sides
02451      * and bottom of the bounding box for the triangles.
02452      *
02453      * We do this first because we already know that the ray does NOT
02454      * just pass through the "foundation " pillar underneath (see test above)
02455      */
02456     bbmin[Z] = dsp_bb->dspb_rpp.dsp_min[Z];
02457     if (dsp_in_rpp(isect, bbmin, bbmax) ) {
02458         /* hit rpp */
02459 
02460         isect_ray_cell_top(isect, dsp_bb);
02461     }
02462 
02463 
02464     /* check for hits on the "foundation" pillar under the top.
02465      * The ray may have entered through the top of the pillar, possibly
02466      * after having come down through the triangles above
02467      */
02468     bbmax[Z] = dsp_bb->dspb_rpp.dsp_min[Z];
02469     bbmin[Z] = 0.0;
02470     if (dsp_in_rpp(isect, bbmin, bbmax) ) {
02471         /* hit rpp */
02472         struct hit in_hit, out_hit;
02473 
02474         VJOIN1(minpt, r->r_pt, r->r_min, r->r_dir);
02475         VJOIN1(maxpt, r->r_pt, r->r_max, r->r_dir);
02476 
02477         in_hit.hit_dist = r->r_min;
02478         in_hit.hit_surfno = isect->dmin;
02479         VMOVE(in_hit.hit_point, minpt);
02480         VMOVE(in_hit.hit_normal, dsp_pl[isect->dmin]);
02481 
02482         out_hit.hit_dist = r->r_max;
02483         out_hit.hit_surfno = isect->dmax;
02484         VMOVE(out_hit.hit_point, maxpt);
02485         VMOVE(out_hit.hit_normal, dsp_pl[isect->dmax]);
02486 
02487         /* add a segment to the list */
02488         return (ADD_SEG(isect, &in_hit, &out_hit, bbmin, bbmax, 255, 255, 0));
02489     }
02490 
02491     return 0;
02492 }
02493 
02494 /**
02495  *                      R T _ D S P _ S H O T
02496  *
02497  *  Intersect a ray with a dsp.
02498  *  If an intersection occurs, a struct seg will be acquired
02499  *  and filled in.
02500  *
02501  *  Returns -
02502  *      0       MISS
02503  *      >0      HIT
02504  */
02505 int
02506 rt_dsp_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
02507 {
02508     register struct dsp_specific *dsp =
02509         (struct dsp_specific *)stp->st_specific;
02510     register struct seg *segp;
02511     int i;
02512     vect_t      dir;    /* temp storage */
02513     vect_t      v;
02514     struct isect_stuff isect;
02515     double      delta;
02516 
02517     RT_DSP_CK_MAGIC(dsp);
02518     BU_CK_VLS(&dsp->dsp_i.dsp_name);
02519 
02520     switch (dsp->dsp_i.dsp_datasrc) {
02521     case RT_DSP_SRC_V4_FILE:
02522     case RT_DSP_SRC_FILE:
02523         BU_CK_MAPPED_FILE(dsp->dsp_i.dsp_mp);
02524         break;
02525     case RT_DSP_SRC_OBJ:
02526         RT_CK_DB_INTERNAL(dsp->dsp_i.dsp_bip);
02527         RT_CK_BINUNIF(dsp->dsp_i.dsp_bip->idb_ptr);
02528         break;
02529     }
02530 
02531     /*
02532      * map ray into the coordinate system of the dsp
02533      */
02534     MAT4X3PNT(isect.r.r_pt, dsp->dsp_i.dsp_mtos, rp->r_pt);
02535     MAT4X3VEC(dir, dsp->dsp_i.dsp_mtos, rp->r_dir);
02536     VMOVE(isect.r.r_dir, dir);
02537     VUNITIZE(isect.r.r_dir);
02538 
02539     /* wrap a bunch of things together */
02540     isect.ap = ap;
02541     isect.stp = stp;
02542     isect.dsp = (struct dsp_specific *)stp->st_specific;
02543     isect.tol = &ap->a_rt_i->rti_tol;
02544     isect.num_segs = 0;
02545 
02546     VINVDIR(isect.inv_dir, isect.r.r_dir);
02547     BU_LIST_INIT(&isect.seglist);
02548 
02549 
02550     if (RT_G_DEBUG & DEBUG_HF) {
02551         bu_log("rt_dsp_shot(pt:(%g %g %g)\n\tdir[%g]:(%g %g %g))\n    pixel(%d,%d)\n",
02552                V3ARGS(rp->r_pt),
02553                MAGNITUDE(rp->r_dir),
02554                V3ARGS(rp->r_dir),
02555                ap->a_x, ap->a_y);
02556 
02557         bn_mat_print("mtos", dsp->dsp_i.dsp_mtos);
02558         bu_log("Solid space ray pt:(%g %g %g)\n", V3ARGS(isect.r.r_pt));
02559         bu_log("\tdir[%g]: [%g %g %g]\n\tunit_dir(%g %g %g)\n",
02560                MAGNITUDE(dir),
02561                V3ARGS(dir),
02562                V3ARGS(isect.r.r_dir));
02563     }
02564 
02565     /* We look at the topmost layer of the bounding-box tree and
02566      * make sure that it has dimension 1.  Otherwise, something is wrong
02567      */
02568     if (isect.dsp->layer[isect.dsp->layers-1].dim[X] != 1 ||
02569         isect.dsp->layer[isect.dsp->layers-1].dim[Y] != 1) {
02570         bu_log("%s:%d how do i find the topmost layer?\n",
02571                __FILE__, __LINE__);
02572         bu_bomb("");
02573     }
02574 
02575 
02576     /* intersect the ray with the bounding rpps */
02577     (void)isect_ray_dsp_bb(&isect, isect.dsp->layer[isect.dsp->layers-1].p);
02578 
02579     /* if we missed it all, give up now */
02580     if (BU_LIST_IS_EMPTY(&isect.seglist))
02581         return 0;
02582 
02583     /* map hit distances back to model space */
02584     i = 0;
02585     for (BU_LIST_FOR(segp, seg, &isect.seglist)) {
02586         i += 2;
02587         if (RT_G_DEBUG & DEBUG_HF) {
02588             bu_log("\nsolid in:%6g out:%6g\t",
02589                    segp->seg_in.hit_dist,
02590                    segp->seg_out.hit_dist);
02591         }
02592 
02593         /* form vector for hit point from start in solid space */
02594         VSCALE(dir, isect.r.r_dir, segp->seg_in.hit_dist);
02595         /* transform vector into model space */
02596         MAT4X3VEC(v, dsp->dsp_i.dsp_stom, dir);
02597         /* get magnitude */
02598         segp->seg_in.hit_dist = MAGNITUDE(v);
02599         /* XXX why is this necessary? */
02600         if (VDOT(v, rp->r_dir) < 0.0) segp->seg_in.hit_dist *= -1.0;
02601 
02602         VSCALE(dir, isect.r.r_dir, segp->seg_out.hit_dist);
02603         MAT4X3VEC(v, dsp->dsp_i.dsp_stom, dir);
02604         segp->seg_out.hit_dist = MAGNITUDE(v);
02605         if (VDOT(v, rp->r_dir) < 0.0) segp->seg_out.hit_dist *= -1.0;
02606 
02607 
02608         delta = segp->seg_out.hit_dist - segp->seg_in.hit_dist;
02609 
02610         if (delta < 0.0 && !NEAR_ZERO(delta, ap->a_rt_i->rti_tol.dist)) {
02611             bu_log("Pixel %d %d seg inside out in:%g out:%g seg_len:%g\n",
02612                    ap->a_x, ap->a_y, segp->seg_in.hit_dist, segp->seg_out.hit_dist,
02613                    delta);
02614         }
02615 
02616 #if 0
02617         /* transform normals into model space */
02618         MAT4X3VEC(v, dsp->dsp_i.dsp_mtos, segp->seg_in.hit_normal);
02619         VMOVE(segp->seg_in.hit_normal, v);
02620         VUNITIZE( segp->seg_in.hit_normal );
02621 
02622         MAT4X3VEC(v, dsp->dsp_i.dsp_mtos, segp->seg_out.hit_normal);
02623         VMOVE(segp->seg_out.hit_normal, v);
02624         VUNITIZE( segp->seg_out.hit_normal );
02625 #endif
02626         if (RT_G_DEBUG & DEBUG_HF) {
02627             bu_log("model in:%6g out:%6g\t",
02628                    segp->seg_in.hit_dist,
02629                    segp->seg_out.hit_dist);
02630         }
02631     }
02632 
02633     if (RT_G_DEBUG & DEBUG_HF) {
02634         double NdotD;
02635         double d;
02636         static const plane_t plane = {0.0, 0.0, -1.0, 0.0};
02637 
02638         NdotD = VDOT(plane, rp->r_dir);
02639         d = - ( (VDOT(plane, rp->r_pt) - plane[H]) / NdotD);
02640         bu_log("rp -> Z=0 dist: %g\n", d);
02641     }
02642 
02643     /* transfer list of hitpoints */
02644     BU_LIST_APPEND_LIST( &(seghead->l), &isect.seglist);
02645 
02646     return i;
02647 }
02648 
02649 #define RT_DSP_SEG_MISS(SEG)    (SEG).seg_stp=RT_SOLTAB_NULL
02650 
02651 /**
02652  *                      R T _ D S P _ V S H O T
02653  *
02654  *  Vectorized version.
02655  */
02656 void
02657 rt_dsp_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
02658                                        /* An array of solid pointers */
02659                                        /* An array of ray pointers */
02660                                     /* array of segs (results returned) */
02661                                        /* Number of ray/object pairs */
02662 
02663 {
02664     if (RT_G_DEBUG & DEBUG_HF)
02665         bu_log("rt_dsp_vshot()\n");
02666 
02667     (void)rt_vstub( stp, rp, segp, n, ap );
02668 }
02669 
02670 
02671 
02672 /***********************************************************************
02673  *
02674  * Compute the model-space normal at a gridpoint
02675  *
02676  */
02677 static void
02678 compute_normal_at_gridpoint(vect_t N,
02679                             struct dsp_specific *dsp,
02680                             int x,
02681                             int y,
02682                             FILE *fd,
02683                             int boolean,
02684                             double len)
02685 {
02686     /*  Gridpoint specified is "B" we compute normal by taking the
02687      *  cross product of the vectors  A->C, D->E
02688      *
02689      *          E
02690      *
02691      *          |
02692      *
02693      *  A   -   B   -   C
02694      *
02695      *          |
02696      *
02697      *          D
02698      */
02699 
02700     point_t A, C, D, E, tmp, pt, endpt;
02701     vect_t Vac, Vde;
02702 
02703     if (RT_G_DEBUG & DEBUG_HF) {
02704         bu_log("normal at %d %d\n", x, y);
02705         mat_print("\tstom", dsp->dsp_i.dsp_stom);
02706     }
02707     VSET(tmp, x, y, DSP(&dsp->dsp_i, x, y));
02708 
02709     if (x == 0) {       VMOVE(A, tmp); }
02710     else {              VSET(A, x-1, y, DSP(&dsp->dsp_i, x-1, y) );     }
02711 
02712     if (x >= XSIZ(dsp)) { VMOVE(C, tmp); }
02713     else {                VSET(C, x+1, y,  DSP(&dsp->dsp_i, x+1, y) );}
02714 
02715     if (y == 0) {       VMOVE(D, tmp); }
02716     else {              VSET(D, x, y-1, DSP(&dsp->dsp_i, x, y-1) );     }
02717 
02718     if (y >= YSIZ(dsp)) { VMOVE(E, tmp); }
02719     else {               VSET(E, x, y+1, DSP(&dsp->dsp_i, x, y+1) );    }
02720 
02721     MAT4X3PNT(pt, dsp->dsp_i.dsp_stom, tmp);
02722 
02723 
02724     /* Computing in world coordinates */
02725     VMOVE(tmp, A);
02726     MAT4X3PNT(A, dsp->dsp_i.dsp_stom, tmp);
02727 
02728     VMOVE(tmp, C);
02729     MAT4X3PNT(C, dsp->dsp_i.dsp_stom, tmp);
02730 
02731     VMOVE(tmp, D);
02732     MAT4X3PNT(D, dsp->dsp_i.dsp_stom, tmp);
02733 
02734     VMOVE(tmp, E);
02735     MAT4X3PNT(E, dsp->dsp_i.dsp_stom, tmp);
02736 
02737     VSUB2(Vac, C, A);
02738     VSUB2(Vde, E, D);
02739 
02740     VUNITIZE(Vac);
02741     VUNITIZE(Vde);
02742     VCROSS(N, Vac, Vde);
02743 
02744     if (RT_G_DEBUG & DEBUG_HF) {
02745         VPRINT("\tA", A);
02746         VPRINT("\tC", C);
02747         VPRINT("\tD", D);
02748         VPRINT("\tE", E);
02749         VPRINT("\tVac", Vac);
02750         VPRINT("\tVde", Vde);
02751         VPRINT("\tModel Cross N", N);
02752     }
02753     VUNITIZE(N);
02754 
02755     if (RT_G_DEBUG & DEBUG_HF) {
02756         VPRINT("\tModel Unit N", N);
02757     }
02758     if (fd) {
02759         VJOIN1(endpt, pt, len, N);
02760 
02761         pl_color(fd, 220, 220, 90);
02762         pdv_3line(fd, A, C);
02763         pdv_3line(fd, D, E);
02764 
02765         pdv_3line(fd, pt, endpt);
02766     }
02767 
02768 
02769 }
02770 
02771 /**
02772  *                      R T _ D S P _ N O R M
02773  *
02774  *  Given ONE ray distance, return the normal and entry/exit point.
02775  */
02776 void
02777 rt_dsp_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
02778 {
02779     vect_t N, t, tmp, A;
02780     struct dsp_specific *dsp = (struct dsp_specific *)stp->st_specific;
02781     vect_t Anorm, Bnorm, Dnorm, Cnorm, ABnorm, CDnorm;
02782     double Xfrac, Yfrac;
02783     int x, y;
02784     point_t pt;
02785     double dot;
02786     double len;
02787     FILE *fd = (FILE *)NULL;
02788 
02789 
02790     RT_DSP_CK_MAGIC(dsp);
02791     BU_CK_VLS(&dsp->dsp_i.dsp_name);
02792 
02793     switch (dsp->dsp_i.dsp_datasrc) {
02794     case RT_DSP_SRC_V4_FILE:
02795     case RT_DSP_SRC_FILE:
02796         BU_CK_MAPPED_FILE(dsp->dsp_i.dsp_mp);
02797         break;
02798     case RT_DSP_SRC_OBJ:
02799         RT_CK_DB_INTERNAL(dsp->dsp_i.dsp_bip);
02800         RT_CK_BINUNIF(dsp->dsp_i.dsp_bip->idb_ptr);
02801         break;
02802     }
02803 
02804     if (RT_G_DEBUG & DEBUG_HF) {
02805         bu_log("rt_dsp_norm(%g %g %g)\n", V3ARGS(hitp->hit_normal));
02806         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
02807         VPRINT("\thit point", hitp->hit_point);
02808         bu_log("hit dist: %g\n", hitp->hit_dist);
02809         bu_log("%s:%d vpriv: %g,%g %g\n",
02810                __FILE__, __LINE__, V3ARGS(hitp->hit_vpriv));
02811     }
02812 
02813     if ( hitp->hit_surfno < XMIN || hitp->hit_surfno > ZTOP ) {
02814         bu_log("%s:%d bogus surface of DSP %d\n",
02815                __FILE__, __LINE__, hitp->hit_surfno);
02816         bu_bomb("");
02817     }
02818 
02819     /* compute hit point */
02820     VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
02821 
02822 
02823     if ( hitp->hit_surfno != ZTOP || !dsp->dsp_i.dsp_smooth ) {
02824         /* We've hit one of the sides or bottom, or the user didn't
02825          * ask for smoothing of the elevation data,
02826          * so there's no interpolation to do.  Just transform the normal to
02827          * model space, and comput the actual hit point
02828          */
02829 
02830         /* transform normal into model space */
02831         MAT4X3VEC(tmp, dsp->dsp_i.dsp_mtos, hitp->hit_normal);
02832         VUNITIZE( tmp );
02833         VMOVE(hitp->hit_normal, tmp);
02834 
02835         if (RT_G_DEBUG & DEBUG_HF)
02836             bu_log("\tno Interpolation needed.  Normal: %g,%g,%g\n",
02837                    V3ARGS(hitp->hit_normal));
02838         return;
02839     }
02840 
02841     if (RT_G_DEBUG & DEBUG_HF)
02842         bu_log("\tNormal Interpolation flag: %d\n", dsp->dsp_i.dsp_smooth);
02843 
02844 
02845     /* compute the distance between grid points in model space */
02846     VSET(tmp, 1.0, 0.0, 0.0);
02847     MAT4X3VEC(t, dsp->dsp_i.dsp_stom, tmp);
02848     len = MAGNITUDE(t);
02849 
02850     if (RT_G_DEBUG & DEBUG_HF) {
02851         fd = bu_fopen_uniq("plotting normals in %s",
02852                       "dsp_gourand%02d.pl", plot_file_num++);
02853 
02854         /* plot the ray */
02855         pl_color(fd, 255, 0, 0);
02856         pdv_3line(fd, rp->r_pt, hitp->hit_point);
02857 
02858         /* plot the normal we started with */
02859         pl_color(fd, 0, 255, 0);
02860         VJOIN1(tmp, hitp->hit_point, len, hitp->hit_normal);
02861         pdv_3line(fd, hitp->hit_point, tmp);
02862 
02863     }
02864 
02865     /* get the cell we hit */
02866     x = hitp->hit_vpriv[X];
02867     y = hitp->hit_vpriv[Y];
02868 
02869     compute_normal_at_gridpoint(Anorm, dsp, x, y, fd, 1, len);
02870     compute_normal_at_gridpoint(Anorm, dsp, x, y, fd, 0, len);
02871     compute_normal_at_gridpoint(Bnorm, dsp, x+1, y, fd, 0, len);
02872     compute_normal_at_gridpoint(Dnorm, dsp, x+1, y+1, fd, 0, len);
02873     compute_normal_at_gridpoint(Cnorm, dsp, x, y+1, fd, 0, len);
02874 
02875     /* transform the hit point into DSP space for determining interpolation */
02876     MAT4X3PNT(pt, dsp->dsp_i.dsp_mtos, hitp->hit_point);
02877 
02878     Xfrac = (pt[X] - x);
02879     Yfrac = (pt[Y] - y);
02880     if (RT_G_DEBUG & DEBUG_HF)
02881         bu_log("Xfract:%g Yfract:%g\n", Xfrac, Yfrac);
02882 
02883     if (Xfrac < 0.0) Xfrac = 0.0;
02884     else if (Xfrac > 1.0) Xfrac = 1.0;
02885 
02886     if (Yfrac < 0.0) Yfrac = 0.0;
02887     else if (Yfrac > 1.0) Yfrac = 1.0;
02888 
02889 
02890     if (dsp->dsp_i.dsp_smooth == 2) {
02891         /* This is an experiment to "flatten" the curvature
02892          * of the dsp near the grid points
02893          */
02894 #define SMOOTHSTEP(x)  ((x)*(x)*(3 - 2*(x)))
02895         Xfrac = SMOOTHSTEP( Xfrac );
02896         Yfrac = SMOOTHSTEP( Yfrac );
02897 #undef SMOOTHSTEP
02898     }
02899 
02900     /* we compute the normal along the "X edges" of the cell */
02901     VSCALE(Anorm, Anorm, (1.0-Xfrac) );
02902     VSCALE(Bnorm, Bnorm,      Xfrac  );
02903     VADD2(ABnorm, Anorm, Bnorm);
02904     VUNITIZE(ABnorm);
02905 
02906     VSCALE(Cnorm, Cnorm, (1.0-Xfrac) );
02907     VSCALE(Dnorm, Dnorm,      Xfrac  );
02908     VADD2(CDnorm, Dnorm, Cnorm);
02909     VUNITIZE(CDnorm);
02910 
02911     /* now we interpolate the two X edge normals to get the final one */
02912     VSCALE(ABnorm, ABnorm, (1.0-Yfrac) );
02913     VSCALE(CDnorm, CDnorm, Yfrac );
02914     VADD2(N, ABnorm, CDnorm);
02915 
02916     VUNITIZE(N);
02917 
02918     dot = VDOT(N, rp->r_dir);
02919     if (RT_G_DEBUG & DEBUG_HF)
02920         bu_log("interpolated %g %g %g  dot:%g\n", V3ARGS(N), dot);
02921 
02922     if ( (hitp->hit_vpriv[Z] == 0.0 && dot > 0.0)/* in-hit needs fix */ ||
02923          (hitp->hit_vpriv[Z] == 1.0 && dot < 0.0)/* out-hit needs fix */){
02924         /* bring the normal back to being perpindicular
02925          * to the ray to avoid "flipped normal" warnings
02926          */
02927         VCROSS(A, rp->r_dir, N);
02928         VCROSS(N, A, rp->r_dir);
02929 
02930         VUNITIZE(N);
02931 
02932         dot = VDOT(N, rp->r_dir);
02933 
02934 
02935         if (RT_G_DEBUG & DEBUG_HF)
02936             bu_log("corrected: %g %g %g dot:%g\n", V3ARGS(N), dot);
02937     }
02938     VMOVE(hitp->hit_normal, N);
02939 
02940     if (RT_G_DEBUG & DEBUG_HF) {
02941             pl_color(fd, 255, 255, 255);
02942             VJOIN1(tmp, hitp->hit_point, len, hitp->hit_normal);
02943             pdv_3line(fd, hitp->hit_point, tmp);
02944 
02945             bu_semaphore_acquire( BU_SEM_SYSCALL);
02946             fclose(fd);
02947             bu_semaphore_release( BU_SEM_SYSCALL);
02948     }
02949 }
02950 
02951 /**
02952  *                      R T _ D S P _ C U R V E
02953  *
02954  *  Return the curvature of the dsp.
02955  */
02956 void
02957 rt_dsp_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
02958 {
02959 
02960     if (RT_G_DEBUG & DEBUG_HF)
02961         bu_log("rt_dsp_curve()\n");
02962 
02963     cvp->crv_c1 = cvp->crv_c2 = 0;
02964 
02965     /* any tangent direction */
02966     bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
02967 }
02968 
02969 /**
02970  *                      R T _ D S P _ U V
02971  *
02972  *  For a hit on the surface of a dsp, return the (u,v) coordinates
02973  *  of the hit point, 0 <= u,v <= 1.
02974  *  u = azimuth
02975  *  v = elevation
02976  */
02977 void
02978 rt_dsp_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
02979 {
02980     register struct dsp_specific *dsp =
02981         (struct dsp_specific *)stp->st_specific;
02982     point_t pt;
02983     vect_t tmp;
02984     double r;
02985     fastf_t min_r_U, min_r_V;
02986     vect_t norm;
02987     vect_t rev_dir;
02988     fastf_t dot_N;
02989     vect_t UV_dir;
02990     vect_t U_dir, V_dir;
02991     fastf_t U_len, V_len;
02992     double one_over_len;
02993 
02994     MAT4X3PNT(pt, dsp->dsp_i.dsp_mtos, hitp->hit_point);
02995 
02996     /* compute U, V */
02997     uvp->uv_u = pt[X] / (double)XSIZ(dsp);
02998     CLAMP(uvp->uv_u, 0.0, 1.0);
02999 
03000     uvp->uv_v = pt[Y] / (double)YSIZ(dsp);
03001     CLAMP(uvp->uv_v, 0.0, 1.0);
03002 
03003 
03004     /* du, dv indicate the extent of the ray radius in UV coordinates.
03005      * To compute this, transform unit vectors from solid space to model
03006      * space.  We remember the length of the resultant vectors and then
03007      * unitize them to get u,v directions in model coordinate space.
03008      */
03009     VSET( tmp, XSIZ(dsp), 0.0, 0.0 );   /* X direction vector */
03010     MAT4X3VEC( U_dir,  dsp->dsp_i.dsp_stom, tmp ); /* into model space */
03011     U_len = MAGNITUDE( U_dir );         /* remember model space length */
03012     one_over_len = 1.0/U_len;
03013     VSCALE( U_dir, U_dir, one_over_len ); /* scale to unit length in model space */
03014 
03015     VSET( tmp, 0.0, YSIZ(dsp), 0.0 );   /* Y direction vector */
03016     MAT4X3VEC( V_dir,  dsp->dsp_i.dsp_stom, tmp );
03017     V_len = MAGNITUDE( V_dir );
03018     one_over_len = 1.0/V_len;
03019     VSCALE( V_dir, V_dir, one_over_len ); /* scale to unit length in model space */
03020 
03021     /* divide the hit-point radius by the U/V unit length distance */
03022     r = ap->a_rbeam + ap->a_diverge * hitp->hit_dist;
03023     min_r_U = r / U_len;
03024     min_r_V = r / V_len;
03025 
03026     /* compute UV_dir, a vector in the plane of the hit point (surface)
03027      * which points in the anti-rayward direction
03028      */
03029     VREVERSE( rev_dir, ap->a_ray.r_dir );
03030     VMOVE( norm, hitp->hit_normal );
03031     dot_N = VDOT( rev_dir, norm );
03032     VJOIN1( UV_dir, rev_dir, -dot_N, norm );
03033     VUNITIZE( UV_dir );
03034 
03035     if (NEAR_ZERO( dot_N, SMALL_FASTF ) ) {
03036         /* ray almost perfectly 90 degrees to surface */
03037         uvp->uv_du = min_r_U;
03038         uvp->uv_dv = min_r_V;
03039     } else {
03040         /* somehow this computes the extent of U and V in the radius */
03041         uvp->uv_du = (r / U_len) * VDOT( UV_dir, U_dir ) / dot_N;
03042         uvp->uv_dv = (r / V_len) * VDOT( UV_dir, V_dir ) / dot_N;
03043     }
03044 
03045 
03046 
03047     if (uvp->uv_du < 0.0 )
03048         uvp->uv_du = -uvp->uv_du;
03049     if (uvp->uv_du < min_r_U )
03050         uvp->uv_du = min_r_U;
03051 
03052     if (uvp->uv_dv < 0.0 )
03053         uvp->uv_dv = -uvp->uv_dv;
03054     if (uvp->uv_dv < min_r_V )
03055         uvp->uv_dv = min_r_V;
03056 
03057     if (RT_G_DEBUG & DEBUG_HF)
03058         bu_log("rt_dsp_uv(pt:%g,%g siz:%d,%d)\n U_len=%g V_len=%g\n r=%g rbeam=%g diverge=%g dist=%g\n u=%g v=%g du=%g dv=%g\n",
03059                pt[X], pt[Y], XSIZ(dsp), YSIZ(dsp),
03060                U_len, V_len,
03061                r, ap->a_rbeam, ap->a_diverge, hitp->hit_dist,
03062                uvp->uv_u, uvp->uv_v,
03063                uvp->uv_du, uvp->uv_dv);
03064 }
03065 
03066 /**
03067  *              R T _ D S P _ F R E E
03068  */
03069 void
03070 rt_dsp_free(register struct soltab *stp)
03071 {
03072     register struct dsp_specific *dsp =
03073         (struct dsp_specific *)stp->st_specific;
03074 
03075     if (RT_G_DEBUG & DEBUG_HF)
03076         bu_log("rt_dsp_free()\n");
03077 
03078     switch (dsp->dsp_i.dsp_datasrc) {
03079     case RT_DSP_SRC_V4_FILE:
03080     case RT_DSP_SRC_FILE:
03081                         if (dsp->dsp_i.dsp_mp) {
03082                                 BU_CK_MAPPED_FILE(dsp->dsp_i.dsp_mp);
03083                                 bu_close_mapped_file(dsp->dsp_i.dsp_mp);
03084                         } else if (dsp->dsp_i.dsp_buf) {
03085                                 bu_free(dsp->dsp_i.dsp_buf, "dsp fake data");
03086                         }
03087                         break;
03088     case RT_DSP_SRC_OBJ:
03089                         break;
03090     }
03091 
03092     bu_free( (char *)dsp, "dsp_specific" );
03093 }
03094 
03095 /**
03096  *                      R T _ D S P _ C L A S S
03097  */
03098 int
03099 rt_dsp_class(void)
03100 {
03101     if (RT_G_DEBUG & DEBUG_HF)
03102         bu_log("rt_dsp_class()\n");
03103 
03104     return(0);
03105 }
03106 
03107 /**
03108  *                      R T _ D S P _ P L O T
03109  */
03110 int
03111 rt_dsp_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
03112 {
03113     struct rt_dsp_internal      *dsp_ip =
03114         (struct rt_dsp_internal *)ip->idb_ptr;
03115     point_t m_pt;
03116     point_t s_pt;
03117     point_t o_pt;
03118     int x, y;
03119     int step;
03120     int xlim = dsp_ip->dsp_xcnt - 1;
03121     int ylim = dsp_ip->dsp_ycnt - 1;
03122     int xfudge, yfudge;
03123     int drawing;
03124 
03125     if (RT_G_DEBUG & DEBUG_HF)
03126         bu_log("rt_dsp_plot()\n");
03127 
03128     RT_CK_DB_INTERNAL(ip);
03129     RT_DSP_CK_MAGIC(dsp_ip);
03130 
03131     switch (dsp_ip->dsp_datasrc) {
03132         case RT_DSP_SRC_V4_FILE:
03133         case RT_DSP_SRC_FILE:
03134             BU_CK_MAPPED_FILE(dsp_ip->dsp_mp);
03135             if (! dsp_ip->dsp_mp ) {
03136                 bu_log("cannot find data for DSP\n");
03137                 return 0;
03138             }
03139             break;
03140         case RT_DSP_SRC_OBJ:
03141             RT_CK_DB_INTERNAL(dsp_ip->dsp_bip);
03142             RT_CK_BINUNIF(dsp_ip->dsp_bip->idb_ptr);
03143             if (! dsp_ip->dsp_bip ) {
03144                 bu_log("cannot find data for DSP\n");
03145                 return 0;
03146             }
03147             break;
03148     }
03149 
03150 
03151 #define MOVE(_pt) \
03152         MAT4X3PNT(m_pt, dsp_ip->dsp_stom, _pt); \
03153         RT_ADD_VLIST( vhead, m_pt, BN_VLIST_LINE_MOVE )
03154 
03155 #define DRAW(_pt) \
03156         MAT4X3PNT(m_pt, dsp_ip->dsp_stom, _pt); \
03157         RT_ADD_VLIST( vhead, m_pt, BN_VLIST_LINE_DRAW )
03158 
03159 
03160     /* Draw the Bottom */
03161     VSETALL(s_pt, 0.0);
03162     MOVE(s_pt);
03163 
03164     s_pt[X] = xlim;
03165     DRAW(s_pt);
03166 
03167     s_pt[Y] = ylim;
03168     DRAW(s_pt);
03169 
03170     s_pt[X] = 0.0;
03171     DRAW(s_pt);
03172 
03173     s_pt[Y] = 0.0;
03174     DRAW(s_pt);
03175 
03176 
03177     /* Draw the corners */
03178     s_pt[Z] = DSP(dsp_ip, 0, 0);
03179     DRAW(s_pt);
03180 
03181     VSET(s_pt, xlim, 0.0, 0.0);
03182     MOVE(s_pt);
03183     s_pt[Z] = DSP(dsp_ip, xlim, 0);
03184     DRAW(s_pt);
03185 
03186 
03187     VSET(s_pt, xlim, ylim, 0.0);
03188     MOVE(s_pt);
03189     s_pt[Z] = DSP(dsp_ip, xlim, ylim);
03190     DRAW(s_pt);
03191 
03192     VSET(s_pt, 0.0, ylim, 0.0);
03193     MOVE(s_pt);
03194     s_pt[Z] = DSP(dsp_ip, 0, ylim);
03195     DRAW(s_pt);
03196 
03197 
03198     /* Draw the outside line of the top
03199      * We draw the four sides of the top at full resolution.
03200      * This helps edge matching.
03201      * The inside of the top, we draw somewhat coarser
03202      */
03203     for (y=0 ; y < dsp_ip->dsp_ycnt ; y += ylim ) {
03204         VSET(s_pt, 0.0, y, DSP(dsp_ip, 0, y));
03205         MOVE(s_pt);
03206 
03207         for (x=0 ; x < dsp_ip->dsp_xcnt ; x++) {
03208             s_pt[X] = x;
03209             s_pt[Z] = DSP(dsp_ip, x, y);
03210             DRAW(s_pt);
03211         }
03212     }
03213 
03214 
03215     for (x=0 ; x < dsp_ip->dsp_xcnt ; x += xlim ) {
03216         VSET(s_pt, x, 0.0, DSP(dsp_ip, x, 0));
03217         MOVE(s_pt);
03218 
03219         for (y=0 ; y < dsp_ip->dsp_ycnt ; y++) {
03220             s_pt[Y] = y;
03221             s_pt[Z] = DSP(dsp_ip, x, y);
03222             DRAW(s_pt);
03223         }
03224     }
03225 
03226     /* now draw the body of the top */
03227     if (ttol->rel )  {
03228         int     rstep;
03229         rstep = dsp_ip->dsp_xcnt;
03230         V_MAX( rstep, dsp_ip->dsp_ycnt );
03231         step = (int)(ttol->rel * rstep);
03232     } else {
03233         int goal = 10000;
03234         goal -= 5;
03235         goal -= 8 + 2 * (dsp_ip->dsp_xcnt+dsp_ip->dsp_ycnt);
03236 
03237         if (goal <= 0) return 0;
03238 
03239         /* Compute data stride based upon producing no more than 'goal' vectors */
03240         step = ceil(
03241                     sqrt( 2*(xlim)*(ylim) /
03242                           (double)goal )
03243                     );
03244     }
03245     if (step < 1 )  step = 1;
03246 
03247 
03248     xfudge = (dsp_ip->dsp_xcnt % step + step) / 2 ;
03249     yfudge = (dsp_ip->dsp_ycnt % step + step) / 2 ;
03250 
03251     if (xfudge < 1) xfudge = 1;
03252     if (yfudge < 1) yfudge = 1;
03253 
03254     /* draw the horizontal (y==const) lines */
03255     for (y=yfudge ; y < ylim ; y += step ) {
03256         VSET(s_pt, 0.0, y, DSP(dsp_ip, 0, y));
03257         VMOVE(o_pt, s_pt);
03258         if (o_pt[Z]) {
03259             drawing = 1;
03260             MOVE(o_pt);
03261         } else {
03262             drawing = 0;
03263         }
03264 
03265         for (x=xfudge ; x < xlim ; x+=step ) {
03266             s_pt[X] = x;
03267 
03268             if ( (s_pt[Z] = DSP(dsp_ip, x, y)) ) {
03269                 if (drawing) {
03270                     DRAW(s_pt);
03271                 } else {
03272                     MOVE(o_pt);
03273                     DRAW(s_pt);
03274                     drawing = 1;
03275                 }
03276             } else {
03277                 if (drawing) {
03278                     DRAW(s_pt);
03279                     drawing = 0;
03280                 }
03281             }
03282 
03283             VMOVE(o_pt, s_pt);
03284         }
03285 
03286         s_pt[X] = xlim;
03287         if ( (s_pt[Z] = DSP(dsp_ip, xlim, y)) ) {
03288             if (drawing) {
03289                 DRAW(s_pt);
03290             } else {
03291                 MOVE(o_pt);
03292                 DRAW(s_pt);
03293                 drawing = 1;
03294             }
03295         } else {
03296             if (drawing) {
03297                 DRAW(s_pt);
03298                 drawing = 0;
03299             }
03300         }
03301 
03302     }
03303 
03304     for (x=xfudge ; x < xlim ; x += step ) {
03305         VSET(s_pt, x, 0.0, DSP(dsp_ip, x, 0));
03306         VMOVE(o_pt, s_pt);
03307         if (o_pt[Z]) {
03308             drawing = 1;
03309             MOVE(o_pt);
03310         } else {
03311             drawing = 0;
03312         }
03313 
03314 
03315         for (y=yfudge ; y < ylim ; y+=step) {
03316             s_pt[Y] = y;
03317 
03318             if ( (s_pt[Z] = DSP(dsp_ip, x, y)) ) {
03319                 if (drawing) {
03320                     DRAW(s_pt);
03321                 } else {
03322                     MOVE(o_pt);
03323                     DRAW(s_pt);
03324                     drawing = 1;
03325                 }
03326             } else {
03327                 if (drawing) {
03328                     DRAW(s_pt);
03329                     drawing = 0;
03330                 }
03331             }
03332 
03333             VMOVE(o_pt, s_pt);
03334         }
03335 
03336         s_pt[Y] = ylim;
03337         if ( (s_pt[Z] = DSP(dsp_ip, x, ylim)) ) {
03338             if (drawing) {
03339                 DRAW(s_pt);
03340             } else {
03341                 MOVE(o_pt);
03342                 DRAW(s_pt);
03343                 drawing = 1;
03344             }
03345         } else {
03346             if (drawing) {
03347                 DRAW(s_pt);
03348                 drawing = 0;
03349             }
03350         }
03351     }
03352 
03353 #undef MOVE
03354 #undef DRAW
03355     return(0);
03356 }
03357 
03358 /**
03359  *                      R T _ D S P _ T E S S
03360  *
03361  *  Returns -
03362  *      -1      failure
03363  *       0      OK.  *r points to nmgregion that holds this tessellation.
03364  */
03365 int
03366 rt_dsp_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
03367 {
03368     LOCAL struct rt_dsp_internal        *dsp_ip;
03369 
03370     if (RT_G_DEBUG & DEBUG_HF)
03371         bu_log("rt_dsp_tess()\n");
03372 
03373     RT_CK_DB_INTERNAL(ip);
03374     dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
03375     RT_DSP_CK_MAGIC(dsp_ip);
03376 
03377     return(-1);
03378 }
03379 
03380 
03381 /**     G E T _ F I L E _ D A T A
03382  *
03383  *      Retrieve data for DSP from external file.
03384  *      Returns:
03385  *              0 Success
03386  *              !0 Failure
03387  */
03388 static int
03389 get_file_data(struct rt_dsp_internal    *dsp_ip,
03390               struct rt_db_internal     *ip,
03391               const struct bu_external  *ep,
03392               register const mat_t      mat,
03393               const struct db_i         *dbip)
03394 {
03395     struct bu_mapped_file               *mf;
03396     int                         count, in_cookie, out_cookie;
03397 
03398     RT_DSP_CK_MAGIC(dsp_ip);
03399     RT_CK_DBI(dbip);
03400 
03401     /* get file */
03402     mf = dsp_ip->dsp_mp =
03403         bu_open_mapped_file_with_path(dbip->dbi_filepath,
03404                                       bu_vls_addr(&dsp_ip->dsp_name), "dsp");
03405     if (!mf) {
03406         bu_log("mapped file open failed\n");
03407         return 0;
03408     }
03409 
03410     if (dsp_ip->dsp_mp->buflen != dsp_ip->dsp_xcnt*dsp_ip->dsp_ycnt*2) {
03411         bu_log("DSP buffer wrong size: %d s/b %d ",
03412                dsp_ip->dsp_mp->buflen, dsp_ip->dsp_xcnt*dsp_ip->dsp_ycnt*2);
03413         return -1;
03414     }
03415 
03416     in_cookie = bu_cv_cookie("nus"); /* data is network unsigned short */
03417     out_cookie = bu_cv_cookie("hus");
03418 
03419     if ( bu_cv_optimize(in_cookie) != bu_cv_optimize(out_cookie) ) {
03420         int got;
03421         /* if we're on a little-endian machine we convert the
03422          * input file from network to host format
03423          */
03424         count = dsp_ip->dsp_xcnt * dsp_ip->dsp_ycnt;
03425         mf->apbuflen = count * sizeof(unsigned short);
03426         mf->apbuf = bu_malloc(mf->apbuflen, "apbuf");
03427 
03428         got = bu_cv_w_cookie(mf->apbuf, out_cookie, mf->apbuflen,
03429                              mf->buf,    in_cookie, count);
03430         if (got != count) {
03431             bu_log("got %d != count %d", got, count);
03432             bu_bomb("\n");
03433         }
03434         dsp_ip->dsp_buf = dsp_ip->dsp_mp->apbuf;
03435     } else {
03436         dsp_ip->dsp_buf = dsp_ip->dsp_mp->buf;
03437     }
03438     return 0;
03439 }
03440 
03441 /**     G E T _ O B J _ D A T A
03442  *
03443  *      Retrieve data for DSP from a database object.
03444  */
03445 static int
03446 get_obj_data(struct rt_dsp_internal     *dsp_ip,
03447              struct rt_db_internal      *ip,
03448              const struct bu_external   *ep,
03449              register const mat_t       mat,
03450              const struct db_i          *dbip)
03451 {
03452     struct rt_binunif_internal  *bip;
03453     int                         in_cookie, out_cookie, got;
03454 
03455     BU_GETSTRUCT(dsp_ip->dsp_bip, rt_db_internal);
03456 
03457     if (rt_retrieve_binunif(dsp_ip->dsp_bip, dbip,
03458                             bu_vls_addr( &dsp_ip->dsp_name) ))
03459         return -1;
03460 
03461     if (RT_G_DEBUG & DEBUG_HF)
03462         bu_log("db_internal magic: 0x%08x  major: %d minor:%d\n",
03463                dsp_ip->dsp_bip->idb_magic,
03464                dsp_ip->dsp_bip->idb_major_type,
03465                dsp_ip->dsp_bip->idb_minor_type);
03466 
03467     bip = dsp_ip->dsp_bip->idb_ptr;
03468 
03469     if (RT_G_DEBUG & DEBUG_HF)
03470         bu_log("binunif magic: 0x%08x  type: %d count:%d data[0]:%u\n",
03471                bip->magic, bip->type, bip->count, bip->u.uint16[0]);
03472 
03473 
03474     in_cookie = bu_cv_cookie("nus"); /* data is network unsigned short */
03475     out_cookie = bu_cv_cookie("hus");
03476 
03477     if ( bu_cv_optimize(in_cookie) != bu_cv_optimize(out_cookie) ) {
03478         /* if we're on a little-endian machine we convert the
03479          * input file from network to host format
03480          */
03481 
03482         got = bu_cv_w_cookie(bip->u.uint16, out_cookie,
03483                              bip->count * sizeof(unsigned short),
03484                              bip->u.uint16, in_cookie, bip->count);
03485 
03486         if (got != bip->count) {
03487             bu_log("got %d != count %d", got, bip->count);
03488             bu_bomb("\n");
03489         }
03490     }
03491 
03492     dsp_ip->dsp_buf = bip->u.uint16;
03493     return 0;
03494 }
03495 
03496 /**
03497  *      D S P _ G E T _ D A T A
03498  *
03499  *  Handle things common to both the v4 and v5 database.
03500  *
03501  *  This include applying the modelling transform, and fetching the
03502  *  actual data.
03503  *
03504  *  Return:
03505  *      0       success
03506  *      !0      failure
03507  */
03508 static int
03509 dsp_get_data(struct rt_dsp_internal     *dsp_ip,
03510              struct rt_db_internal      *ip,
03511              const struct bu_external   *ep,
03512              register const mat_t       mat,
03513              const struct db_i          *dbip)
03514 {
03515     mat_t       tmp;
03516     char        *p;
03517 
03518     /* Apply Modeling transform */
03519     MAT_COPY(tmp, dsp_ip->dsp_stom);
03520     bn_mat_mul(dsp_ip->dsp_stom, mat, tmp);
03521 
03522     bn_mat_inv(dsp_ip->dsp_mtos, dsp_ip->dsp_stom);
03523 
03524     p = bu_vls_addr(&dsp_ip->dsp_name);
03525 
03526     switch (dsp_ip->dsp_datasrc) {
03527     case RT_DSP_SRC_FILE:
03528     case RT_DSP_SRC_V4_FILE:
03529                         /* Retrieve the data from an external file */
03530                         if (RT_G_DEBUG & DEBUG_HF)
03531                                 bu_log("getting data from file \"%s\"\n", p);
03532 
03533                         if (get_file_data(dsp_ip, ip, ep, mat, dbip) != 0) {
03534                                 p = "file";
03535                         } else {
03536                                 return 0;
03537                         }
03538 
03539                         break;
03540     case RT_DSP_SRC_OBJ:
03541                         /* Retrieve the data from an internal db object */
03542                         if (RT_G_DEBUG & DEBUG_HF)
03543                                 bu_log("getting data from object \"%s\"\n", p);
03544 
03545                         if (get_obj_data(dsp_ip, ip, ep, mat, dbip) != 0) {
03546                                 p = "object";
03547                         }
03548                         else {
03549                                 RT_CK_DB_INTERNAL(dsp_ip->dsp_bip);
03550                                 RT_CK_BINUNIF(dsp_ip->dsp_bip->idb_ptr);
03551                                 return 0;
03552                         }
03553                         break;
03554     default:
03555                         bu_log("%s:%d Odd dsp data src '%c' s/b '%c' or '%c'\n",
03556                                                  __FILE__, __LINE__, dsp_ip->dsp_datasrc,
03557                                                  RT_DSP_SRC_FILE, RT_DSP_SRC_OBJ);
03558                         return -1;
03559     }
03560 
03561     bu_log("Cannot retrieve DSP data from %s \"%s\"\n", p,
03562                                          bu_vls_addr(&dsp_ip->dsp_name));
03563 
03564     dsp_ip->dsp_mp = (struct bu_mapped_file *)NULL;
03565     dsp_ip->dsp_buf = bu_calloc(sizeof(short),
03566                                                                                                                                 dsp_ip->dsp_xcnt*dsp_ip->dsp_ycnt,
03567                                                                                                                                 "dsp fake data");
03568 
03569     return 1;
03570 }
03571 
03572 /**
03573  *                      R T _ D S P _ I M P O R T
03574  *
03575  *  Import an DSP from the database format to the internal format.
03576  *  Apply modeling transformations as well.
03577  */
03578 int
03579 rt_dsp_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
03580 {
03581         LOCAL struct rt_dsp_internal    *dsp_ip;
03582         union record                    *rp;
03583         struct bu_vls                   str;
03584 
03585 
03586 
03587         if (RT_G_DEBUG & DEBUG_HF)
03588                 bu_log("rt_dsp_import_v4()\n");
03589 
03590 
03591 
03592 #define IMPORT_FAIL(_s) \
03593         bu_log("rt_dsp_import(%d) '%s' %s\n", __LINE__, \
03594                bu_vls_addr(&dsp_ip->dsp_name), _s);\
03595         bu_free( (char *)dsp_ip , "rt_dsp_import: dsp_ip" ); \
03596         ip->idb_type = ID_NULL; \
03597         ip->idb_ptr = (genptr_t)NULL; \
03598         return -2
03599 
03600         BU_CK_EXTERNAL( ep );
03601         rp = (union record *)ep->ext_buf;
03602 
03603         if (RT_G_DEBUG & DEBUG_HF)
03604                 bu_log("rt_dsp_import(%s)\n", rp->ss.ss_args);
03605         /*----------------------------------------------------------------------*/
03606 
03607 
03608 
03609         /* Check record type */
03610         if (rp->u_id != DBID_STRSOL )  {
03611                 bu_log("rt_dsp_import: defective record\n");
03612                 return(-1);
03613         }
03614 
03615         RT_CK_DB_INTERNAL( ip );
03616         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
03617         ip->idb_type = ID_DSP;
03618         ip->idb_meth = &rt_functab[ID_DSP];
03619         ip->idb_ptr = bu_malloc( sizeof(struct rt_dsp_internal), "rt_dsp_internal");
03620         dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
03621         dsp_ip->magic = RT_DSP_INTERNAL_MAGIC;
03622 
03623         /* set defaults */
03624         /* XXX bu_struct_parse does not set the null?
03625          * memset(&dsp_ip->dsp_name[0], 0, DSP_NAME_LEN);
03626          */
03627         dsp_ip->dsp_xcnt = dsp_ip->dsp_ycnt = 0;
03628 
03629         dsp_ip->dsp_cuttype = DSP_CUT_DIR_ADAPT;
03630         dsp_ip->dsp_smooth = 1;
03631         MAT_IDN(dsp_ip->dsp_stom);
03632         MAT_IDN(dsp_ip->dsp_mtos);
03633 
03634         bu_vls_init( &str );
03635         bu_vls_strcpy( &str, rp->ss.ss_args );
03636         if (bu_struct_parse( &str, rt_dsp_parse, (char *)dsp_ip ) < 0) {
03637                 if (BU_VLS_IS_INITIALIZED( &str )) bu_vls_free( &str );
03638                 IMPORT_FAIL("parse error");
03639         }
03640 
03641 
03642         /* Validate parameters */
03643         if (dsp_ip->dsp_xcnt == 0 || dsp_ip->dsp_ycnt == 0) {
03644                 IMPORT_FAIL("zero dimension on map");
03645         }
03646 
03647         if (dsp_get_data(dsp_ip, ip, ep, mat, dbip)!=0) {
03648                 IMPORT_FAIL("unable to load displacement map data");
03649         }
03650 
03651         if (RT_G_DEBUG & DEBUG_HF) {
03652                 bu_vls_trunc(&str, 0);
03653                 bu_vls_struct_print( &str, rt_dsp_ptab, (char *)dsp_ip);
03654                 bu_log("  imported as(%s)\n", bu_vls_addr(&str));
03655 
03656         }
03657 
03658         if (BU_VLS_IS_INITIALIZED( &str )) bu_vls_free( &str );
03659 
03660         RT_CK_DB_INTERNAL(dsp_ip->dsp_bip);
03661         RT_CK_BINUNIF(dsp_ip->dsp_bip->idb_ptr);
03662 
03663         return(0);                      /* OK */
03664 }
03665 
03666 
03667 /**
03668  *                      R T _ D S P _ E X P O R T
03669  *
03670  *  The name is added by the caller, in the usual place.
03671  */
03672 int
03673 rt_dsp_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
03674 {
03675     struct rt_dsp_internal      *dsp_ip;
03676     struct rt_dsp_internal      dsp;
03677     union record                *rec;
03678     struct bu_vls               str;
03679 
03680 
03681     RT_CK_DB_INTERNAL(ip);
03682     if (ip->idb_type != ID_DSP )  return(-1);
03683     dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
03684     RT_DSP_CK_MAGIC(dsp_ip);
03685     BU_CK_VLS(&dsp_ip->dsp_name);
03686 
03687 
03688     BU_CK_EXTERNAL(ep);
03689     ep->ext_nbytes = sizeof(union record)*DB_SS_NGRAN;
03690     ep->ext_buf = bu_calloc( 1, ep->ext_nbytes, "dsp external");
03691     rec = (union record *)ep->ext_buf;
03692 
03693     dsp = *dsp_ip;      /* struct copy */
03694 
03695     /* Since libwdb users may want to operate in units other
03696      * than mm, we offer the opportunity to scale the solid
03697      * (to get it into mm) on the way out.
03698      */
03699     dsp.dsp_stom[15] *= local2mm;
03700 
03701     bu_vls_init( &str );
03702     bu_vls_struct_print( &str, rt_dsp_ptab, (char *)&dsp);
03703     if (RT_G_DEBUG & DEBUG_HF)
03704         bu_log("rt_dsp_export_v4(%s)\n", bu_vls_addr(&str) );
03705 
03706     rec->ss.ss_id = DBID_STRSOL;
03707     strncpy( rec->ss.ss_keyword, "dsp", NAMESIZE-1 );
03708     strncpy( rec->ss.ss_args, bu_vls_addr(&str), DB_SS_LEN-1 );
03709 
03710 
03711     if (BU_VLS_IS_INITIALIZED( &str )) bu_vls_free( &str );
03712 
03713     return(0);
03714 }
03715 
03716 
03717 
03718 
03719 /**
03720  *                      R T _ D S P _ I M P O R T 5
03721  *
03722  *  Import an DSP from the database format to the internal format.
03723  *  Apply modeling transformations as well.
03724  */
03725 int
03726 rt_dsp_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip, struct resource *resp, const int minor_type)
03727 {
03728         struct rt_dsp_internal  *dsp_ip;
03729         unsigned char           *cp;
03730 
03731         if (RT_G_DEBUG & DEBUG_HF)
03732                 bu_log("rt_dsp_import_v5()\n");
03733 
03734 
03735 
03736         BU_CK_EXTERNAL( ep );
03737 
03738         BU_ASSERT_LONG( ep->ext_nbytes, >, 141 );
03739 
03740         RT_CK_DB_INTERNAL( ip );
03741 
03742         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
03743         ip->idb_type = ID_DSP;
03744         ip->idb_meth = &rt_functab[ID_DSP];
03745         dsp_ip = ip->idb_ptr = bu_malloc( sizeof(struct rt_dsp_internal), "rt_dsp_internal");
03746         memset(dsp_ip, 0, sizeof(*dsp_ip));
03747 
03748         dsp_ip->magic = RT_DSP_INTERNAL_MAGIC;
03749 
03750         /* get x, y counts */
03751         cp = (unsigned char *)ep->ext_buf;
03752 
03753         dsp_ip->dsp_xcnt = (unsigned) bu_glong( cp );
03754         cp += SIZEOF_NETWORK_LONG;
03755         if (dsp_ip->dsp_xcnt < 2) {
03756                 bu_log("%s:%d DSP X dimension (%d) < 2 \n",
03757                                          __FILE__, __LINE__,
03758                                          dsp_ip->dsp_xcnt);
03759         }
03760 
03761 
03762         dsp_ip->dsp_ycnt = (unsigned) bu_glong( cp );
03763         cp += SIZEOF_NETWORK_LONG;
03764         if (dsp_ip->dsp_ycnt < 2) {
03765                 bu_log("%s:%d DSP X dimension (%d) < 2 \n",
03766                                          __FILE__, __LINE__,
03767                                          dsp_ip->dsp_ycnt);
03768         }
03769 
03770         /* convert matrix */
03771         ntohd((unsigned char *)dsp_ip->dsp_stom, cp, 16);
03772         cp += SIZEOF_NETWORK_DOUBLE * 16;
03773         bn_mat_inv(dsp_ip->dsp_mtos, dsp_ip->dsp_stom);
03774 
03775         /* convert smooth flag */
03776         dsp_ip->dsp_smooth = bu_gshort( cp );
03777         cp += SIZEOF_NETWORK_SHORT;
03778 
03779         dsp_ip->dsp_datasrc = *cp;
03780         cp++;
03781         switch (dsp_ip->dsp_datasrc) {
03782         case RT_DSP_SRC_V4_FILE:
03783         case RT_DSP_SRC_FILE:
03784         case RT_DSP_SRC_OBJ:
03785                 break;
03786         default:
03787                 bu_log("%s:%d bogus DSP datasrc '%c' (%d)\n",
03788                                          __FILE__, __LINE__,
03789                                          dsp_ip->dsp_datasrc, dsp_ip->dsp_datasrc);
03790                 break;
03791         }
03792 
03793 
03794         dsp_ip->dsp_cuttype = *cp;
03795         cp++;
03796         switch (dsp_ip->dsp_cuttype) {
03797         case DSP_CUT_DIR_ADAPT:
03798         case DSP_CUT_DIR_llUR:
03799         case DSP_CUT_DIR_ULlr:
03800                 break;
03801         default:
03802                 bu_log("%s:%d bogus DSP cut type '%c' (%d)\n",
03803                                          __FILE__, __LINE__,
03804                                          dsp_ip->dsp_cuttype, dsp_ip->dsp_cuttype);
03805                 break;
03806         }
03807 
03808 
03809         /* convert name of data location */
03810         bu_vls_init( &dsp_ip->dsp_name );
03811         bu_vls_strncpy( &dsp_ip->dsp_name, (char *)cp,
03812                                                                         ep->ext_nbytes - (cp - (unsigned char *)ep->ext_buf) );
03813 
03814         if (dsp_get_data(dsp_ip, ip, ep, mat, dbip)!=0) {
03815                 IMPORT_FAIL("unable to load displacement map data");
03816         }
03817 
03818         return 0; /* OK */
03819 }
03820 
03821 /**
03822  *                      R T _ D S P _ E X P O R T 5
03823  *
03824  *  The name is added by the caller, in the usual place.
03825  */
03826 int
03827 rt_dsp_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip, struct resource *resp, const int minor_type)
03828 {
03829         struct rt_dsp_internal  *dsp_ip;
03830         unsigned long           name_len;
03831         unsigned char           *cp;
03832 
03833         RT_CK_DB_INTERNAL(ip);
03834         if (ip->idb_type != ID_DSP )  return(-1);
03835         dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
03836         RT_DSP_CK_MAGIC(dsp_ip);
03837 
03838         if (RT_G_DEBUG & DEBUG_HF)
03839                 bu_log("rt_dsp_export_v5()\n");
03840 
03841         name_len = bu_vls_strlen(&dsp_ip->dsp_name) + 1;
03842 
03843         BU_CK_EXTERNAL(ep);
03844 
03845         ep->ext_nbytes =
03846                 SIZEOF_NETWORK_LONG * 2 +
03847                 SIZEOF_NETWORK_DOUBLE * ELEMENTS_PER_MAT +
03848                 SIZEOF_NETWORK_SHORT +
03849                 2 + name_len;
03850 
03851         ep->ext_buf = bu_malloc( ep->ext_nbytes, "dsp external");
03852         cp = (unsigned char *)ep->ext_buf;
03853 
03854         memset(ep->ext_buf, 0, ep->ext_nbytes);
03855 
03856         /* Now we fill the buffer with the data, making sure everything is
03857          * converted to Big-Endian IEEE
03858          */
03859 
03860         bu_plong( cp, (unsigned long)dsp_ip->dsp_xcnt );
03861         cp += SIZEOF_NETWORK_LONG;
03862 
03863         bu_plong( cp, (unsigned long)dsp_ip->dsp_ycnt );
03864         cp += SIZEOF_NETWORK_LONG;
03865 
03866         /* Since libwdb users may want to operate in units other
03867          * than mm, we offer the opportunity to scale the solid
03868          * (to get it into mm) on the way out.
03869          */
03870         dsp_ip->dsp_stom[15] *= local2mm;
03871 
03872         htond(cp, (unsigned char *)dsp_ip->dsp_stom, 16);
03873         cp += SIZEOF_NETWORK_DOUBLE * 16;
03874 
03875         bu_pshort( cp, (int)dsp_ip->dsp_smooth );
03876         cp += SIZEOF_NETWORK_SHORT;
03877 
03878         switch(dsp_ip->dsp_datasrc) {
03879         case RT_DSP_SRC_V4_FILE:
03880         case RT_DSP_SRC_FILE:
03881         case RT_DSP_SRC_OBJ:
03882                 *cp = dsp_ip->dsp_datasrc;
03883                 break;
03884         default:
03885                 *cp = RT_DSP_SRC_FILE;
03886                 break;
03887         }
03888         cp++;
03889 
03890         switch(dsp_ip->dsp_cuttype) {
03891         case DSP_CUT_DIR_ADAPT:
03892         case DSP_CUT_DIR_llUR:
03893         case DSP_CUT_DIR_ULlr:
03894                 *cp = dsp_ip->dsp_cuttype;
03895                 break;
03896         default:
03897                 *cp = DSP_CUT_DIR_ADAPT;
03898                 break;
03899         }
03900         cp++;
03901 
03902         strcpy((char *)cp, bu_vls_addr(&dsp_ip->dsp_name));
03903 
03904         return 0; /* OK */
03905 }
03906 
03907 
03908 
03909 
03910 /**
03911  *                      R T _ D S P _ D E S C R I B E
03912  *
03913  *  Make human-readable formatted presentation of this solid.
03914  *  First line describes type of solid.
03915  *  Additional lines are indented one tab, and give parameter values.
03916  */
03917 int
03918 rt_dsp_describe(struct bu_vls           *str,
03919                 const struct rt_db_internal *ip,
03920                 int                     verbose,
03921                 double                  mm2local,
03922                 struct resource         *resp,
03923                 struct db_i             *db_ip)
03924 {
03925     register struct rt_dsp_internal     *dsp_ip =
03926         (struct rt_dsp_internal *)ip->idb_ptr;
03927     struct bu_vls vls;
03928 
03929     RT_CK_DBI(db_ip);
03930 
03931     bu_vls_init( &vls );
03932 
03933     if (RT_G_DEBUG & DEBUG_HF)
03934         bu_log("rt_dsp_describe()\n");
03935 
03936     RT_DSP_CK_MAGIC(dsp_ip);
03937 
03938     switch (db_ip->dbi_version) {
03939     case 4:
03940         dsp_print_v4(&vls, dsp_ip );
03941         break;
03942     case 5:
03943         dsp_print_v5(&vls, dsp_ip );
03944         break;
03945     }
03946 
03947     bu_vls_vlscat( str, &vls );
03948 
03949     if (BU_VLS_IS_INITIALIZED( &vls )) bu_vls_free( &vls );
03950 
03951     return(0);
03952 }
03953 
03954 /**
03955  *                      R T _ D S P _ I F R E E
03956  *
03957  *  Free the storage associated with the rt_db_internal version of this solid.
03958  */
03959 void
03960 rt_dsp_ifree(struct rt_db_internal *ip)
03961 {
03962     register struct rt_dsp_internal     *dsp_ip;
03963 
03964     if (RT_G_DEBUG & DEBUG_HF)
03965         bu_log("rt_dsp_ifree()\n");
03966 
03967     RT_CK_DB_INTERNAL(ip);
03968     dsp_ip = (struct rt_dsp_internal *)ip->idb_ptr;
03969     RT_DSP_CK_MAGIC(dsp_ip);
03970 
03971     if (dsp_ip->dsp_mp) {
03972         BU_CK_MAPPED_FILE(dsp_ip->dsp_mp);
03973         bu_close_mapped_file(dsp_ip->dsp_mp);
03974     }
03975 
03976     if (dsp_ip->dsp_bip) {
03977         rt_binunif_ifree( (struct rt_db_internal *) dsp_ip->dsp_bip);
03978     }
03979 
03980     dsp_ip->magic = 0;                  /* sanity */
03981     dsp_ip->dsp_mp = (struct bu_mapped_file *)0;
03982 
03983     if (BU_VLS_IS_INITIALIZED(&dsp_ip->dsp_name))
03984         bu_vls_free(  &dsp_ip->dsp_name );
03985     else
03986         bu_log("Freeing Bogus DSP, VLS string not initialized\n");
03987 
03988 
03989     bu_free( (char *)dsp_ip, "dsp ifree" );
03990     ip->idb_ptr = GENPTR_NULL;  /* sanity */
03991 }
03992 
03993 static void
03994 hook_verify(const struct bu_structparse *ip,
03995                                                 const char                      *sp_name,
03996                                                 genptr_t                        base,
03997                                                 char                    *p)
03998 {
03999         struct rt_dsp_internal *dsp_ip = (struct rt_dsp_internal *)base;
04000 
04001         if (!strcmp(sp_name, "src")) {
04002                 switch (dsp_ip->dsp_datasrc) {
04003                 case RT_DSP_SRC_V4_FILE:
04004                 case RT_DSP_SRC_FILE:
04005                 case RT_DSP_SRC_OBJ:
04006             break;
04007                 default:
04008             bu_log("Error in DSP data source field s/b one of [%c%c%c]\n",
04009                                                  RT_DSP_SRC_V4_FILE,
04010                                                  RT_DSP_SRC_FILE,
04011                                                  RT_DSP_SRC_OBJ);
04012             break;
04013                 }
04014 
04015         } else if (!strcmp(sp_name, "w")) {
04016                 if (dsp_ip->dsp_xcnt == 0)
04017             bu_log("Error in DSP width dimension (0)\n");
04018         } else if (!strcmp(sp_name, "n")) {
04019                 if (dsp_ip->dsp_ycnt == 0)
04020             bu_log("Error in DSP width dimension (0)\n");
04021         } else if (!strcmp(sp_name, "cut")) {
04022                 switch (dsp_ip->dsp_cuttype) {
04023                 case DSP_CUT_DIR_ADAPT:
04024                 case DSP_CUT_DIR_llUR:
04025                 case DSP_CUT_DIR_ULlr:
04026             break;
04027                 default:
04028             bu_log("Error in DSP cut type: %c s/b one of [%c%c%c]\n",
04029                                                  dsp_ip->dsp_cuttype,
04030                                                  DSP_CUT_DIR_ADAPT,
04031                                                  DSP_CUT_DIR_llUR,
04032                                                  DSP_CUT_DIR_ULlr);
04033             break;
04034                 }
04035         }
04036 }
04037 
04038 
04039 
04040 const struct bu_structparse fake_dsp_printab[] = {
04041     {"%c",  1, "src", DSP_O(dsp_datasrc), hook_verify },
04042     {"%S",  1, "name", DSP_O(dsp_name), BU_STRUCTPARSE_FUNC_NULL },
04043     {"%d",  1, "w",  DSP_O(dsp_xcnt),    hook_verify },
04044     {"%d",  1, "n",  DSP_O(dsp_ycnt),    hook_verify },
04045     {"%i",  1, "sm", DSP_O(dsp_smooth), BU_STRUCTPARSE_FUNC_NULL },
04046     {"%c",  1, "cut", DSP_O(dsp_cuttype), hook_verify },
04047     {"%f", 16, "stom", DSP_AO(dsp_stom), hook_verify },
04048     {"",    0, (char *)0, 0,             BU_STRUCTPARSE_FUNC_NULL }
04049 };
04050 
04051 
04052 /**
04053  *                      R T _ P A R S E T A B _ T C L G E T
04054  *
04055  *  This is the generic routine to be listed in rt_functab[].ft_tclget
04056  *  for those solid types which are fully described by their ft_parsetab
04057  *  entry.
04058  *
04059  *  'attr' is specified to retrieve only one attribute, rather than all.
04060  *  Example:  "db get ell.s B" to get only the B vector.
04061  */
04062 int
04063 rt_dsp_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
04064 {
04065         register const struct bu_structparse    *sp = NULL;
04066         const struct rt_dsp_internal *dsp_ip;
04067         int                     status;
04068         Tcl_DString             ds;
04069         struct bu_vls           str;
04070 
04071 
04072 
04073         /* XXX if dsp_datasrc == RT_DSP_SRC_V4_FILE we have a V4 dsp
04074          * otherwise, a V5 dsp.  Take advantage of this.
04075          */
04076 
04077         RT_CK_DB_INTERNAL( intern );
04078         dsp_ip = (struct rt_dsp_internal *)intern->idb_ptr;
04079 
04080         bu_vls_init( &str );
04081         Tcl_DStringInit( &ds );
04082 
04083         if( attr == (char *)0 ) {
04084             /* Print out solid type and all attributes */
04085 
04086             Tcl_DStringAppendElement( &ds, "dsp" );
04087 
04088 
04089 
04090             switch (dsp_ip->dsp_datasrc) {
04091             case RT_DSP_SRC_V4_FILE:
04092                                 sp = rt_dsp_ptab;
04093                                 break;
04094             case RT_DSP_SRC_FILE:
04095             case RT_DSP_SRC_OBJ:
04096                                 sp = fake_dsp_printab;
04097                                 break;
04098             }
04099 
04100             while( sp && sp->sp_name != NULL ) {
04101                 Tcl_DStringAppendElement( &ds, sp->sp_name );
04102                 bu_vls_trunc( &str, 0 );
04103                 bu_vls_struct_item(&str,sp,(char *)dsp_ip,' ');
04104                 Tcl_DStringAppendElement( &ds, bu_vls_addr(&str) );
04105                 ++sp;
04106             }
04107             status = TCL_OK;
04108 
04109         } else {
04110                 switch (dsp_ip->dsp_datasrc) {
04111                 case RT_DSP_SRC_V4_FILE:
04112                         sp = rt_dsp_ptab;
04113                 case RT_DSP_SRC_FILE:
04114                 case RT_DSP_SRC_OBJ:
04115                         sp = fake_dsp_printab;
04116                         break;
04117                 }
04118 
04119             if( bu_vls_struct_item_named( &str, sp, attr,
04120                                           (char *)dsp_ip, ' ') < 0 ) {
04121                 bu_vls_printf(&str,
04122                               "Objects of type %s do not have a %s attribute.",
04123                               "dsp", attr);
04124                 status = TCL_ERROR;
04125             } else {
04126                 status = TCL_OK;
04127             }
04128             Tcl_DStringAppendElement( &ds, bu_vls_addr(&str) );
04129         }
04130 
04131         Tcl_DStringResult( interp, &ds );
04132         Tcl_DStringFree( &ds );
04133         bu_vls_free( &str );
04134 
04135         return status;
04136 }
04137 
04138 /**
04139  *                      R T _ P A R S E T A B _ T C L A D J U S T
04140  *
04141  *  For those solids entirely defined by their parsetab.
04142  *  Invoked via rt_functab[].ft_tcladjust()
04143  */
04144 int
04145 rt_dsp_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
04146 {
04147         register const struct bu_structparse    *sp = NULL;
04148         const struct rt_dsp_internal *dsp_ip;
04149 
04150 
04151         RT_CK_DB_INTERNAL(intern);
04152         dsp_ip = (struct rt_dsp_internal *)intern->idb_ptr;
04153         RT_DSP_CK_MAGIC(dsp_ip);
04154         BU_CK_VLS(&dsp_ip->dsp_name);
04155 
04156         switch (dsp_ip->dsp_datasrc) {
04157         case RT_DSP_SRC_V4_FILE:
04158                 sp = rt_dsp_ptab;
04159         case RT_DSP_SRC_FILE:
04160         case RT_DSP_SRC_OBJ:
04161                 sp = fake_dsp_printab;
04162                 break;
04163         }
04164 
04165         if (! sp) return TCL_ERROR;
04166 
04167         return bu_structparse_argv(interp, argc, argv, sp,
04168                                 (char *)intern->idb_ptr );
04169 }
04170 
04171 void
04172 rt_dsp_make(const struct rt_functab *ftp, struct rt_db_internal *intern, double diameter)
04173 {
04174     struct rt_dsp_internal *dsp;
04175 
04176     intern->idb_major_type = DB5_MAJORTYPE_BRLCAD;
04177     intern->idb_type = ID_DSP;
04178 
04179     BU_ASSERT(&rt_functab[intern->idb_type] == ftp);
04180     intern->idb_meth = ftp;
04181 
04182     dsp =(struct rt_dsp_internal *)bu_calloc(sizeof(struct rt_dsp_internal),1, "rt_dsp_internal");
04183 
04184     intern->idb_ptr = (genptr_t)dsp;
04185     dsp->magic = RT_DSP_INTERNAL_MAGIC;
04186     bu_vls_init(&dsp->dsp_name);
04187     bu_vls_strcpy(&dsp->dsp_name, "/dev/null");
04188     dsp->dsp_cuttype = DSP_CUT_DIR_ADAPT;
04189     MAT_IDN( dsp->dsp_mtos );
04190     MAT_IDN( dsp->dsp_stom );
04191     dsp->dsp_datasrc = RT_DSP_SRC_FILE;
04192 
04193 }
04194 
04195 /**     S W A P _ C E L L _ P T S
04196  *
04197  */
04198 static int
04199 swap_cell_pts(int A[3],
04200               int B[3],
04201               int C[3],
04202               int D[3],
04203               struct dsp_specific *dsp)
04204 
04205 {
04206     switch (dsp->dsp_i.dsp_cuttype) {
04207     case DSP_CUT_DIR_llUR:
04208         return  0;
04209         break;
04210 
04211     case DSP_CUT_DIR_ADAPT: {
04212         int lo[2], hi[2];
04213         double h1, h2, h3, h4;
04214         double cAD, cBC;  /* curvature in direction AD, and BC */
04215 
04216 
04217         /*
04218          *  We look at the points in the diagonal next cells to determine
04219          *  the curvature along each diagonal of this cell.  This cell is
04220          *  divided into two triangles by cutting across the cell in the
04221          *  direction of least curvature.
04222          *
04223          *      *  *  *  *
04224          *       \      /
04225          *        \C  D/
04226          *      *  *--*  *
04227          *         |\/|
04228          *         |/\|
04229          *      *  *--*  *
04230          *        /A  B\
04231          *       /      \
04232          *      *  *  *  *
04233          */
04234 
04235         lo[X] = A[X] - 1;
04236         lo[Y] = A[Y] - 1;
04237         hi[X] = D[X] + 1;
04238         hi[Y] = D[Y] + 1;
04239 
04240         /* a little bounds checking */
04241         if (lo[X] < 0) lo[X] = 0;
04242         if (lo[Y] < 0) lo[Y] = 0;
04243         if (hi[X] > dsp->xsiz)
04244             hi[X] = dsp->xsiz;
04245 
04246         if (hi[Y] > dsp->ysiz)
04247             hi[Y] = dsp->ysiz;
04248 
04249         /* compute curvature along the A->D direction */
04250         h1 = DSP(&dsp->dsp_i, lo[X], lo[Y]);
04251         h2 = A[Z];
04252         h3 = D[Z];
04253         h4 = DSP(&dsp->dsp_i, hi[X], hi[Y]);
04254 
04255         cAD = fabs(h3 + h1 - 2*h2 ) + fabs( h4 + h2 - 2*h3 );
04256 
04257 
04258         /* compute curvature along the B->C direction */
04259         h1 = DSP(&dsp->dsp_i, hi[X], lo[Y]);
04260         h2 = B[Z];
04261         h3 = C[Z];
04262         h4 = DSP(&dsp->dsp_i, lo[X], hi[Y]);
04263 
04264         cBC = fabs(h3 + h1 - 2*h2 ) + fabs( h4 + h2 - 2*h3 );
04265 
04266         if ( cAD < cBC ) {
04267             /* A-D cut is fine, no need to permute */
04268             if (RT_G_DEBUG & DEBUG_HF)
04269                 bu_log("A-D cut (no swap)\n");
04270 
04271             return 0;
04272         }
04273 
04274         /* fallthrough */
04275 
04276     }
04277     case DSP_CUT_DIR_ULlr:
04278         {
04279         /* prefer the B-C cut */
04280         int tmp[3];
04281 
04282         VMOVE(tmp, A);
04283         VMOVE(A, B);
04284         VMOVE(B, tmp);
04285 
04286         VMOVE(tmp, D);
04287         VMOVE(D, C);
04288         VMOVE(C, tmp);
04289 
04290         if (RT_G_DEBUG & DEBUG_HF)
04291             bu_log("B-C cut (swap)\n");
04292         }
04293         return 0;
04294         break;
04295     }
04296     bu_log("%s:%d Unknown DSP cut direction: %d\n",
04297            __FILE__, __LINE__, dsp->dsp_i.dsp_cuttype);
04298     bu_bomb("");
04299     /* not reached */
04300     return -1;
04301 }
04302 
04303 
04304 
04305 /*
04306  *
04307  *
04308  *
04309  * triangle with origin at A, X axis along AB, Y axis along AC
04310  *
04311  *      B--A    C       A--B       C
04312  *         |    |       |          |
04313  *         C    A--B    C       B--A
04314  */
04315 int
04316 project_pt(point_t out,
04317            int A[3],
04318            int B[3],
04319            int C[3],
04320            point_t pt)
04321 {
04322     int dx, dy;
04323     double alpha, beta, x, y;
04324     vect_t AB, AC;
04325 
04326     if (RT_G_DEBUG & DEBUG_HF) {
04327         bu_log("     pt %g %g %g\n", V3ARGS(pt));
04328         bu_log(" origin %d %d %d\n", V3ARGS(A));
04329         bu_log("    Bpt %d %d %d\n", V3ARGS(B));
04330         bu_log("    Cpt %d %d %d\n", V3ARGS(C));
04331     }
04332     if ((B[X] - A[X]) < 0) dx = -1;
04333     else dx = 1;
04334     if ((C[Y] - A[Y]) < 0) dy = -1;
04335     else dy = 1;
04336 
04337     x = pt[X] - A[X];
04338     y = pt[Y] - A[Y];
04339 
04340     alpha = x * dx;
04341     beta = y * dy;
04342     if (RT_G_DEBUG & DEBUG_HF) {
04343         bu_log("alpha:%g beta:%g\n", alpha, beta);
04344     }
04345     if (alpha < -SMALL_FASTF) {
04346         bu_log ("Alpha negative: %g  x:%g  dx:%d\n", alpha, x, dx);
04347     }
04348     if (beta < -SMALL_FASTF) {
04349         bu_log ("Beta negative: %g  x:%g  dx:%d\n", beta, y, dy);
04350     }
04351     CLAMP(alpha, 0.0, 1.0);
04352     CLAMP(beta, 0.0, 1.0);
04353 
04354     if (RT_G_DEBUG & DEBUG_HF) {
04355         bu_log("x:%g y:%g dx:%d dy:%d alpha:%g beta:%g\n",
04356                x, y, dx, dy, alpha, beta);
04357     }
04358     if ((alpha+beta) > (1.0+SMALL_FASTF)) {
04359         if (RT_G_DEBUG & DEBUG_HF) bu_log("Not this triangle\n");
04360         return 1;
04361     }
04362 
04363     VSUB2(AB, B, A);
04364     VSUB2(AC, C, A);
04365 
04366     VJOIN2(out, A, alpha, AB, beta, AC);
04367     if (RT_G_DEBUG & DEBUG_HF) bu_log("out: %g %g %g\n", V3ARGS(out));
04368 
04369     return 0;
04370 }
04371 /**     D S P _ P O S
04372  *
04373  *
04374  *      Given an arbitrary point return the projection of that point onto
04375  *      the surface of the DSP.  If the point is outside the bounds of the DSP
04376  *      then it will be projected to the nearest edge of the DSP.
04377  *      Return the cell number and the height above/below the plane
04378  */
04379 int
04380 dsp_pos(point_t out, /* return value */
04381         struct soltab *stp, /* pointer to soltab for dsp */
04382         point_t p)      /* model space point */
04383 {
04384     struct dsp_specific *dsp;
04385     point_t pt, tri_pt;
04386     int x, y;
04387     int A[3], B[3], C[3], D[3];
04388 
04389     struct dsp_rpp dsp_rpp;
04390 
04391     RT_CK_SOLTAB(stp);
04392 
04393     if (stp->st_id != ID_DSP) return 1;
04394 
04395     dsp = (struct dsp_specific *)stp->st_specific;
04396 
04397     MAT4X3PNT(pt, dsp->dsp_i.dsp_mtos, p);
04398 
04399 
04400     if (RT_G_DEBUG & DEBUG_HF) {
04401         VPRINT("user_point", p);
04402         VPRINT("dsp_point", pt);
04403     }
04404     x = pt[X];
04405     y = pt[Y];
04406 
04407     CLAMP(x, 0, XSIZ(dsp)-1);
04408     CLAMP(y, 0, YSIZ(dsp)-1);
04409 
04410     if (RT_G_DEBUG & DEBUG_HF)
04411         bu_log("x:%d y:%d\n", x, y);
04412 
04413     VSET(dsp_rpp.dsp_min, x, y, 0);
04414     VSET(dsp_rpp.dsp_max, x+1, y+1, 0);
04415 
04416     VSET(A, x, y, DSP(&dsp->dsp_i, x, y) );
04417     x += 1;
04418     VSET(B, x, y, DSP(&dsp->dsp_i, x, y) );
04419     y += 1;
04420     VSET(D, x, y, DSP(&dsp->dsp_i, x, y) );
04421     x -= 1;
04422     VSET(C, x, y, DSP(&dsp->dsp_i, x, y) );
04423     y -= 1;
04424 
04425     if (RT_G_DEBUG & DEBUG_HF) {
04426         bu_log(" A: %d %d %d\n", V3ARGS(A));
04427         bu_log(" B: %d %d %d\n", V3ARGS(B));
04428         bu_log(" C: %d %d %d\n", V3ARGS(C));
04429         bu_log(" D: %d %d %d\n", V3ARGS(D));
04430     }
04431 
04432     swap_cell_pts(A, B, C, D, dsp);
04433     if (RT_G_DEBUG & DEBUG_HF) {
04434         bu_log(" A: %d %d %d\n", V3ARGS(A));
04435         bu_log(" B: %d %d %d\n", V3ARGS(B));
04436         bu_log(" C: %d %d %d\n", V3ARGS(C));
04437         bu_log(" D: %d %d %d\n", V3ARGS(D));
04438     }
04439 
04440     if (project_pt(tri_pt, B, A, D, pt)) {
04441         if (project_pt(tri_pt, C, D, A, pt)) {
04442             bu_log("Now what???\n");
04443         }
04444     }
04445 
04446     MAT4X3PNT(out, dsp->dsp_i.dsp_stom, tri_pt);
04447     if (RT_G_DEBUG & DEBUG_HF) {
04448         VPRINT("user_pt", p);
04449         VPRINT("tri_pt", tri_pt);
04450         VPRINT("model_space", out);
04451         bu_log("X: %d Y:%d\n",x, y);
04452     }
04453 
04454     return 0;
04455 }
04456 
04457 
04458 /* Important when concatenating source files together */
04459 #undef dlog
04460 #undef XMIN
04461 #undef XMAX
04462 #undef YMIN
04463 #undef YMAX
04464 #undef ZMIN
04465 #undef ZMAX
04466 #undef ZMID
04467 #undef DSP
04468 #undef XCNT
04469 #undef YCNT
04470 #undef XSIZ
04471 #undef YSIZ
04472 
04473 /*@}*/
04474 /*
04475  * Local Variables:
04476  * mode: C
04477  * tab-width: 8
04478  * c-basic-offset: 4
04479  * indent-tabs-mode: t
04480  * End:
04481  * ex: shiftwidth=4 tabstop=8
04482  */

Generated on Mon Sep 18 01:24:50 2006 for BRL-CAD by  doxygen 1.4.6