nmg_eval.c

Go to the documentation of this file.
00001 /*                      N M G _ E V A L . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-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_eval.c
00026  *      Evaluate boolean operations on NMG objects.
00027  *
00028  *  Authors -
00029  *      Michael John Muuss
00030  *      Lee A. Butler
00031  *
00032  *  Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *      The U. S. Army Ballistic Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland  21005
00036  *
00037  */
00038 /*@}*/
00039 
00040 #ifndef lint
00041 static const char RCSnmg_eval[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_eval.c,v 14.12 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00042 #endif
00043 
00044 #include "common.h"
00045 
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <math.h>
00049 
00050 #include "machine.h"
00051 #include "vmath.h"
00052 #include "nmg.h"
00053 #include "raytrace.h"
00054 
00055 
00056 struct nmg_bool_state  {
00057         struct shell    *bs_dest;
00058         struct shell    *bs_src;
00059         int             bs_isA;         /* true if A, else doing B */
00060         long            **bs_classtab;
00061         const int       *bs_actions;
00062         const struct bn_tol     *bs_tol;
00063 };
00064 
00065 static void nmg_eval_shell BU_ARGS( (struct shell *s,
00066                 struct nmg_bool_state *bs));
00067 static void nmg_eval_plot BU_ARGS( (struct nmg_bool_state *bs,
00068                 int num, int delay));
00069 
00070 
00071 #define BACTION_KILL                    1
00072 #define BACTION_RETAIN                  2
00073 #define BACTION_RETAIN_AND_FLIP         3
00074 
00075 static const char       *nmg_baction_names[] = {
00076         "*undefined 0*",
00077         "BACTION_KILL",
00078         "BACTION_RETAIN",
00079         "BACTION_RETAIN_AND_FLIP",
00080         "*undefined 4*"
00081 };
00082 
00083 #define NMG_CLASS_BAD           8
00084 static const char       *nmg_class_names[] = {
00085         "onAinB",
00086         "onAonBshared",
00087         "onAonBanti",
00088         "onAoutB",
00089         "inAonB",
00090         "onAonBshared",
00091         "onAonBanti",
00092         "outAonB",
00093         "*BAD*CLASS*"
00094 };
00095 
00096 /**
00097  *                      N M G _ C K _ L U _ O R I E N T A T I O N
00098  *
00099  *  Make sure that the lu and fu orientation flags are consistent with
00100  *  the geometric arrangement of the vertices and the faceuse normal.
00101  */
00102 void
00103 nmg_ck_lu_orientation(struct loopuse *lu, const struct bn_tol *tolp)
00104 {
00105         struct faceuse  *fu;
00106         plane_t         fu_peqn;
00107         plane_t         lu_peqn;
00108         fastf_t         dot;
00109 
00110         NMG_CK_LOOPUSE(lu);
00111         fu = lu->up.fu_p;               /* parent had better be faceuse */
00112         NMG_CK_FACEUSE(fu);
00113 
00114         NMG_GET_FU_PLANE( fu_peqn, fu );
00115         nmg_loop_plane_newell( lu, lu_peqn );
00116 
00117         dot = VDOT( fu_peqn, lu_peqn );
00118 
00119         if( dot == 0.0 )
00120                 return;         /* can't determine geometric orientation */
00121 
00122 
00123         if( dot < 0.0 )
00124         {
00125                 bu_log("nmg_ck_lu_orientation() lu=x%x, dot=%g, fu_orient=%s, lu_orient=%s\n", lu,
00126                         dot,
00127                         nmg_orientation(fu->orientation),
00128                         nmg_orientation(lu->orientation)
00129                 );
00130                 rt_bomb("nmg_ck_lu_orientation() loop orientation flags do not match geometry\n");
00131         }
00132 }
00133 
00134 
00135 /**
00136  *                      N M G _ C L A S S _ N A M E
00137  *
00138  *  Convert an NMG_CLASS_xxx token into a string name.
00139  */
00140 const char *
00141 nmg_class_name(int class)
00142 {
00143         if( class == NMG_CLASS_Unknown )  return "Unknown";
00144         if( class < 0 || class > NMG_CLASS_BAD )  class = NMG_CLASS_BAD;
00145         return nmg_class_names[class];
00146 }
00147 
00148 /*
00149  *              Action Table for Boolean Operations.
00150  *
00151  *  Each table lists what actions are to be taken for topological elements
00152  *  which have have each kind of classification.
00153  *
00154  *  Actions are listed in this order:
00155  *      (Aon)   onAinB, onAonBshared, onAonBanti-shared, onAoutB,
00156  *      (Bon)   inAonB, onAonBshared, onAonBanti-shared, outAonB
00157  */
00158 static const int                subtraction_actions[8] = {
00159         BACTION_KILL,
00160         BACTION_KILL,           /* shared */
00161         BACTION_RETAIN,         /* anti-shared */
00162         BACTION_RETAIN,
00163 
00164         BACTION_RETAIN,         /* (formerly BACTION_RETAIN_AND_FLIP) */
00165         BACTION_KILL,
00166         BACTION_KILL,
00167         BACTION_KILL
00168 };
00169 
00170 static const int                union_actions[8] = {
00171         BACTION_KILL,
00172         BACTION_RETAIN,         /* shared */
00173         BACTION_KILL,           /* anti-shared */
00174         BACTION_RETAIN,
00175 
00176         BACTION_KILL,
00177         BACTION_KILL,
00178         BACTION_KILL,
00179         BACTION_RETAIN
00180 };
00181 
00182 static const int                intersect_actions[8] = {
00183         BACTION_RETAIN,
00184         BACTION_RETAIN,         /* shared */
00185         BACTION_KILL,           /* anti-shared ==> non-manifold result */
00186         BACTION_KILL,
00187 
00188         BACTION_RETAIN,
00189         BACTION_KILL,
00190         BACTION_KILL,
00191         BACTION_KILL
00192 };
00193 
00194 /**
00195  *                      N M G _ E V A L U A T E _ B O O L E A N
00196  *
00197  *  Evaluate a boolean operation on the two shells "A" and "B",
00198  *  of the form "answer = A op B".
00199  *  As input, each element (loop-in-face, wire loop, wire edge, vertex)
00200  *  in both A and B has been classified as being
00201  *  "in", "on", or "out" of the other shell.
00202  *  Using these classifications, operate on the input shells.
00203  *  At the end, shell A contains the resultant object, and
00204  *  shell B is destroyed.
00205  *
00206  */
00207 void
00208 nmg_evaluate_boolean(struct shell *sA, struct shell *sB, int op, long int **classlist, const struct bn_tol *tol)
00209 {
00210         int const       *actions;
00211         struct nmg_bool_state   bool_state;
00212 
00213         NMG_CK_SHELL(sA);
00214         NMG_CK_SHELL(sB);
00215         BN_CK_TOL(tol);
00216 
00217         if (rt_g.NMG_debug & DEBUG_BOOLEVAL) {
00218                 bu_log("nmg_evaluate_boolean(sA=x%x, sB=x%x, op=%d) START\n",
00219                         sA, sB, op );
00220         }
00221 
00222         switch( op )  {
00223         case NMG_BOOL_SUB:
00224                 actions = subtraction_actions;
00225                 nmg_invert_shell(sB, tol);      /* FLIP all faceuse normals */
00226                 break;
00227         case NMG_BOOL_ADD:
00228                 actions = union_actions;
00229                 break;
00230         case NMG_BOOL_ISECT:
00231                 actions = intersect_actions;
00232                 break;
00233         default:
00234                 actions = union_actions;        /* shut up lint */
00235                 bu_log("ERROR nmg_evaluate_boolean() op=%d.\n", op);
00236                 rt_bomb("bad boolean\n");
00237         }
00238 
00239         bool_state.bs_dest = sA;
00240         bool_state.bs_src = sB;
00241         bool_state.bs_classtab = classlist;
00242         bool_state.bs_actions = actions;
00243         bool_state.bs_tol = tol;
00244 
00245         bool_state.bs_isA = 1;
00246         nmg_eval_shell( sA, &bool_state );
00247 
00248         bool_state.bs_isA = 0;
00249         nmg_eval_shell( sB, &bool_state );
00250 
00251         if (rt_g.NMG_debug & DEBUG_BOOLEVAL) {
00252                 bu_log("nmg_evaluate_boolean(sA=x%x, sB=x%x, op=%d), evaluations done\n",
00253                         sA, sB, op );
00254         }
00255         /* Write sA and sB into separate files, if wanted? */
00256 
00257         /* Move everything left in sB into sA.  sB is killed. */
00258         nmg_js( sA, sB, tol );
00259 
00260         /* Plot the result */
00261         if (rt_g.NMG_debug & DEBUG_BOOLEVAL && rt_g.NMG_debug & DEBUG_PLOTEM) {
00262                 FILE    *fp;
00263 
00264                 if ((fp=fopen("bool_ans.pl", "w")) == (FILE *)NULL) {
00265                         (void)perror("bool_ans.pl");
00266                         bu_bomb("unable to open bool_ans.pl for writing");
00267                 }
00268                 bu_log("plotting bool_ans.pl\n");
00269                 nmg_pl_s( fp, sA );
00270                 (void)fclose(fp);
00271         }
00272 
00273         /* Remove loops/edges/vertices that appear more than once in result */
00274         nmg_rm_redundancies( sA, tol );
00275 
00276         if (rt_g.NMG_debug & DEBUG_BOOLEVAL) {
00277                 bu_log("nmg_evaluate_boolean(sA=x%x, sB=x%x, op=%d) END\n",
00278                         sA, sB, op );
00279         }
00280 }
00281 
00282 static int      nmg_eval_count = 0;     /* debug -- plot file numbering */
00283 
00284 /**
00285  *                      N M G _ E V A L _ A C T I O N
00286  *
00287  *  Given a pointer to some NMG data structure,
00288  *  search the 4 classification lists to determine it's classification.
00289  *  (XXX In the future, this should be done with one big array).
00290  *  Then, return the action code for an item of that classification.
00291  */
00292 int
00293 nmg_eval_action(long int *ptr, register struct nmg_bool_state *bs)
00294 {
00295         register int    ret;
00296         register int    class;
00297         int             index;
00298 
00299         BN_CK_TOL(bs->bs_tol);
00300 
00301         index = nmg_index_of_struct(ptr);
00302         if( bs->bs_isA )  {
00303                 if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AinB], index) )  {
00304                         class = NMG_CLASS_AinB;
00305                         ret = bs->bs_actions[NMG_CLASS_AinB];
00306                         goto out;
00307                 }
00308                 if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AonBshared], index) )  {
00309                         class = NMG_CLASS_AonBshared;
00310                         ret = bs->bs_actions[NMG_CLASS_AonBshared];
00311                         goto out;
00312                 }
00313                 if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AonBanti], index) )  {
00314                         class = NMG_CLASS_AonBanti;
00315                         ret = bs->bs_actions[NMG_CLASS_AonBanti];
00316                         goto out;
00317                 }
00318                 if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AoutB], index) )  {
00319                         class = NMG_CLASS_AoutB;
00320                         ret = bs->bs_actions[NMG_CLASS_AoutB];
00321                         goto out;
00322                 }
00323                 bu_log("nmg_eval_action(ptr=x%x) %s has no A classification, retaining\n",
00324                         ptr, bu_identify_magic( *((long *)ptr) ) );
00325                 class = NMG_CLASS_BAD;
00326                 ret = BACTION_RETAIN;
00327                 goto out;
00328         }
00329 
00330         /* is B */
00331         if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BinA], index) )  {
00332                 class = NMG_CLASS_BinA;
00333                 ret = bs->bs_actions[NMG_CLASS_BinA];
00334                 goto out;
00335         }
00336         if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BonAshared], index) )  {
00337                 class = NMG_CLASS_BonAshared;
00338                 ret = bs->bs_actions[NMG_CLASS_BonAshared];
00339                 goto out;
00340         }
00341         if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BonAanti], index) )  {
00342                 class = NMG_CLASS_BonAanti;
00343                 ret = bs->bs_actions[NMG_CLASS_BonAanti];
00344                 goto out;
00345         }
00346         if( NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BoutA], index) )  {
00347                 class = NMG_CLASS_BoutA;
00348                 ret = bs->bs_actions[NMG_CLASS_BoutA];
00349                 goto out;
00350         }
00351         bu_log("nmg_eval_action(ptr=x%x) %s has no B classification, retaining\n",
00352                 ptr, bu_identify_magic( *((long *)ptr) ) );
00353         class = NMG_CLASS_BAD;
00354         ret = BACTION_RETAIN;
00355 out:
00356         if (rt_g.NMG_debug & DEBUG_BOOLEVAL) {
00357                 bu_log("nmg_eval_action(ptr=x%x) index=%d %s %s %s %s\n",
00358                         ptr, index,
00359                         bs->bs_isA ? "A" : "B",
00360                         bu_identify_magic( *((long *)ptr) ),
00361                         nmg_class_name(class),
00362                         nmg_baction_names[ret] );
00363         }
00364         return(ret);
00365 }
00366 
00367 /**
00368  *                      N M G _ E V A L _ S H E L L
00369  *
00370  *  Make a life-and-death decision on every element of a shell.
00371  *  Descend the "great chain of being" from the face to loop to edge
00372  *  to vertex, saving or demoting along the way.
00373  *
00374  *  Note that there is no moving of items from one shell to another.
00375  */
00376 static void
00377 nmg_eval_shell(register struct shell *s, struct nmg_bool_state *bs)
00378 {
00379         struct faceuse  *fu;
00380         struct faceuse  *nextfu;
00381         struct loopuse  *lu;
00382         struct loopuse  *nextlu;
00383         struct edgeuse  *eu;
00384         struct edgeuse  *nexteu;
00385         struct vertexuse *vu;
00386         int             loops_retained;
00387 
00388         NMG_CK_SHELL(s);
00389         BN_CK_TOL(bs->bs_tol);
00390 
00391         if( rt_g.NMG_debug & DEBUG_VERIFY )
00392                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00393 
00394         /*
00395          *  For each face in the shell, process all the loops in the face,
00396          *  and then handle the face and all loops as a unit.
00397          */
00398         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00399         fu = BU_LIST_FIRST( faceuse, &s->fu_hd );
00400         while( BU_LIST_NOT_HEAD( fu, &s->fu_hd ) )  {
00401                 NMG_CK_FACEUSE(fu);
00402                 nextfu = BU_LIST_PNEXT( faceuse, fu );
00403 
00404                 /* Faceuse mates will be handled at same time as OT_SAME fu */
00405                 if( fu->orientation != OT_SAME )  {
00406                         fu = nextfu;
00407                         continue;
00408                 }
00409                 if( fu->fumate_p == nextfu )
00410                         nextfu = BU_LIST_PNEXT( faceuse, nextfu );
00411 
00412                 /* Consider this face */
00413                 NMG_CK_FACE(fu->f_p);
00414 
00415                 loops_retained = 0;
00416                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
00417                 while( BU_LIST_NOT_HEAD( lu, &fu->lu_hd ) )  {
00418                         NMG_CK_LOOPUSE(lu);
00419                         nextlu = BU_LIST_PNEXT( loopuse, lu );
00420                         if( lu->lumate_p == nextlu )
00421                                 nextlu = BU_LIST_PNEXT( loopuse, nextlu );
00422 
00423                         NMG_CK_LOOP( lu->l_p );
00424 #if 0
00425                         if (rt_g.NMG_debug & DEBUG_BOOLEVAL)
00426 #endif
00427                         {
00428                                 nmg_ck_lu_orientation( lu, bs->bs_tol );
00429                         }
00430                         switch( nmg_eval_action( &lu->l_p->magic, bs ) )  {
00431                         case BACTION_KILL:
00432                                 /* Kill by demoting loop to edges */
00433                                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )  {
00434                                         /* loop of single vertex */
00435                                         (void)nmg_klu( lu );
00436                                 } else if( nmg_demote_lu( lu ) == 0 )  {
00437                                         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00438                                 }
00439                                 lu = nextlu;
00440                                 continue;
00441                         case BACTION_RETAIN:
00442                                 loops_retained++;
00443                                 break;
00444                         default:
00445                                 rt_bomb("nmg_eval_shell() bad BACTION\n");
00446                         }
00447                         lu = nextlu;
00448                 }
00449 
00450                 if (rt_g.NMG_debug & DEBUG_BOOLEVAL)
00451                         bu_log("faceuse x%x loops retained=%d\n",
00452                                 fu, loops_retained);
00453                 if( rt_g.NMG_debug & DEBUG_VERIFY )
00454                         nmg_vshell( &s->r_p->s_hd, s->r_p );
00455 
00456                 /*
00457                  *  Here, faceuse will have 0 or more loopuses still in it.
00458                  *  Decide the fate of the face;  if the face dies,
00459                  *  then any remaining loops, edges, etc, will die too.
00460                  */
00461                 if( BU_LIST_IS_EMPTY( &fu->lu_hd ) )  {
00462                         if( loops_retained )  rt_bomb("nmg_eval_shell() empty faceuse with retained loops?\n");
00463                         /* faceuse is empty, face & mate die */
00464                         if (rt_g.NMG_debug & DEBUG_BOOLEVAL)
00465                                 bu_log("faceuse x%x empty, kill\n", fu);
00466                         nmg_kfu( fu );  /* kill face & mate, dequeue from shell */
00467                         if( rt_g.NMG_debug & DEBUG_VERIFY )
00468                                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00469                         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00470                         fu = nextfu;
00471                         continue;
00472                 }
00473 
00474                 if( loops_retained <= 0 )  {
00475                         nmg_pr_fu(fu, (char *)NULL);
00476                         rt_bomb("nmg_eval_shell() non-empty faceuse, no loops retained?\n");
00477                 }
00478                 fu = nextfu;
00479         }
00480         if( rt_g.NMG_debug & DEBUG_VERIFY )
00481                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00482 
00483         /*
00484          *  For each loop in the shell, process.
00485          *  Each loop is either a wire-loop, or a vertex-with-self-loop.
00486          *  Only consider wire loops here.
00487          */
00488         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00489         lu = BU_LIST_FIRST( loopuse, &s->lu_hd );
00490         while( BU_LIST_NOT_HEAD( lu, &s->lu_hd ) )  {
00491                 NMG_CK_LOOPUSE(lu);
00492                 nextlu = BU_LIST_PNEXT( loopuse, lu );
00493                 if( lu->lumate_p == nextlu )
00494                         nextlu = BU_LIST_PNEXT( loopuse, nextlu );
00495 
00496                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )  {
00497                         /* ignore vertex-with-self-loop */
00498                         lu = nextlu;
00499                         continue;
00500                 }
00501                 NMG_CK_LOOP( lu->l_p );
00502                 switch( nmg_eval_action( &lu->l_p->magic, bs ) )  {
00503                 case BACTION_KILL:
00504                         /* Demote the loopuse into wire edges */
00505                         /* kill loop & mate */
00506                         if( nmg_demote_lu( lu ) == 0 )
00507                                 nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00508                         lu = nextlu;
00509                         continue;
00510                 case BACTION_RETAIN:
00511                         break;
00512                 default:
00513                         rt_bomb("nmg_eval_shell() bad BACTION\n");
00514                 }
00515                 lu = nextlu;
00516         }
00517         if( rt_g.NMG_debug & DEBUG_VERIFY )
00518                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00519 
00520         /*
00521          *  For each wire-edge in the shell, ...
00522          */
00523         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00524         eu = BU_LIST_FIRST( edgeuse, &s->eu_hd );
00525         while( BU_LIST_NOT_HEAD( eu, &s->eu_hd ) )  {
00526                 NMG_CK_EDGEUSE(eu);
00527                 nexteu = BU_LIST_PNEXT( edgeuse, eu );  /* may be head */
00528                 if( eu->eumate_p == nexteu )
00529                         nexteu = BU_LIST_PNEXT( edgeuse, nexteu );
00530 
00531                 /* Consider this edge */
00532                 NMG_CK_EDGE( eu->e_p );
00533                 switch( nmg_eval_action( &eu->e_p->magic, bs ) )  {
00534                 case BACTION_KILL:
00535                         /* Demote the edegeuse (and mate) into vertices */
00536                         if( nmg_demote_eu( eu ) == 0 )
00537                                 nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00538                         eu = nexteu;
00539                         continue;
00540                 case BACTION_RETAIN:
00541                         break;
00542                 default:
00543                         rt_bomb("nmg_eval_shell() bad BACTION\n");
00544                 }
00545                 eu = nexteu;
00546         }
00547 
00548         /*
00549          *  For each lone vertex-with-self-loop, process.
00550          *  Note that these are intermixed in the loop list.
00551          *  Each loop is either a wire-loop, or a vertex-with-self-loop.
00552          *  Only consider cases of vertex-with-self-loop here.
00553          *
00554          *  This case has to be handled separately, because a wire-loop
00555          *  may be demoted to a set of wire-edges above, some of which
00556          *  may be retained.  The non-retained wire-edges may in turn
00557          *  be demoted into vertex-with-self-loop objects above,
00558          *  which will be processed here.
00559          */
00560         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00561         lu = BU_LIST_FIRST( loopuse, &s->lu_hd );
00562         while( BU_LIST_NOT_HEAD( lu, &s->lu_hd ) )  {
00563                 NMG_CK_LOOPUSE(lu);
00564                 nextlu = BU_LIST_PNEXT( loopuse, lu );
00565 
00566                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_VERTEXUSE_MAGIC )  {
00567                         /* ignore any remaining wire-loops */
00568                         lu = nextlu;
00569                         continue;
00570                 }
00571                 if( nextlu == lu->lumate_p )
00572                         nextlu = BU_LIST_PNEXT(loopuse, nextlu);
00573                 vu = BU_LIST_PNEXT( vertexuse, &lu->down_hd );
00574                 NMG_CK_VERTEXUSE( vu );
00575                 NMG_CK_VERTEX( vu->v_p );
00576                 switch( nmg_eval_action( &vu->v_p->magic, bs ) )  {
00577                 case BACTION_KILL:
00578                         /* Eliminate the loopuse, and mate */
00579                         nmg_klu( lu );
00580                         lu = nextlu;
00581                         continue;
00582                 case BACTION_RETAIN:
00583                         break;
00584                 default:
00585                         rt_bomb("nmg_eval_shell() bad BACTION\n");
00586                 }
00587                 lu = nextlu;
00588         }
00589         if( rt_g.NMG_debug & DEBUG_VERIFY )
00590                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00591 
00592         /*
00593          * Final case:  shell of a single vertexuse
00594          */
00595         if( (vu = s->vu_p) )  {
00596                 NMG_CK_VERTEXUSE( vu );
00597                 NMG_CK_VERTEX( vu->v_p );
00598                 switch( nmg_eval_action( &vu->v_p->magic, bs ) )  {
00599                 case BACTION_KILL:
00600                         nmg_kvu( vu );
00601                         nmg_eval_plot( bs, nmg_eval_count++, 0 );       /* debug */
00602                         s->vu_p = (struct vertexuse *)0;        /* sanity */
00603                         break;
00604                 case BACTION_RETAIN:
00605                         break;
00606                 default:
00607                         rt_bomb("nmg_eval_shell() bad BACTION\n");
00608                 }
00609         }
00610         if( rt_g.NMG_debug & DEBUG_VERIFY )
00611                 nmg_vshell( &s->r_p->s_hd, s->r_p );
00612         nmg_eval_plot( bs, nmg_eval_count++, 1 );       /* debug */
00613 }
00614 
00615 
00616 /**
00617  *                      N M G _ E V A L _ P L O T
00618  *
00619  *  Called from nmg_eval_shell
00620  *
00621  *  Located here because definition of nmg_bool_state is local to this module.
00622  */
00623 static void
00624 nmg_eval_plot(struct nmg_bool_state *bs, int num, int delay)
00625 {
00626         FILE    *fp;
00627         char    fname[128];
00628         int     do_plot = 0;
00629         int     do_anim = 0;
00630 
00631         if (rt_g.NMG_debug & DEBUG_BOOLEVAL && rt_g.NMG_debug & DEBUG_PLOTEM)
00632                 do_plot = 1;
00633         if( rt_g.NMG_debug & DEBUG_PL_ANIM )  do_anim = 1;
00634 
00635         if( !do_plot && !do_anim )  return;
00636 
00637         BN_CK_TOL(bs->bs_tol);
00638 
00639         if( do_plot )  {
00640                 sprintf(fname, "nmg_eval%d.pl", num);
00641                 if( (fp = fopen(fname,"w")) == NULL )  {
00642                         perror(fname);
00643                         return;
00644                 }
00645                 bu_log("Plotting %s\n", fname);
00646 
00647                 nmg_pl_s( fp, bs->bs_dest );
00648                 nmg_pl_s( fp, bs->bs_src );
00649 
00650                 fclose(fp);
00651         }
00652 
00653         if( do_anim )  {
00654                 extern void (*nmg_vlblock_anim_upcall)();
00655                 struct bn_vlblock       *vbp;
00656 
00657                 vbp = rt_vlblock_init();
00658 
00659                 nmg_vlblock_s( vbp, bs->bs_dest, 0 );
00660                 nmg_vlblock_s( vbp, bs->bs_src, 0 );
00661 
00662                 /* Cause animation of boolean operation as it proceeds! */
00663                 if( nmg_vlblock_anim_upcall )  {
00664                         /* if requested, delay 1/4 second */
00665                         (*nmg_vlblock_anim_upcall)( vbp,
00666                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? 250000 : 0,
00667                                 0 );
00668                 } else {
00669                         bu_log("null nmg_vlblock_anim_upcall, no animation\n");
00670                 }
00671                 rt_vlblock_free(vbp);
00672         }
00673 }
00674 
00675 /*
00676  * Local Variables:
00677  * mode: C
00678  * tab-width: 8
00679  * c-basic-offset: 4
00680  * indent-tabs-mode: t
00681  * End:
00682  * ex: shiftwidth=4 tabstop=8
00683  */

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