g_pg.c

Go to the documentation of this file.
00001 /*                          G _ P G . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-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_pg.c
00026  *      Intersect a ray with a Polygonal Object
00027  *      that has no explicit topology.
00028  *      It is assumed that the solid has no holes.
00029  *
00030  *  Author -
00031  *      Michael John Muuss
00032  *
00033  *  Source -
00034  *      SECAD/VLD Computing Consortium, Bldg 394
00035  *      The U. S. Army Ballistic Research Laboratory
00036  *      Aberdeen Proving Ground, Maryland  21005
00037  *
00038  */
00039 /*@}*/
00040 
00041 #ifndef lint
00042 static const char RCSpg[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_pg.c,v 14.11 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00043 #endif
00044 
00045 #include "common.h"
00046 
00047 
00048 
00049 #include <stdio.h>
00050 #include <math.h>
00051 #include "machine.h"
00052 #include "vmath.h"
00053 #include "db.h"
00054 #include "nmg.h"
00055 #include "rtgeom.h"
00056 #include "raytrace.h"
00057 #include "./debug.h"
00058 #include "./plane.h"
00059 
00060 #define TRI_NULL        ((struct tri_specific *)0)
00061 
00062 HIDDEN int rt_pgface(struct soltab *stp, fastf_t *ap, fastf_t *bp, fastf_t *cp, const struct bn_tol *tol);
00063 
00064 /* Describe algorithm here */
00065 
00066 
00067 /**
00068  *                      R T _ P G _ P R E P
00069  *
00070  *  This routine is used to prepare a list of planar faces for
00071  *  being shot at by the triangle routines.
00072  *
00073  * Process a PG, which is represented as a vector
00074  * from the origin to the first point, and many vectors
00075  * from the first point to the remaining points.
00076  *
00077  */
00078 int
00079 rt_pg_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00080 {
00081         struct rt_pg_internal   *pgp;
00082         register int    i;
00083         int             p;
00084 
00085         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00086         RT_PG_CK_MAGIC(pgp);
00087 
00088         for( p = 0; p < pgp->npoly; p++ )  {
00089                 LOCAL vect_t    work[3];
00090 
00091                 VMOVE( work[0], &pgp->poly[p].verts[0*3] );
00092                 VMINMAX( stp->st_min, stp->st_max, work[0] );
00093                 VMOVE( work[1], &pgp->poly[p].verts[1*3] );
00094                 VMINMAX( stp->st_min, stp->st_max, work[1] );
00095 
00096                 for( i=2; i < pgp->poly[p].npts; i++ )  {
00097                         VMOVE( work[2], &pgp->poly[p].verts[i*3] );
00098                         VMINMAX( stp->st_min, stp->st_max, work[2] );
00099 
00100                         /* output a face */
00101                         (void)rt_pgface( stp,
00102                                 work[0], work[1], work[2], &rtip->rti_tol );
00103 
00104                         /* Chop off a triangle, and continue */
00105                         VMOVE( work[1], work[2] );
00106                 }
00107         }
00108         if( stp->st_specific == (genptr_t)0 )  {
00109                 bu_log("pg(%s):  no faces\n", stp->st_name);
00110                 return(-1);             /* BAD */
00111         }
00112 
00113         {
00114                 LOCAL fastf_t dx, dy, dz;
00115                 LOCAL fastf_t   f;
00116 
00117                 VADD2SCALE( stp->st_center, stp->st_max, stp->st_min, 0.5 );
00118 
00119                 dx = (stp->st_max[X] - stp->st_min[X])/2;
00120                 f = dx;
00121                 dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00122                 if( dy > f )  f = dy;
00123                 dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00124                 if( dz > f )  f = dz;
00125                 stp->st_aradius = f;
00126                 stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00127         }
00128 
00129         return(0);              /* OK */
00130 }
00131 
00132 /**
00133  *                      R T _ P G F A C E
00134  *
00135  *  This function is called with pointers to 3 points,
00136  *  and is used to prepare PG faces.
00137  *  ap, bp, cp point to vect_t points.
00138  *
00139  * Return -
00140  *      0       if the 3 points didn't form a plane (eg, colinear, etc).
00141  *      # pts   (3) if a valid plane resulted.
00142  */
00143 HIDDEN int
00144 rt_pgface(struct soltab *stp, fastf_t *ap, fastf_t *bp, fastf_t *cp, const struct bn_tol *tol)
00145 {
00146         register struct tri_specific *trip;
00147         vect_t work;
00148         LOCAL fastf_t m1, m2, m3, m4;
00149 
00150         BU_GETSTRUCT( trip, tri_specific );
00151         VMOVE( trip->tri_A, ap );
00152         VSUB2( trip->tri_BA, bp, ap );
00153         VSUB2( trip->tri_CA, cp, ap );
00154         VCROSS( trip->tri_wn, trip->tri_BA, trip->tri_CA );
00155 
00156         /* Check to see if this plane is a line or pnt */
00157         m1 = MAGNITUDE( trip->tri_BA );
00158         m2 = MAGNITUDE( trip->tri_CA );
00159         VSUB2( work, bp, cp );
00160         m3 = MAGNITUDE( work );
00161         m4 = MAGNITUDE( trip->tri_wn );
00162         if( m1 < tol->dist || m2 < tol->dist ||
00163             m3 < tol->dist || m4 < tol->dist )  {
00164                 bu_free( (char *)trip, "getstruct tri_specific");
00165                 if( RT_G_DEBUG & DEBUG_ARB8 )
00166                         bu_log("pg(%s): degenerate facet\n", stp->st_name);
00167                 return(0);                      /* BAD */
00168         }
00169 
00170         /*  wn is a normal of not necessarily unit length.
00171          *  N is an outward pointing unit normal.
00172          *  We depend on the points being given in CCW order here.
00173          */
00174         VMOVE( trip->tri_N, trip->tri_wn );
00175         VUNITIZE( trip->tri_N );
00176 
00177         /* Add this face onto the linked list for this solid */
00178         trip->tri_forw = (struct tri_specific *)stp->st_specific;
00179         stp->st_specific = (genptr_t)trip;
00180         return(3);                              /* OK */
00181 }
00182 
00183 /**
00184  *                      R T _ P G _ P R I N T
00185  */
00186 void
00187 rt_pg_print(register const struct soltab *stp)
00188 {
00189         register const struct tri_specific *trip =
00190                 (struct tri_specific *)stp->st_specific;
00191 
00192         if( trip == TRI_NULL )  {
00193                 bu_log("pg(%s):  no faces\n", stp->st_name);
00194                 return;
00195         }
00196         do {
00197                 VPRINT( "A", trip->tri_A );
00198                 VPRINT( "B-A", trip->tri_BA );
00199                 VPRINT( "C-A", trip->tri_CA );
00200                 VPRINT( "BA x CA", trip->tri_wn );
00201                 VPRINT( "Normal", trip->tri_N );
00202                 bu_log("\n");
00203         } while( (trip = trip->tri_forw) );
00204 }
00205 
00206 /**
00207  *                      R T _ P G _ S H O T
00208  *
00209  * Function -
00210  *      Shoot a ray at a polygonal object.
00211  *
00212  * Returns -
00213  *      0       MISS
00214  *      >0      HIT
00215  */
00216 int
00217 rt_pg_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00218 {
00219         register struct tri_specific *trip =
00220                 (struct tri_specific *)stp->st_specific;
00221 #define MAXHITS 128             /* # surfaces hit, must be even */
00222         LOCAL struct hit hits[MAXHITS];
00223         register struct hit *hp;
00224         LOCAL int       nhits;
00225 
00226         nhits = 0;
00227         hp = &hits[0];
00228 
00229         /* consider each face */
00230         for( ; trip; trip = trip->tri_forw )  {
00231                 FAST fastf_t    dn;             /* Direction dot Normal */
00232                 LOCAL fastf_t   abs_dn;
00233                 FAST fastf_t    k;
00234                 LOCAL fastf_t   alpha, beta;
00235                 LOCAL vect_t    wxb;            /* vertex - ray_start */
00236                 LOCAL vect_t    xp;             /* wxb cross ray_dir */
00237 
00238                 /*
00239                  *  Ray Direction dot N.  (N is outward-pointing normal)
00240                  *  wn points inwards, and is not unit length.
00241                  */
00242                 dn = VDOT( trip->tri_wn, rp->r_dir );
00243 
00244                 /*
00245                  *  If ray lies directly along the face, (ie, dot product
00246                  *  is zero), drop this face.
00247                  */
00248                 abs_dn = dn >= 0.0 ? dn : (-dn);
00249                 if( abs_dn < SQRT_SMALL_FASTF )
00250                         continue;
00251                 VSUB2( wxb, trip->tri_A, rp->r_pt );
00252                 VCROSS( xp, wxb, rp->r_dir );
00253 
00254                 /* Check for exceeding along the one side */
00255                 alpha = VDOT( trip->tri_CA, xp );
00256                 if( dn < 0.0 )  alpha = -alpha;
00257                 if( alpha < 0.0 || alpha > abs_dn )
00258                         continue;
00259 
00260                 /* Check for exceeding along the other side */
00261                 beta = VDOT( trip->tri_BA, xp );
00262                 if( dn > 0.0 )  beta = -beta;
00263                 if( beta < 0.0 || beta > abs_dn )
00264                         continue;
00265                 if( alpha+beta > abs_dn )
00266                         continue;
00267                 k = VDOT( wxb, trip->tri_wn ) / dn;
00268 
00269                 /* For hits other than the first one, might check
00270                  *  to see it this is approx. equal to previous one */
00271 
00272                 /*  If dn < 0, we should be entering the solid.
00273                  *  However, we just assume in/out sorting later will work.
00274                  *  Really should mark and check this!
00275                  */
00276                 VJOIN1( hp->hit_point, rp->r_pt, k, rp->r_dir );
00277 
00278                 /* HIT is within planar face */
00279                 hp->hit_magic = RT_HIT_MAGIC;
00280                 hp->hit_dist = k;
00281                 VMOVE( hp->hit_normal, trip->tri_N );
00282                 if( ++nhits >= MAXHITS )  {
00283                         bu_log("rt_pg_shot(%s): too many hits (%d)\n", stp->st_name, nhits);
00284                         break;
00285                 }
00286                 hp++;
00287         }
00288         if( nhits == 0 )
00289                 return(0);              /* MISS */
00290 
00291         /* Sort hits, Near to Far */
00292         rt_hitsort( hits, nhits );
00293 
00294         /* Remove duplicate hits.
00295            We remove one of a pair of hits when they are
00296                 1) close together, and
00297                 2) both "entry" or both "exit" occurrences.
00298            Two immediate "entry" or two immediate "exit" hits suggest
00299            that we hit both of two joined faces, while we want to hit only
00300            one.  An "entry" followed by an "exit" (or vice versa) suggests
00301            that we grazed an edge, and thus we should leave both
00302            in the hit list. */
00303 
00304         {
00305                 register int i, j;
00306 
00307                 for( i=0 ; i<nhits-1 ; i++ )
00308                 {
00309                         fastf_t dist;
00310 
00311                         dist = hits[i].hit_dist - hits[i+1].hit_dist;
00312                         if( NEAR_ZERO( dist, ap->a_rt_i->rti_tol.dist ) &&
00313                                 VDOT( hits[i].hit_normal, rp->r_dir ) *
00314                                 VDOT( hits[i+1].hit_normal, rp->r_dir) > 0)
00315                         {
00316                                 for( j=i ; j<nhits-1 ; j++ )
00317                                         hits[j] = hits[j+1];
00318                                 nhits--;
00319                                 i--;
00320                         }
00321                 }
00322         }
00323 
00324 
00325         if( nhits == 1 )
00326                 nhits = 0;
00327 
00328         if( nhits&1 )  {
00329                 register int i;
00330                 static int nerrors = 0;         /* message counter */
00331                 /*
00332                  * If this condition exists, it is almost certainly due to
00333                  * the dn==0 check above.  Thus, we will make the last
00334                  * surface rather thin.
00335                  * This at least makes the
00336                  * presence of this solid known.  There may be something
00337                  * better we can do.
00338                  */
00339 
00340                 if( nerrors++ < 6 )  {
00341                         bu_log("rt_pg_shot(%s): WARNING %d hits:\n", stp->st_name, nhits);
00342                         bu_log( "\tray start = (%g %g %g) ray dir = (%g %g %g)\n",
00343                                 V3ARGS( rp->r_pt ), V3ARGS( rp->r_dir ) );
00344                         for(i=0; i < nhits; i++ )
00345                         {
00346                                 point_t tmp_pt;
00347 
00348                                 VJOIN1( tmp_pt, rp->r_pt, hits[i].hit_dist, rp->r_dir );
00349                                 if( VDOT( rp->r_dir, hits[i].hit_normal ) < 0.0 )
00350                                         bu_log("\tentrance at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS( tmp_pt ) );
00351                                 else
00352                                         bu_log("\texit at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS( tmp_pt ) );
00353                         }
00354                 }
00355 
00356                 if( nhits > 2 )
00357                 {
00358                         fastf_t dot1,dot2;
00359                         int j;
00360 
00361                         /* likely an extra hit,
00362                          * look for consecutive entrances or exits */
00363 
00364                         dot2 = 1.0;
00365                         i = 0;
00366                         while( i<nhits )
00367                         {
00368                                 dot1 = dot2;
00369                                 dot2 = VDOT( rp->r_dir, hits[i].hit_normal );
00370                                 if( dot1 > 0.0 && dot2 > 0.0 )
00371                                 {
00372                                         /* two consectutive exits,
00373                                          * manufacture an entrance at same distance
00374                                          * as second exit.
00375                                          */
00376                                         for( j=nhits ; j>i ; j-- )
00377                                                 hits[j] = hits[j-1];    /* struct copy */
00378 
00379                                         VREVERSE( hits[i].hit_normal, hits[i].hit_normal );
00380                                         dot2 = VDOT( rp->r_dir, hits[i].hit_normal );
00381                                         nhits++;
00382                                         bu_log( "\t\tadding fictitious entry at %f (%s)\n", hits[i].hit_dist, stp->st_name );
00383                                 }
00384                                 else if( dot1 < 0.0 && dot2 < 0.0 )
00385                                 {
00386                                         /* two consectutive entrances,
00387                                          * manufacture an exit between them.
00388                                          */
00389 
00390                                         for( j=nhits ; j>i ; j-- )
00391                                                 hits[j] = hits[j-1];    /* struct copy */
00392 
00393                                         hits[i] = hits[i-1];    /* struct copy */
00394                                         VREVERSE( hits[i].hit_normal, hits[i-1].hit_normal );
00395                                         dot2 = VDOT( rp->r_dir, hits[i].hit_normal );
00396                                         nhits++;
00397                                         bu_log( "\t\tadding fictitious exit at %f (%s)\n", hits[i].hit_dist, stp->st_name );
00398                                 }
00399                                 i++;
00400                         }
00401 
00402                 }
00403                 else
00404                 {
00405                         hits[nhits] = hits[nhits-1];    /* struct copy */
00406                         VREVERSE( hits[nhits].hit_normal, hits[nhits-1].hit_normal );
00407                         bu_log( "\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name );
00408                         nhits++;
00409                 }
00410         }
00411 
00412         if( nhits&1 )
00413         {
00414                 if( nhits < MAXHITS )
00415                 {
00416                         hits[nhits] = hits[nhits-1];    /* struct copy */
00417                         VREVERSE( hits[nhits].hit_normal, hits[nhits-1].hit_normal );
00418                         bu_log( "\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name );
00419                         nhits++;
00420                 }
00421                 else
00422                         nhits--;
00423         }
00424 
00425         /* nhits is even, build segments */
00426         {
00427                 register struct seg *segp;
00428                 register int    i;
00429                 for( i=0; i < nhits; i += 2 )  {
00430                         RT_GET_SEG(segp, ap->a_resource);
00431                         segp->seg_stp = stp;
00432                         segp->seg_in = hits[i];         /* struct copy */
00433                         segp->seg_out = hits[i+1];      /* struct copy */
00434                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00435                 }
00436         }
00437         return(nhits);                  /* HIT */
00438 }
00439 
00440 /**
00441  *                      R T _ P G _ F R E E
00442  */
00443 void
00444 rt_pg_free(struct soltab *stp)
00445 {
00446         register struct tri_specific *trip =
00447                 (struct tri_specific *)stp->st_specific;
00448 
00449         while( trip != TRI_NULL )  {
00450                 register struct tri_specific *nexttri = trip->tri_forw;
00451 
00452                 bu_free( (char *)trip, "pg tri_specific");
00453                 trip = nexttri;
00454         }
00455 }
00456 
00457 /**
00458  *                      R T _ P G _ N O R M
00459  */
00460 void
00461 rt_pg_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00462 {
00463         /* Normals computed in rt_pg_shot, nothing to do here */
00464 }
00465 
00466 /**
00467  *                      R T _ P G _ U V
00468  */
00469 void
00470 rt_pg_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00471 {
00472         /* Do nothing.  Really, should do what ARB does. */
00473         uvp->uv_u = uvp->uv_v = 0;
00474         uvp->uv_du = uvp->uv_dv = 0;
00475 }
00476 
00477 /**
00478  *                      R T _ P G _ C L A S S
00479  */
00480 int
00481 rt_pg_class(void)
00482 {
00483         return(0);
00484 }
00485 
00486 /**
00487  *                      R T _ P G _ P L O T
00488  */
00489 int
00490 rt_pg_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00491 {
00492         register int    i;
00493         register int    p;      /* current polygon number */
00494         struct rt_pg_internal   *pgp;
00495 
00496         RT_CK_DB_INTERNAL(ip);
00497         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00498         RT_PG_CK_MAGIC(pgp);
00499 
00500         for( p = 0; p < pgp->npoly; p++ )  {
00501                 register struct rt_pg_face_internal     *pp;
00502 
00503                 pp = &pgp->poly[p];
00504                 RT_ADD_VLIST( vhead, &pp->verts[3*(pp->npts-1)],
00505                         BN_VLIST_LINE_MOVE );
00506                 for( i=0; i < pp->npts; i++ )  {
00507                         RT_ADD_VLIST( vhead, &pp->verts[3*i],
00508                                 BN_VLIST_LINE_DRAW );
00509                 }
00510         }
00511         return(0);              /* OK */
00512 }
00513 
00514 /**
00515  *                      R T _ P G _ P L O T _ P O L Y
00516  *
00517  *  Convert to vlist, draw as polygons.
00518  */
00519 int
00520 rt_pg_plot_poly(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00521 {
00522         register int    i;
00523         register int    p;      /* current polygon number */
00524         struct rt_pg_internal   *pgp;
00525 
00526         RT_CK_DB_INTERNAL(ip);
00527         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00528         RT_PG_CK_MAGIC(pgp);
00529 
00530         for( p = 0; p < pgp->npoly; p++ )  {
00531                 register struct rt_pg_face_internal     *pp;
00532                 vect_t aa, bb, norm;
00533 
00534                 pp = &pgp->poly[p];
00535                 if (pp->npts < 3)
00536                         continue;
00537                 VSUB2( aa, &pp->verts[3*(0)], &pp->verts[3*(1)] );
00538                 VSUB2( bb, &pp->verts[3*(0)], &pp->verts[3*(2)] );
00539                 VCROSS( norm, aa, bb );
00540                 VUNITIZE(norm);
00541                 RT_ADD_VLIST(vhead, norm, BN_VLIST_POLY_START);
00542 
00543                 RT_ADD_VLIST(vhead, &pp->verts[3*(pp->npts-1)], BN_VLIST_POLY_MOVE);
00544                 for (i=0; i < pp->npts-1; i++) {
00545                         RT_ADD_VLIST(vhead, &pp->verts[3*i], BN_VLIST_POLY_DRAW);
00546                 }
00547                 RT_ADD_VLIST(vhead, &pp->verts[3*(pp->npts-1)], BN_VLIST_POLY_END);
00548         }
00549         return(0);              /* OK */
00550 }
00551 
00552 /**
00553  *                      R T _ P G _ C U R V E
00554  */
00555 void
00556 rt_pg_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00557 {
00558         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00559         cvp->crv_c1 = cvp->crv_c2 = 0;
00560 }
00561 
00562 /**
00563  *                      R T _ P G _ T E S S
00564  */
00565 int
00566 rt_pg_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00567 {
00568         register int    i;
00569         struct shell    *s;
00570         struct vertex   **verts;        /* dynamic array of pointers */
00571         struct vertex   ***vertp;/* dynamic array of ptrs to pointers */
00572         struct faceuse  *fu;
00573         register int    p;      /* current polygon number */
00574         struct rt_pg_internal   *pgp;
00575 
00576         RT_CK_DB_INTERNAL(ip);
00577         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00578         RT_PG_CK_MAGIC(pgp);
00579 
00580         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
00581         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
00582 
00583         verts = (struct vertex **)bu_malloc(
00584                 pgp->max_npts * sizeof(struct vertex *), "pg_tess verts[]");
00585         vertp = (struct vertex ***)bu_malloc(
00586                 pgp->max_npts * sizeof(struct vertex **), "pg_tess vertp[]");
00587         for( i=0; i < pgp->max_npts; i++ )
00588                 vertp[i] = &verts[i];
00589 
00590         for( p = 0; p < pgp->npoly; p++ )  {
00591                 register struct rt_pg_face_internal     *pp;
00592 
00593                 pp = &pgp->poly[p];
00594 
00595                 /* Locate these points, if previously mentioned */
00596                 for( i=0; i < pp->npts; i++ )  {
00597                         verts[i] = nmg_find_pt_in_shell( s,
00598                                 &pp->verts[3*i], tol );
00599                 }
00600 
00601                 /* Construct the face.  Verts should be in CCW order */
00602                 if( (fu = nmg_cmface( s, vertp, pp->npts )) == (struct faceuse *)0 )  {
00603                         bu_log("rt_pg_tess() nmg_cmface failed, skipping face %d\n",
00604                                 p);
00605                 }
00606 
00607                 /* Associate vertex geometry, where none existed before */
00608                 for( i=0; i < pp->npts; i++ )  {
00609                         if( verts[i]->vg_p )  continue;
00610                         nmg_vertex_gv( verts[i], &pp->verts[3*i] );
00611                 }
00612 
00613                 /* Associate face geometry */
00614                 if( nmg_calc_face_g( fu ) )
00615                 {
00616                         nmg_pr_fu_briefly( fu, "" );
00617                         bu_free( (char *)verts, "pg_tess verts[]" );
00618                         bu_free( (char *)vertp, "pg_tess vertp[]" );
00619                         return -1;                      /* FAIL */
00620                 }
00621         }
00622 
00623         /* Compute "geometry" for region and shell */
00624         nmg_region_a( *r, tol );
00625 
00626         /* Polysolids are often built with incorrect face normals.
00627          * Don't depend on them here.
00628          */
00629         nmg_fix_normals( s , tol );
00630 #if 0
00631         /* mark edges as real */
00632         (void)nmg_mark_edges_real( &s->l );
00633 #endif
00634         bu_free( (char *)verts, "pg_tess verts[]" );
00635         bu_free( (char *)vertp, "pg_tess vertp[]" );
00636 
00637         return(0);              /* OK */
00638 }
00639 
00640 /**
00641  *                      R T _ P G _ I M P O R T
00642  *
00643  *  Read all the polygons in as a complex dynamic structure.
00644  *  The caller is responsible for freeing the dynamic memory.
00645  *  (vid rt_pg_ifree).
00646  */
00647 int
00648 rt_pg_import(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00649 {
00650         struct rt_pg_internal   *pgp;
00651         union record            *rp;
00652         register int            i;
00653         int                     rno;            /* current record number */
00654         int                     p;              /* current polygon index */
00655 
00656         BU_CK_EXTERNAL( ep );
00657         rp = (union record *)ep->ext_buf;
00658         if( rp->u_id != ID_P_HEAD )  {
00659                 bu_log("rt_pg_import: defective header record\n");
00660                 return(-1);
00661         }
00662 
00663         RT_CK_DB_INTERNAL( ip );
00664         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00665         ip->idb_type = ID_POLY;
00666         ip->idb_meth = &rt_functab[ID_POLY];
00667         ip->idb_ptr = bu_malloc(sizeof(struct rt_pg_internal), "rt_pg_internal");
00668         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00669         pgp->magic = RT_PG_INTERNAL_MAGIC;
00670 
00671         pgp->npoly = (ep->ext_nbytes - sizeof(union record)) /
00672                 sizeof(union record);
00673         if( pgp->npoly <= 0 )  {
00674                 bu_log("rt_pg_import: polysolid with no polygons!\n");
00675                 return -1;
00676         }
00677         if( pgp->npoly )
00678                 pgp->poly = (struct rt_pg_face_internal *)bu_malloc(
00679                         pgp->npoly * sizeof(struct rt_pg_face_internal), "rt_pg_face_internal");
00680         pgp->max_npts = 0;
00681 
00682         for( p=0; p < pgp->npoly; p++ )  {
00683                 register struct rt_pg_face_internal     *pp;
00684 
00685                 pp = &pgp->poly[p];
00686                 rno = p+1;
00687                 if( rp[rno].q.q_id != ID_P_DATA )  {
00688                         bu_log("rt_pg_import: defective data record\n");
00689                         return -1;
00690                 }
00691                 pp->npts = rp[rno].q.q_count;
00692                 pp->verts = (fastf_t *)bu_malloc(
00693                         pp->npts * 3 * sizeof(fastf_t), "pg verts[]" );
00694                 pp->norms = (fastf_t *)bu_malloc(
00695                         pp->npts * 3 * sizeof(fastf_t), "pg norms[]" );
00696 #               include "noalias.h"
00697                 for( i=0; i < pp->npts; i++ )  {
00698                         /* Note:  side effect of importing dbfloat_t */
00699                         MAT4X3PNT( &pp->verts[i*3], mat,
00700                                 rp[rno].q.q_verts[i] );
00701                         MAT4X3VEC( &pp->norms[i*3], mat,
00702                                 rp[rno].q.q_norms[i] );
00703                 }
00704                 if( pp->npts > pgp->max_npts )  pgp->max_npts = pp->npts;
00705         }
00706         if( pgp->max_npts < 3 )  {
00707                 bu_log("rt_pg_import: polysolid with all polygons of less than %d vertices!\n", pgp->max_npts);
00708                 /* XXX free storage */
00709                 return -1;
00710         }
00711         return( 0 );
00712 }
00713 
00714 /**
00715  *                      R T _ P G _ E X P O R T
00716  *
00717  *  The name will be added by the caller.
00718  *  Generally, only libwdb will set conv2mm != 1.0
00719  */
00720 int
00721 rt_pg_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00722 {
00723         struct rt_pg_internal   *pgp;
00724         union record            *rec;
00725         register int            i;
00726         int                     rno;            /* current record number */
00727         int                     p;              /* current polygon index */
00728 
00729         RT_CK_DB_INTERNAL(ip);
00730         if( ip->idb_type != ID_POLY )  return(-1);
00731         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00732         RT_PG_CK_MAGIC(pgp);
00733 
00734         BU_CK_EXTERNAL(ep);
00735         ep->ext_nbytes = (1 + pgp->npoly) * sizeof(union record);
00736         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "pg external");
00737         rec = (union record *)ep->ext_buf;
00738 
00739         rec[0].p.p_id = ID_P_HEAD;
00740 
00741         for( p=0; p < pgp->npoly; p++ )  {
00742                 register struct rt_pg_face_internal     *pp;
00743 
00744                 rno = p+1;
00745                 pp = &pgp->poly[p];
00746                 if( pp->npts < 3 || pp->npts > 5 )  {
00747                         bu_log("rt_pg_export:  unable to support npts=%d\n",
00748                                 pp->npts);
00749                         return(-1);
00750                 }
00751 
00752                 rec[rno].q.q_id = ID_P_DATA;
00753                 rec[rno].q.q_count = pp->npts;
00754 #               include "noalias.h"
00755                 for( i=0; i < pp->npts; i++ )  {
00756                         /* NOTE: type conversion to dbfloat_t */
00757                         VSCALE( rec[rno].q.q_verts[i],
00758                                 &pp->verts[i*3], local2mm );
00759                         VMOVE( rec[rno].q.q_norms[i], &pp->norms[i*3] );
00760                 }
00761         }
00762         return(0);
00763 }
00764 
00765 int
00766 rt_pg_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00767 {
00768         bu_log( "As of release 6.0 the polysolid is superceded by the BOT primitive.\n" );
00769         bu_log( "\tTo convert polysolids to BOT primitives, use 'dbupgrade'.\n");
00770         /* The rt_pg_to_bot() routine can also be used. */
00771         return -1;
00772 }
00773 
00774 int
00775 rt_pg_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00776 {
00777         bu_log( "As of release 6.0 the polysolid is superceded by the BOT primitive.\n" );
00778         bu_log( "\tTo convert polysolids to BOT primitives, use 'dbupgrade'.\n" );
00779         /* The rt_pg_to_bot() routine can also be used. */
00780         return -1;
00781 }
00782 
00783 /**
00784  *                      R T _ P G _ D E S C R I B E
00785  *
00786  *  Make human-readable formatted presentation of this solid.
00787  *  First line describes type of solid.
00788  *  Additional lines are indented one tab, and give parameter values.
00789  */
00790 int
00791 rt_pg_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
00792 {
00793         register int                    j;
00794         register struct rt_pg_internal  *pgp =
00795                 (struct rt_pg_internal *)ip->idb_ptr;
00796         char                            buf[256];
00797         int                             i;
00798 
00799         RT_PG_CK_MAGIC(pgp);
00800         bu_vls_strcat( str, "polygon solid with no topology (POLY)\n");
00801 
00802         sprintf(buf, "\t%d polygons (faces)\n",
00803                 pgp->npoly );
00804         bu_vls_strcat( str, buf );
00805 
00806         sprintf(buf, "\tMost complex face has %d vertices\n",
00807                 pgp->max_npts );
00808         bu_vls_strcat( str, buf );
00809 
00810         if( pgp->npoly )
00811         {
00812                 sprintf(buf, "\tFirst vertex (%g, %g, %g)\n",
00813                         INTCLAMP(pgp->poly[0].verts[X] * mm2local),
00814                         INTCLAMP(pgp->poly[0].verts[Y] * mm2local),
00815                         INTCLAMP(pgp->poly[0].verts[Z] * mm2local) );
00816                 bu_vls_strcat( str, buf );
00817         }
00818 
00819         if( !verbose )  return(0);
00820 
00821         /* Print out all the vertices of all the faces */
00822         for( i=0; i < pgp->npoly; i++ )  {
00823                 register fastf_t *v = pgp->poly[i].verts;
00824                 register fastf_t *n = pgp->poly[i].norms;
00825 
00826                 sprintf( buf, "\tPolygon %d: (%d pts)\n",
00827                         i, pgp->poly[i].npts );
00828                 bu_vls_strcat( str, buf );
00829                 for( j=0; j < pgp->poly[i].npts; j++ )  {
00830                         sprintf(buf, "\t\tV (%g, %g, %g)\n\t\t N (%g, %g, %g)\n",
00831                                 INTCLAMP(v[X] * mm2local),
00832                                 INTCLAMP(v[Y] * mm2local),
00833                                 INTCLAMP(v[Z] * mm2local),
00834                                 INTCLAMP(n[X] * mm2local),
00835                                 INTCLAMP(n[Y] * mm2local),
00836                                 INTCLAMP(n[Z] * mm2local) );
00837                         bu_vls_strcat( str, buf );
00838                         v += ELEMENTS_PER_VECT;
00839                         n += ELEMENTS_PER_VECT;
00840                 }
00841         }
00842 
00843         return(0);
00844 }
00845 
00846 /**
00847  *                      R T _ P G _ I F R E E
00848  *
00849  *  Free the storage associated with the rt_db_internal version of this solid.
00850  */
00851 void
00852 rt_pg_ifree(struct rt_db_internal *ip)
00853 {
00854         register struct rt_pg_internal  *pgp;
00855         register int                    i;
00856 
00857         RT_CK_DB_INTERNAL(ip);
00858         pgp = (struct rt_pg_internal *)ip->idb_ptr;
00859         RT_PG_CK_MAGIC(pgp);
00860 
00861         /*
00862          *  Free storage for each polygon
00863          */
00864         for( i=0; i < pgp->npoly; i++ )  {
00865                 bu_free( (char *)pgp->poly[i].verts, "pg verts[]");
00866                 bu_free( (char *)pgp->poly[i].norms, "pg norms[]");
00867         }
00868         if( pgp->npoly )
00869                 bu_free( (char *)pgp->poly, "pg poly[]" );
00870         pgp->magic = 0;                 /* sanity */
00871         pgp->npoly = 0;
00872         bu_free( (char *)pgp, "pg ifree" );
00873         ip->idb_ptr = GENPTR_NULL;      /* sanity */
00874 }
00875 
00876 /**
00877  *                      R T _ P G _ T O _ B O T
00878  *
00879  *  Convert in-memory form of a polysolid (pg) to a bag of triangles (BoT)
00880  *  There is no record in the V5 database for a polysolid.
00881  *
00882  *  Depends on the "max_npts" parameter having been set.
00883  *
00884  *  Returns -
00885  *      -1      FAIL
00886  *      0       OK
00887  */
00888 int
00889 rt_pg_to_bot( struct rt_db_internal *ip, const struct bn_tol *tol, struct resource *resp )
00890 {
00891         struct rt_pg_internal *ip_pg;
00892         struct rt_bot_internal *ip_bot;
00893         int max_pts;
00894         int max_tri;
00895         int p, i;
00896 
00897         RT_CK_DB_INTERNAL(ip);
00898         RT_CK_TOL( tol );
00899         RT_CK_RESOURCE( resp );
00900 
00901         if( ip->idb_type != ID_POLY )
00902         {
00903                 bu_log( "ERROR: rt_pt_to_bot() called with a non-polysolid!!!\n" );
00904                 return -1;
00905         }
00906         ip_pg = (struct rt_pg_internal *)ip->idb_ptr;
00907 
00908         RT_PG_CK_MAGIC( ip_pg );
00909 
00910         ip_bot = (struct rt_bot_internal *)bu_malloc( sizeof( struct rt_bot_internal ), "BOT internal" );
00911         ip_bot->magic = RT_BOT_INTERNAL_MAGIC;
00912         ip_bot->mode = RT_BOT_SOLID;
00913         ip_bot->orientation = RT_BOT_CCW;
00914         ip_bot->bot_flags = 0;
00915 
00916         /* maximum possible vertices */
00917         max_pts = ip_pg->npoly * ip_pg->max_npts;
00918         BU_ASSERT_LONG( max_pts, >, 0 );
00919 
00920         /* maximum possible triangular faces */
00921         max_tri = ip_pg->npoly * 3;
00922         BU_ASSERT_LONG( max_tri, >, 0 );
00923 
00924         ip_bot->num_vertices = 0;
00925         ip_bot->num_faces = 0;
00926         ip_bot->thickness = (fastf_t *)NULL;
00927         ip_bot->face_mode = (struct bu_bitv *)NULL;
00928 
00929         ip_bot->vertices = (fastf_t *)bu_calloc( max_pts * 3, sizeof( fastf_t ), "BOT vertices" );
00930         ip_bot->faces = (int *)bu_calloc( max_tri * 3, sizeof( int ), "BOT faces" );
00931 
00932         for( p=0 ; p<ip_pg->npoly ; p++ )
00933         {
00934                 LOCAL vect_t work[3], tmp;
00935                 LOCAL struct tri_specific trip;
00936                 LOCAL fastf_t m1, m2, m3, m4;
00937                 LOCAL int first, v0=0, v2=0;
00938 
00939                 first = 1;
00940                 VMOVE( work[0], &ip_pg->poly[p].verts[0*3] );
00941                 VMOVE( work[1], &ip_pg->poly[p].verts[1*3] );
00942 
00943                 for( i=2; i < ip_pg->poly[p].npts; i++ )  {
00944                         VMOVE( work[2], &ip_pg->poly[p].verts[i*3] );
00945 
00946                         VSUB2( trip.tri_BA, work[1], work[0] );
00947                         VSUB2( trip.tri_CA, work[2], work[0] );
00948                         VCROSS( trip.tri_wn, trip.tri_BA, trip.tri_CA );
00949 
00950                         /* Check to see if this plane is a line or pnt */
00951                         m1 = MAGNITUDE( trip.tri_BA );
00952                         m2 = MAGNITUDE( trip.tri_CA );
00953                         VSUB2( tmp, work[1], work[2] );
00954                         m3 = MAGNITUDE( tmp );
00955                         m4 = MAGNITUDE( trip.tri_wn );
00956                         if( m1 >= tol->dist && m2 >= tol->dist &&
00957                             m3 >= tol->dist && m4 >= tol->dist )  {
00958 
00959                                 /* add this triangle to the BOT */
00960                                 if( first ) {
00961                                         ip_bot->faces[ip_bot->num_faces * 3] = ip_bot->num_vertices;
00962                                         VMOVE( &ip_bot->vertices[ip_bot->num_vertices * 3], work[0] );
00963                                         v0 = ip_bot->num_vertices;
00964                                         ip_bot->num_vertices++;
00965 
00966                                         ip_bot->faces[ip_bot->num_faces * 3 + 1] = ip_bot->num_vertices;
00967                                         VMOVE( &ip_bot->vertices[ip_bot->num_vertices * 3], work[1] );
00968                                         ip_bot->num_vertices++;
00969                                         first = 0;
00970                                 } else {
00971                                         ip_bot->faces[ip_bot->num_faces * 3] = v0;
00972                                         ip_bot->faces[ip_bot->num_faces * 3 + 1] = v2;
00973                                 }
00974                                 VMOVE( &ip_bot->vertices[ip_bot->num_vertices * 3], work[2] );
00975                                 ip_bot->faces[ip_bot->num_faces * 3 + 2] = ip_bot->num_vertices;
00976                                 v2 = ip_bot->num_vertices;
00977                                 ip_bot->num_vertices++;
00978 
00979                                 ip_bot->num_faces++;
00980                         }
00981 
00982                         /* Chop off a triangle, and continue */
00983                         VMOVE( work[1], work[2] );
00984                 }
00985         }
00986 
00987         (void)rt_bot_vertex_fuse( ip_bot );
00988         (void)rt_bot_condense( ip_bot );
00989 
00990         ip_bot->faces = (int *)bu_realloc( ip_bot->faces, ip_bot->num_faces * 3 * sizeof( int ), "BOT faces" );
00991 
00992         rt_db_free_internal( ip, resp );
00993 
00994         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00995         ip->idb_type = ID_BOT;
00996         ip->idb_meth = &rt_functab[ID_BOT];
00997         ip->idb_ptr = ip_bot;
00998 
00999         return 0;
01000 }
01001 
01002 /*
01003  * Local Variables:
01004  * mode: C
01005  * tab-width: 8
01006  * c-basic-offset: 4
01007  * indent-tabs-mode: t
01008  * End:
01009  * ex: shiftwidth=4 tabstop=8
01010  */

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