BRL-CAD
poly.c
Go to the documentation of this file.
1 /* P O L Y . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1985-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 primitives */
21 /** @{ */
22 /** @file primitives/poly/poly.c
23  *
24  * Intersect a ray with a Polygonal Object that has no explicit
25  * topology. It is assumed that the solid has no holes.
26  *
27  */
28 /** @} */
29 
30 #include "common.h"
31 
32 #include <math.h>
33 #include "bio.h"
34 
35 #include "vmath.h"
36 #include "db.h"
37 #include "nmg.h"
38 #include "rtgeom.h"
39 #include "raytrace.h"
40 
41 #include "../../librt_private.h"
42 
43 
44 #define TRI_NULL ((struct tri_specific *)0)
45 
46 HIDDEN int rt_pgface(struct soltab *stp, fastf_t *ap, fastf_t *bp, fastf_t *cp, const struct bn_tol *tol);
47 
48 /* Describe algorithm here */
49 
50 /**
51  * Calculate the bounding RPP for a poly
52  */
53 int
54 rt_pg_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol))
55 {
56  struct rt_pg_internal *pgp;
57  size_t i;
58  size_t p;
59 
60  pgp = (struct rt_pg_internal *)ip->idb_ptr;
61  RT_PG_CK_MAGIC(pgp);
62 
63  VSETALL((*min), INFINITY);
64  VSETALL((*max), -INFINITY);
65 
66  for (p = 0; p < pgp->npoly; p++) {
67  vect_t work[3];
68 
69  VMOVE(work[0], &pgp->poly[p].verts[0*3]);
70  VMINMAX((*min), (*max), work[0]);
71  VMOVE(work[1], &pgp->poly[p].verts[1*3]);
72  VMINMAX((*min), (*max), work[1]);
73 
74  for (i=2; i < pgp->poly[p].npts; i++) {
75  VMOVE(work[2], &pgp->poly[p].verts[i*3]);
76  VMINMAX((*min), (*max), work[2]);
77 
78  /* Chop off a triangle, and continue */
79  VMOVE(work[1], work[2]);
80  }
81  }
82 
83  return 0; /* OK */
84 }
85 
86 
87 /**
88  * This routine is used to prepare a list of planar faces for
89  * being shot at by the triangle routines.
90  *
91  * Process a PG, which is represented as a vector
92  * from the origin to the first point, and many vectors
93  * from the first point to the remaining points.
94  *
95  */
96 int
97 rt_pg_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
98 {
99  struct rt_pg_internal *pgp;
100  size_t i;
101  size_t p;
102 
103  pgp = (struct rt_pg_internal *)ip->idb_ptr;
104  RT_PG_CK_MAGIC(pgp);
105 
106  if (rt_pg_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1;
107 
108  for (p = 0; p < pgp->npoly; p++) {
109  vect_t work[3];
110 
111  VMOVE(work[0], &pgp->poly[p].verts[0*3]);
112  VMOVE(work[1], &pgp->poly[p].verts[1*3]);
113 
114  for (i=2; i < pgp->poly[p].npts; i++) {
115  VMOVE(work[2], &pgp->poly[p].verts[i*3]);
116 
117  /* output a face */
118  (void)rt_pgface(stp,
119  work[0], work[1], work[2], &rtip->rti_tol);
120 
121  /* Chop off a triangle, and continue */
122  VMOVE(work[1], work[2]);
123  }
124  }
125  if (stp->st_specific == (void *)0) {
126  bu_log("pg(%s): no faces\n", stp->st_name);
127  return -1; /* BAD */
128  }
129 
130  {
131  fastf_t dx, dy, dz;
132  fastf_t f;
133 
134  VADD2SCALE(stp->st_center, stp->st_max, stp->st_min, 0.5);
135 
136  dx = (stp->st_max[X] - stp->st_min[X])/2;
137  f = dx;
138  dy = (stp->st_max[Y] - stp->st_min[Y])/2;
139  if (dy > f) f = dy;
140  dz = (stp->st_max[Z] - stp->st_min[Z])/2;
141  if (dz > f) f = dz;
142  stp->st_aradius = f;
143  stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
144  }
145 
146  return 0; /* OK */
147 }
148 
149 
150 /**
151  * This function is called with pointers to 3 points,
152  * and is used to prepare PG faces.
153  * ap, bp, cp point to vect_t points.
154  *
155  * Return -
156  * 0 if the 3 points didn't form a plane (e.g., collinear, etc.).
157  * # pts (3) if a valid plane resulted.
158  */
159 HIDDEN int
160 rt_pgface(struct soltab *stp, fastf_t *ap, fastf_t *bp, fastf_t *cp, const struct bn_tol *tol)
161 {
162  struct tri_specific *trip;
163  vect_t work;
164  fastf_t m1, m2, m3, m4;
165 
166  BU_GET(trip, struct tri_specific);
167  VMOVE(trip->tri_A, ap);
168  VSUB2(trip->tri_BA, bp, ap);
169  VSUB2(trip->tri_CA, cp, ap);
170  VCROSS(trip->tri_wn, trip->tri_BA, trip->tri_CA);
171 
172  /* Check to see if this plane is a line or pnt */
173  m1 = MAGNITUDE(trip->tri_BA);
174  m2 = MAGNITUDE(trip->tri_CA);
175  VSUB2(work, bp, cp);
176  m3 = MAGNITUDE(work);
177  m4 = MAGNITUDE(trip->tri_wn);
178  if (m1 < tol->dist || m2 < tol->dist ||
179  m3 < tol->dist || m4 < tol->dist) {
180  BU_PUT(trip, struct tri_specific);
181  if (RT_G_DEBUG & DEBUG_ARB8)
182  bu_log("pg(%s): degenerate facet\n", stp->st_name);
183  return 0; /* BAD */
184  }
185 
186  /* wn is a normal of not necessarily unit length.
187  * N is an outward pointing unit normal.
188  * We depend on the points being given in CCW order here.
189  */
190  VMOVE(trip->tri_N, trip->tri_wn);
191  VUNITIZE(trip->tri_N);
192 
193  /* Add this face onto the linked list for this solid */
194  trip->tri_forw = (struct tri_specific *)stp->st_specific;
195  stp->st_specific = (void *)trip;
196  return 3; /* OK */
197 }
198 
199 
200 void
201 rt_pg_print(const struct soltab *stp)
202 {
203  const struct tri_specific *trip =
204  (struct tri_specific *)stp->st_specific;
205 
206  if (trip == TRI_NULL) {
207  bu_log("pg(%s): no faces\n", stp->st_name);
208  return;
209  }
210  do {
211  VPRINT("A", trip->tri_A);
212  VPRINT("B-A", trip->tri_BA);
213  VPRINT("C-A", trip->tri_CA);
214  VPRINT("BA x CA", trip->tri_wn);
215  VPRINT("Normal", trip->tri_N);
216  bu_log("\n");
217 
218  trip = trip->tri_forw;
219  } while (trip);
220 }
221 
222 
223 /**
224  * Function -
225  * Shoot a ray at a polygonal object.
226  *
227  * Returns -
228  * 0 MISS
229  * >0 HIT
230  */
231 int
232 rt_pg_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
233 {
234  struct tri_specific *trip =
235  (struct tri_specific *)stp->st_specific;
236 #define MAXHITS 128 /* # surfaces hit, must be even */
237  struct hit hits[MAXHITS];
238  struct hit *hp;
239  size_t nhits;
240 
241  nhits = 0;
242  hp = &hits[0];
243 
244  /* consider each face */
245  for (; trip; trip = trip->tri_forw) {
246  fastf_t dn; /* Direction dot Normal */
247  fastf_t abs_dn;
248  fastf_t k;
249  fastf_t alpha, beta;
250  vect_t wxb; /* vertex - ray_start */
251  vect_t xp; /* wxb cross ray_dir */
252 
253  /*
254  * Ray Direction dot N. (N is outward-pointing normal)
255  * wn points inwards, and is not unit length.
256  */
257  dn = VDOT(trip->tri_wn, rp->r_dir);
258 
259  /*
260  * If ray lies directly along the face, (i.e., dot product
261  * is zero), drop this face.
262  */
263  abs_dn = dn >= 0.0 ? dn : (-dn);
264  if (abs_dn < SQRT_SMALL_FASTF)
265  continue;
266  VSUB2(wxb, trip->tri_A, rp->r_pt);
267  VCROSS(xp, wxb, rp->r_dir);
268 
269  /* Check for exceeding along the one side */
270  alpha = VDOT(trip->tri_CA, xp);
271  if (dn < 0.0) alpha = -alpha;
272  if (alpha < 0.0 || alpha > abs_dn)
273  continue;
274 
275  /* Check for exceeding along the other side */
276  beta = VDOT(trip->tri_BA, xp);
277  if (dn > 0.0) beta = -beta;
278  if (beta < 0.0 || beta > abs_dn)
279  continue;
280  if (alpha+beta > abs_dn)
281  continue;
282  k = VDOT(wxb, trip->tri_wn) / dn;
283 
284  /* For hits other than the first one, might check
285  * to see it this is approx. equal to previous one */
286 
287  /* If dn < 0, we should be entering the solid.
288  * However, we just assume in/out sorting later will work.
289  * Really should mark and check this!
290  */
291  VJOIN1(hp->hit_point, rp->r_pt, k, rp->r_dir);
292 
293  /* HIT is within planar face */
294  hp->hit_magic = RT_HIT_MAGIC;
295  hp->hit_dist = k;
296  VMOVE(hp->hit_normal, trip->tri_N);
297  hp->hit_surfno = trip->tri_surfno;
298  if (++nhits >= MAXHITS) {
299  bu_log("rt_pg_shot(%s): too many hits (%zu)\n", stp->st_name, nhits);
300  break;
301  }
302  hp++;
303  }
304  if (nhits == 0)
305  return 0; /* MISS */
306 
307  /* Sort hits, Near to Far */
308  rt_hitsort(hits, nhits);
309 
310  /* Remove duplicate hits.
311  We remove one of a pair of hits when they are
312  1) close together, and
313  2) both "entry" or both "exit" occurrences.
314  Two immediate "entry" or two immediate "exit" hits suggest
315  that we hit both of two joined faces, while we want to hit only
316  one. An "entry" followed by an "exit" (or vice versa) suggests
317  that we grazed an edge, and thus we should leave both
318  in the hit list. */
319 
320  {
321  size_t i, j;
322 
323  for (i=0; i<nhits-1; i++) {
324  fastf_t dist;
325 
326  dist = hits[i].hit_dist - hits[i+1].hit_dist;
327  if (NEAR_ZERO(dist, ap->a_rt_i->rti_tol.dist) &&
328  VDOT(hits[i].hit_normal, rp->r_dir) *
329  VDOT(hits[i+1].hit_normal, rp->r_dir) > 0)
330  {
331  for (j=i; j<nhits-1; j++)
332  hits[j] = hits[j+1];
333  nhits--;
334  i--;
335  }
336  }
337  }
338 
339 
340  if (nhits == 1)
341  nhits = 0;
342 
343  if (nhits&1) {
344  size_t i;
345  static int nerrors = 0; /* message counter */
346  /*
347  * If this condition exists, it is almost certainly due to
348  * the dn==0 check above. Thus, we will make the last
349  * surface rather thin.
350  * This at least makes the
351  * presence of this solid known. There may be something
352  * better we can do.
353  */
354 
355  if (nerrors++ < 6) {
356  bu_log("rt_pg_shot(%s): WARNING %zu hits:\n", stp->st_name, nhits);
357  bu_log("\tray start = (%g %g %g) ray dir = (%g %g %g)\n",
358  V3ARGS(rp->r_pt), V3ARGS(rp->r_dir));
359  for (i=0; i < nhits; i++) {
360  point_t tmp_pt;
361 
362  VJOIN1(tmp_pt, rp->r_pt, hits[i].hit_dist, rp->r_dir);
363  if (VDOT(rp->r_dir, hits[i].hit_normal) < 0.0)
364  bu_log("\tentrance at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS(tmp_pt));
365  else
366  bu_log("\texit at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS(tmp_pt));
367  }
368  }
369 
370  if (nhits > 2) {
371  fastf_t dot1, dot2;
372  size_t j;
373 
374  /* likely an extra hit,
375  * look for consecutive entrances or exits */
376 
377  dot2 = 1.0;
378  i = 0;
379  while (i<nhits) {
380  dot1 = dot2;
381  dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
382  if (dot1 > 0.0 && dot2 > 0.0) {
383  /* two consecutive exits,
384  * manufacture an entrance at same distance
385  * as second exit.
386  */
387  for (j=nhits; j>i; j--)
388  hits[j] = hits[j-1]; /* struct copy */
389 
390  VREVERSE(hits[i].hit_normal, hits[i].hit_normal);
391  dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
392  nhits++;
393  bu_log("\t\tadding fictitious entry at %f (%s)\n", hits[i].hit_dist, stp->st_name);
394  } else if (dot1 < 0.0 && dot2 < 0.0) {
395  /* two consecutive entrances,
396  * manufacture an exit between them.
397  */
398 
399  for (j=nhits; j>i; j--)
400  hits[j] = hits[j-1]; /* struct copy */
401 
402  hits[i] = hits[i-1]; /* struct copy */
403  VREVERSE(hits[i].hit_normal, hits[i-1].hit_normal);
404  dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
405  nhits++;
406  bu_log("\t\tadding fictitious exit at %f (%s)\n", hits[i].hit_dist, stp->st_name);
407  }
408  i++;
409  }
410 
411  } else {
412  hits[nhits] = hits[nhits-1]; /* struct copy */
413  VREVERSE(hits[nhits].hit_normal, hits[nhits-1].hit_normal);
414  bu_log("\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name);
415  nhits++;
416  }
417  }
418 
419  if (nhits&1) {
420  if (nhits < MAXHITS) {
421  hits[nhits] = hits[nhits-1]; /* struct copy */
422  VREVERSE(hits[nhits].hit_normal, hits[nhits-1].hit_normal);
423  bu_log("\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name);
424  nhits++;
425  } else
426  nhits--;
427  }
428 
429  /* nhits is even, build segments */
430  {
431  struct seg *segp;
432  size_t i;
433  for (i=0; i < nhits; i += 2) {
434  RT_GET_SEG(segp, ap->a_resource);
435  segp->seg_stp = stp;
436  segp->seg_in = hits[i]; /* struct copy */
437  segp->seg_out = hits[i+1]; /* struct copy */
438  BU_LIST_INSERT(&(seghead->l), &(segp->l));
439  }
440  }
441  return nhits; /* HIT */
442 }
443 
444 
445 void
446 rt_pg_free(struct soltab *stp)
447 {
448  struct tri_specific *trip =
449  (struct tri_specific *)stp->st_specific;
450 
451  while (trip != TRI_NULL) {
452  struct tri_specific *nexttri = trip->tri_forw;
453 
454  BU_PUT(trip, struct tri_specific);
455  trip = nexttri;
456  }
457 }
458 
459 
460 void
461 rt_pg_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
462 {
463  if (!hitp || !stp || !rp)
464  return;
465  RT_CK_HIT(hitp);
466  RT_CK_SOLTAB(stp);
467  RT_CK_RAY(rp);
468 
469  /* Normals computed in rt_pg_shot, nothing to do here */
470 }
471 
472 
473 void
474 rt_pg_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp)
475 {
476  if (ap) RT_CK_APPLICATION(ap);
477  if (stp) RT_CK_SOLTAB(stp);
478  if (hitp) RT_CK_HIT(hitp);
479  if (!uvp)
480  return;
481 
482  /* Do nothing. Really, should do what ARB does. */
483  uvp->uv_u = uvp->uv_v = 0;
484  uvp->uv_du = uvp->uv_dv = 0;
485 }
486 
487 
488 int
489 rt_pg_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info))
490 {
491  size_t i;
492  size_t p; /* current polygon number */
493  struct rt_pg_internal *pgp;
494 
495  BU_CK_LIST_HEAD(vhead);
496  RT_CK_DB_INTERNAL(ip);
497  pgp = (struct rt_pg_internal *)ip->idb_ptr;
498  RT_PG_CK_MAGIC(pgp);
499 
500  for (p = 0; p < pgp->npoly; p++) {
501  struct rt_pg_face_internal *pp;
502 
503  pp = &pgp->poly[p];
504  RT_ADD_VLIST(vhead, &pp->verts[3*(pp->npts-1)],
506  for (i=0; i < pp->npts; i++) {
507  RT_ADD_VLIST(vhead, &pp->verts[3*i],
509  }
510  }
511  return 0; /* OK */
512 }
513 
514 
515 /**
516  * Convert to vlist, draw as polygons.
517  */
518 int
519 rt_pg_plot_poly(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol))
520 {
521  size_t i;
522  size_t p; /* current polygon number */
523  struct rt_pg_internal *pgp;
524 
525  BU_CK_LIST_HEAD(vhead);
526  RT_CK_DB_INTERNAL(ip);
527  pgp = (struct rt_pg_internal *)ip->idb_ptr;
528  RT_PG_CK_MAGIC(pgp);
529 
530  for (p = 0; p < pgp->npoly; p++) {
531  struct rt_pg_face_internal *pp;
532  vect_t aa, bb, norm;
533 
534  pp = &pgp->poly[p];
535  if (pp->npts < 3)
536  continue;
537  VSUB2(aa, &pp->verts[3*(0)], &pp->verts[3*(1)]);
538  VSUB2(bb, &pp->verts[3*(0)], &pp->verts[3*(2)]);
539  VCROSS(norm, aa, bb);
540  VUNITIZE(norm);
541  RT_ADD_VLIST(vhead, norm, BN_VLIST_POLY_START);
542 
543  RT_ADD_VLIST(vhead, &pp->verts[3*(pp->npts-1)], BN_VLIST_POLY_MOVE);
544  for (i=0; i < pp->npts-1; i++) {
545  RT_ADD_VLIST(vhead, &pp->verts[3*i], BN_VLIST_POLY_DRAW);
546  }
547  RT_ADD_VLIST(vhead, &pp->verts[3*(pp->npts-1)], BN_VLIST_POLY_END);
548  }
549  return 0; /* OK */
550 }
551 
552 
553 void
554 rt_pg_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
555 {
556  if (!cvp || !hitp)
557  return;
558  RT_CK_HIT(hitp);
559  if (stp) RT_CK_SOLTAB(stp);
560 
561  bn_vec_ortho(cvp->crv_pdir, hitp->hit_normal);
562  cvp->crv_c1 = cvp->crv_c2 = 0;
563 }
564 
565 
566 int
567 rt_pg_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
568 {
569  size_t i;
570  struct shell *s;
571  struct vertex **verts; /* dynamic array of pointers */
572  struct vertex ***vertp;/* dynamic array of ptrs to pointers */
573  struct faceuse *fu;
574  size_t p; /* current polygon number */
575  struct rt_pg_internal *pgp;
576 
577  RT_CK_DB_INTERNAL(ip);
578  pgp = (struct rt_pg_internal *)ip->idb_ptr;
579  RT_PG_CK_MAGIC(pgp);
580 
581  *r = nmg_mrsv(m); /* Make region, empty shell, vertex */
582  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
583 
584  verts = (struct vertex **)bu_malloc(
585  pgp->max_npts * sizeof(struct vertex *), "pg_tess verts[]");
586  vertp = (struct vertex ***)bu_malloc(
587  pgp->max_npts * sizeof(struct vertex **), "pg_tess vertp[]");
588  for (i=0; i < pgp->max_npts; i++)
589  vertp[i] = &verts[i];
590 
591  for (p = 0; p < pgp->npoly; p++) {
592  struct rt_pg_face_internal *pp;
593 
594  pp = &pgp->poly[p];
595 
596  /* Locate these points, if previously mentioned */
597  for (i=0; i < pp->npts; i++) {
598  verts[i] = nmg_find_pt_in_shell(s,
599  &pp->verts[3*i], tol);
600  }
601 
602  /* Construct the face. Verts should be in CCW order */
603  if ((fu = nmg_cmface(s, vertp, pp->npts)) == (struct faceuse *)0) {
604  bu_log("rt_pg_tess() nmg_cmface failed, skipping face %zu\n",
605  p);
606  }
607 
608  /* Associate vertex geometry, where none existed before */
609  for (i=0; i < pp->npts; i++) {
610  if (verts[i]->vg_p) continue;
611  nmg_vertex_gv(verts[i], &pp->verts[3*i]);
612  }
613 
614  /* Associate face geometry */
615  if (nmg_calc_face_g(fu)) {
616  nmg_pr_fu_briefly(fu, "");
617  bu_free((char *)verts, "pg_tess verts[]");
618  bu_free((char *)vertp, "pg_tess vertp[]");
619  return -1; /* FAIL */
620  }
621  }
622 
623  /* Compute "geometry" for region and shell */
624  nmg_region_a(*r, tol);
625 
626  /* Polysolids are often built with incorrect face normals.
627  * Don't depend on them here.
628  */
629  nmg_fix_normals(s, tol);
630  bu_free((char *)verts, "pg_tess verts[]");
631  bu_free((char *)vertp, "pg_tess vertp[]");
632 
633  return 0; /* OK */
634 }
635 
636 
637 /**
638  * Read all the polygons in as a complex dynamic structure.
639  * The caller is responsible for freeing the dynamic memory.
640  * (vid rt_pg_ifree).
641  */
642 int
643 rt_pg_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
644 {
645  struct rt_pg_internal *pgp;
646  union record *rp;
647  size_t i;
648  size_t rno; /* current record number */
649  size_t p; /* current polygon index */
650 
651  if (dbip) RT_CK_DBI(dbip);
652 
653  BU_CK_EXTERNAL(ep);
654  rp = (union record *)ep->ext_buf;
655  if (rp->u_id != ID_P_HEAD) {
656  bu_log("rt_pg_import4: defective header record\n");
657  return -1;
658  }
659 
660  RT_CK_DB_INTERNAL(ip);
661  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
662  ip->idb_type = ID_POLY;
663  ip->idb_meth = &OBJ[ID_POLY];
664  BU_ALLOC(ip->idb_ptr, struct rt_pg_internal);
665 
666  pgp = (struct rt_pg_internal *)ip->idb_ptr;
667  pgp->magic = RT_PG_INTERNAL_MAGIC;
668 
669  pgp->npoly = (ep->ext_nbytes - sizeof(union record)) /
670  sizeof(union record);
671  if (pgp->npoly <= 0) {
672  bu_log("rt_pg_import4: polysolid with no polygons!\n");
673  return -1;
674  }
675  if (pgp->npoly)
676  pgp->poly = (struct rt_pg_face_internal *)bu_malloc(
677  pgp->npoly * sizeof(struct rt_pg_face_internal), "rt_pg_face_internal");
678  pgp->max_npts = 0;
679 
680  if (mat == NULL) mat = bn_mat_identity;
681  for (p=0; p < pgp->npoly; p++) {
682  struct rt_pg_face_internal *pp;
683 
684  pp = &pgp->poly[p];
685  rno = p+1;
686  if (rp[rno].q.q_id != ID_P_DATA) {
687  bu_log("rt_pg_import4: defective data record\n");
688  return -1;
689  }
690  pp->npts = rp[rno].q.q_count;
691  pp->verts = (fastf_t *)bu_malloc(pp->npts * 3 * sizeof(fastf_t), "pg verts[]");
692  pp->norms = (fastf_t *)bu_malloc(pp->npts * 3 * sizeof(fastf_t), "pg norms[]");
693  for (i=0; i < pp->npts; i++) {
694  point_t pnt;
695  vect_t vec;
696 
697  if (dbip->dbi_version < 0) {
698  flip_fastf_float(pnt, rp[rno].q.q_verts[i], 1, 1);
699  flip_fastf_float(vec, rp[rno].q.q_norms[i], 1, 1);
700  } else {
701  VMOVE(pnt, rp[rno].q.q_verts[i]);
702  VMOVE(vec, rp[rno].q.q_norms[i]);
703  }
704 
705  /* Note: side effect of importing dbfloat_t */
706  MAT4X3PNT(&pp->verts[i*3], mat, pnt);
707  MAT4X3VEC(&pp->norms[i*3], mat, vec);
708  }
709  if (pp->npts > pgp->max_npts) pgp->max_npts = pp->npts;
710  }
711  if (pgp->max_npts < 3) {
712  bu_log("rt_pg_import4: polysolid with all polygons of less than %zu vertices!\n", pgp->max_npts);
713  /* XXX free storage */
714  return -1;
715  }
716  return 0;
717 }
718 
719 
720 /**
721  * The name will be added by the caller.
722  * Generally, only libwdb will set conv2mm != 1.0
723  */
724 int
725 rt_pg_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
726 {
727  struct rt_pg_internal *pgp;
728  union record *rec;
729  size_t i;
730  size_t rno; /* current record number */
731  size_t p; /* current polygon index */
732 
733  if (dbip) RT_CK_DBI(dbip);
734 
735  RT_CK_DB_INTERNAL(ip);
736  if (ip->idb_type != ID_POLY) return -1;
737  pgp = (struct rt_pg_internal *)ip->idb_ptr;
738  RT_PG_CK_MAGIC(pgp);
739 
740  BU_CK_EXTERNAL(ep);
741  ep->ext_nbytes = (1 + pgp->npoly) * sizeof(union record);
742  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "pg external");
743  rec = (union record *)ep->ext_buf;
744 
745  rec[0].p.p_id = ID_P_HEAD;
746 
747  for (p=0; p < pgp->npoly; p++) {
748  struct rt_pg_face_internal *pp;
749 
750  rno = p+1;
751  pp = &pgp->poly[p];
752  if (pp->npts < 3 || pp->npts > 5) {
753  bu_log("rt_pg_export4: unable to support npts=%zu\n",
754  pp->npts);
755  return -1;
756  }
757 
758  rec[rno].q.q_id = ID_P_DATA;
759  rec[rno].q.q_count = pp->npts;
760  for (i=0; i < pp->npts; i++) {
761  /* NOTE: type conversion to dbfloat_t */
762  VSCALE(rec[rno].q.q_verts[i],
763  &pp->verts[i*3], local2mm);
764  VMOVE(rec[rno].q.q_norms[i], &pp->norms[i*3]);
765  }
766  }
767 
768  bu_log("DEPRECATED: The 'poly' primitive is no longer supported. Use the 'bot' or 'nmg' polygonal mesh instead.\n");
769  bu_log("\tTo convert polysolids to BOT primitives, use 'dbupgrade'.\n");
770 
771  return 0;
772 }
773 
774 
775 int
776 rt_pg_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
777 {
778  if (ip) RT_CK_DB_INTERNAL(ip);
779  if (!ep || !mat)
780  return -1;
781  if (dbip) RT_CK_DBI(dbip);
782 
783  bu_log("As of release 6.0 the polysolid is superceded by the BOT primitive.\n");
784  bu_log("\tTo convert polysolids to BOT primitives, use 'dbupgrade'.\n");
785  /* The rt_pg_to_bot() routine can also be used. */
786  return -1;
787 }
788 
789 
790 int
791 rt_pg_export5(struct bu_external *ep, const struct rt_db_internal *ip, double UNUSED(local2mm), const struct db_i *dbip)
792 {
793  if (!ep)
794  return -1;
795  if (ip) RT_CK_DB_INTERNAL(ip);
796  if (dbip) RT_CK_DBI(dbip);
797 
798  bu_log("DEPRECATED: The 'poly' primitive is no longer supported. Use the 'bot' or 'nmg' polygonal mesh instead.\n");
799  bu_log("\tTo convert polysolids to BOT primitives, use 'dbupgrade'.\n");
800  /* The rt_pg_to_bot() routine can also be used. */
801  return -1;
802 }
803 
804 
805 /**
806  * Make human-readable formatted presentation of this solid.
807  * First line describes type of solid.
808  * Additional lines are indented one tab, and give parameter values.
809  */
810 int
811 rt_pg_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
812 {
813  size_t i, j;
814  struct rt_pg_internal *pgp = (struct rt_pg_internal *)ip->idb_ptr;
815  char buf[256] = {0};
816 
817  RT_PG_CK_MAGIC(pgp);
818  bu_vls_strcat(str, "polygon solid with no topology (POLY)\n");
819 
820  sprintf(buf, "\t%ld polygons (faces)\n",
821  (long int)pgp->npoly);
822  bu_vls_strcat(str, buf);
823 
824  sprintf(buf, "\tMost complex face has %lu vertices\n", (long unsigned)pgp->max_npts);
825  bu_vls_strcat(str, buf);
826 
827  if (pgp->npoly) {
828  sprintf(buf, "\tFirst vertex (%g, %g, %g)\n",
829  INTCLAMP(pgp->poly[0].verts[X] * mm2local),
830  INTCLAMP(pgp->poly[0].verts[Y] * mm2local),
831  INTCLAMP(pgp->poly[0].verts[Z] * mm2local));
832  bu_vls_strcat(str, buf);
833  }
834 
835  if (!verbose) return 0;
836 
837  /* Print out all the vertices of all the faces */
838  for (i=0; i < pgp->npoly; i++) {
839  fastf_t *v = pgp->poly[i].verts;
840  fastf_t *n = pgp->poly[i].norms;
841 
842  sprintf(buf, "\tPolygon %lu: (%lu pts)\n", (long unsigned)i, (long unsigned)pgp->poly[i].npts);
843  bu_vls_strcat(str, buf);
844  for (j=0; j < pgp->poly[i].npts; j++) {
845  sprintf(buf, "\t\tV (%g, %g, %g)\n\t\t N (%g, %g, %g)\n",
846  INTCLAMP(v[X] * mm2local),
847  INTCLAMP(v[Y] * mm2local),
848  INTCLAMP(v[Z] * mm2local),
849  INTCLAMP(n[X] * mm2local),
850  INTCLAMP(n[Y] * mm2local),
851  INTCLAMP(n[Z] * mm2local));
852  bu_vls_strcat(str, buf);
853  v += ELEMENTS_PER_VECT;
854  n += ELEMENTS_PER_VECT;
855  }
856  }
857 
858  return 0;
859 }
860 
861 
862 /**
863  * Free the storage associated with the rt_db_internal version of this solid.
864  */
865 void
867 {
868  struct rt_pg_internal *pgp;
869  size_t i;
870 
871  RT_CK_DB_INTERNAL(ip);
872 
873  pgp = (struct rt_pg_internal *)ip->idb_ptr;
874  RT_PG_CK_MAGIC(pgp);
875 
876  /*
877  * Free storage for each polygon
878  */
879  for (i=0; i < pgp->npoly; i++) {
880  bu_free((char *)pgp->poly[i].verts, "pg verts[]");
881  bu_free((char *)pgp->poly[i].norms, "pg norms[]");
882  }
883  if (pgp->npoly)
884  bu_free((char *)pgp->poly, "pg poly[]");
885  pgp->magic = 0; /* sanity */
886  pgp->npoly = 0;
887  bu_free((char *)pgp, "pg ifree");
888  ip->idb_ptr = ((void *)0); /* sanity */
889 }
890 int
891 rt_pg_params(struct pc_pc_set *UNUSED(ps), const struct rt_db_internal *ip)
892 {
893  if (ip) RT_CK_DB_INTERNAL(ip);
894 
895  return 0; /* OK */
896 }
897 
898 
899 /**
900  * Convert in-memory form of a polysolid (pg) to a bag of triangles (BoT)
901  * There is no record in the V5 database for a polysolid.
902  *
903  * Depends on the "max_npts" parameter having been set.
904  *
905  * Returns -
906  * -1 FAIL
907  * 0 OK
908  */
909 int
910 rt_pg_to_bot(struct rt_db_internal *ip, const struct bn_tol *tol, struct resource *resp)
911 {
912  struct rt_pg_internal *ip_pg;
913  struct rt_bot_internal *ip_bot;
914  size_t max_pts;
915  size_t max_tri;
916  size_t p;
917  size_t i;
918 
919  RT_CK_DB_INTERNAL(ip);
920  BN_CK_TOL(tol);
921  RT_CK_RESOURCE(resp);
922 
923  if (ip->idb_type != ID_POLY) {
924  bu_log("ERROR: rt_pt_to_bot() called with a non-polysolid!!!\n");
925  return -1;
926  }
927  ip_pg = (struct rt_pg_internal *)ip->idb_ptr;
928 
929  RT_PG_CK_MAGIC(ip_pg);
930 
931  BU_ALLOC(ip_bot, struct rt_bot_internal);
932  ip_bot->magic = RT_BOT_INTERNAL_MAGIC;
933  ip_bot->mode = RT_BOT_SOLID;
934  ip_bot->orientation = RT_BOT_CCW;
935  ip_bot->bot_flags = 0;
936 
937  /* maximum possible vertices */
938  max_pts = ip_pg->npoly * ip_pg->max_npts;
939  BU_ASSERT_SIZE_T(max_pts, >, 0);
940 
941  /* maximum possible triangular faces */
942  max_tri = ip_pg->npoly * 3;
943  BU_ASSERT_SIZE_T(max_tri, >, 0);
944 
945  ip_bot->num_vertices = 0;
946  ip_bot->num_faces = 0;
947  ip_bot->thickness = (fastf_t *)NULL;
948  ip_bot->face_mode = (struct bu_bitv *)NULL;
949 
950  ip_bot->vertices = (fastf_t *)bu_calloc(max_pts * 3, sizeof(fastf_t), "BOT vertices");
951  ip_bot->faces = (int *)bu_calloc(max_tri * 3, sizeof(int), "BOT faces");
952 
953  for (p=0; p<ip_pg->npoly; p++) {
954  vect_t work[3], tmp;
955  struct tri_specific trip;
956  fastf_t m1, m2, m3, m4;
957  size_t v0=0, v2=0;
958  int first;
959 
960  first = 1;
961  VMOVE(work[0], &ip_pg->poly[p].verts[0*3]);
962  VMOVE(work[1], &ip_pg->poly[p].verts[1*3]);
963 
964  for (i=2; i < ip_pg->poly[p].npts; i++) {
965  VMOVE(work[2], &ip_pg->poly[p].verts[i*3]);
966 
967  VSUB2(trip.tri_BA, work[1], work[0]);
968  VSUB2(trip.tri_CA, work[2], work[0]);
969  VCROSS(trip.tri_wn, trip.tri_BA, trip.tri_CA);
970 
971  /* Check to see if this plane is a line or pnt */
972  m1 = MAGNITUDE(trip.tri_BA);
973  m2 = MAGNITUDE(trip.tri_CA);
974  VSUB2(tmp, work[1], work[2]);
975  m3 = MAGNITUDE(tmp);
976  m4 = MAGNITUDE(trip.tri_wn);
977  if (m1 >= tol->dist && m2 >= tol->dist &&
978  m3 >= tol->dist && m4 >= tol->dist) {
979 
980  /* add this triangle to the BOT */
981  if (first) {
982  ip_bot->faces[ip_bot->num_faces * 3] = ip_bot->num_vertices;
983  VMOVE(&ip_bot->vertices[ip_bot->num_vertices * 3], work[0]);
984  v0 = ip_bot->num_vertices;
985  ip_bot->num_vertices++;
986 
987  ip_bot->faces[ip_bot->num_faces * 3 + 1] = ip_bot->num_vertices;
988  VMOVE(&ip_bot->vertices[ip_bot->num_vertices * 3], work[1]);
989  ip_bot->num_vertices++;
990  first = 0;
991  } else {
992  ip_bot->faces[ip_bot->num_faces * 3] = v0;
993  ip_bot->faces[ip_bot->num_faces * 3 + 1] = v2;
994  }
995  VMOVE(&ip_bot->vertices[ip_bot->num_vertices * 3], work[2]);
996  ip_bot->faces[ip_bot->num_faces * 3 + 2] = ip_bot->num_vertices;
997  v2 = ip_bot->num_vertices;
998  ip_bot->num_vertices++;
999 
1000  ip_bot->num_faces++;
1001  }
1002 
1003  /* Chop off a triangle, and continue */
1004  VMOVE(work[1], work[2]);
1005  }
1006  }
1007 
1008  rt_bot_vertex_fuse(ip_bot, tol);
1009  rt_bot_face_fuse(ip_bot);
1010 
1011  rt_db_free_internal(ip);
1012 
1013  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1014  ip->idb_type = ID_BOT;
1015  ip->idb_meth = &OBJ[ID_BOT];
1016  ip->idb_ptr = ip_bot;
1017 
1018  return 0;
1019 }
1020 
1021 
1022 /*
1023  * Local Variables:
1024  * mode: C
1025  * tab-width: 8
1026  * indent-tabs-mode: t
1027  * c-file-style: "stroustrup"
1028  * End:
1029  * ex: shiftwidth=4 tabstop=8
1030  */
void nmg_fix_normals(struct shell *s_orig, const struct bn_tol *tol)
Definition: nmg_misc.c:3505
int rt_pg_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: poly.c:811
Definition: raytrace.h:800
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
struct hit seg_in
IN information.
Definition: raytrace.h:370
Definition: list.h:118
#define RT_BOT_INTERNAL_MAGIC
Definition: magic.h:85
void rt_pg_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
Definition: poly.c:554
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
int rt_pg_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: poly.c:567
double dist
>= 0
Definition: tol.h:73
vect_t crv_pdir
Principle direction.
Definition: raytrace.h:307
const mat_t bn_mat_identity
Matrix and vector functionality.
Definition: mat.c:46
fastf_t uv_u
Range 0..1.
Definition: raytrace.h:341
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
if lu s
Definition: nmg_mod.c:3860
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
#define ID_BOT
Bag o' triangles.
Definition: raytrace.h:488
Definition: pc.h:108
void rt_hitsort(struct hit h[], int nh)
Definition: raytrace.h:368
vect_t tri_CA
Definition: plane_struct.h:64
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
int rt_pg_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: poly.c:776
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
Header file for the BRL-CAD common definitions.
int rt_pg_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: poly.c:643
vect_t tri_wn
Definition: plane_struct.h:65
#define RT_CK_RAY(_p)
Definition: raytrace.h:224
void flip_fastf_float(fastf_t *ff, const dbfloat_t *fp, int n, int flip)
Definition: db_flip.c:74
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
int rt_pg_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: poly.c:725
#define HIDDEN
Definition: common.h:86
int nmg_calc_face_g(struct faceuse *fu)
Definition: nmg_misc.c:1786
struct bu_list l
Definition: raytrace.h:369
#define BN_VLIST_POLY_MOVE
move to first poly vertex
Definition: vlist.h:85
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
int rt_pg_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: poly.c:791
if(share_geom)
Definition: nmg_mod.c:3829
int idb_major_type
Definition: raytrace.h:192
int rt_pg_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
Definition: poly.c:232
int rt_bot_vertex_fuse(struct rt_bot_internal *bot, const struct bn_tol *tol)
Definition: bot.c:3060
Definition: color.c:49
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
void rt_pg_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
Definition: poly.c:461
#define RT_G_DEBUG
Definition: raytrace.h:1718
#define RT_ADD_VLIST(hd, pnt, draw)
Definition: raytrace.h:1865
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
struct tri_specific * tri_forw
Definition: plane_struct.h:69
int rt_pg_to_bot(struct rt_db_internal *ip, const struct bn_tol *tol, struct resource *resp)
Definition: poly.c:910
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
fastf_t st_bradius
Radius of BOUNDING sphere.
Definition: raytrace.h:434
fastf_t crv_c2
curvature in other direction
Definition: raytrace.h:309
#define TRI_NULL
Definition: poly.c:44
#define RT_CK_HIT(_p)
Definition: raytrace.h:259
#define BN_VLIST_POLY_START
pt[] has surface normal
Definition: vlist.h:84
#define BN_VLIST_LINE_MOVE
Definition: vlist.h:82
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
fastf_t uv_dv
delta in v
Definition: raytrace.h:344
#define V3ARGS(a)
Definition: color.c:56
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
unsigned char * bp
Definition: rot.c:56
uint8_t * ext_buf
Definition: parse.h:216
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
point_t st_max
max X, Y, Z of bounding RPP
Definition: raytrace.h:438
#define SQRT_SMALL_FASTF
Definition: defines.h:346
struct hit seg_out
OUT information.
Definition: raytrace.h:371
int rt_pg_plot_poly(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: poly.c:519
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
int rt_pg_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: poly.c:54
#define MAXHITS
#define UNUSED(parameter)
Definition: common.h:239
#define BN_VLIST_POLY_DRAW
subsequent poly vertex
Definition: vlist.h:86
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
ustring alpha
int rt_pg_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *info)
Definition: poly.c:489
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
vect_t tri_N
Definition: plane_struct.h:66
int rt_bot_face_fuse(struct rt_bot_internal *bot)
Definition: bot.c:3283
void * idb_ptr
Definition: raytrace.h:195
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
point_t st_min
min X, Y, Z of bounding RPP
Definition: raytrace.h:437
const struct rt_functab OBJ[]
Definition: table.c:159
#define RT_CK_RESOURCE(_p)
Definition: raytrace.h:1490
void bn_vec_ortho(vect_t out, const vect_t in)
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
#define BN_VLIST_POLY_END
last vert (repeats 1st), draw poly
Definition: vlist.h:87
#define ID_POLY
Polygonal faceted object.
Definition: raytrace.h:466
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
#define RT_PG_INTERNAL_MAGIC
Definition: magic.h:103
fastf_t uv_du
delta in u
Definition: raytrace.h:343
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
void rt_pg_free(struct soltab *stp)
Definition: poly.c:446
Definition: color.c:51
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
point_t tri_A
Definition: plane_struct.h:62
#define BU_ASSERT_SIZE_T(_lhs, _relation, _rhs)
Definition: defines.h:253
int rt_pg_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: poly.c:891
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
#define BU_CK_LIST_HEAD(_p)
Definition: list.h:142
int rt_pg_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: poly.c:97
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
struct vertex * nmg_find_pt_in_shell(const struct shell *s, const fastf_t *pt, const struct bn_tol *tol)
Definition: nmg_info.c:1634
void nmg_pr_fu_briefly(const struct faceuse *fu, char *h)
Definition: nmg_pr.c:359
struct faceuse * nmg_cmface(struct shell *s, struct vertex ***verts, int n)
Definition: nmg_mod.c:979
void rt_pg_ifree(struct rt_db_internal *ip)
Definition: poly.c:866
size_t ext_nbytes
Definition: parse.h:210
Definition: bitv.h:105
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
Definition: vls.h:56
HIDDEN int rt_pgface(struct soltab *stp, fastf_t *ap, fastf_t *bp, fastf_t *cp, const struct bn_tol *tol)
Definition: poly.c:160
double fastf_t
Definition: defines.h:300
#define VPRINT(a, b)
Definition: raytrace.h:1881
void rt_pg_print(const struct soltab *stp)
Definition: poly.c:201
void rt_pg_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp)
Definition: poly.c:474
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
Definition: color.c:50
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
fastf_t uv_v
Range 0..1.
Definition: raytrace.h:342
vect_t tri_BA
Definition: plane_struct.h:63
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
#define RT_HIT_MAGIC
Definition: magic.h:161
#define DEBUG_ARB8
8 Print voluminous ARB8 details
Definition: raytrace.h:91
void nmg_region_a(struct nmgregion *r, const struct bn_tol *tol)
Definition: nmg_mk.c:2557