g_submodel.c

Go to the documentation of this file.
00001 /*                    G _ S U B M O D E L . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2000-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup g_  */
00023 
00024 /*@{*/
00025 /** @file g_submodel.c
00026  *      Intersect a ray with an entire subspace full of geometry,
00027  *      possibly included from another .g file, with a subordinate
00028  *      instance of LIBRT.
00029  *
00030  *  This solid is particularly useful when instancing millions of copies
00031  *  of a given complex object, such as a detailed tree.
00032  *
00033  *
00034  *  Author -
00035  *      Michael John Muuss
00036  *
00037  *  Source -
00038  *      The U. S. Army Research Laboratory
00039  *      Aberdeen Proving Ground, Maryland  21005-5066
00040  */
00041 /*@}*/
00042 
00043 #ifndef lint
00044 static const char RCSsubmodel[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_submodel.c,v 14.14 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00045 #endif
00046 
00047 #include "common.h"
00048 
00049 #include <stddef.h>
00050 #include <stdio.h>
00051 #include <math.h>
00052 #include <string.h>
00053 
00054 #include "machine.h"
00055 #include "vmath.h"
00056 #include "db.h"
00057 #include "nmg.h"
00058 #include "raytrace.h"
00059 #include "rtgeom.h"
00060 
00061 #define RT_SUBMODEL_O(m)        bu_offsetof(struct rt_submodel_internal, m)
00062 
00063 const struct bu_structparse rt_submodel_parse[] = {
00064         {"%S",  1, "file",      RT_SUBMODEL_O(file),            BU_STRUCTPARSE_FUNC_NULL },
00065         {"%S",  1, "treetop",   RT_SUBMODEL_O(treetop),         BU_STRUCTPARSE_FUNC_NULL },
00066         {"%d",  1, "meth",      RT_SUBMODEL_O(meth),            BU_STRUCTPARSE_FUNC_NULL },
00067         {"",    0, (char *)0, 0,                        BU_STRUCTPARSE_FUNC_NULL }
00068 };
00069 
00070 /* ray tracing form of solid, including precomputed terms */
00071 struct submodel_specific {
00072         long            magic;
00073         mat_t           subm2m;         /* To transform normals back out to model coords */
00074         mat_t           m2subm;         /* To transform rays into local coord sys */
00075         struct rt_i     *rtip;          /* sub model */
00076 };
00077 #define RT_SUBMODEL_SPECIFIC_MAGIC      0x73756253      /* subS */
00078 #define RT_CK_SUBMODEL_SPECIFIC(_p)     BU_CKMAG(_p,RT_SUBMODEL_SPECIFIC_MAGIC,"submodel_specific")
00079 
00080 
00081 /**
00082  *                      R T _ S U B M O D E L _ P R E P
00083  *
00084  *  Given a pointer to a GED database record, and a transformation matrix,
00085  *  determine if this is a valid SUBMODEL, and if so, precompute various
00086  *  terms of the formula.
00087  *
00088  *  Returns -
00089  *      0       SUBMODEL is OK
00090  *      !0      Error in description
00091  *
00092  *  Implicit return -
00093  *      A struct submodel_specific is created, and it's address is stored in
00094  *      stp->st_specific for use by submodel_shot().
00095  */
00096 int
00097 rt_submodel_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00098 {
00099         struct rt_submodel_internal     *sip;
00100         struct submodel_specific        *submodel;
00101         struct rt_i                     *sub_rtip;
00102         struct db_i                     *sub_dbip;
00103         struct resource                 *resp;
00104         vect_t  radvec;
00105         vect_t  diam;
00106         char    *argv[2];
00107         struct rt_i     **rtipp;
00108 
00109         RT_CK_DB_INTERNAL(ip);
00110         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00111         RT_SUBMODEL_CK_MAGIC(sip);
00112 
00113         bu_semaphore_acquire(RT_SEM_MODEL);
00114         /*
00115          * This code must be prepared to run in parallel
00116          * without tripping over itself.
00117          */
00118         if( bu_vls_strlen( &sip->file ) == 0 )  {
00119                 /* No .g file name given, tree is in current .g file */
00120                 sub_dbip = rtip->rti_dbip;
00121         } else {
00122                 /* db_open will cache dbip's via bu_open_mapped_file() */
00123                 if( (sub_dbip = db_open( bu_vls_addr( &sip->file ), "r" )) == DBI_NULL )
00124                         return -1;
00125 
00126                 /* Save the overhead of stat() calls on subsequent opens */
00127                 if( sub_dbip->dbi_mf )  sub_dbip->dbi_mf->dont_restat = 1;
00128 
00129                 if( !db_is_directory_non_empty(sub_dbip) )  {
00130                         /* This is first open of db, build directory */
00131                         if( db_dirbuild( sub_dbip ) < 0 )  {
00132                                 db_close( sub_dbip );
00133                                 bu_semaphore_release(RT_SEM_MODEL);
00134                                 return -1;
00135                         }
00136                 }
00137         }
00138 
00139         /*
00140          *  Search for a previous exact use of this file and treetop,
00141          *  so as to obtain storage efficiency from re-using it.
00142          *  Search dbi_client list for a re-use of an rt_i.
00143          *  rtip's are registered there by db_clone_dbi().
00144          */
00145         for( BU_PTBL_FOR( rtipp, (struct rt_i **), &sub_dbip->dbi_clients ) )  {
00146                 register char   *ttp;
00147                 RT_CK_RTI(*rtipp);
00148                 ttp = (*rtipp)->rti_treetop;
00149                 if( ttp && strcmp( ttp, bu_vls_addr( &sip->treetop ) ) == 0 )  {
00150                         /* Re-cycle an already prepped rti */
00151                         sub_rtip = *rtipp;
00152                         sub_rtip->rti_uses++;
00153 
00154                         bu_semaphore_release(RT_SEM_MODEL);
00155 
00156                         if( RT_G_DEBUG & (DEBUG_DB|DEBUG_SOLIDS) )  {
00157                                 bu_log("rt_submodel_prep(%s): Re-used already prepped database %s, rtip=x%lx\n",
00158                                         stp->st_dp->d_namep,
00159                                         sub_dbip->dbi_filename,
00160                                         (long)sub_rtip );
00161                         }
00162                         goto done;
00163                 }
00164         }
00165 
00166         sub_rtip = rt_new_rti( sub_dbip );      /* does db_clone_dbi() */
00167         RT_CK_RTI(sub_rtip);
00168 
00169         /* Set search term before leaving critical section */
00170         sub_rtip->rti_treetop = bu_vls_strdup(&sip->treetop);
00171 
00172         bu_semaphore_release(RT_SEM_MODEL);
00173 
00174         if( RT_G_DEBUG & (DEBUG_DB|DEBUG_SOLIDS) )  {
00175                 bu_log("rt_submodel_prep(%s): Opened database %s\n",
00176                         stp->st_dp->d_namep, sub_dbip->dbi_filename );
00177         }
00178 
00179         /*
00180          *  Initialize per-processor resources for the submodel.
00181          *  We treewalk here with only one processor (CPU 0).
00182          *  db_walk_tree() as called from
00183          *  rt_gettrees() will pluck the 0th resource out of the rtip table.
00184          *  rt_submodel_shot() will get additional resources as needed.
00185          */
00186         BU_GETSTRUCT( resp, resource );
00187         BU_PTBL_SET(&sub_rtip->rti_resources, 0, resp);
00188         rt_init_resource( resp, 0, sub_rtip );
00189 
00190         /* Propagate some important settings downward */
00191         sub_rtip->useair = rtip->useair;
00192         sub_rtip->rti_dont_instance = rtip->rti_dont_instance;
00193         sub_rtip->rti_hasty_prep = rtip->rti_hasty_prep;
00194         sub_rtip->rti_tol = rtip->rti_tol;      /* struct copy */
00195         sub_rtip->rti_ttol = rtip->rti_ttol;    /* struct copy */
00196 
00197         if( sip->meth )  {
00198                 sub_rtip->rti_space_partition = sip->meth;
00199         } else {
00200                 sub_rtip->rti_space_partition = rtip->rti_space_partition;
00201         }
00202 
00203         argv[0] = bu_vls_addr( &sip->treetop );
00204         argv[1] = NULL;
00205         if( rt_gettrees( sub_rtip, 1, (const char **)argv, 1 ) < 0 )  {
00206                 bu_log("submodel(%s) rt_gettrees(%s) failed\n", stp->st_name, argv[0]);
00207                 /* Can't call rt_free_rti( sub_rtip ) because it may have
00208                  * already been instanced!
00209                  */
00210                 return -2;
00211         }
00212 
00213         if( sub_rtip->nsolids <= 0 )  {
00214                 bu_log("rt_submodel_prep(%s): %s No primitives found\n",
00215                         stp->st_dp->d_namep, bu_vls_addr( &sip->file ) );
00216                 /* Can't call rt_free_rti( sub_rtip ) because it may have
00217                  * already been instanced!
00218                  */
00219                 return -3;
00220         }
00221 
00222         /* OK, it's going to work.  Prep the submodel. */
00223         /* Stay on 1 CPU because we're already multi-threaded at this point. */
00224         rt_prep_parallel(sub_rtip, 1);
00225 
00226         /* Ensure bu_ptbl rti_resources is full size.  Ptrs will be null */
00227         if( BU_PTBL_LEN(&sub_rtip->rti_resources) < sub_rtip->rti_resources.blen )  {
00228                 BU_PTBL_LEN(&sub_rtip->rti_resources) = sub_rtip->rti_resources.blen;
00229         }
00230 
00231 if(RT_G_DEBUG) rt_pr_cut_info( sub_rtip, stp->st_name );
00232 
00233 done:
00234         BU_GETSTRUCT( submodel, submodel_specific );
00235         submodel->magic = RT_SUBMODEL_SPECIFIC_MAGIC;
00236         stp->st_specific = (genptr_t)submodel;
00237 
00238         MAT_COPY( submodel->subm2m, sip->root2leaf );
00239         bn_mat_inv( submodel->m2subm, sip->root2leaf );
00240         submodel->rtip = sub_rtip;
00241 
00242         /* Propagage submodel bounding box back upwards, rotated&scaled. */
00243         bn_rotate_bbox( stp->st_min, stp->st_max,
00244                 submodel->subm2m,
00245                 sub_rtip->mdl_min, sub_rtip->mdl_max );
00246 
00247         VSUB2( diam, stp->st_max, stp->st_min );
00248         VADD2SCALE( stp->st_center, stp->st_min, stp->st_max, 0.5 );
00249         VSCALE( radvec, diam, 0.5 );
00250         stp->st_aradius = stp->st_bradius = MAGNITUDE( radvec );
00251 
00252         if( RT_G_DEBUG & (DEBUG_DB|DEBUG_SOLIDS) )  {
00253                 bu_log("rt_submodel_prep(%s): finished loading database %s\n",
00254                         stp->st_dp->d_namep, sub_dbip->dbi_filename );
00255         }
00256 
00257         return(0);              /* OK */
00258 }
00259 
00260 /**
00261  *                      R T _ S U B M O D E L _ P R I N T
00262  */
00263 void
00264 rt_submodel_print(register const struct soltab *stp)
00265 {
00266         register const struct submodel_specific *submodel =
00267                 (struct submodel_specific *)stp->st_specific;
00268 
00269         RT_CK_SUBMODEL_SPECIFIC(submodel);
00270 
00271         bn_mat_print("subm2m", submodel->subm2m);
00272         bn_mat_print("m2subm", submodel->m2subm);
00273 
00274         bu_log_indent_delta(4);
00275         bu_log("submodel->rtip=x%x\n", submodel->rtip);
00276 
00277         /* Loop through submodel's solid table printing them too. */
00278         RT_VISIT_ALL_SOLTABS_START( stp, submodel->rtip )  {
00279                 rt_pr_soltab(stp);
00280         } RT_VISIT_ALL_SOLTABS_END
00281         bu_log_indent_delta(-4);
00282 }
00283 
00284 
00285 /**
00286  *                      R T _ S U B M O D E L _ A _ M I S S
00287  */
00288 int
00289 rt_submodel_a_miss(struct application *ap)
00290 {
00291         return 0;
00292 }
00293 
00294 struct submodel_gobetween {
00295         struct application      *up_ap;
00296         struct seg              *up_seghead;
00297         struct soltab           *up_stp;
00298         fastf_t                 delta;          /* distance offset */
00299 };
00300 
00301 /**
00302  *                      R T _ S U B M O D E L _ A _ H I T
00303  */
00304 int
00305 rt_submodel_a_hit(struct application *ap, struct partition *PartHeadp, struct seg *segHeadp)
00306 {
00307         register struct partition *pp;
00308         struct application      *up_ap;
00309         struct soltab           *up_stp;
00310         struct region           *up_reg;
00311         struct submodel_gobetween *gp;
00312         struct submodel_specific *submodel;
00313         int                     count = 0;
00314 
00315         RT_AP_CHECK(ap);
00316         RT_CK_PT_HD(PartHeadp);
00317         gp = (struct submodel_gobetween *)ap->a_uptr;
00318         up_ap = gp->up_ap;
00319         RT_AP_CHECK(up_ap);             /* original ap, in containing  */
00320         RT_CK_RTI(up_ap->a_rt_i);
00321         up_stp = gp->up_stp;
00322         RT_CK_SOLTAB(up_stp);
00323         submodel = (struct submodel_specific *)up_stp->st_specific;
00324         RT_CK_SUBMODEL_SPECIFIC(submodel);
00325 
00326         /* Take the first containing region */
00327         up_reg = (struct region *)BU_PTBL_GET(&(up_stp->st_regions), 0);
00328         RT_CK_REGION(up_reg);
00329 
00330         /* Need to tackle this honestly --
00331          * build a totally new segment list from the partition list,
00332          * with normals, uv, and curvature already computed,
00333          * and converted back into up_model coordinate system,
00334          * so the lazy-evaluation routines don't have to do anything.
00335          * This is probably almost as cheap as the coordinate
00336          * re-mapping in the special hook routines.
00337          * Then the submodel can be stacked arbitrarily deep.
00338          */
00339         for( BU_LIST_FOR( pp, partition, (struct bu_list *)PartHeadp ) )  {
00340                 struct seg      *up_segp;
00341                 struct seg      *inseg;
00342                 struct seg      *outseg;
00343 
00344                 RT_CK_PT(pp);
00345                 inseg = pp->pt_inseg;
00346                 outseg = pp->pt_outseg;
00347                 RT_CK_SEG(inseg);
00348                 RT_CK_SEG(outseg);
00349 
00350                 /*
00351                  * Construct a completely new segment
00352                  *   build seg_in, seg_out, and seg_stp.
00353                  * Take seg_in and seg_out literally, to track surfno, etc.,
00354                  * then update specific values.
00355                  */
00356                 RT_GET_SEG(up_segp, up_ap->a_resource );
00357                 up_segp->seg_in = inseg->seg_in;                /* struct copy */
00358                 up_segp->seg_out = outseg->seg_out;     /* struct copy */
00359                 up_segp->seg_stp = up_stp;
00360 
00361                 /* Adjust for scale difference */
00362                 MAT4XSCALOR( up_segp->seg_in.hit_dist, submodel->subm2m, inseg->seg_in.hit_dist);
00363                 up_segp->seg_in.hit_dist -= gp->delta;
00364                 MAT4XSCALOR( up_segp->seg_out.hit_dist, submodel->subm2m, outseg->seg_out.hit_dist);
00365                 up_segp->seg_out.hit_dist -= gp->delta;
00366 
00367                 BU_ASSERT_DOUBLE(up_segp->seg_in.hit_dist, <=, up_segp->seg_out.hit_dist );
00368 
00369                 /* Link to ray in upper model, not submodel */
00370                 up_segp->seg_in.hit_rayp = &up_ap->a_ray;
00371                 up_segp->seg_out.hit_rayp = &up_ap->a_ray;
00372 
00373                 /* Pre-calculate what would have been "lazy evaluation" */
00374                 VJOIN1( up_segp->seg_in.hit_point,  up_ap->a_ray.r_pt,
00375                         up_segp->seg_in.hit_dist, up_ap->a_ray.r_dir );
00376                 VJOIN1( up_segp->seg_out.hit_point,  up_ap->a_ray.r_pt,
00377                         up_segp->seg_out.hit_dist, up_ap->a_ray.r_dir );
00378 
00379                 /* RT_HIT_NORMAL */
00380                 inseg->seg_stp->st_meth->ft_norm(
00381                         &inseg->seg_in,
00382                         inseg->seg_stp,
00383                         inseg->seg_in.hit_rayp );
00384                 outseg->seg_stp->st_meth->ft_norm(
00385                         &outseg->seg_out,
00386                         outseg->seg_stp,
00387                         outseg->seg_out.hit_rayp );
00388 /* XXX error checking */
00389         { fastf_t cosine = fabs(VDOT( ap->a_ray.r_dir, inseg->seg_in.hit_normal ));
00390                 if( cosine > 1.00001 )  {
00391                         bu_log("rt_submodel_a_hit() cos=1+%g, %s surfno=%d\n",
00392                                 cosine-1,
00393                                 inseg->seg_stp->st_dp->d_namep,
00394                                 inseg->seg_in.hit_surfno );
00395                         VPRINT("inseg->seg_in.hit_normal", inseg->seg_in.hit_normal);
00396                 }
00397         }
00398                 MAT3X3VEC( up_segp->seg_in.hit_normal, submodel->subm2m,
00399                         inseg->seg_in.hit_normal );
00400 /* XXX error checking */
00401         { fastf_t cosine = fabs(VDOT( up_ap->a_ray.r_dir, up_segp->seg_in.hit_normal ));
00402                 if( cosine > 1.00001 )  {
00403                         bu_log("rt_submodel_a_hit() cos=1+%g, %s surfno=%d\n",
00404                                 cosine-1,
00405                                 inseg->seg_stp->st_dp->d_namep,
00406                                 inseg->seg_in.hit_surfno );
00407                         VPRINT("up_segp->seg_in.hit_normal", up_segp->seg_in.hit_normal);
00408                 }
00409         }
00410                 MAT3X3VEC( up_segp->seg_out.hit_normal, submodel->subm2m,
00411                         outseg->seg_out.hit_normal );
00412 
00413                 /* RT_HIT_UV */
00414                 {
00415                         struct uvcoord  uv;
00416                         RT_HIT_UVCOORD( ap, inseg->seg_stp, &inseg->seg_in, &uv );
00417                         up_segp->seg_in.hit_vpriv[X] = uv.uv_u;
00418                         up_segp->seg_in.hit_vpriv[Y] = uv.uv_v;
00419                         if( uv.uv_du >= uv.uv_dv )
00420                                 up_segp->seg_in.hit_vpriv[Z] = uv.uv_du;
00421                         else
00422                                 up_segp->seg_in.hit_vpriv[Z] = uv.uv_dv;
00423 
00424                         RT_HIT_UVCOORD( ap, outseg->seg_stp, &outseg->seg_out, &uv );
00425                         up_segp->seg_out.hit_vpriv[X] = uv.uv_u;
00426                         up_segp->seg_out.hit_vpriv[Y] = uv.uv_v;
00427                         if( uv.uv_du >= uv.uv_dv )
00428                                 up_segp->seg_out.hit_vpriv[Z] = uv.uv_du;
00429                         else
00430                                 up_segp->seg_out.hit_vpriv[Z] = uv.uv_dv;
00431                 }
00432 
00433                 /* RT_HIT_CURVATURE */
00434                 /* no place to stash curvature data! */
00435 
00436                 /*
00437                  *  Here, the surfno reported upwards is the solid's
00438                  *  index (bit) number in the submodel.
00439                  *  This can be used as subscript to rti_Solids[]
00440                  *  to retrieve the identity of the solid that was hit.
00441                  */
00442                 up_segp->seg_in.hit_surfno = inseg->seg_stp->st_bit;
00443                 up_segp->seg_out.hit_surfno = outseg->seg_stp->st_bit;
00444 
00445                 /* Put this segment on caller's shot routine seglist */
00446                 BU_LIST_INSERT( &(gp->up_seghead->l), &(up_segp->l) );
00447                 count++;
00448         }
00449         return count;
00450 }
00451 
00452 /**
00453  *                      R T _ S U B M O D E L _ S H O T
00454  *
00455  *  Intersect a ray with a submodel.
00456  *  If an intersection occurs, a struct seg will be acquired
00457  *  and filled in.
00458  *
00459  *  Returns -
00460  *      0       MISS
00461  *      >0      HIT
00462  */
00463 int
00464 rt_submodel_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00465 {
00466         register struct submodel_specific *submodel =
00467                 (struct submodel_specific *)stp->st_specific;
00468         struct application      sub_ap;
00469         struct submodel_gobetween       gb;
00470         vect_t                  vdiff;
00471         int                     code;
00472         struct bu_ptbl          *restbl;
00473         struct resource         *resp;
00474         int                     cpu;
00475 
00476         RT_CK_SOLTAB(stp);
00477         RT_CK_RTI(ap->a_rt_i);
00478         RT_CK_SUBMODEL_SPECIFIC(submodel);
00479 
00480         gb.up_ap = ap;
00481         gb.up_seghead = seghead;
00482         gb.up_stp = stp;
00483 
00484         sub_ap = *ap;           /* struct copy */
00485         sub_ap.a_rt_i = submodel->rtip;
00486         sub_ap.a_hit = rt_submodel_a_hit;
00487         sub_ap.a_miss = rt_submodel_a_miss;
00488         sub_ap.a_uptr = (genptr_t)&gb;
00489         sub_ap.a_purpose = "rt_submodel_shot";
00490 
00491         /* Ensure even # of accurate hits, for building good partitions */
00492         if( sub_ap.a_onehit < 0 )  {
00493                 if( sub_ap.a_onehit&1 )  sub_ap.a_onehit--;
00494         } else {
00495                 if( sub_ap.a_onehit&1 )  sub_ap.a_onehit++;
00496         }
00497 
00498         /*
00499          * Obtain the resource structure for this CPU.
00500          * No need to semaphore because there is one pointer per cpu already.
00501          */
00502         restbl = &submodel->rtip->rti_resources;        /* a ptbl */
00503         cpu = ap->a_resource->re_cpu;
00504         BU_ASSERT_LONG( cpu, <, BU_PTBL_END(restbl) );
00505         if( (resp = (struct resource *)BU_PTBL_GET(restbl, cpu)) == NULL )  {
00506                 /* First ray for this cpu for this submodel, alloc up */
00507                 BU_GETSTRUCT( resp, resource );
00508                 BU_PTBL_SET(restbl, cpu, resp);
00509                 rt_init_resource( resp, cpu, submodel->rtip );
00510         }
00511         RT_CK_RESOURCE(resp);
00512         sub_ap.a_resource = resp;
00513 
00514         /* shootray already computed a_ray.r_min & r_max for us */
00515         /* Construct the ray in submodel coords. */
00516         /* Do this in a repeatable way */
00517         /* Distances differ only by a scale factor of m[15] */
00518         MAT4X3PNT( sub_ap.a_ray.r_pt, submodel->m2subm, ap->a_ray.r_pt );
00519         MAT3X3VEC( sub_ap.a_ray.r_dir, submodel->m2subm, ap->a_ray.r_dir );
00520 
00521         /* NOTE: ap->a_ray.r_pt is not the same as rp->r_pt! */
00522         /* This changes the distances */
00523         VSUB2( vdiff, rp->r_pt, ap->a_ray.r_pt );
00524         gb.delta = VDOT( vdiff, ap->a_ray.r_dir );
00525 
00526         code = rt_shootray( &sub_ap );
00527 
00528         if( code <= 0 )  return 0;      /* MISS */
00529 
00530         /* All the real (sneaky) work is done in the hit routine */
00531         /* a_hit routine will have added the segs to seghead */
00532 
00533         return 1;               /* HIT */
00534 }
00535 
00536 #define RT_SUBMODEL_SEG_MISS(SEG)       (SEG).seg_stp=RT_SOLTAB_NULL
00537 
00538 /**
00539  *                      R T _ S U B M O D E L _ V S H O T
00540  *
00541  *  Vectorized version.
00542  */
00543 void
00544 rt_submodel_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00545                                /* An array of solid pointers */
00546                                /* An array of ray pointers */
00547                                /* array of segs (results returned) */
00548                                /* Number of ray/object pairs */
00549 
00550 {
00551         rt_vstub( stp, rp, segp, n, ap );
00552 }
00553 
00554 /**
00555  *                      R T _ S U B M O D E L _ N O R M
00556  *
00557  *  Given ONE ray distance, return the normal and entry/exit point.
00558  */
00559 void
00560 rt_submodel_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00561 {
00562         RT_CK_HIT(hitp);
00563 
00564         /* hitp->hit_point is already valid */
00565         /* hitp->hit_normal is already valid */
00566 /* XXX error checking */
00567         { fastf_t cosine = fabs(VDOT( rp->r_dir, hitp->hit_normal ));
00568                 if( cosine > 1.00001 )  {
00569                         bu_log("rt_submodel_norm() cos=1+%g, %s surfno=%d\n",
00570                                 cosine-1,
00571                                 stp->st_dp->d_namep,
00572                                 hitp->hit_surfno );
00573                 }
00574         }
00575 }
00576 
00577 /**
00578  *                      R T _ S U B M O D E L _ C U R V E
00579  *
00580  *  Return the curvature of the submodel.
00581  */
00582 void
00583 rt_submodel_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00584 {
00585         cvp->crv_c1 = cvp->crv_c2 = 0;
00586 
00587         /* any tangent direction */
00588         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00589 
00590         /* XXX This will never be called */
00591         bu_log("rt_submodel_curve() not implemented, need extra fields in 'struct hit'\n");
00592 }
00593 
00594 /**
00595  *                      R T _ S U B M O D E L _ U V
00596  *
00597  *  For a hit on the surface of an submodel, return the (u,v) coordinates
00598  *  of the hit point, 0 <= u,v <= 1.
00599  *  u = azimuth
00600  *  v = elevation
00601  */
00602 void
00603 rt_submodel_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00604 {
00605         RT_CK_HIT(hitp);
00606 
00607         uvp->uv_u = hitp->hit_vpriv[X];
00608         uvp->uv_v = hitp->hit_vpriv[Y];
00609         uvp->uv_du = uvp->uv_dv = hitp->hit_vpriv[Z];
00610 }
00611 
00612 /**
00613  *              R T _ S U B M O D E L _ F R E E
00614  */
00615 void
00616 rt_submodel_free(register struct soltab *stp)
00617 {
00618         register struct submodel_specific *submodel =
00619                 (struct submodel_specific *)stp->st_specific;
00620         struct resource **rpp;
00621         struct rt_i     *rtip;
00622 
00623         RT_CK_SUBMODEL_SPECIFIC(submodel);
00624         rtip = submodel->rtip;
00625         RT_CK_RTI(rtip);
00626 
00627         /* Specificially free resource structures here */
00628         BU_CK_PTBL( &rtip->rti_resources );
00629         for( BU_PTBL_FOR( rpp, (struct resource **), &rtip->rti_resources ) )  {
00630                 if( *rpp == NULL )  continue;
00631                 if( *rpp == &rt_uniresource )  continue;
00632                 RT_CK_RESOURCE(*rpp);
00633                 /* Cleans but does not free the resource struct */
00634                 rt_clean_resource(rtip, *rpp);
00635                 bu_free( *rpp, "struct resource (submodel)" );
00636                 /* Forget remembered ptr */
00637                 *rpp = NULL;
00638         }
00639         /* Keep the ptbl allocated. */
00640 
00641         rt_free_rti( submodel->rtip );
00642 
00643         bu_free( (genptr_t)submodel, "submodel_specific" );
00644 }
00645 
00646 /**
00647  *                      R T _ S U B M O D E L _ C L A S S
00648  */
00649 int
00650 rt_submodel_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
00651 {
00652         return RT_CLASSIFY_UNIMPLEMENTED;
00653 }
00654 
00655 struct goodies {
00656         struct db_i             *dbip;
00657         struct bu_list          *vheadp;
00658 };
00659 
00660 /**
00661  *                      R T _ S U B M O D E L _ W I R E F R A M E _ L E A F
00662  *
00663  *  This routine must be prepared to run in parallel.
00664  *  This routine should be generally exported for other uses.
00665  */
00666 HIDDEN union tree *rt_submodel_wireframe_leaf(struct db_tree_state *tsp, struct db_full_path *pathp, struct rt_db_internal *ip, genptr_t client_data)
00667 {
00668         union tree      *curtree;
00669         struct goodies  *gp;
00670 
00671         RT_CK_TESS_TOL(tsp->ts_ttol);
00672         BN_CK_TOL(tsp->ts_tol);
00673         RT_CK_DB_INTERNAL(ip );
00674         RT_CK_RESOURCE(tsp->ts_resp);
00675 
00676         gp = (struct goodies *)tsp->ts_m;       /* hack */
00677         RT_CK_DBI(gp->dbip);
00678 
00679         /* NON-PARALLEL access to vlist pointed to by vheadp is not semaphored */
00680         if(bu_is_parallel()) bu_bomb("rt_submodel_wireframe_leaf() non-parallel code\n");
00681 
00682         if(RT_G_DEBUG&DEBUG_TREEWALK)  {
00683                 char    *sofar = db_path_to_string(pathp);
00684 
00685                 bu_log("rt_submodel_wireframe_leaf(%s) path=%s\n",
00686                         ip->idb_meth->ft_name, sofar );
00687                 bu_free((genptr_t)sofar, "path string");
00688         }
00689 
00690         if( ip->idb_meth->ft_plot(
00691             gp->vheadp, ip,
00692             tsp->ts_ttol, tsp->ts_tol ) < 0 )  {
00693                 bu_log("rt_submodel_wireframe_leaf(%s): %s plot failure\n",
00694                         ip->idb_meth->ft_name,
00695                         DB_FULL_PATH_CUR_DIR(pathp)->d_namep );
00696                 return(TREE_NULL);              /* ERROR */
00697         }
00698 
00699         /* Indicate success by returning something other than TREE_NULL */
00700         RT_GET_TREE( curtree, tsp->ts_resp);
00701         curtree->magic = RT_TREE_MAGIC;
00702         curtree->tr_op = OP_NOP;
00703 
00704         return( curtree );
00705 }
00706 
00707 /**
00708  *                      R T _ S U B M O D E L _ P L O T
00709  *
00710  *  Not unlike mged/dodraw.c drawtrees()
00711  *
00712  *  Note:  The submodel will be drawn entirely in one color
00713  *  (for mged, typically this is red),
00714  *  because we can't return a vlblock, only one vlist,
00715  *  which by definition, is all one color.
00716  */
00717 int
00718 rt_submodel_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00719 {
00720         LOCAL struct rt_submodel_internal       *sip;
00721         struct db_tree_state    state;
00722         int                     ret;
00723         char                    *argv[2];
00724         struct goodies          good;
00725 
00726         RT_CK_DB_INTERNAL(ip);
00727         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00728         RT_SUBMODEL_CK_MAGIC(sip);
00729 
00730         /*      BU_LIST_INIT( vhead ); */
00731 
00732         state = rt_initial_tree_state;  /* struct copy */
00733         state.ts_ttol = ttol;
00734         state.ts_tol = tol;
00735         MAT_COPY( state.ts_mat, sip->root2leaf );
00736 
00737         state.ts_m = (struct model **)&good;    /* hack -- passthrough to rt_submodel_wireframe_leaf() */
00738         good.vheadp = vhead;
00739 
00740         if( bu_vls_strlen( &sip->file ) != 0 )  {
00741                 /* db_open will cache dbip's via bu_open_mapped_file() */
00742                 if( (good.dbip = db_open( bu_vls_addr( &sip->file ), "r" )) == DBI_NULL )  {
00743                         bu_log("rt_submodel_plot() db_open(%s) failure\n", bu_vls_addr( &sip->file ));
00744                         return -1;
00745                 }
00746                 if( !db_is_directory_non_empty(good.dbip) )  {
00747                         /* This is first open of this database, build directory */
00748                         if( db_dirbuild( good.dbip ) < 0 )  {
00749                                 bu_log("rt_submodel_plot() db_dirbuild() failure\n");
00750                                 db_close(good.dbip);
00751                                 return -1;
00752                         }
00753                 }
00754         } else {
00755                 /* stash a pointer to the current database instance
00756                  * (should the dbi be cloned?)
00757                  */
00758                 RT_CK_DBI(sip->dbip);
00759                 good.dbip = (struct db_i *)sip->dbip;   /* un-const-cast */
00760         }
00761 
00762         argv[0] = bu_vls_addr( &sip->treetop );
00763         argv[1] = NULL;
00764         ret = db_walk_tree( good.dbip, 1, (const char **)argv,
00765                 1,
00766                 &state,
00767                 0,                      /* take all regions */
00768                 NULL,                   /* rt_submodel_wireframe_region_end */
00769                 rt_submodel_wireframe_leaf,
00770                 (genptr_t)NULL );
00771 
00772         if( ret < 0 )  bu_log("rt_submodel_plot() db_walk_tree(%s) failure\n", bu_vls_addr( &sip->treetop ));
00773         if( bu_vls_strlen( &sip->file ) != 0 )
00774                 db_close(good.dbip);
00775         return ret;
00776 }
00777 
00778 /**
00779  *                      R T _ S U B M O D E L _ T E S S
00780  *
00781  *  Returns -
00782  *      -1      failure
00783  *       0      OK.  *r points to nmgregion that holds this tessellation.
00784  */
00785 int
00786 rt_submodel_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00787 {
00788         LOCAL struct rt_submodel_internal       *sip;
00789 
00790         RT_CK_DB_INTERNAL(ip);
00791         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00792         RT_SUBMODEL_CK_MAGIC(sip);
00793 
00794         return(-1);
00795 }
00796 
00797 /**
00798  *                      R T _ S U B M O D E L _ I M P O R T
00799  *
00800  *  Import an SUBMODEL from the database format to the internal format.
00801  *  Apply modeling transformations as well.
00802  */
00803 int
00804 rt_submodel_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00805 {
00806         LOCAL struct rt_submodel_internal       *sip;
00807         union record                    *rp;
00808         struct bu_vls           str;
00809 
00810         BU_CK_EXTERNAL( ep );
00811         RT_CK_DBI(dbip);
00812 
00813         rp = (union record *)ep->ext_buf;
00814         /* Check record type */
00815         if( rp->u_id != DBID_STRSOL )  {
00816                 bu_log("rt_submodel_import: defective strsol record\n");
00817                 return(-1);
00818         }
00819 
00820         RT_CK_DB_INTERNAL( ip );
00821         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00822         ip->idb_type = ID_SUBMODEL;
00823         ip->idb_meth = &rt_functab[ID_SUBMODEL];
00824         ip->idb_ptr = bu_malloc( sizeof(struct rt_submodel_internal), "rt_submodel_internal");
00825         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00826         sip->magic = RT_SUBMODEL_INTERNAL_MAGIC;
00827         sip->dbip = dbip;
00828 
00829         MAT_COPY( sip->root2leaf, mat );
00830 
00831         bu_vls_init( &str );
00832         bu_vls_strcpy( &str, rp->ss.ss_args );
00833 #if 0
00834 bu_log("rt_submodel_import: '%s'\n", rp->ss.ss_args);
00835 #endif
00836         if( bu_struct_parse( &str, rt_submodel_parse, (char *)sip ) < 0 )  {
00837                 bu_vls_free( &str );
00838 fail:
00839                 bu_free( (char *)sip , "rt_submodel_import: sip" );
00840                 ip->idb_type = ID_NULL;
00841                 ip->idb_ptr = (genptr_t)NULL;
00842                 return -2;
00843         }
00844         bu_vls_free( &str );
00845 
00846         /* Check for reasonable values */
00847         if( bu_vls_strlen( &sip->treetop ) == 0 )  {
00848                 bu_log("rt_submodel_import() treetop= must be specified\n");
00849                 goto fail;
00850         }
00851 #if 0
00852 bu_log("import: file='%s', treetop='%s', meth=%d\n", bu_vls_addr( &sip->file ), bu_vls_addr( &sip->treetop ), sip->meth);
00853 bn_mat_print("root2leaf", sip->root2leaf );
00854 #endif
00855 
00856         return(0);                      /* OK */
00857 }
00858 
00859 /**
00860  *                      R T _ S U B M O D E L _ E X P O R T
00861  *
00862  *  The name is added by the caller, in the usual place.
00863  */
00864 int
00865 rt_submodel_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00866 {
00867         struct rt_submodel_internal     *sip;
00868         union record            *rec;
00869         struct bu_vls           str;
00870 
00871         RT_CK_DB_INTERNAL(ip);
00872         if( ip->idb_type != ID_SUBMODEL )  return(-1);
00873         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00874         RT_SUBMODEL_CK_MAGIC(sip);
00875 #if 0
00876 bu_log("export: file='%s', treetop='%s', meth=%d\n", bu_vls_addr( &sip->file ), bu_vls_addr( &sip->treetop ), sip->meth);
00877 #endif
00878 
00879         /* Ignores scale factor */
00880         BU_ASSERT( local2mm == 1.0 );
00881 
00882         BU_CK_EXTERNAL(ep);
00883         ep->ext_nbytes = sizeof(union record)*DB_SS_NGRAN;
00884         ep->ext_buf = bu_calloc( 1, ep->ext_nbytes, "submodel external");
00885         rec = (union record *)ep->ext_buf;
00886 
00887         bu_vls_init( &str );
00888         bu_vls_struct_print( &str, rt_submodel_parse, (char *)sip );
00889 
00890         rec->ss.ss_id = DBID_STRSOL;
00891         strncpy( rec->ss.ss_keyword, "submodel", NAMESIZE-1 );
00892         strncpy( rec->ss.ss_args, bu_vls_addr(&str), DB_SS_LEN-1 );
00893         bu_vls_free( &str );
00894 #if 0
00895 bu_log("rt_submodel_export: '%s'\n", rec->ss.ss_args);
00896 #endif
00897 
00898         return(0);
00899 }
00900 
00901 
00902 /**
00903  *                      R T _ S U B M O D E L _ I M P O R T 5
00904  *
00905  *  Import an SUBMODEL from the database format to the internal format.
00906  *  Apply modeling transformations as well.
00907  */
00908 int
00909 rt_submodel_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00910 {
00911         LOCAL struct rt_submodel_internal       *sip;
00912         struct bu_vls           str;
00913 
00914         BU_CK_EXTERNAL( ep );
00915         RT_CK_DBI(dbip);
00916 
00917         RT_CK_DB_INTERNAL( ip );
00918         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00919         ip->idb_type = ID_SUBMODEL;
00920         ip->idb_meth = &rt_functab[ID_SUBMODEL];
00921         ip->idb_ptr = bu_malloc( sizeof(struct rt_submodel_internal), "rt_submodel_internal");
00922         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00923         sip->magic = RT_SUBMODEL_INTERNAL_MAGIC;
00924         sip->dbip = dbip;
00925 
00926         MAT_COPY( sip->root2leaf, mat );
00927 
00928         bu_vls_init( &str );
00929         bu_vls_strncpy( &str, ep->ext_buf, ep->ext_nbytes );
00930 #if 0
00931 bu_log("rt_submodel_import: '%s'\n", rp->ss.ss_args);
00932 #endif
00933         if( bu_struct_parse( &str, rt_submodel_parse, (char *)sip ) < 0 )  {
00934                 bu_vls_free( &str );
00935 fail:
00936                 bu_free( (char *)sip , "rt_submodel_import: sip" );
00937                 ip->idb_type = ID_NULL;
00938                 ip->idb_ptr = (genptr_t)NULL;
00939                 return -2;
00940         }
00941         bu_vls_free( &str );
00942 
00943         /* Check for reasonable values */
00944         if( bu_vls_strlen( &sip->treetop ) == 0 )  {
00945                 bu_log("rt_submodel_import() treetop= must be specified\n");
00946                 goto fail;
00947         }
00948 #if 0
00949 bu_log("import: file='%s', treetop='%s', meth=%d\n", bu_vls_addr( &sip->file ), bu_vls_addr( &sip->treetop ), sip->meth);
00950 bn_mat_print("root2leaf", sip->root2leaf );
00951 #endif
00952 
00953         return(0);                      /* OK */
00954 }
00955 
00956 /**
00957  *                      R T _ S U B M O D E L _ E X P O R T 5
00958  *
00959  *  The name is added by the caller, in the usual place.
00960  */
00961 int
00962 rt_submodel_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00963 {
00964         struct rt_submodel_internal     *sip;
00965         struct bu_vls           str;
00966 
00967         RT_CK_DB_INTERNAL(ip);
00968         if( ip->idb_type != ID_SUBMODEL )  return(-1);
00969         sip = (struct rt_submodel_internal *)ip->idb_ptr;
00970         RT_SUBMODEL_CK_MAGIC(sip);
00971 #if 0
00972 bu_log("export: file='%s', treetop='%s', meth=%d\n", bu_vls_addr( &sip->file ), bu_vls_addr( &sip->treetop ), sip->meth);
00973 #endif
00974 
00975         /* Ignores scale factor */
00976         BU_ASSERT( local2mm == 1.0 );
00977         BU_CK_EXTERNAL(ep);
00978 
00979         bu_vls_init( &str );
00980         bu_vls_struct_print( &str, rt_submodel_parse, (char *)sip );
00981         ep->ext_nbytes = bu_vls_strlen( &str );
00982         ep->ext_buf = bu_calloc( 1, ep->ext_nbytes, "submodel external");
00983 
00984         strncpy(ep->ext_buf, bu_vls_addr(&str), ep->ext_nbytes);
00985         bu_vls_free( &str );
00986 #if 0
00987 bu_log("rt_submodel_export: '%s'\n", rec->ss.ss_args);
00988 #endif
00989 
00990         return(0);
00991 }
00992 
00993 /**
00994  *                      R T _ S U B M O D E L _ D E S C R I B E
00995  *
00996  *  Make human-readable formatted presentation of this solid.
00997  *  First line describes type of solid.
00998  *  Additional lines are indented one tab, and give parameter values.
00999  */
01000 int
01001 rt_submodel_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01002 {
01003         register struct rt_submodel_internal    *sip =
01004                 (struct rt_submodel_internal *)ip->idb_ptr;
01005 
01006         RT_SUBMODEL_CK_MAGIC(sip);
01007         bu_vls_strcat( str, "instanced submodel (SUBMODEL)\n");
01008 
01009         bu_vls_printf(str, "\tfile='%s', treetop='%s', meth=%d\n",
01010                 bu_vls_addr( &sip->file ),
01011                 bu_vls_addr( &sip->treetop ),
01012                 sip->meth );
01013 
01014         return(0);
01015 }
01016 
01017 /**
01018  *                      R T _ S U B M O D E L _ I F R E E
01019  *
01020  *  Free the storage associated with the rt_db_internal version of this solid.
01021  */
01022 void
01023 rt_submodel_ifree(struct rt_db_internal *ip)
01024 {
01025         register struct rt_submodel_internal    *sip;
01026 
01027         RT_CK_DB_INTERNAL(ip);
01028         sip = (struct rt_submodel_internal *)ip->idb_ptr;
01029         RT_SUBMODEL_CK_MAGIC(sip);
01030         sip->magic = 0;                 /* sanity */
01031 
01032         bu_free( (genptr_t)sip, "submodel ifree" );
01033         ip->idb_ptr = GENPTR_NULL;      /* sanity */
01034 }
01035 
01036 /*
01037  * Local Variables:
01038  * mode: C
01039  * tab-width: 8
01040  * c-basic-offset: 4
01041  * indent-tabs-mode: t
01042  * End:
01043  * ex: shiftwidth=4 tabstop=8
01044  */

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