BRL-CAD
nmg_eval.c
Go to the documentation of this file.
1 /* N M G _ E V A L . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1990-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup nmg */
21 /** @{ */
22 /** @file primitives/nmg/nmg_eval.c
23  *
24  * Evaluate boolean operations on NMG objects.
25  *
26  *
27  */
28 /** @} */
29 
30 #include "common.h"
31 
32 #include <stdlib.h>
33 #include <math.h>
34 #include "bio.h"
35 
36 #include "vmath.h"
37 #include "nmg.h"
38 #include "raytrace.h"
39 
40 
42  struct shell *bs_dest;
43  struct shell *bs_src;
44  int bs_isA; /* true if A, else doing B */
45  char **bs_classtab;
46  const int *bs_actions;
47  const struct bn_tol *bs_tol;
48 };
49 
50 
51 HIDDEN void nmg_eval_shell(struct shell *s, struct nmg_bool_state *bs);
52 HIDDEN void nmg_eval_plot(struct nmg_bool_state *bs, int num);
53 
54 
55 #define BACTION_KILL 1
56 #define BACTION_RETAIN 2
57 #define BACTION_RETAIN_AND_FLIP 3
58 
59 static const char *nmg_baction_names[] = {
60  "*undefined 0*",
61  "BACTION_KILL",
62  "BACTION_RETAIN",
63  "BACTION_RETAIN_AND_FLIP",
64  "*undefined 4*"
65 };
66 
67 
68 #define NMG_CLASS_BAD 8
69 static const char *nmg_class_names[] = {
70  "onAinB",
71  "onAonBshared",
72  "onAonBanti",
73  "onAoutB",
74  "inAonB",
75  "onAonBshared",
76  "onAonBanti",
77  "outAonB",
78  "*BAD*CLASS*"
79 };
80 
81 
82 /**
83  * Make sure that the lu and fu orientation flags are consistent with
84  * the geometric arrangement of the vertices and the faceuse normal.
85  */
86 void
87 nmg_ck_lu_orientation(struct loopuse *lu, const struct bn_tol *tolp)
88 {
89  struct faceuse *fu;
90  plane_t fu_peqn;
91  plane_t lu_peqn;
92  fastf_t dot;
93 
94  NMG_CK_LOOPUSE(lu);
95  fu = lu->up.fu_p; /* parent had better be faceuse */
96  NMG_CK_FACEUSE(fu);
97 
98  NMG_GET_FU_PLANE(fu_peqn, fu);
99  nmg_loop_plane_newell(lu, lu_peqn);
100 
101  dot = VDOT(fu_peqn, lu_peqn);
102 
103  if (NEAR_ZERO(dot, tolp->perp))
104  return; /* can't determine geometric orientation */
105 
106 
107  if (dot < 0.0) {
108  bu_log("nmg_ck_lu_orientation() lu=%p, dot=%g, fu_orient=%s, lu_orient=%s\n",
109  (void *)lu, dot,
110  nmg_orientation(fu->orientation),
111  nmg_orientation(lu->orientation)
112  );
113  bu_bomb("nmg_ck_lu_orientation() loop orientation flags do not match geometry\n");
114  }
115 }
116 
117 
118 /**
119  * Convert an NMG_CLASS_xxx token into a string name.
120  */
121 const char *
122 nmg_class_name(int nmg_class)
123 {
124  if (nmg_class == NMG_CLASS_Unknown) return "Unknown";
125  if (nmg_class < 0 || nmg_class > NMG_CLASS_BAD) nmg_class = NMG_CLASS_BAD;
126  return nmg_class_names[nmg_class];
127 }
128 
129 
130 /*
131  * Action Table for Boolean Operations.
132  *
133  * Each table lists what actions are to be taken for topological elements
134  * which have have each kind of classification.
135  *
136  * Actions are listed in this order:
137  * (Aon) onAinB, onAonBshared, onAonBanti-shared, onAoutB,
138  * (Bon) inAonB, onAonBshared, onAonBanti-shared, outAonB
139  */
140 static const int subtraction_actions[8] = {
141  BACTION_KILL,
142  BACTION_KILL, /* shared */
143  BACTION_RETAIN, /* anti-shared */
145 
146  BACTION_RETAIN, /* (formerly BACTION_RETAIN_AND_FLIP) */
147  BACTION_KILL,
148  BACTION_KILL,
149  BACTION_KILL
150 };
151 
152 
153 static const int union_actions[8] = {
154  BACTION_KILL,
155  BACTION_RETAIN, /* shared */
156  BACTION_KILL, /* anti-shared */
158 
159  BACTION_KILL,
160  BACTION_KILL,
161  BACTION_KILL,
162  BACTION_RETAIN
163 };
164 
165 
166 static const int intersect_actions[8] = {
168  BACTION_RETAIN, /* shared */
169  BACTION_KILL, /* anti-shared ==> non-manifold result */
170  BACTION_KILL,
171 
173  BACTION_KILL,
174  BACTION_KILL,
175  BACTION_KILL
176 };
177 
178 
179 /**
180  * Evaluate a boolean operation on the two shells "A" and "B", of the
181  * form "answer = A op B". As input, each element (loop-in-face, wire
182  * loop, wire edge, vertex) in both A and B has been classified as
183  * being "in", "on", or "out" of the other shell. Using these
184  * classifications, operate on the input shells. At the end, shell A
185  * contains the resultant object, and shell B is destroyed.
186  *
187  */
188 void
189 nmg_evaluate_boolean(struct shell *sA, struct shell *sB, int op, char **classlist, const struct bn_tol *tol)
190 {
191  int const *actions;
192  struct nmg_bool_state bool_state;
193 
194  NMG_CK_SHELL(sA);
195  NMG_CK_SHELL(sB);
196  BN_CK_TOL(tol);
197 
198  if (RTG.NMG_debug & DEBUG_BOOLEVAL) {
199  bu_log("nmg_evaluate_boolean(sA=%p, sB=%p, op=%d) START\n",
200  (void *)sA, (void *)sB, op);
201  }
202 
203  switch (op) {
204  case NMG_BOOL_SUB:
205  actions = subtraction_actions;
206  nmg_invert_shell(sB); /* FLIP all faceuse normals */
207  break;
208  case NMG_BOOL_ADD:
209  actions = union_actions;
210  break;
211  case NMG_BOOL_ISECT:
212  actions = intersect_actions;
213  break;
214  default:
215  actions = union_actions; /* shut up lint */
216  bu_log("ERROR nmg_evaluate_boolean() op=%d.\n", op);
217  bu_bomb("bad boolean\n");
218  }
219 
220  bool_state.bs_dest = sA;
221  bool_state.bs_src = sB;
222  bool_state.bs_classtab = classlist;
223  bool_state.bs_actions = actions;
224  bool_state.bs_tol = tol;
225 
226  bool_state.bs_isA = 1;
227  nmg_eval_shell(sA, &bool_state);
228 
229  bool_state.bs_isA = 0;
230  nmg_eval_shell(sB, &bool_state);
231 
232  if (RTG.NMG_debug & DEBUG_BOOLEVAL) {
233  bu_log("nmg_evaluate_boolean(sA=%p, sB=%p, op=%d), evaluations done\n",
234  (void *)sA, (void *)sB, op);
235  }
236  /* Write sA and sB into separate files, if wanted? */
237 
238  /* Move everything left in sB into sA. sB is killed. */
239  nmg_js(sA, sB, tol);
240 
241  /* Plot the result */
242  if (RTG.NMG_debug & DEBUG_BOOLEVAL && RTG.NMG_debug & DEBUG_PLOTEM) {
243  FILE *fp;
244 
245  if ((fp=fopen("bool_ans.plot3", "wb")) == (FILE *)NULL) {
246  (void)perror("bool_ans.plot3");
247  bu_bomb("unable to open bool_ans.plot3 for writing");
248  }
249  bu_log("plotting bool_ans.plot3\n");
250  nmg_pl_s(fp, sA);
251  (void)fclose(fp);
252  }
253 
254  /* Remove loops/edges/vertices that appear more than once in result */
255  nmg_rm_redundancies(sA, tol);
256 }
257 
258 
259 static int nmg_eval_count = 0; /* debug -- plot file numbering */
260 
261 
262 /**
263  * Given a pointer to some NMG data structure, search the 4
264  * classification lists to determine its classification. (XXX In the
265  * future, this should be done with one big array). Then, return the
266  * action code for an item of that classification.
267  */
268 HIDDEN int
269 nmg_eval_action(uint32_t *ptr, register struct nmg_bool_state *bs)
270 {
271  register int ret;
272  register int nmg_class;
273  int index;
274 
275  BN_CK_TOL(bs->bs_tol);
276 
277  index = nmg_index_of_struct(ptr);
278  if (bs->bs_isA) {
279  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AinB], index)) {
280  nmg_class = NMG_CLASS_AinB;
281  ret = bs->bs_actions[NMG_CLASS_AinB];
282  goto out;
283  }
284  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AonBshared], index)) {
285  nmg_class = NMG_CLASS_AonBshared;
286  ret = bs->bs_actions[NMG_CLASS_AonBshared];
287  goto out;
288  }
289  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AonBanti], index)) {
290  nmg_class = NMG_CLASS_AonBanti;
291  ret = bs->bs_actions[NMG_CLASS_AonBanti];
292  goto out;
293  }
294  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_AoutB], index)) {
295  nmg_class = NMG_CLASS_AoutB;
296  ret = bs->bs_actions[NMG_CLASS_AoutB];
297  goto out;
298  }
299  bu_log("nmg_eval_action(ptr=%p) %s has no A classification, retaining\n",
300  (void *)ptr, bu_identify_magic(*((uint32_t *)ptr)));
301  nmg_class = NMG_CLASS_BAD;
302  ret = BACTION_RETAIN;
303  goto out;
304  }
305 
306  /* is B */
307  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BinA], index)) {
308  nmg_class = NMG_CLASS_BinA;
309  ret = bs->bs_actions[NMG_CLASS_BinA];
310  goto out;
311  }
312  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BonAshared], index)) {
313  nmg_class = NMG_CLASS_BonAshared;
314  ret = bs->bs_actions[NMG_CLASS_BonAshared];
315  goto out;
316  }
317  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BonAanti], index)) {
318  nmg_class = NMG_CLASS_BonAanti;
319  ret = bs->bs_actions[NMG_CLASS_BonAanti];
320  goto out;
321  }
322  if (NMG_INDEX_VALUE(bs->bs_classtab[NMG_CLASS_BoutA], index)) {
323  nmg_class = NMG_CLASS_BoutA;
324  ret = bs->bs_actions[NMG_CLASS_BoutA];
325  goto out;
326  }
327  bu_log("nmg_eval_action(ptr=%p) %s has no B classification, retaining\n",
328  (void *)ptr, bu_identify_magic(*((uint32_t *)ptr)));
329  nmg_class = NMG_CLASS_BAD;
330  ret = BACTION_RETAIN;
331 out:
332  if (RTG.NMG_debug & DEBUG_BOOLEVAL) {
333  bu_log("nmg_eval_action(ptr=%p) index=%d %s %s %s %s\n",
334  (void *)ptr, index,
335  bs->bs_isA ? "A" : "B",
336  bu_identify_magic(*((uint32_t *)ptr)),
337  nmg_class_name(nmg_class),
338  nmg_baction_names[ret]);
339  }
340  return ret;
341 }
342 
343 
344 /**
345  * Make a life-and-death decision on every element of a shell.
346  * Descend the "great chain of being" from the face to loop to edge to
347  * vertex, saving or demoting along the way.
348  *
349  * Note that there is no moving of items from one shell to another.
350  */
351 HIDDEN void
352 nmg_eval_shell(register struct shell *s, struct nmg_bool_state *bs)
353 {
354  struct faceuse *fu;
355  struct faceuse *nextfu;
356  struct loopuse *lu;
357  struct loopuse *nextlu;
358  struct edgeuse *eu;
359  struct edgeuse *nexteu;
360  struct vertexuse *vu;
361  int loops_retained;
362 
363  NMG_CK_SHELL(s);
364  BN_CK_TOL(bs->bs_tol);
365 
366  if (RTG.NMG_debug & DEBUG_VERIFY)
367  nmg_vshell(&s->r_p->s_hd, s->r_p);
368 
369  /*
370  * For each face in the shell, process all the loops in the face,
371  * and then handle the face and all loops as a unit.
372  */
373  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
374  fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
375  while (BU_LIST_NOT_HEAD(fu, &s->fu_hd)) {
376  NMG_CK_FACEUSE(fu);
377  nextfu = BU_LIST_PNEXT(faceuse, fu);
378 
379  /* Faceuse mates will be handled at same time as OT_SAME fu */
380  if (fu->orientation != OT_SAME) {
381  fu = nextfu;
382  continue;
383  }
384  if (fu->fumate_p == nextfu)
385  nextfu = BU_LIST_PNEXT(faceuse, nextfu);
386 
387  /* Consider this face */
388  NMG_CK_FACE(fu->f_p);
389 
390  loops_retained = 0;
391  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
392  while (BU_LIST_NOT_HEAD(lu, &fu->lu_hd)) {
393  NMG_CK_LOOPUSE(lu);
394  nextlu = BU_LIST_PNEXT(loopuse, lu);
395  if (lu->lumate_p == nextlu)
396  nextlu = BU_LIST_PNEXT(loopuse, nextlu);
397 
398  NMG_CK_LOOP(lu->l_p);
399  nmg_ck_lu_orientation(lu, bs->bs_tol);
400  switch (nmg_eval_action(&lu->l_p->magic, bs)) {
401  case BACTION_KILL:
402  /* Kill by demoting loop to edges */
403  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
404  /* loop of single vertex */
405  (void)nmg_klu(lu);
406  } else if (nmg_demote_lu(lu) == 0) {
407  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
408  }
409  lu = nextlu;
410  continue;
411  case BACTION_RETAIN:
412  loops_retained++;
413  break;
414  default:
415  bu_bomb("nmg_eval_shell() bad BACTION\n");
416  }
417  lu = nextlu;
418  }
419 
420  if (RTG.NMG_debug & DEBUG_BOOLEVAL)
421  bu_log("faceuse %p loops retained=%d\n",
422  (void *)fu, loops_retained);
423  if (RTG.NMG_debug & DEBUG_VERIFY)
424  nmg_vshell(&s->r_p->s_hd, s->r_p);
425 
426  /*
427  * Here, faceuse will have 0 or more loopuses still in it.
428  * Decide the fate of the face; if the face dies,
429  * then any remaining loops, edges, etc., will die too.
430  */
431  if (BU_LIST_IS_EMPTY(&fu->lu_hd)) {
432  if (loops_retained) bu_bomb("nmg_eval_shell() empty faceuse with retained loops?\n");
433  /* faceuse is empty, face & mate die */
434  if (RTG.NMG_debug & DEBUG_BOOLEVAL)
435  bu_log("faceuse %p empty, kill\n", (void *)fu);
436  nmg_kfu(fu); /* kill face & mate, dequeue from shell */
437  if (RTG.NMG_debug & DEBUG_VERIFY)
438  nmg_vshell(&s->r_p->s_hd, s->r_p);
439  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
440  fu = nextfu;
441  continue;
442  }
443 
444  if (loops_retained <= 0) {
445  nmg_pr_fu(fu, (char *)NULL);
446  bu_bomb("nmg_eval_shell() non-empty faceuse, no loops retained?\n");
447  }
448  fu = nextfu;
449  }
450  if (RTG.NMG_debug & DEBUG_VERIFY)
451  nmg_vshell(&s->r_p->s_hd, s->r_p);
452 
453  /*
454  * For each loop in the shell, process.
455  * Each loop is either a wire-loop, or a vertex-with-self-loop.
456  * Only consider wire loops here.
457  */
458  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
459  lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
460  while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) {
461  NMG_CK_LOOPUSE(lu);
462  nextlu = BU_LIST_PNEXT(loopuse, lu);
463  if (lu->lumate_p == nextlu)
464  nextlu = BU_LIST_PNEXT(loopuse, nextlu);
465 
466  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
467  /* ignore vertex-with-self-loop */
468  lu = nextlu;
469  continue;
470  }
471  NMG_CK_LOOP(lu->l_p);
472  switch (nmg_eval_action(&lu->l_p->magic, bs)) {
473  case BACTION_KILL:
474  /* Demote the loopuse into wire edges */
475  /* kill loop & mate */
476  if (nmg_demote_lu(lu) == 0)
477  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
478  lu = nextlu;
479  continue;
480  case BACTION_RETAIN:
481  break;
482  default:
483  bu_bomb("nmg_eval_shell() bad BACTION\n");
484  }
485  lu = nextlu;
486  }
487  if (RTG.NMG_debug & DEBUG_VERIFY)
488  nmg_vshell(&s->r_p->s_hd, s->r_p);
489 
490  /*
491  * For each wire-edge in the shell, ...
492  */
493  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
494  eu = BU_LIST_FIRST(edgeuse, &s->eu_hd);
495  while (BU_LIST_NOT_HEAD(eu, &s->eu_hd)) {
496  NMG_CK_EDGEUSE(eu);
497  nexteu = BU_LIST_PNEXT(edgeuse, eu); /* may be head */
498  if (eu->eumate_p == nexteu)
499  nexteu = BU_LIST_PNEXT(edgeuse, nexteu);
500 
501  /* Consider this edge */
502  NMG_CK_EDGE(eu->e_p);
503  switch (nmg_eval_action(&eu->e_p->magic, bs)) {
504  case BACTION_KILL:
505  /* Demote the edegeuse (and mate) into vertices */
506  if (nmg_demote_eu(eu) == 0)
507  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
508  eu = nexteu;
509  continue;
510  case BACTION_RETAIN:
511  break;
512  default:
513  bu_bomb("nmg_eval_shell() bad BACTION\n");
514  }
515  eu = nexteu;
516  }
517 
518  /*
519  * For each lone vertex-with-self-loop, process.
520  * Note that these are intermixed in the loop list.
521  * Each loop is either a wire-loop, or a vertex-with-self-loop.
522  * Only consider cases of vertex-with-self-loop here.
523  *
524  * This case has to be handled separately, because a wire-loop
525  * may be demoted to a set of wire-edges above, some of which
526  * may be retained. The non-retained wire-edges may in turn
527  * be demoted into vertex-with-self-loop objects above,
528  * which will be processed here.
529  */
530  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
531  lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
532  while (BU_LIST_NOT_HEAD(lu, &s->lu_hd)) {
533  NMG_CK_LOOPUSE(lu);
534  nextlu = BU_LIST_PNEXT(loopuse, lu);
535 
536  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_VERTEXUSE_MAGIC) {
537  /* ignore any remaining wire-loops */
538  lu = nextlu;
539  continue;
540  }
541  if (nextlu == lu->lumate_p)
542  nextlu = BU_LIST_PNEXT(loopuse, nextlu);
543  vu = BU_LIST_PNEXT(vertexuse, &lu->down_hd);
544  NMG_CK_VERTEXUSE(vu);
545  NMG_CK_VERTEX(vu->v_p);
546  switch (nmg_eval_action(&vu->v_p->magic, bs)) {
547  case BACTION_KILL:
548  /* Eliminate the loopuse, and mate */
549  nmg_klu(lu);
550  lu = nextlu;
551  continue;
552  case BACTION_RETAIN:
553  break;
554  default:
555  bu_bomb("nmg_eval_shell() bad BACTION\n");
556  }
557  lu = nextlu;
558  }
559  if (RTG.NMG_debug & DEBUG_VERIFY)
560  nmg_vshell(&s->r_p->s_hd, s->r_p);
561 
562  /*
563  * Final case: shell of a single vertexuse
564  */
565  vu = s->vu_p;
566  if (vu) {
567  NMG_CK_VERTEXUSE(vu);
568  NMG_CK_VERTEX(vu->v_p);
569  switch (nmg_eval_action(&vu->v_p->magic, bs)) {
570  case BACTION_KILL:
571  nmg_kvu(vu);
572  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
573  s->vu_p = (struct vertexuse *)0; /* sanity */
574  break;
575  case BACTION_RETAIN:
576  break;
577  default:
578  bu_bomb("nmg_eval_shell() bad BACTION\n");
579  }
580  }
581  if (RTG.NMG_debug & DEBUG_VERIFY)
582  nmg_vshell(&s->r_p->s_hd, s->r_p);
583  nmg_eval_plot(bs, nmg_eval_count++); /* debug */
584 }
585 
586 
587 /**
588  * Called from nmg_eval_shell
589  *
590  * Located here because definition of nmg_bool_state is local to this
591  * module.
592  */
593 HIDDEN void
594 nmg_eval_plot(struct nmg_bool_state *bs, int num)
595 {
596  FILE *fp;
597  char fname[128];
598  int do_plot = 0;
599  int do_anim = 0;
600 
601  if (RTG.NMG_debug & DEBUG_BOOLEVAL && RTG.NMG_debug & DEBUG_PLOTEM)
602  do_plot = 1;
603  if (RTG.NMG_debug & DEBUG_PL_ANIM) do_anim = 1;
604 
605  if (!do_plot && !do_anim) return;
606 
607  BN_CK_TOL(bs->bs_tol);
608 
609  if (do_plot) {
610  sprintf(fname, "nmg_eval%d.plot3", num);
611  if ((fp = fopen(fname, "wb")) == NULL) {
612  perror(fname);
613  return;
614  }
615  bu_log("Plotting %s\n", fname);
616 
617  nmg_pl_s(fp, bs->bs_dest);
618  nmg_pl_s(fp, bs->bs_src);
619 
620  fclose(fp);
621  }
622 
623  if (do_anim) {
624  struct bn_vlblock *vbp;
625 
626  vbp = rt_vlblock_init();
627 
628  nmg_vlblock_s(vbp, bs->bs_dest, 0);
629  nmg_vlblock_s(vbp, bs->bs_src, 0);
630 
631  /* Cause animation of boolean operation as it proceeds! */
633  /* if requested, delay 1/4 second */
634  /* need to cast nmg_vlblock_anim_upcall pointer for actual use as a function */
635  void (*cfp)(struct bn_vlblock *, int, int);
636  cfp = (void (*)(struct bn_vlblock *, int, int))nmg_vlblock_anim_upcall;
637  cfp(vbp,
638  (RTG.NMG_debug&DEBUG_PL_SLOW) ? 250000 : 0,
639  0);
640  } else {
641  bu_log("null nmg_vlblock_anim_upcall, no animation\n");
642  }
643  rt_vlblock_free(vbp);
644  }
645 }
646 
647 
648 /*
649  * Local Variables:
650  * mode: C
651  * tab-width: 8
652  * indent-tabs-mode: t
653  * c-file-style: "stroustrup"
654  * End:
655  * ex: shiftwidth=4 tabstop=8
656  */
void nmg_pl_s(FILE *fp, const struct shell *s)
Definition: nmg_plot.c:746
struct shell * bs_src
Definition: nmg_eval.c:43
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
void rt_vlblock_free(struct bn_vlblock *vbp)
Definition: vlist.c:78
#define NMG_CLASS_BAD
Definition: nmg_eval.c:68
HIDDEN int nmg_eval_action(uint32_t *ptr, register struct nmg_bool_state *bs)
Definition: nmg_eval.c:269
int nmg_kfu(struct faceuse *fu1)
Definition: nmg_mk.c:1207
int nmg_demote_eu(struct edgeuse *eu)
Definition: nmg_mk.c:2676
struct shell * bs_dest
Definition: nmg_eval.c:42
void nmg_evaluate_boolean(struct shell *sA, struct shell *sB, int op, char **classlist, const struct bn_tol *tol)
Definition: nmg_eval.c:189
if lu s
Definition: nmg_mod.c:3860
lu
Definition: nmg_mod.c:3855
#define BACTION_RETAIN
Definition: nmg_eval.c:56
#define BU_LIST_IS_EMPTY(hp)
Definition: list.h:295
int nmg_demote_lu(struct loopuse *lu1)
Definition: nmg_mk.c:2610
int nmg_index_of_struct(register const uint32_t *p)
Definition: nmg_index.c:49
Header file for the BRL-CAD common definitions.
struct bn_vlblock * rt_vlblock_init(void)
Definition: vlist.c:71
int nmg_kvu(struct vertexuse *vu)
Definition: nmg_mk.c:1095
HIDDEN void nmg_eval_shell(struct shell *s, struct nmg_bool_state *bs)
void nmg_vlblock_s(struct bn_vlblock *vbp, const struct shell *s, int fancy)
Definition: nmg_plot.c:1134
#define HIDDEN
Definition: common.h:86
NMG_CK_LOOPUSE(lu)
void nmg_invert_shell(struct shell *s)
Definition: nmg_mod.c:890
uint32_t NMG_debug
debug bits for NMG's see nmg.h
Definition: raytrace.h:1699
#define BACTION_KILL
Definition: nmg_eval.c:55
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
void nmg_ck_lu_orientation(struct loopuse *lu, const struct bn_tol *tolp)
Definition: nmg_eval.c:87
#define BU_LIST_PNEXT(structure, p)
Definition: list.h:422
char ** bs_classtab
Definition: nmg_eval.c:45
goto out
Definition: nmg_mod.c:3846
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
#define BU_LIST_FIRST_MAGIC(hp)
Definition: list.h:416
#define NMG_VERTEXUSE_MAGIC
Definition: magic.h:145
void nmg_vshell(const struct bu_list *hp, const struct nmgregion *r)
Definition: nmg_ck.c:591
void nmg_rm_redundancies(struct shell *s, const struct bn_tol *tol)
Definition: nmg_mod.c:242
double perp
nearly 0
Definition: tol.h:75
int nmg_klu(struct loopuse *lu1)
Definition: nmg_mk.c:1277
HIDDEN void nmg_eval_plot(struct nmg_bool_state *bs, int num)
Definition: nmg_eval.c:594
void nmg_js(register struct shell *s1, register struct shell *s2, const struct bn_tol *tol)
Definition: nmg_mod.c:740
const struct bn_tol * bs_tol
Definition: nmg_eval.c:47
const char * nmg_class_name(int nmg_class)
Definition: nmg_eval.c:122
NMG_CK_SHELL(s)
void nmg_pr_fu(const struct faceuse *fu, char *h)
Definition: nmg_pr.c:327
const int * bs_actions
Definition: nmg_eval.c:46
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
const char * bu_identify_magic(uint32_t magic)
char * nmg_orientation(int orientation)
Definition: nmg_pr.c:50
#define BU_LIST_NOT_HEAD(p, hp)
Definition: list.h:324
void nmg_loop_plane_newell(const struct loopuse *lu, fastf_t *pl)
Definition: nmg_misc.c:1250
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
void(* nmg_vlblock_anim_upcall)(void)
Definition: globals.c:45
struct rt_g RTG
Definition: globals.c:39