nmg_extrude.c

Go to the documentation of this file.
00001 /*                   N M G _ E X T R U D E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-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 nmg */
00023 
00024 /*@{*/
00025 /** @file nmg_extrude.c
00026  *      Routines for extruding nmg's.
00027  *
00028  *  Authors -
00029  *      Michael Markowski
00030  *      John R. Anderson
00031  *
00032  *  Source -
00033  *      The U. S. Army Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00035  */
00036 /*@}*/
00037 
00038 #ifndef lint
00039 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_extrude.c,v 14.12 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00040 #endif
00041 
00042 #include "common.h"
00043 
00044 
00045 #include <stdio.h>
00046 #include <math.h>
00047 #include <string.h>
00048 #include "machine.h"
00049 #include "vmath.h"
00050 #include "db.h"
00051 #include "nmg.h"
00052 #include "raytrace.h"
00053 #include "rtgeom.h"
00054 #include "./debug.h"
00055 
00056 
00057 /**
00058  *      V e r t s _ i n _ N M G _ L o o p
00059  *
00060  *      Count number of vertices in an NMG loop.
00061  */
00062 static int
00063 verts_in_nmg_loop(struct loopuse *lu)
00064 {
00065         int             cnt;
00066         struct edgeuse  *eu;
00067         struct vertex   *v;
00068 
00069         /* Count number of vertices in loop. */
00070         cnt = 0;
00071         NMG_CK_LOOPUSE(lu);
00072         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
00073                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00074                         NMG_CK_EDGEUSE(eu);
00075                         NMG_CK_EDGE(eu->e_p);
00076                         NMG_CK_VERTEXUSE(eu->vu_p);
00077                         NMG_CK_VERTEX(eu->vu_p->v_p);
00078                         cnt++;
00079                 }
00080         } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
00081                 v = BU_LIST_PNEXT(vertexuse, &lu->down_hd)->v_p;
00082                 NMG_CK_VERTEX(v);
00083                 cnt++;
00084         } else
00085                 rt_bomb("verts_in_nmg_loop: bad loopuse\n");
00086         return(cnt);
00087 }
00088 
00089 /**
00090  *      V e r t s _ i n _ N M G _ F a c e
00091  *
00092  *      Count number of vertices in an NMG face.
00093  */
00094 static int
00095 verts_in_nmg_face(struct faceuse *fu)
00096 {
00097         int             cnt;
00098         struct loopuse  *lu;
00099 
00100         cnt = 0;
00101         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
00102                 cnt += verts_in_nmg_loop(lu);
00103         return(cnt);
00104 }
00105 
00106 /**
00107  *      T r a n s l a t e _ N M G _ F a c e
00108  *
00109  *      Translate a face using a vector's magnitude and direction.
00110  */
00111 void
00112 nmg_translate_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
00113 {
00114         int             cnt,            /* Number of vertices in face. */
00115                         cur,
00116                         i,
00117                         in_there;
00118         struct vertex   **verts;        /* List of verts in face. */
00119         struct edgeuse  *eu;
00120         struct loopuse  *lu;
00121         struct vertex   *v;
00122         struct faceuse  *fu_tmp;
00123         plane_t pl;
00124         struct bu_ptbl  edge_g_tbl;
00125 
00126         bu_ptbl_init( &edge_g_tbl , 64, " &edge_g_tbl ");
00127 
00128         cur = 0;
00129         cnt = verts_in_nmg_face(fu);
00130         verts = (struct vertex **)
00131                 bu_malloc(cnt * sizeof(struct vertex *), "verts");
00132         for (i = 0; i < cnt; i++)
00133                 verts[i] = NULL;
00134 
00135         /* Go through each loop and translate it. */
00136         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00137                 NMG_CK_LOOPUSE(lu);
00138                 if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
00139                         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00140                                 in_there = 0;
00141                                 for (i = 0; i < cur && !in_there; i++)
00142                                         if (verts[i] == eu->vu_p->v_p)
00143                                                 in_there = 1;
00144                                 if (!in_there) {
00145                                         verts[cur++] = eu->vu_p->v_p;
00146                                         VADD2(eu->vu_p->v_p->vg_p->coord,
00147                                                 eu->vu_p->v_p->vg_p->coord,
00148                                                 Vec);
00149                                 }
00150                         }
00151                 } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd)
00152                         == NMG_VERTEXUSE_MAGIC) {
00153                         v = BU_LIST_FIRST(vertexuse, &lu->down_hd)->v_p;
00154                         NMG_CK_VERTEX(v);
00155                         VADD2(v->vg_p->coord, v->vg_p->coord, Vec);
00156                 } else
00157                         rt_bomb("nmg_translate_face: bad loopuse\n");
00158         }
00159 
00160         fu_tmp = fu;
00161         if( fu_tmp->orientation != OT_SAME )
00162                 fu_tmp = fu_tmp->fumate_p;
00163 
00164         /* Move edge geometry */
00165         nmg_edge_g_tabulate( &edge_g_tbl , &fu->l.magic );
00166         for( i=0 ; i<BU_PTBL_END( &edge_g_tbl ) ; i++ )
00167         {
00168                 long *ep;
00169                 struct edge_g_lseg *eg;
00170 
00171                 ep = BU_PTBL_GET( &edge_g_tbl , i );
00172                 switch( *ep )
00173                 {
00174                         case NMG_EDGE_G_LSEG_MAGIC:
00175                                 eg = (struct edge_g_lseg *)ep;
00176                                 NMG_CK_EDGE_G_LSEG( eg );
00177                                 VADD2( eg->e_pt , eg->e_pt , Vec );
00178                                 break;
00179                         case NMG_EDGE_G_CNURB_MAGIC:
00180                                 /* XXX Move cnurb edge geometry??? */
00181                                 break;
00182                 }
00183         }
00184 
00185         bu_ptbl_free( &edge_g_tbl );
00186 
00187         if(nmg_loop_plane_area( BU_LIST_FIRST( loopuse , &fu_tmp->lu_hd ) , pl ) < 0.0 )
00188         {
00189                 rt_bomb( "nmg_translate_face: Cannot calculate plane equation for face\n" );
00190         }
00191         nmg_face_g( fu_tmp , pl );
00192         bu_free((char *)verts, "verts");
00193 }
00194 
00195 /**
00196  *      N M G _ E x t r u d e _ F a c e
00197  *
00198  *      Duplicate a given NMG face, move it by specified vector,
00199  *      and create a solid bounded by these faces.
00200  */
00201 int
00202 nmg_extrude_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
00203                         /* Face to extrude. */
00204                                 /* Magnitude and direction of extrusion. */
00205                                 /* NMG tolerances. */
00206 {
00207         fastf_t         cosang;
00208         int             nfaces;
00209         struct faceuse  *fu2, *nmg_dup_face(struct faceuse *fu, struct shell *s), **outfaces;
00210         int             face_count=2;
00211         struct loopuse  *lu, *lu2;
00212         plane_t         n;
00213 
00214 #define MIKE_TOL 0.0001
00215 
00216         NMG_CK_FACEUSE( fu );
00217         BN_CK_TOL( tol );
00218 
00219         /* Duplicate and reverse face. */
00220         fu2 = nmg_dup_face(fu, fu->s_p);
00221         nmg_reverse_face( fu2 );
00222         if( fu2->orientation != OT_OPPOSITE )
00223                 fu2 = fu2->fumate_p;
00224 
00225         /* Figure out which face to translate. */
00226         NMG_GET_FU_PLANE( n, fu );
00227         cosang = VDOT(Vec, n);
00228         if (NEAR_ZERO(cosang, MIKE_TOL))
00229                 rt_bomb("extrude_nmg_face: extrusion cannot be parallel to face\n");
00230         if (cosang > 0.)
00231                 nmg_translate_face(fu, Vec, tol);
00232         else if (cosang < 0.)
00233                 nmg_translate_face(fu2->fumate_p, Vec, tol);
00234 
00235         nfaces = verts_in_nmg_face( fu );
00236         outfaces = (struct faceuse **)bu_calloc( nfaces+2 , sizeof( struct faceuse *) ,
00237                 "nmg_extrude_face: outfaces" );
00238 
00239         outfaces[0] = fu;
00240         outfaces[1] = fu2->fumate_p;
00241 
00242         for( BU_LIST_FOR2(lu , lu2 , loopuse , &fu->lu_hd , &fu2->lu_hd ) )
00243         {
00244                 struct edgeuse *eu,*eu2;
00245 
00246                 NMG_CK_LOOPUSE( lu );
00247                 NMG_CK_LOOPUSE( lu2 );
00248 
00249                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00250                         continue;
00251                 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) != NMG_EDGEUSE_MAGIC )
00252                 {
00253                         bu_log( "nmg_extrude_face: Original face and dup face don't match up!!\n" );
00254                         return( -1 );
00255                 }
00256                 for( BU_LIST_FOR2( eu , eu2 , edgeuse , &lu->down_hd , &lu2->down_hd ) )
00257                 {
00258                         struct vertex   *vertlist[4];
00259 
00260                         NMG_CK_EDGEUSE( eu );
00261                         NMG_CK_EDGEUSE( eu2 );
00262 
00263                         vertlist[0] = eu->vu_p->v_p;
00264                         vertlist[1] = eu2->vu_p->v_p;
00265                         vertlist[2] = eu2->eumate_p->vu_p->v_p;
00266                         vertlist[3] = eu->eumate_p->vu_p->v_p;
00267                         outfaces[face_count] = nmg_cface( fu->s_p , vertlist , 4 );
00268                         if( nmg_calc_face_g( outfaces[face_count] ) )
00269                         {
00270                                 bu_log( "nmg_extrude_face: failed to calculate plane eqn\n" );
00271                                 return( -1 );
00272                         }
00273                         face_count++;
00274                 }
00275 
00276         }
00277 
00278         nmg_gluefaces( outfaces , face_count, tol );
00279 
00280         bu_free( (char *)outfaces , "nmg_extrude_face: outfaces" );
00281 
00282         return( 0 );
00283 }
00284 
00285 /**     N M G _ F I N D _ V E R T E X _ I N _ L U
00286  *
00287  * find a use of vertex v in loopuse lu
00288  */
00289 
00290 struct vertexuse *
00291 nmg_find_vertex_in_lu(const struct vertex *v, const struct loopuse *lu)
00292 {
00293         struct edgeuse *eu;
00294         struct vertexuse *ret_vu;
00295 
00296         NMG_CK_VERTEX( v );
00297         NMG_CK_LOOPUSE( lu );
00298 
00299         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
00300         {
00301                 struct vertexuse *vu;
00302 
00303                 vu = BU_LIST_FIRST( vertexuse , &lu->down_hd );
00304                 NMG_CK_VERTEXUSE( vu );
00305 
00306                 if( vu->v_p == v )
00307                         return( vu );
00308                 else
00309                         return( (struct vertexuse *)NULL );
00310         }
00311 
00312         ret_vu = (struct vertexuse *)NULL;
00313         for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
00314         {
00315                 NMG_CK_EDGEUSE( eu );
00316 
00317                 if( eu->vu_p->v_p == v )
00318                 {
00319                         ret_vu = eu->vu_p;
00320                         break;
00321                 }
00322         }
00323 
00324         return( ret_vu );
00325 }
00326 
00327 /**     N M G _ S T A R T _ N E W _ L O O P
00328  *
00329  * recursive routine to build tables of edgeuse that may be used
00330  * to create new loopuses. lu1 and lu2 are overlapping edgeuses
00331  * from the same faceuse. This is a support routine for nmg_fix_overlapping loops
00332  */
00333 static void
00334 nmg_start_new_loop(struct edgeuse *start_eu, struct loopuse *lu1, struct loopuse *lu2, struct bu_ptbl *loops)
00335 {
00336         struct bu_ptbl *new_lu_tab;
00337         struct loopuse *this_lu;
00338         struct loopuse *other_lu;
00339         struct edgeuse *eu;
00340         int edges=0;
00341         int done=0;
00342 
00343         NMG_CK_EDGEUSE( start_eu );
00344         NMG_CK_LOOPUSE( lu1 );
00345         NMG_CK_LOOPUSE( lu2 );
00346 
00347         /* create a table to hold eu pointers for a new loop */
00348         new_lu_tab = (struct bu_ptbl *)bu_malloc( sizeof( struct bu_ptbl ) , "nmg_start_new_loop: new_lu_tab" );
00349         bu_ptbl_init( new_lu_tab , 64, " new_lu_tab ");
00350 
00351         /* add this table to the list of loops */
00352         bu_ptbl_ins( loops , (long *)new_lu_tab );
00353 
00354         /* put edgeuses from lu1 into new_lu_tab until a vertex shared by lu1 and lu2 is encountered
00355          * or until start_eu is encountered
00356          */
00357 
00358         this_lu = lu1;
00359         other_lu = lu2;
00360         eu = start_eu;
00361         while( !done )
00362         {
00363                 struct edgeuse *next_eu;
00364                 struct vertexuse *vu2;
00365 
00366                 next_eu = BU_LIST_PNEXT_CIRC( edgeuse , &eu->l );
00367 
00368                 /* skip this checking until we get by the first edgeuse */
00369                 if( edges )
00370                 {
00371                         /* Are we back to the begining? */
00372                         if( (eu->vu_p->v_p == start_eu->vu_p->v_p ) )
00373                         {
00374                                 /* done with this loop */
00375                                 done = 1;
00376                                 break;
00377                         }
00378 
00379                         /* Are we at an intersect point? */
00380                         vu2 = nmg_find_vertex_in_lu( eu->vu_p->v_p , other_lu );
00381                         if( vu2 )
00382                         {
00383                                 /* Yes, we may need to start another loop */
00384                                 struct edgeuse *eu2;
00385                                 struct loopuse *lu_tmp;
00386                                 int loop_started=0;
00387                                 int i;
00388 
00389                                 eu2 = vu2->up.eu_p;
00390 
00391                                 /* check if a loop has already been started here */
00392                                 for( i=0 ; i<BU_PTBL_END( loops ) ; i++ )
00393                                 {
00394                                         struct bu_ptbl *loop_tab;
00395                                         struct edgeuse *loop_start_eu;
00396 
00397                                         loop_tab = (struct bu_ptbl *)BU_PTBL_GET( loops , i );
00398                                         loop_start_eu = (struct edgeuse *)BU_PTBL_GET( loop_tab , 0 );
00399                                         if( loop_start_eu == eu )
00400                                         {
00401                                                 loop_started = 1;
00402                                                 break;
00403                                         }
00404                                 }
00405 
00406                                 /* if a loop has not already been started here
00407                                  * start one with the current edgeuse
00408                                  */
00409                                 if( !loop_started )
00410                                         nmg_start_new_loop( eu , this_lu , other_lu , loops );
00411 
00412                                 /* continue this loop by switching to the other loopuse */
00413                                 eu = eu2;
00414                                 next_eu = BU_LIST_PNEXT_CIRC( edgeuse , &eu->l );
00415                                 lu_tmp = this_lu;
00416                                 this_lu = other_lu;
00417                                 other_lu = lu_tmp;
00418                         }
00419                 }
00420 
00421                 /* add this edgeuse to the current list */
00422                 bu_ptbl_ins( new_lu_tab , (long *)eu );
00423 
00424                 edges++;
00425 
00426                 /* go to the next edgeuse */
00427                 eu = next_eu;
00428         }
00429 
00430 }
00431 
00432 /**     N M G _ F I X _ O V E R L A P P I N G _ L O O P S
00433  *
00434  * Looks at each faceuse in the shell and checks if loopuses in that
00435  * faceuse overlap each other. This code can only handle faceuses that
00436  * have at most one OT_SAME loopuse and one OT_OPPOSITE loopuse, so
00437  * nmg_split_loops_into_faces is called to simplify the faceuses.
00438  *
00439  * Overlapping OT_SAME and OT_OPPOSITE loops are broken into some
00440  * number of OT_SAME loopuses. An edgeuse (from the OT_SAME loopuse)
00441  * departing from a point where the loops intersect and outside the
00442  * OT_OPPOSITE loopuse is found as a starting point. Edgeuses from this
00443  * loopuse are moved to a new loopuse until another intersect point is
00444  * encountered. At that point, another loop is started using the next edgeuse
00445  * and the current loopuse is continued by following the other loopuse.
00446  * this is continued until the original edgeuse is encountered.
00447  *
00448  * If overlapping loops are found, new loopsuses are created and the
00449  * original loopuses are killed
00450  */
00451 void
00452 nmg_fix_overlapping_loops(struct shell *s, const struct bn_tol *tol)
00453 {
00454         struct faceuse *fu;
00455         struct edgeuse *start_eu;
00456         struct bu_ptbl loops;
00457         int i;
00458 
00459         NMG_CK_SHELL( s );
00460 
00461         if( rt_g.NMG_debug & DEBUG_BASIC )
00462                 bu_log( "nmg_fix_overlapping_loops: s = x%x\n" , s );
00463 
00464         /* this routine needs simple faceuses */
00465         nmg_split_loops_into_faces( &s->l.magic , tol );
00466 
00467         /* This table will contain a list of bu_ptbl's when we are
00468          * finished. Each of those bu_ptbl's will be a list of
00469          * edgeuses that comprise a new loop
00470          */
00471         bu_ptbl_init( &loops , 64, " &loops ");
00472 
00473         /* process all faceuses in the shell */
00474         for( BU_LIST_FOR( fu , faceuse , &s->fu_hd ) )
00475         {
00476                 struct loopuse *lu1,*lu2;
00477                 struct edgeuse *eu1;
00478                 struct edgeuse *eu;
00479                 int inside=0;
00480                 int outside=0;
00481 
00482                 NMG_CK_FACEUSE( fu );
00483 
00484                 /* don't process the same face twice */
00485                 if( fu->orientation != OT_SAME )
00486                         continue;
00487 
00488                 /* This is pretty simple-minded right now, assuming that
00489                  * there are only two loopuses
00490                  */
00491                 lu1 = BU_LIST_FIRST( loopuse , &fu->lu_hd );
00492                 NMG_CK_LOOPUSE( lu1 );
00493 
00494                 lu2 = BU_LIST_PNEXT( loopuse , &lu1->l );
00495 
00496                 /* if there is only one loopuse, nothing to do */
00497                 if( BU_LIST_IS_HEAD( lu2 , &fu->lu_hd ) )
00498                         continue;
00499 
00500                 NMG_CK_LOOPUSE( lu2 );
00501 
00502 
00503                 /* if the loopuses aren't both loops af edges, nothing to do */
00504                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_EDGEUSE_MAGIC )
00505                         continue;
00506 
00507                 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) != NMG_EDGEUSE_MAGIC )
00508                         continue;
00509 
00510                 /* if both loopuses are the same orientation, something is wrong */
00511                 if( lu1->orientation == lu2->orientation )
00512                 {
00513                         bu_log( "nmg_fix_overlapping_loops: Cannot handle loops of same orientation\n" );
00514                         nmg_pr_fu_briefly( fu , (char *)NULL );
00515                         continue;
00516                 }
00517 
00518                 /* At this point we have an OT_SAME and an OT_OPPOSITE loopuses
00519                  * for simplicity, force lu1 to be the OT_SAME loopuse */
00520                 if( lu1->orientation == OT_OPPOSITE && lu2->orientation == OT_SAME )
00521                 {
00522                         struct loopuse *lu_tmp;
00523 
00524                         lu_tmp = lu1;
00525                         lu1 = lu2;
00526                         lu2 = lu_tmp;
00527                 }
00528                 else if( lu2->orientation != OT_OPPOSITE || lu1->orientation != OT_SAME )
00529                 {
00530                         bu_log( "nmg_fix_overlapping_loops: bad loop orientations %s and %s\n",
00531                                 nmg_orientation( lu1->orientation ),
00532                                 nmg_orientation( lu2->orientation ) );
00533                         continue;
00534                 }
00535 
00536                 /* lu1 is OT_SAME and lu2 is OT_OPPOSITE, check for overlap */
00537 
00538                 /* count how many vertices in lu2 are inside lu1 and outside lu1 */
00539                 for( BU_LIST_FOR( eu , edgeuse , &lu2->down_hd ) )
00540                 {
00541                         struct vertexuse *vu;
00542 
00543                         NMG_CK_EDGEUSE( eu );
00544 
00545                         vu = eu->vu_p;
00546 
00547                         /* ignore vertices that are shared between the loops */
00548                         if( !nmg_find_vertex_in_lu( vu->v_p , lu1 ) )
00549                         {
00550                                 int class;
00551 
00552                                 class = nmg_classify_pt_loop( vu->v_p->vg_p->coord , lu1 , tol );
00553                                 if( class == NMG_CLASS_AoutB )
00554                                         outside++;
00555                                 else if( class == NMG_CLASS_AinB )
00556                                         inside++;
00557                         }
00558                 }
00559 
00560                 /* if we don't have vertices both inside and outside lu1,
00561                  * then there is no overlap
00562                  */
00563                 if( !inside || !outside ) /* no overlap */
00564                         continue;
00565 
00566                 /* the loops overlap, now fix it */
00567 
00568                 /* first, split the edges where the two loops cross each other */
00569                 for( BU_LIST_FOR( eu1 , edgeuse , &lu1->down_hd ) )
00570                 {
00571                         vect_t v1;
00572                         struct edgeuse *eu2;
00573 
00574                         VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord , eu1->vu_p->v_p->vg_p->coord );
00575                         for( BU_LIST_FOR( eu2 , edgeuse , &lu2->down_hd ) )
00576                         {
00577                                 vect_t v2;
00578                                 fastf_t dist[2];
00579                                 struct vertex *v=(struct vertex *)NULL;
00580 
00581                                 VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00582                                                 eu2->vu_p->v_p->vg_p->coord );
00583 
00584                                 if( bn_isect_lseg3_lseg3( dist , eu1->vu_p->v_p->vg_p->coord , v1 ,
00585                                         eu2->vu_p->v_p->vg_p->coord , v2 , tol ) >= 0 )
00586                                 {
00587                                         struct edgeuse *new_eu;
00588 
00589                                         if( dist[0]>0.0 && dist[0]<1.0 &&
00590                                             dist[1]>=0.0 && dist[1]<=1.0 )
00591                                         {
00592                                                 point_t pt;
00593 
00594                                                 if( dist[1] == 0.0 )
00595                                                         v = eu2->vu_p->v_p;
00596                                                 else if( dist[1] == 1.0 )
00597                                                         v = eu2->eumate_p->vu_p->v_p;
00598                                                 else
00599                                                 {
00600                                                         VJOIN1( pt , eu1->vu_p->v_p->vg_p->coord , dist[0] , v1 );
00601                                                         new_eu = nmg_esplit( v , eu1, 0 );
00602                                                         v = new_eu->vu_p->v_p;
00603                                                         if( !v->vg_p )
00604                                                                 nmg_vertex_gv( v , pt );
00605                                                 }
00606 
00607                                                 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00608                                                                 eu1->vu_p->v_p->vg_p->coord );
00609                                         }
00610                                         if( dist[1]>0.0 && dist[1]<1.0 && dist[0]>=0.0 && dist[0]<=1.0 )
00611                                         {
00612                                                 point_t pt;
00613 
00614                                                 if( dist[0] == 0.0 )
00615                                                         v = eu1->vu_p->v_p;
00616                                                 else if( dist[0] == 1.0 )
00617                                                         v = eu2->eumate_p->vu_p->v_p;
00618                                                 else
00619                                                 {
00620                                                         VJOIN1( pt , eu2->vu_p->v_p->vg_p->coord , dist[1] , v2 );
00621                                                         new_eu = nmg_esplit( v , eu2, 0 );
00622                                                         v = new_eu->vu_p->v_p;
00623                                                         if( !v->vg_p )
00624                                                                 nmg_vertex_gv( v , pt );
00625                                                 }
00626 
00627                                                 VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00628                                                                 eu2->vu_p->v_p->vg_p->coord );
00629                                         }
00630                                 }
00631                         }
00632                 }
00633 
00634                 /* find a vertex that lu1 and lu2 share, where eu1 is outside lu2
00635                  * this will be a starting edgeuse for a new loopuse
00636                  */
00637                 start_eu = (struct edgeuse *)NULL;
00638                 for( BU_LIST_FOR( eu1 , edgeuse , &lu1->down_hd ) )
00639                 {
00640                         struct vertex *v1,*v2;
00641                         point_t mid_pt;
00642 
00643                         /* must be a shared vertex */
00644                         if( !nmg_find_vertex_in_lu( eu1->vu_p->v_p , lu2 ) )
00645                                 continue;
00646 
00647                         v1 = eu1->vu_p->v_p;
00648                         NMG_CK_VERTEX( v1 );
00649                         v2 = eu1->eumate_p->vu_p->v_p;
00650                         NMG_CK_VERTEX( v2 );
00651 
00652                         /* use midpoint to determine if edgeuse is in or out of lu2 */
00653                         VBLEND2( mid_pt , 0.5 , v1->vg_p->coord , 0.5 , v2->vg_p->coord )
00654 
00655                         if( nmg_classify_pt_loop( mid_pt , lu2 , tol ) == NMG_CLASS_AoutB )
00656                         {
00657                                 start_eu = eu1;
00658                                 break;
00659                         }
00660                 }
00661 
00662                 if( !start_eu )
00663                 {
00664                         bu_log( "nmg_fix_overlapping_loops: cannot find start point for new loops\n" );
00665                         bu_log( "lu1=x%x, lu2=x%x\n" , lu1 , lu2 );
00666                         nmg_pr_fu_briefly( fu , (char *)NULL );
00667                         continue;;
00668                 }
00669 
00670                 bu_ptbl_reset( &loops );
00671 
00672                 /* start new loop
00673                  * this routine will recurse, building as many tables as needed
00674                  */
00675                 nmg_start_new_loop( start_eu , lu1 , lu2 , &loops );
00676 
00677                 /* use loops table to create the new loops */
00678                 for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ )
00679                 {
00680                         struct loopuse *new_lu;
00681                         struct loopuse *new_lu_mate;
00682                         struct bu_ptbl *loop_tab;
00683                         int eu_no;
00684 
00685                         /* each table represents a new loopuse to be constructed */
00686                         loop_tab = (struct bu_ptbl *)BU_PTBL_GET( &loops , i );
00687 
00688                         /* if there are some entries in this table, make a new loopuse */
00689                         if( BU_PTBL_END( loop_tab ) )
00690                         {
00691                                 /* create new loop */
00692                                 new_lu = nmg_mlv( &fu->l.magic , (struct vertex *)NULL , OT_SAME );
00693                                 new_lu_mate = new_lu->lumate_p;
00694 
00695                                 /* get rid of vertex just created */
00696                                 nmg_kvu( BU_LIST_FIRST( vertexuse , &new_lu->down_hd ) );
00697                                 nmg_kvu( BU_LIST_FIRST( vertexuse , &new_lu_mate->down_hd ) );
00698 
00699                                 /* move edgeuses to new loops */
00700                                 for( eu_no=0 ; eu_no<BU_PTBL_END( loop_tab ) ; eu_no++ )
00701                                 {
00702                                         struct edgeuse *mv_eu;
00703 
00704                                         /* get edgeuse to be moved */
00705                                         mv_eu = (struct edgeuse *)BU_PTBL_GET( loop_tab , eu_no );
00706                                         NMG_CK_EDGEUSE( mv_eu );
00707 
00708                                         /* move it to new loopuse */
00709                                         BU_LIST_DEQUEUE( &mv_eu->l );
00710                                         BU_LIST_INSERT( &new_lu->down_hd , &mv_eu->l );
00711                                         mv_eu->up.lu_p = new_lu;
00712 
00713                                         /* move edgeuse mate to loopuse mate */
00714                                         BU_LIST_DEQUEUE( &mv_eu->eumate_p->l );
00715                                         BU_LIST_APPEND( &new_lu_mate->down_hd , &mv_eu->eumate_p->l );
00716                                         mv_eu->eumate_p->up.lu_p = new_lu_mate;
00717                                 }
00718 
00719                                 bu_ptbl_free( loop_tab );
00720                                 bu_free( (char *)loop_tab , "nmg_fix_overlapping_loops: loop_tab" );
00721                         }
00722                 }
00723 
00724                 /* kill empty loopuses left in faceuse */
00725                 lu1 = BU_LIST_FIRST( loopuse , &fu->lu_hd );
00726                 while( BU_LIST_NOT_HEAD( lu1 , &fu->lu_hd ) )
00727                 {
00728                         struct loopuse *next_lu;
00729 
00730                         next_lu = BU_LIST_PNEXT( loopuse , &lu1->l );
00731 
00732                         if( BU_LIST_IS_EMPTY( &lu1->down_hd ) )
00733                         {
00734                                 if( nmg_klu( lu1 ) )
00735                                         rt_bomb( "nmg_fix_overlapping_loops: Emptied faceuse!!\n" );
00736                         }
00737                         lu1 = next_lu;
00738                 }
00739         }
00740         bu_ptbl_free( &loops );
00741 
00742         if( rt_g.NMG_debug & DEBUG_BASIC )
00743                 bu_log( "nmg_fix_overlapping_loops: done\n" );
00744 }
00745 
00746 /**     N M G _ B R E A K _ C R O S S E D _ L O O P S
00747  *
00748  *      Extrusion may create crossed loops within a face.
00749  *      This routine intersects each edge within a loop with every other edge
00750  *      in the loop
00751  */
00752 void
00753 nmg_break_crossed_loops(struct shell *is, const struct bn_tol *tol)
00754 {
00755         struct faceuse *fu;
00756 
00757         NMG_CK_SHELL( is );
00758         BN_CK_TOL( tol );
00759 
00760         for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
00761         {
00762                 struct loopuse *lu;
00763 
00764                 NMG_CK_FACEUSE( fu );
00765 
00766                 if( fu->orientation != OT_SAME )
00767                         continue;
00768 
00769                 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
00770                 {
00771                         struct edgeuse *eu1,*eu2;
00772                         vect_t v1,v2;
00773 
00774                         NMG_CK_LOOPUSE( lu );
00775 
00776                         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00777                                 continue;
00778 
00779                         for( BU_LIST_FOR( eu1 , edgeuse , &lu->down_hd ) )
00780                         {
00781                                 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00782                                                 eu1->vu_p->v_p->vg_p->coord );
00783 
00784                                 eu2 = BU_LIST_PNEXT( edgeuse , eu1 );
00785                                 while( BU_LIST_NOT_HEAD( eu2 , &lu->down_hd ) )
00786                                 {
00787                                         fastf_t dist[2];
00788 
00789                                         VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00790                                                         eu2->vu_p->v_p->vg_p->coord );
00791 
00792                                         if( bn_isect_lseg3_lseg3( dist , eu1->vu_p->v_p->vg_p->coord , v1 ,
00793                                                 eu2->vu_p->v_p->vg_p->coord , v2 , tol ) >= 0 )
00794                                         {
00795                                                 point_t pt;
00796                                                 struct edgeuse *new_eu;
00797                                                 struct vertex *v=(struct vertex *)NULL;
00798 
00799                                                 if( dist[0]>0.0 && dist[0]<1.0 &&
00800                                                         dist[1]>=0.0 && dist[1]<=1.0 )
00801                                                 {
00802                                                         if( dist[1] == 0.0 )
00803                                                                 v = eu2->vu_p->v_p;
00804                                                         else if( dist[1] == 1.0 )
00805                                                                 v = eu2->eumate_p->vu_p->v_p;
00806                                                         else
00807                                                         {
00808                                                                 VJOIN1( pt , eu1->vu_p->v_p->vg_p->coord ,
00809                                                                         dist[0] , v1 );
00810                                                                 v = nmg_find_pt_in_shell( is , pt , tol );
00811                                                         }
00812 
00813                                                         new_eu = nmg_esplit( v , eu1, 0 );
00814                                                         v = new_eu->vu_p->v_p;
00815                                                         if( !v->vg_p )
00816                                                                 nmg_vertex_gv( v , pt );
00817 
00818                                                         VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00819                                                                 eu1->vu_p->v_p->vg_p->coord );
00820                                                 }
00821                                                 if( dist[1] > 0.0 && dist[1] < 1.0 &&
00822                                                         dist[0]>=0.0 && dist[0]<=1.0 )
00823                                                 {
00824                                                         if( dist[0] == 0.0 )
00825                                                                 v = eu1->vu_p->v_p;
00826                                                         else if( dist[0] == 1.0 )
00827                                                                 v = eu1->eumate_p->vu_p->v_p;
00828                                                         else
00829                                                         {
00830                                                                 VJOIN1( pt , eu2->vu_p->v_p->vg_p->coord , dist[1] , v2 );
00831                                                                 v = nmg_find_pt_in_shell( is , pt , tol );
00832                                                         }
00833 
00834                                                         new_eu = nmg_esplit( v , eu2, 0 );
00835                                                         v = new_eu->vu_p->v_p;
00836                                                         if( !v->vg_p )
00837                                                                 nmg_vertex_gv( v , pt );
00838                                                 }
00839                                         }
00840                                         eu2 = BU_LIST_PNEXT( edgeuse , eu2 );
00841                                 }
00842                         }
00843                 }
00844         }
00845 }
00846 
00847 /**
00848  *      N M G _ E X T R U D E _ C L E A N U P
00849  *
00850  *      Clean up after nmg_extrude_shell.
00851  *      intersects each face with every other face in the shell and
00852  *      makes new face boundaries at the intersections.
00853  *      decomposes the result into seperate shells.
00854  *      where faces have intersected, new shells will be created.
00855  *      These shells are detected and killed
00856  */
00857 struct shell *
00858 nmg_extrude_cleanup(struct shell *is, const int is_void, const struct bn_tol *tol)
00859 {
00860         struct model *m;
00861         struct nmgregion *new_r;
00862         struct faceuse *fu;
00863         struct loopuse *lu;
00864         struct vertexuse *vu;
00865         struct nmgregion *old_r;
00866         struct shell *s_tmp;
00867 
00868         NMG_CK_SHELL( is );
00869         BN_CK_TOL( tol );
00870 
00871         if( rt_g.NMG_debug & DEBUG_BASIC )
00872                 bu_log( "nmg_extrude_cleanup( is=x%x )\n" , is );
00873 
00874         m = nmg_find_model( &is->l.magic );
00875 
00876         /* intersect each face in the shell with every other face in the same shell */
00877         nmg_isect_shell_self( is , tol );
00878 
00879         /* Extrusion may create loops that overlap */
00880         nmg_fix_overlapping_loops( is , tol );
00881 
00882         /* look for self-touching loops */
00883         for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
00884         {
00885                 if( fu->orientation != OT_SAME )
00886                         continue;
00887 
00888                 lu = BU_LIST_LAST( loopuse , &fu->lu_hd );
00889                 while( BU_LIST_NOT_HEAD( lu , &fu->lu_hd ) )
00890                 {
00891                         struct loopuse *new_lu;
00892                         int orientation;
00893 
00894                         /* check this loopuse */
00895                         while( (vu=(struct vertexuse *)nmg_loop_touches_self( lu ) ) != (struct vertexuse *)NULL )
00896                         {
00897                                 /* Split this touching loop, but give both resulting loops
00898                                  * the same orientation as the original. This will result
00899                                  * in the part of the loop that needs to be discarded having
00900                                  * an incorrect orientation with respect to the face.
00901                                  * This incorrect orientation will be discovered later by
00902                                  * "nmg_bad_face_normals" and will result in the undesirable
00903                                  * portion's demise
00904                                  */
00905 
00906                                 orientation = lu->orientation;
00907                                 new_lu = nmg_split_lu_at_vu( lu , vu );
00908                                 new_lu->orientation = orientation;
00909                                 lu->orientation = orientation;
00910                                 new_lu->lumate_p->orientation = orientation;
00911                                 lu->lumate_p->orientation = orientation;
00912                         }
00913 
00914                         lu = BU_LIST_PLAST( loopuse , &lu->l );
00915                 }
00916         }
00917 
00918         nmg_rebound( m , tol );
00919 
00920         /* remember the nmgregion where "is" came from */
00921         old_r = is->r_p;
00922 
00923         /* make a new nmgregion , shell, and vertex */
00924         new_r = nmg_mrsv( m );
00925 
00926         /* s_tmp is the shell just created */
00927         s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
00928 
00929         /* move our shell (is) to the new nmgregion
00930          * in preparaion for nmg_decompose_shell.
00931          * don't want to confuse pieces of this shell
00932          * with other shells in "old_r"
00933          */
00934         (void)nmg_mv_shell_to_region( is , new_r );
00935 
00936         /* kill the unused, newly created shell */
00937         if( nmg_ks( s_tmp ) )
00938                 rt_bomb( "nmg_extrude_shell: Nothing got moved to new region\n" );
00939 
00940         /* now decompose our shell, count number of inside shells */
00941         if( (nmg_decompose_shell( is , tol )) < 2 )
00942         {
00943                 /*  we still have only one shell */
00944                 if( nmg_bad_face_normals( is , tol ) )
00945                 {
00946                         (void)nmg_ks( is );
00947                         is = (struct shell *)NULL;
00948                 }
00949                 else if( is_void != -1 && nmg_shell_is_void( is ) != is_void )
00950                 {
00951                         (void)nmg_ks( is );
00952                         is = (struct shell *)NULL;
00953                 }
00954                 else
00955                         (void)nmg_mv_shell_to_region( is , old_r );
00956 
00957                 nmg_kr( new_r );
00958                 new_r = NULL;
00959         }
00960         else
00961         {
00962                 /* look at each shell in "new_r" */
00963                 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
00964                 while( BU_LIST_NOT_HEAD( s_tmp , &new_r->s_hd ) )
00965                 {
00966                         struct shell *next_s;
00967                         int kill_it=0;
00968 
00969                         next_s = BU_LIST_PNEXT( shell , &s_tmp->l );
00970 
00971                         if( nmg_bad_face_normals( s_tmp , tol ) )
00972                                 kill_it = 1;
00973 
00974                         if( !kill_it )
00975                         {
00976                                 if( is_void != -1 && nmg_shell_is_void( s_tmp ) != is_void )
00977                                         kill_it = 1;
00978                         }
00979 
00980                         if( kill_it )
00981                         {
00982                                 /* Bad shell, kill it */
00983                                 if( nmg_ks( s_tmp ) )
00984                                 {
00985                                         nmg_kr( new_r );
00986                                         new_r = (struct nmgregion *)NULL;
00987                                         is = (struct shell *)NULL;
00988                                         break;
00989                                 }
00990                         }
00991                         s_tmp = next_s;
00992                 }
00993         }
00994 
00995         if( new_r )
00996         {
00997                 /* merge remaining shells in "new_r" */
00998                 is = BU_LIST_FIRST( shell , &new_r->s_hd );
00999 
01000                 s_tmp = BU_LIST_PNEXT( shell , &is->l );
01001                 while( BU_LIST_NOT_HEAD( s_tmp , &new_r->s_hd ) )
01002                 {
01003                         struct shell *next_s;
01004 
01005                         next_s = BU_LIST_PNEXT( shell , &s_tmp->l );
01006 
01007                         if( s_tmp == is )
01008                         {
01009                                 s_tmp = next_s;
01010                                 continue;
01011                         }
01012 
01013                         nmg_js( is , s_tmp , tol );
01014                         s_tmp = next_s;
01015                 }
01016 
01017                 /* move it all back into the original nmgregion */
01018                 if( is )
01019                         (void)nmg_mv_shell_to_region( is , old_r );
01020 
01021                 /* kill the temporary nmgregion */
01022                 if( BU_LIST_NON_EMPTY( &new_r->s_hd ) )
01023                         bu_log( "nmg_extrude_cleanup: temporary nmgregion not empty!!\n" );
01024 
01025                 (void)nmg_kr( new_r );
01026         }
01027         return( is );
01028 }
01029 
01030 /**
01031  *      N M G _ H O L L O W _ S H E L L
01032  *
01033  *      Hollows out a shell producing a wall thickness of thickness "thick"
01034  *      by creating a new "inner" shell and combining the two shells.
01035  *
01036  *      If the original shell is closed, the new shell is simply
01037  *      merged with the original shell.  If the original shell is open, then faces
01038  *      are constructed along the free edges of the two shells to make a closed shell.
01039  *
01040  *      if approximate is non-zero, new vertex geometry at vertices where more than
01041  *      three faces intersect may be approximated by a point of minimum distance from
01042  *      the intersecting faces.
01043  *
01044  */
01045 void
01046 nmg_hollow_shell(struct shell *s, const fastf_t thick, const int approximate, const struct bn_tol *tol)
01047 {
01048         struct nmgregion *new_r,*old_r;
01049         struct vertexuse *vu;
01050         struct edgeuse *eu;
01051         struct loopuse *lu;
01052         struct faceuse *fu;
01053         struct face_g_plane *fg_p;
01054         struct model *m;
01055         struct shell *is;       /* inside shell */
01056         struct shell *s_tmp;
01057         struct bu_ptbl shells;
01058         long *flags;
01059         long **copy_tbl;
01060         int shell_no;
01061         int is_void;
01062         int s_tmp_is_closed;
01063 
01064         if( rt_g.NMG_debug & DEBUG_BASIC )
01065                 bu_log( "nmg_extrude_shell( s=x%x , thick=%f)\n" , s , thick );
01066 
01067         NMG_CK_SHELL( s );
01068         BN_CK_TOL( tol );
01069 
01070         if( thick < 0.0 )
01071         {
01072                 bu_log( "nmg_extrude_shell: thickness less than zero not allowed" );
01073                 return;
01074         }
01075 
01076         if( thick < tol->dist )
01077         {
01078                 bu_log( "nmg_extrude_shell: thickness less than tolerance not allowed" );
01079                 return;
01080         }
01081 
01082         m = nmg_find_model( (long *)s );
01083 
01084         /* remember region where this shell came from */
01085         old_r = s->r_p;
01086         NMG_CK_REGION( old_r );
01087 
01088         /* move this shell to another region */
01089         new_r = nmg_mrsv( m );
01090         s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01091         (void)nmg_mv_shell_to_region( s , new_r );
01092 
01093         /* decompose this shell */
01094         (void)nmg_decompose_shell( s , tol );
01095 
01096         /* kill the extra shell created by nmg_mrsv above */
01097         (void)nmg_ks( s_tmp );
01098 
01099         /* recompute the bounding boxes */
01100         nmg_region_a( new_r , tol );
01101 
01102         /* make a list of all the shells in the new region */
01103         bu_ptbl_init( &shells , 64, " &shells ");
01104         for( BU_LIST_FOR( s_tmp , shell , &new_r->s_hd ) )
01105                 bu_ptbl_ins( &shells , (long *)s_tmp );
01106 
01107         /* extrude a copy of each shell, one at a time */
01108         for( shell_no=0 ; shell_no<BU_PTBL_END( &shells ) ; shell_no ++ )
01109         {
01110                 s_tmp = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01111 
01112                 /* first make a copy of this shell */
01113                 is = nmg_dup_shell( s_tmp , &copy_tbl, tol );
01114 
01115                 /* make a translation table for this model */
01116                 flags = (long *)bu_calloc( m->maxindex , sizeof( long ) , "nmg_extrude_shell flags" );
01117 
01118                 /* now adjust all the planes, first move them inward by distance "thick" */
01119                 for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
01120                 {
01121                         NMG_CK_FACEUSE( fu );
01122                         NMG_CK_FACE( fu->f_p );
01123                         fg_p = fu->f_p->g.plane_p;
01124                         NMG_CK_FACE_G_PLANE( fg_p );
01125 
01126                         /* move the faces by the distance "thick" */
01127                         if( NMG_INDEX_TEST_AND_SET( flags , fg_p ) )
01128                         {
01129                                 if( fu->f_p->flip )
01130                                         fg_p->N[3] += thick;
01131                                 else
01132                                         fg_p->N[3] -= thick;
01133                         }
01134                 }
01135 
01136                 /* Reverse the normals of all the faces */
01137                 nmg_invert_shell( is , tol );
01138 
01139                 is_void = nmg_shell_is_void( is );
01140 
01141                 /* now start adjusting the vertices
01142                  * Use the original shell so that we can pass the original vertex to nmg_inside_vert
01143                  */
01144                 for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01145                 {
01146                         if( fu->orientation != OT_SAME )
01147                                 continue;
01148 
01149                         for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01150                         {
01151                                 NMG_CK_LOOPUSE( lu );
01152                                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
01153                                 {
01154                                         /* the vertex in a loop of one vertex
01155                                          * must show up in an edgeuse somewhere,
01156                                          * so don't mess with it here */
01157                                         continue;
01158                                 }
01159                                 else
01160                                 {
01161                                         for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
01162                                         {
01163                                                 struct vertex *new_v;
01164 
01165                                                 NMG_CK_EDGEUSE( eu );
01166                                                 vu = eu->vu_p;
01167                                                 NMG_CK_VERTEXUSE( vu );
01168                                                 new_v = NMG_INDEX_GETP( vertex , copy_tbl , vu->v_p );
01169                                                 NMG_CK_VERTEX( new_v )
01170                                                 if( NMG_INDEX_TEST_AND_SET( flags , new_v ) )
01171                                                 {
01172                                                         /* move this vertex */
01173                                                         if( nmg_in_vert( new_v , approximate , tol ) )
01174                                                                 rt_bomb( "Failed to get a new point from nmg_inside_vert\n" );
01175                                                 }
01176                                         }
01177                                 }
01178                         }
01179                 }
01180 
01181                 /* recompute the bounding boxes */
01182                 nmg_region_a( is->r_p , tol );
01183 
01184                 nmg_vmodel( m );
01185 
01186                 s_tmp_is_closed = !nmg_check_closed_shell( s_tmp , tol );
01187                 if( s_tmp_is_closed )
01188                         is = nmg_extrude_cleanup( is , is_void , tol );
01189 
01190                 /* Inside shell is done */
01191                 if( is )
01192                 {
01193                         if( s_tmp_is_closed )
01194                         {
01195                                 if( nmg_check_closed_shell( is , tol ) )
01196                                 {
01197                                         bu_log( "nmg_extrude_shell: inside shell is not closed, calling nmg_close_shell\n" );
01198                                         nmg_close_shell( is, tol );
01199                                 }
01200 
01201                                 nmg_shell_coplanar_face_merge( is , tol , 0 );
01202                                 nmg_simplify_shell( is );
01203 
01204                                 /* now merge the inside and outside shells */
01205                                 nmg_js( s_tmp , is , tol );
01206                         }
01207                         else
01208                         {
01209                                 if( !nmg_check_closed_shell( is , tol ) )
01210                                 {
01211                                         bu_log( "nmg_extrude_shell: inside shell is closed, outer isn't!!\n" );
01212                                         nmg_shell_coplanar_face_merge( is , tol , 0 );
01213                                         nmg_simplify_shell( is );
01214                                         nmg_js( s_tmp , is , tol );
01215                                 }
01216                                 else
01217                                 {
01218                                         /* connect the boundaries of the two open shells */
01219                                         nmg_open_shells_connect( s_tmp , is ,
01220                                                 (const long **)copy_tbl , tol );
01221                                 }
01222                         }
01223                 }
01224 
01225                 /* recompute the bounding boxes */
01226                 nmg_region_a( s_tmp->r_p , tol );
01227 
01228                 /* free memory */
01229                 bu_free( (char *)flags , "nmg_extrude_shell: flags" );
01230                 bu_free( (char *)copy_tbl , "nmg_extrude_shell: copy_tbl" );
01231         }
01232 
01233         /* put it all back together */
01234         for( shell_no=0 ; shell_no<BU_PTBL_END( &shells ) ; shell_no++ )
01235         {
01236                 struct shell *s2;
01237 
01238                 s2 = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01239                 if( s2 != s )
01240                         nmg_js( s , s2 , tol );
01241         }
01242 
01243         bu_ptbl_free( &shells );
01244 
01245         (void)nmg_mv_shell_to_region( s , old_r );
01246         nmg_kr( new_r );
01247 }
01248 
01249 /**     N M G _ E X T R U D E _ S H E L L
01250  *
01251  * Extrudes a shell (s) by a distance (dist) in the direction
01252  * of the face normals if normal_ward, or the opposite direction
01253  * if !normal_ward.  The shell (s) is modified by adjusting the
01254  * plane equations for each face and calculating new vertex geometry.
01255  * if approximate is non-zero, new vertex geometry, for vertices
01256  * where more than three faces intersect, will be approximated
01257  * by a point with minimum distance from the intersecting faces.
01258  * if approximate is zero, additional faces and/or edges may be added to the shell.
01259  *
01260  * returns:
01261  *      a pointer to the modified shell on success
01262  *      NULL on failure
01263  */
01264 struct shell *
01265 nmg_extrude_shell(struct shell *s, const fastf_t dist, const int normal_ward, const int approximate, const struct bn_tol *tol)
01266 {
01267         fastf_t thick;
01268         int along_normal;
01269         struct model *m;
01270         struct nmgregion *new_r,*old_r;
01271         struct shell *s_tmp,*s2;
01272         struct bu_ptbl shells;
01273         struct bu_ptbl verts;
01274         int shell_no;
01275         int failed=0;
01276 
01277         NMG_CK_SHELL( s );
01278         BN_CK_TOL( tol );
01279 
01280         if( NEAR_ZERO( dist , tol->dist ) )
01281         {
01282                 bu_log( "nmg_extrude_shell: Cannot extrude a distance less than tolerance distance\n" );
01283                 return( s );
01284         }
01285 
01286         along_normal = normal_ward;
01287         if( dist < 0.0 )
01288         {
01289                 thick = (-dist);
01290                 along_normal = (!normal_ward);
01291         }
01292         else
01293                 thick = dist;
01294 
01295         m = nmg_find_model( &s->l.magic );
01296         NMG_CK_MODEL( m );
01297 
01298         old_r = s->r_p;
01299         NMG_CK_REGION( old_r );
01300 
01301         /* decompose this shell and extrude each piece seperately */
01302         new_r = nmg_mrsv( m );
01303         s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01304         (void)nmg_mv_shell_to_region( s , new_r );
01305         (void)nmg_decompose_shell( s , tol );
01306 
01307         /* kill the not-needed shell created by nmg_mrsv() */
01308         (void)nmg_ks( s_tmp );
01309 
01310         /* recompute the bounding boxes */
01311         nmg_region_a( new_r , tol );
01312 
01313         /* make a list of all the shells to be extruded */
01314         bu_ptbl_init( &shells , 64, " &shells ");
01315         for( BU_LIST_FOR( s_tmp , shell , &new_r->s_hd ) )
01316                 bu_ptbl_ins( &shells , (long *)s_tmp );
01317 
01318         bu_ptbl_init( &verts , 64, " &verts ");
01319 
01320         /* extrude each shell */
01321         for( shell_no=0 ; shell_no < BU_PTBL_END( &shells ) ; shell_no++ )
01322         {
01323                 int vert_no;
01324                 int is_void;
01325                 long *flags;
01326                 struct faceuse *fu;
01327 
01328                 s_tmp = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01329                 NMG_CK_SHELL( s_tmp );
01330 
01331                 is_void = nmg_shell_is_void( s_tmp );
01332 
01333                 /* make a translation table for this model */
01334                 flags = (long *)bu_calloc( m->maxindex , sizeof( long ) , "nmg_extrude_shell flags" );
01335 
01336                 /* now adjust all the planes, first move them by distance "thick" */
01337                 for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01338                 {
01339                         struct face_g_plane *fg_p;
01340 
01341                         NMG_CK_FACEUSE( fu );
01342                         NMG_CK_FACE( fu->f_p );
01343                         fg_p = fu->f_p->g.plane_p;
01344                         NMG_CK_FACE_G_PLANE( fg_p );
01345 
01346                         /* move the faces by the distance "thick" */
01347                         if( NMG_INDEX_TEST_AND_SET( flags , fg_p ) )
01348                         {
01349                                 if( along_normal ^ fu->f_p->flip )
01350                                         fg_p->N[3] += thick;
01351                                 else
01352                                         fg_p->N[3] -= thick;
01353                         }
01354                 }
01355 
01356                 bu_free( (char *)flags , "nmg_extrude_shell flags" );
01357 
01358                 /* get table of vertices in this shell */
01359                 nmg_vertex_tabulate( &verts , &s_tmp->l.magic );
01360 
01361                 /* now move all the vertices */
01362                 for( vert_no = 0 ; vert_no < BU_PTBL_END( &verts ) ; vert_no++ )
01363                 {
01364                         struct vertex *new_v;
01365 
01366                         new_v = (struct vertex *)BU_PTBL_GET( &verts , vert_no );
01367                         NMG_CK_VERTEX( new_v );
01368 
01369                         if( nmg_in_vert( new_v , approximate , tol ) )
01370                         {
01371                                 bu_log( "nmg_extrude_shell: Failed to calculate new vertex at v=x%x was ( %f %f %f )\n",
01372                                         new_v , V3ARGS( new_v->vg_p->coord ) );
01373                                 failed = 1;
01374                                 goto out;
01375                         }
01376                 }
01377 
01378                 bu_ptbl_free( &verts );
01379 
01380                 if( approximate )       /* need to recalculate plane eqns */
01381                 {
01382                         for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01383                         {
01384                                 struct loopuse *lu;
01385                                 int got_plane=0;
01386 
01387                                 if( fu->orientation != OT_SAME )
01388                                         continue;
01389 
01390                                 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01391                                 {
01392                                         fastf_t area;
01393                                         plane_t pl;
01394 
01395                                         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
01396                                                 continue;
01397 
01398                                         if( lu->orientation != OT_SAME )
01399                                                 continue;
01400 
01401                                         area = nmg_loop_plane_area( lu , pl );
01402 
01403                                         if( area > 0.0 )
01404                                         {
01405                                                 nmg_face_g( fu , pl );
01406                                                 got_plane = 1;
01407                                                 break;
01408                                         }
01409                                 }
01410                                 if( !got_plane )
01411                                 {
01412                                         bu_log( "nmg_extrude_shell: Cannot recalculate plane for face:\n" );
01413                                         nmg_pr_fu_briefly( fu , (char *)NULL );
01414                                         failed = 1;
01415                                         goto out;
01416                                 }
01417                         }
01418                 }
01419 
01420                 /* recompute the bounding boxes */
01421                 nmg_region_a( s_tmp->r_p , tol );
01422 
01423                 (void)nmg_extrude_cleanup( s_tmp , is_void , tol );
01424         }
01425 
01426 out:
01427         bu_ptbl_free( &shells );
01428 
01429         /* put it all back together */
01430         if( BU_LIST_NON_EMPTY( &new_r->s_hd ) )
01431         {
01432                 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01433                 s2 = BU_LIST_PNEXT( shell , &s_tmp->l );
01434                 while( BU_LIST_NOT_HEAD( s2 , &new_r->s_hd ) )
01435                 {
01436                         struct shell *next_s;
01437 
01438                         next_s = BU_LIST_PNEXT( shell , &s2->l );
01439                         nmg_js( s_tmp , s2 , tol );
01440 
01441                         s2 = next_s;
01442                 }
01443         }
01444         else
01445                 s_tmp = (struct shell *)NULL;
01446 
01447         if( s_tmp )
01448                 (void)nmg_mv_shell_to_region( s_tmp , old_r );
01449 
01450         nmg_kr( new_r );
01451 
01452         if( failed )
01453                 return( (struct shell *)NULL );
01454         else
01455                 return( s_tmp );
01456 }
01457 
01458 /*
01459  * Local Variables:
01460  * mode: C
01461  * tab-width: 8
01462  * c-basic-offset: 4
01463  * indent-tabs-mode: t
01464  * End:
01465  * ex: shiftwidth=4 tabstop=8
01466  */

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