BRL-CAD
arb8.c
Go to the documentation of this file.
1 /* A R B 8 . 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/arb8/arb8.c
23  *
24  * Intersect a ray with an Arbitrary Regular Polyhedron with as many
25  * as 8 vertices.
26  *
27  * An ARB is a convex volume bounded by 4 (pyramid), 5 (wedge), or 6
28  * (box) planes. This analysis depends on the properties of objects
29  * with convex hulls. Let the ray in question be defined such that
30  * any point X on the ray may be expressed as X = P + k D. Intersect
31  * the ray with each of the planes bounding the ARB as discussed
32  * above, and record the values of the parametric distance k along the
33  * ray.
34  *
35  * With outward pointing normal vectors, note that the ray enters the
36  * half-space defined by a plane when D cdot N < 0, is parallel to the
37  * plane when D cdot N = 0, and exits otherwise. Find the entry point
38  * farthest away from the starting point bold P, i.e. it has the
39  * largest value of k among the entry points. The ray enters the
40  * solid at this point. Similarly, find the exit point closest to
41  * point P, i.e. it has the smallest value of k among the exit points.
42  * The ray exits the solid here.
43  *
44  * This algorithm is due to Cyrus & Beck, USAF.
45  *
46  */
47 
48 #include "common.h"
49 
50 #include <stddef.h>
51 #include <math.h>
52 #include <string.h>
53 #include "bio.h"
54 
55 
56 #include "bu/parallel.h"
57 #include "bu/cv.h"
58 #include "vmath.h"
59 #include "bn.h"
60 #include "nmg.h"
61 #include "db.h"
62 #include "rtgeom.h"
63 #include "rt/arb_edit.h"
64 #include "raytrace.h"
65 #include "nurb.h"
66 
67 #include "../../librt_private.h"
68 
69 
70 #define RT_SLOPPY_DOT_TOL 0.0087 /* inspired by RT_DOT_TOL, but less tight (.5 deg) */
71 
72 /* Optionally, one of these for each face. (Lazy evaluation) */
73 struct oface {
74  fastf_t arb_UVorig[3]; /* origin of UV coord system */
75  fastf_t arb_U[3]; /* unit U vector (along B-A) */
76  fastf_t arb_V[3]; /* unit V vector (perp to N and U) */
77  fastf_t arb_Ulen; /* length of U basis (for du) */
78  fastf_t arb_Vlen; /* length of V basis (for dv) */
79 };
80 
81 
82 /* One of these for each face */
83 struct aface {
84  fastf_t A[3]; /* "A" point */
85  plane_t peqn; /* Plane equation, unit normal */
86 };
87 
88 
89 /* One of these for each ARB, custom allocated to size */
90 struct arb_specific {
91  int arb_nmfaces; /* number of faces */
92  struct oface *arb_opt; /* pointer to optional info */
93  struct aface arb_face[6]; /* May really be up to [6] faces */
94 };
95 
96 
97 /* These hold temp values for the face being prep'ed */
98 struct prep_arb {
99  vect_t pa_center; /* center point */
100  int pa_faces; /* Number of faces done so far */
101  int pa_npts[6]; /* # of points on face's plane */
102  int pa_pindex[4][6]; /* subscr in arbi_pt[] */
103  int pa_clockwise[6]; /* face normal was flipped */
104  struct aface pa_face[6]; /* required face info work area */
105  struct oface pa_opt[6]; /* optional face info work area */
106  /* These elements must be initialized before using */
107  fastf_t pa_tol_sq; /* points-are-equal tol sq */
108  int pa_doopt; /* compute pa_opt[] stuff */
109 };
110 
111 
112 /*
113  * Layout of arb in input record.
114  * Points are listed in "clockwise" order,
115  * to make proper outward-pointing face normals.
116  * (Although the cross product wants counter-clockwise order)
117  */
118 struct arb_info {
119  char *ai_title;
120  int ai_sub[4];
121 };
122 
123 
124 static const struct arb_info rt_arb_info[6] = {
125  { "1234", {3, 2, 1, 0} }, /* "bottom" face */
126  { "8765", {4, 5, 6, 7} }, /* "top" face */
127  { "1485", {4, 7, 3, 0} },
128  { "2673", {2, 6, 5, 1} },
129  { "1562", {1, 5, 4, 0} },
130  { "4378", {7, 6, 2, 3} }
131 };
132 
133 
134 /* division of an arb8 into 6 arb4s */
135 static const int farb4[6][4] = {
136  {0, 1, 2, 4},
137  {4, 5, 6, 1},
138  {1, 2, 6, 4},
139  {0, 2, 3, 4},
140  {4, 6, 7, 2},
141  {2, 3, 7, 4},
142 };
143 
144 
145 #define ARB_AO(_t, _a, _i) offsetof(_t, _a) + sizeof(point_t) * _i + sizeof(point_t) / ELEMENTS_PER_POINT * X
146 
147 const struct bu_structparse rt_arb_parse[] = {
148  { "%f", 3, "V1", ARB_AO(struct rt_arb_internal, pt, 0), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
149  { "%f", 3, "V2", ARB_AO(struct rt_arb_internal, pt, 1), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
150  { "%f", 3, "V3", ARB_AO(struct rt_arb_internal, pt, 2), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
151  { "%f", 3, "V4", ARB_AO(struct rt_arb_internal, pt, 3), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
152  { "%f", 3, "V5", ARB_AO(struct rt_arb_internal, pt, 4), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
153  { "%f", 3, "V6", ARB_AO(struct rt_arb_internal, pt, 5), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
154  { "%f", 3, "V7", ARB_AO(struct rt_arb_internal, pt, 6), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
155  { "%f", 3, "V8", ARB_AO(struct rt_arb_internal, pt, 7), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
156  { {'\0', '\0', '\0', '\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
157 };
158 
159 
160 const short local_arb6_edge_vertex_mapping[10][2] = {
161  {0, 1}, /* edge 12 */
162  {1, 2}, /* edge 23 */
163  {2, 3}, /* edge 34 */
164  {0, 3}, /* edge 14 */
165  {0, 4}, /* edge 15 */
166  {1, 4}, /* edge 25 */
167  {2, 7}, /* edge 36 */
168  {3, 7}, /* edge 46 */
169  {4, 4}, /* point 5 */
170  {7, 7}, /* point 6 */
171 };
172 
173 
174 const short local_arb4_edge_vertex_mapping[6][2] = {
175  {0, 1}, /* edge 12 */
176  {1, 2}, /* edge 23 */
177  {2, 0}, /* edge 31 */
178  {0, 4}, /* edge 14 */
179  {1, 4}, /* edge 24 */
180  {2, 4}, /* edge 34 */
181 };
182 
183 
184 /* rt_arb_get_cgtype(), rt_arb_std_type(), and rt_arb_centroid()
185  * stolen from mged/arbs.c */
186 
187 /**
188  * determines COMGEOM arb types from GED general arbs
189  *
190  * Inputs -
191  *
192  * Returns number of distinct edge vectors (number of entries in uvec array)
193  *
194  * Implicit returns -
195  * *cgtype - Comgeom type (number range 4..8; ARB4 .. ARB8).
196  * uvec[8] - indices of unique vertices (return value is the number of valid entries)
197  * svec[11] - Entries [0] and [1] are special (they are the counts of duplicates)
198  * entries 2-10 are 2 lists of duplicate vertices
199  * entry[0] gives length of first list (starts at entry[2])
200  * entry[1] gives length of second list (starts at entry[2+entry[0]])
201  */
202 int
204  int *cgtype,
205  struct rt_arb_internal *arb,
206  const struct bn_tol *tol,
207  register int *uvec, /* array of indexes to unique points in arb->pt[] */
208  register int *svec) /* array of indexes to like points in arb->pt[] */
209 {
210  register int i, j;
211  int numuvec, unique;
212  int si = 2; /* working index into svec */
213  int dup_list = 0; /* index for the first two entries in svec */
214  int idx = 1; /* index to the beginning of a list of duplicate vertices in svec,
215  * compared against si to determine length of list */
216  RT_ARB_CK_MAGIC(arb);
217  BN_CK_TOL(tol);
218 
219  svec[0] = svec[1] = 0;
220  /* compare each point against every other point
221  * to find duplicates */
222  for (i = 0; i < 7; i++) {
223  unique = 1;
224  /* store possible duplicate point,
225  * will be overwritten if no duplicate is found */
226  svec[si] = i;
227  for (j = i + 1; j < 8; j++) {
228  /* check if points are "equal" */
229  if (VNEAR_EQUAL(arb->pt[i], arb->pt[j], tol->dist)) {
230  svec[++si] = j;
231  unique = 0;
232  }
233  }
234  if (!unique) {
235  /* record length */
236  svec[dup_list] = si - idx;
237 
238  /* arb5 only has one set of duplicates, end early */
239  if (si == 5 && svec[5] >= 6) break;
240  /* second list of duplicates, done looking */
241  if (dup_list) break;
242 
243  /* remember the current index so we can compare
244  * the new value of si to it later */
245  idx = si++;
246  dup_list = 1;
247  }
248  }
249 
250  /* mark invalid entries */
251  for (i = svec[0] + svec[1] + 2; i < 11; i++) {
252  svec[i] = -1;
253  }
254 
255  /* find the unique points */
256  numuvec = 0;
257  for (i = 0; i < 8; i++) {
258  unique = 1;
259  for (j = 2; j < svec[0] + svec[1] + 2; j++) {
260  if (i == svec[j]) {
261  unique = 0;
262  break;
263  }
264  }
265  if (unique) {
266  uvec[numuvec++] = i;
267  }
268  }
269 
270  /* Figure out what kind of ARB this is */
271  switch (numuvec) {
272  case 8:
273  *cgtype = ARB8; /* ARB8 */
274  break;
275 
276  case 6:
277  *cgtype = ARB7; /* ARB7 */
278  break;
279 
280  case 4:
281  if (svec[0] == 2)
282  *cgtype = ARB6; /* ARB6 */
283  else
284  *cgtype = ARB5; /* ARB5 */
285  break;
286 
287  case 2:
288  *cgtype = ARB4; /* ARB4 */
289  break;
290 
291  default:
292  bu_log("rt_arb_get_cgtype: bad number of unique vectors (%d)\n",
293  numuvec);
294  return 0;
295  }
296  return numuvec;
297 }
298 
299 
300 /**
301  * Given an ARB in internal form, return its specific ARB type.
302  *
303  * Set tol.dist = 0.0001 to obtain past behavior.
304  *
305  * Returns -
306  * 0 Error in input ARB
307  * 4 ARB4
308  * 5 ARB5
309  * 6 ARB6
310  * 7 ARB7
311  * 8 ARB8
312  *
313  * Implicit return -
314  * rt_arb_internal pt[] array reorganized into GIFT "standard" order.
315  */
316 int
317 rt_arb_std_type(const struct rt_db_internal *ip, const struct bn_tol *tol)
318 {
319  struct rt_arb_internal *arb;
320  int uvec[8], svec[11];
321  int cgtype = 0;
322 
323  RT_CK_DB_INTERNAL(ip);
324  BN_CK_TOL(tol);
325 
326  if (ip->idb_type != ID_ARB8) bu_bomb("rt_arb_std_type: not ARB!\n");
327 
328  arb = (struct rt_arb_internal *)ip->idb_ptr;
329  RT_ARB_CK_MAGIC(arb);
330 
331  /* return rt_arb_get_cgtype(...); causes segfault in bk_mk_plane_3pts() when
332  * using analyze command */
333  if (rt_arb_get_cgtype(&cgtype, arb, tol, uvec, svec) == 0)
334  return 0;
335 
336  return cgtype;
337 }
338 
339 
340 /**
341  * Find the center point for the arb in the rt_db_internal structure,
342  * and return it as a point_t.
343  */
344 void
345 rt_arb_centroid(point_t *cent, const struct rt_db_internal *ip)
346 {
347 
348  struct rt_arb_internal *aip;
349  struct bn_tol tmp_tol;
350  int arb_type = -1;
351  int i;
352  fastf_t x_avg, y_avg, z_avg;
353 
354  if (!cent || !ip)
355  return;
356  aip = (struct rt_arb_internal *)ip->idb_ptr;
357  RT_ARB_CK_MAGIC(aip);
358 
359  /* set up tolerance for rt_arb_std_type */
360  tmp_tol.magic = BN_TOL_MAGIC;
361  tmp_tol.dist = 0.0001; /* to get old behavior of rt_arb_std_type() */
362  tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
363  tmp_tol.perp = 1e-5;
364  tmp_tol.para = 1 - tmp_tol.perp;
365  x_avg = y_avg = z_avg = 0;
366 
367  /* get number of vertices in arb_type */
368  arb_type = rt_arb_std_type(ip, &tmp_tol);
369 
370  /* centroid is the average for each axis of all coordinates of vertices */
371  for (i = 0; i < arb_type; i++) {
372  x_avg += aip->pt[i][0];
373  y_avg += aip->pt[i][1];
374  z_avg += aip->pt[i][2];
375  }
376 
377  x_avg /= arb_type;
378  y_avg /= arb_type;
379  z_avg /= arb_type;
380 
381  (*cent)[0] = x_avg;
382  (*cent)[1] = y_avg;
383  (*cent)[2] = z_avg;
384 
385 }
386 
387 
388 /**
389  * Add another point to a struct arb_specific, checking for unique
390  * pts. The first two points are easy. The third one triggers most
391  * of the plane calculations, and forth and subsequent ones are merely
392  * checked for validity.
393  *
394  * Returns -
395  * 0 point was accepted
396  * -1 point was rejected
397  */
398 HIDDEN int
399 rt_arb_add_pt(register pointp_t point, const char *title, struct prep_arb *pap, int ptno, const char *name)
400 
401 
402 /* current point # on face */
403 
404 {
405  vect_t work;
406  vect_t P_A; /* new point minus A */
407  fastf_t f;
408  register struct aface *afp;
409  register struct oface *ofp;
410 
411  afp = &pap->pa_face[pap->pa_faces];
412  ofp = &pap->pa_opt[pap->pa_faces];
413 
414  /* The first 3 points are treated differently */
415  switch (ptno) {
416  case 0:
417  VMOVE(afp->A, point);
418  if (pap->pa_doopt) {
419  VMOVE(ofp->arb_UVorig, point);
420  }
421  return 0; /* OK */
422  case 1:
423  VSUB2(ofp->arb_U, point, afp->A); /* B-A */
424  f = MAGNITUDE(ofp->arb_U);
425  if (ZERO(f)) {
426  return -1; /* BAD */
427  }
428  ofp->arb_Ulen = f;
429  f = 1/f;
430  VSCALE(ofp->arb_U, ofp->arb_U, f);
431  /* Note that arb_U is used to build N, below */
432  return 0; /* OK */
433  case 2:
434  VSUB2(P_A, point, afp->A); /* C-A */
435  /* Pts are given clockwise, so reverse terms of cross prod. */
436  /* peqn = (C-A)x(B-A), which points inwards */
437  VCROSS(afp->peqn, P_A, ofp->arb_U);
438  /* Check for co-linear, i.e., |(B-A)x(C-A)| ~= 0 */
439  f = MAGNITUDE(afp->peqn);
440  if (NEAR_ZERO(f, RT_SLOPPY_DOT_TOL)) {
441  return -1; /* BAD */
442  }
443  f = 1/f;
444  VSCALE(afp->peqn, afp->peqn, f);
445 
446  if (pap->pa_doopt) {
447  /*
448  * Get vector perp. to AB in face of plane ABC.
449  * Scale by projection of AC, make this V.
450  */
451  VCROSS(work, afp->peqn, ofp->arb_U);
452  VUNITIZE(work);
453  f = VDOT(work, P_A);
454  VSCALE(ofp->arb_V, work, f);
455  f = MAGNITUDE(ofp->arb_V);
456  ofp->arb_Vlen = f;
457  f = 1/f;
458  VSCALE(ofp->arb_V, ofp->arb_V, f);
459 
460  /* Check for new Ulen */
461  VSUB2(P_A, point, ofp->arb_UVorig);
462  f = VDOT(P_A, ofp->arb_U);
463  if (f > ofp->arb_Ulen) {
464  ofp->arb_Ulen = f;
465  } else if (f < 0.0) {
466  VJOIN1(ofp->arb_UVorig, ofp->arb_UVorig, f,
467  ofp->arb_U);
468  ofp->arb_Ulen += (-f);
469  }
470  }
471 
472  /*
473  * If C-A is clockwise from B-A, then the normal
474  * points inwards, so we need to fix it here.
475  * Build a vector from the centroid to vertex A.
476  * If the surface normal points in the same direction,
477  * then the vertices were given in CCW order;
478  * otherwise, vertices were given in CW order, and
479  * the normal needs to be flipped.
480  */
481  VSUB2(work, afp->A, pap->pa_center);
482  f = VDOT(work, afp->peqn);
483  if (f < 0.0) {
484  VREVERSE(afp->peqn, afp->peqn); /* "fix" normal */
485  pap->pa_clockwise[pap->pa_faces] = 1;
486  } else {
487  pap->pa_clockwise[pap->pa_faces] = 0;
488  }
489  afp->peqn[W] = VDOT(afp->peqn, afp->A);
490  return 0; /* OK */
491  default:
492  /* Merely validate 4th and subsequent points */
493  if (pap->pa_doopt) {
494  VSUB2(P_A, point, ofp->arb_UVorig);
495  /* Check for new Ulen, Vlen */
496  f = VDOT(P_A, ofp->arb_U);
497  if (f > ofp->arb_Ulen) {
498  ofp->arb_Ulen = f;
499  } else if (f < 0.0) {
500  VJOIN1(ofp->arb_UVorig, ofp->arb_UVorig, f,
501  ofp->arb_U);
502  ofp->arb_Ulen += (-f);
503  }
504  f = VDOT(P_A, ofp->arb_V);
505  if (f > ofp->arb_Vlen) {
506  ofp->arb_Vlen = f;
507  } else if (f < 0.0) {
508  VJOIN1(ofp->arb_UVorig, ofp->arb_UVorig, f,
509  ofp->arb_V);
510  ofp->arb_Vlen += (-f);
511  }
512  }
513 
514  VSUB2(P_A, point, afp->A);
515  VUNITIZE(P_A); /* Checking direction only */
516  f = VDOT(afp->peqn, P_A);
517  if (! NEAR_ZERO(f, RT_SLOPPY_DOT_TOL)) {
518  /* Non-planar face */
519  bu_log("arb(%s): face %s[%d] non-planar, dot=%g\n",
520  name, title, ptno, f);
521 #ifdef CONSERVATIVE
522  return -1; /* BAD */
523 #endif
524  }
525  return 0; /* OK */
526  }
527  /* NOTREACHED */
528 }
529 
530 
531 /**
532  * Given an rt_arb_internal structure with 8 points in it, compute the
533  * face information.
534  *
535  * Returns -
536  * 0 OK
537  * <0 failure
538  */
539 HIDDEN int
540 rt_arb_mk_planes(register struct prep_arb *pap, struct rt_arb_internal *aip, const char *name)
541 {
542  vect_t sum; /* Sum of all endpoints */
543  register int i;
544  register int j;
545  register int k;
546  int equiv_pts[8];
547 
548  /*
549  * Determine a point which is guaranteed to be within the solid.
550  * This is done by averaging all the vertices. This center is
551  * needed for rt_arb_add_pt, which demands a point inside the
552  * solid. The center of the enclosing RPP strategy used for the
553  * bounding sphere can be tricked by thin plates which are
554  * non-axis aligned, so this dual-strategy is required. (What a
555  * bug hunt!).
556  */
557  VSETALL(sum, 0);
558  for (i = 0; i < 8; i++) {
559  VADD2(sum, sum, aip->pt[i]);
560  }
561  VSCALE(pap->pa_center, sum, 0.125); /* sum/8 */
562 
563  /*
564  * Find all points that are equivalent, within the specified tol.
565  * Build the array equiv_pts[] so that it is indexed by vertex
566  * number, and returns the lowest numbered equivalent vertex (or
567  * its own vertex number, if non-equivalent).
568  */
569  equiv_pts[0] = 0;
570  for (i = 1; i < 8; i++) {
571  for (j = i-1; j >= 0; j--) {
572  /* Compare vertices I and J */
573  vect_t work;
574 
575  VSUB2(work, aip->pt[i], aip->pt[j]);
576  if (MAGSQ(work) < pap->pa_tol_sq) {
577  /* Points I and J are the same, J is lower */
578  equiv_pts[i] = equiv_pts[j];
579  goto next_point;
580  }
581  }
582  equiv_pts[i] = i;
583  next_point: ;
584  }
585  if (RT_G_DEBUG & DEBUG_ARB8) {
586  bu_log("arb(%s) equiv_pts[] = %d %d %d %d %d %d %d %d\n",
587  name,
588  equiv_pts[0], equiv_pts[1], equiv_pts[2], equiv_pts[3],
589  equiv_pts[4], equiv_pts[5], equiv_pts[6], equiv_pts[7]);
590  }
591 
592  pap->pa_faces = 0;
593  for (i = 0; i < 6; i++) {
594  int npts;
595 
596  npts = 0;
597  for (j = 0; j < 4; j++) {
598  int pt_index;
599 
600  pt_index = rt_arb_info[i].ai_sub[j];
601  if (RT_G_DEBUG & DEBUG_ARB8) {
602  bu_log("face %d, j=%d, npts=%d, orig_vert=%d, vert=%d\n",
603  i, j, npts,
604  pt_index, equiv_pts[pt_index]);
605  }
606  pt_index = equiv_pts[pt_index];
607 
608  /* Verify that this point is not the same as an earlier
609  * point, by checking point indices
610  */
611  for (k = npts-1; k >= 0; k--) {
612  if (pap->pa_pindex[k][pap->pa_faces] == pt_index) {
613  /* Point is the same -- skip it */
614  goto skip_pt;
615  }
616  }
617  if (rt_arb_add_pt(aip->pt[pt_index],
618  rt_arb_info[i].ai_title, pap, npts, name) == 0) {
619  /* Point was accepted */
620  pap->pa_pindex[npts][pap->pa_faces] = pt_index;
621  npts++;
622  }
623 
624  skip_pt: ;
625  }
626 
627  if (npts < 3) {
628  /* This face is BAD */
629  continue;
630  }
631 
632  if (pap->pa_doopt) {
633  register struct oface *ofp;
634 
635  ofp = &pap->pa_opt[pap->pa_faces];
636  /* Scale U and V basis vectors by
637  * the inverse of Ulen and Vlen
638  */
639  ofp->arb_Ulen = 1.0 / ofp->arb_Ulen;
640  ofp->arb_Vlen = 1.0 / ofp->arb_Vlen;
641  VSCALE(ofp->arb_U, ofp->arb_U, ofp->arb_Ulen);
642  VSCALE(ofp->arb_V, ofp->arb_V, ofp->arb_Vlen);
643  }
644 
645  pap->pa_npts[pap->pa_faces] = npts;
646  pap->pa_faces++;
647  }
648  if (pap->pa_faces < 4 || pap->pa_faces > 6) {
649  bu_log("arb(%s): only %d faces present\n",
650  name, pap->pa_faces);
651  return -1; /* Error */
652  }
653  return 0; /* OK */
654 }
655 
656 
657 /**
658  * Find the bounding RPP of an arb
659  */
660 int
661 rt_arb_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {
662  int i;
663  struct rt_arb_internal *aip;
664 
665  aip = (struct rt_arb_internal *)ip->idb_ptr;
666  RT_ARB_CK_MAGIC(aip);
667 
668  VSETALL((*min), INFINITY);
669  VSETALL((*max), -INFINITY);
670 
671  for (i = 0; i < 8; i++) {
672  VMINMAX((*min), (*max), aip->pt[i]);
673  }
674 
675  return 0;
676 }
677 
678 
679 /**
680  * This is packaged as a separate function, so that it can also be
681  * called "on the fly" from the UV mapper.
682  *
683  * Returns -
684  * 0 OK
685  * !0 failure
686  */
687 HIDDEN int
688 rt_arb_setup(struct soltab *stp, struct rt_arb_internal *aip, struct rt_i *rtip, int uv_wanted)
689 {
690  register int i;
691  struct prep_arb pa;
692 
693  RT_ARB_CK_MAGIC(aip);
694 
695  pa.pa_doopt = uv_wanted;
696  pa.pa_tol_sq = rtip->rti_tol.dist_sq;
697 
698  if (rt_arb_mk_planes(&pa, aip, stp->st_dp->d_namep) < 0) {
699  return -2; /* Error */
700  }
701 
702  /*
703  * Allocate a private copy of the accumulated parameters
704  * of exactly the right size.
705  * The size to malloc is chosen based upon the
706  * exact number of faces.
707  */
708  {
709  register struct arb_specific *arbp;
710  if ((arbp = (struct arb_specific *)stp->st_specific) == 0) {
711  arbp = (struct arb_specific *)bu_malloc(
712  sizeof(struct arb_specific) +
713  sizeof(struct aface) * (pa.pa_faces - 4),
714  "arb_specific");
715  stp->st_specific = (void *)arbp;
716  }
717  arbp->arb_nmfaces = pa.pa_faces;
718  memcpy((char *)arbp->arb_face, (char *)pa.pa_face,
719  pa.pa_faces * sizeof(struct aface));
720 
721  if (uv_wanted) {
722  register struct oface *ofp;
723 
724  /*
725  * To avoid a multi-processor race here,
726  * copy the data first, THEN update arb_opt,
727  * because arb_opt doubles as the "UV avail" flag.
728  */
729  ofp = (struct oface *)bu_malloc(
730  pa.pa_faces * sizeof(struct oface), "arb_opt");
731  memcpy((char *)ofp, (char *)pa.pa_opt,
732  pa.pa_faces * sizeof(struct oface));
733  arbp->arb_opt = ofp;
734  } else {
735  arbp->arb_opt = (struct oface *)0;
736  }
737  }
738 
739  /*
740  * Compute bounding sphere which contains the bounding RPP.
741  * Find min and max of the point co-ordinates to find the
742  * bounding RPP. Note that this center is NOT guaranteed
743  * to be contained within the solid!
744  */
745  {
746  vect_t work;
747  register fastf_t f;
748 
749  for (i = 0; i < 8; i++) {
750  VMINMAX(stp->st_min, stp->st_max, aip->pt[i]);
751  }
752  VADD2SCALE(stp->st_center, stp->st_min, stp->st_max, 0.5);
753  VSUB2SCALE(work, stp->st_max, stp->st_min, 0.5);
754 
755  f = work[X];
756  if (work[Y] > f) f = work[Y];
757  if (work[Z] > f) f = work[Z];
758  stp->st_aradius = f;
759  stp->st_bradius = MAGNITUDE(work);
760  }
761  return 0; /* OK */
762 }
763 
764 
765 /**
766  * This is the actual LIBRT "prep" interface.
767  *
768  * Returns -
769  * 0 OK
770  * !0 failure
771  */
772 int
773 rt_arb_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
774 {
775  struct rt_arb_internal *aip;
776 
777  aip = (struct rt_arb_internal *)ip->idb_ptr;
778  RT_ARB_CK_MAGIC(aip);
779 
780  return rt_arb_setup(stp, aip, rtip, 0);
781 }
782 
783 
784 void
785 rt_arb_print(register const struct soltab *stp)
786 {
787  register struct arb_specific *arbp =
788  (struct arb_specific *)stp->st_specific;
789  register struct aface *afp;
790  register int i;
791 
792  if (arbp == (struct arb_specific *)0) {
793  bu_log("arb(%s): no faces\n", stp->st_name);
794  return;
795  }
796  bu_log("%d faces:\n", arbp->arb_nmfaces);
797  for (i = 0; i < arbp->arb_nmfaces; i++) {
798  afp = &(arbp->arb_face[i]);
799  VPRINT("A", afp->A);
800  HPRINT("Peqn", afp->peqn);
801  if (arbp->arb_opt) {
802  register struct oface *op;
803  op = &(arbp->arb_opt[i]);
804  VPRINT("UVorig", op->arb_UVorig);
805  VPRINT("U", op->arb_U);
806  VPRINT("V", op->arb_V);
807  bu_log("Ulen = %g, Vlen = %g\n",
808  op->arb_Ulen, op->arb_Vlen);
809  }
810  }
811 }
812 
813 
814 /**
815  * Function -
816  * Shoot a ray at an ARB8.
817  *
818  * Algorithm -
819  * The intersection distance is computed for each face. The largest
820  * IN distance and the smallest OUT distance are used as the entry and
821  * exit points.
822  *
823  * Returns -
824  * 0 MISS
825  * >0 HIT
826  */
827 int
828 rt_arb_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
829 {
830  struct arb_specific *arbp = (struct arb_specific *)stp->st_specific;
831  int iplane, oplane;
832  fastf_t in, out; /* ray in/out distances */
833  register struct aface *afp;
834  register int j;
835 
836  in = -INFINITY;
837  out = INFINITY;
838  iplane = oplane = -1;
839 
840  if (RT_G_DEBUG & DEBUG_ARB8) {
841  bu_log("\n\n------------\n arb: ray point %g %g %g -> %g %g %g\n",
842  V3ARGS(rp->r_pt),
843  V3ARGS(rp->r_dir));
844  }
845 
846  /* consider each face */
847  for (afp = &arbp->arb_face[j=arbp->arb_nmfaces-1]; j >= 0; j--, afp--) {
848  fastf_t dn; /* Direction dot Normal */
849  fastf_t dxbdn;
850  fastf_t s;
851 
852  /* XXX some of this math should be prep work
853  * (including computing dxbdn/dn ?) *$*/
854  dxbdn = VDOT(afp->peqn, rp->r_pt) - afp->peqn[W];
855  dn = -VDOT(afp->peqn, rp->r_dir);
856 
857  if (RT_G_DEBUG & DEBUG_ARB8) {
858  HPRINT("arb: Plane Equation", afp->peqn);
859  bu_log("arb: dn=%g dxbdn=%g s=%g\n", dn, dxbdn, dxbdn/dn);
860  }
861 
862  if (dn < -SQRT_SMALL_FASTF) {
863  /* exit point, when dir.N < 0. out = min(out, s) */
864  if (out > (s = dxbdn/dn)) {
865  out = s;
866  oplane = j;
867  }
868  } else if (dn > SQRT_SMALL_FASTF) {
869  /* entry point, when dir.N > 0. in = max(in, s) */
870  if (in < (s = dxbdn/dn)) {
871  in = s;
872  iplane = j;
873  }
874  } else {
875  /* ray is parallel to plane when dir.N == 0.
876  * If it is outside the solid, stop now.
877  * Allow very small amount of slop, to catch
878  * rays that lie very nearly in the plane of a face.
879  */
880  if (dxbdn > SQRT_SMALL_FASTF)
881  return 0; /* MISS */
882  }
883  if (in > out)
884  return 0; /* MISS */
885  }
886  /* Validate */
887  if (iplane == -1 || oplane == -1) {
888  bu_log("rt_arb_shoot(%s): 1 hit => MISS\n",
889  stp->st_name);
890  return 0; /* MISS */
891  }
892  if (in >= out || out >= INFINITY)
893  return 0; /* MISS */
894 
895  {
896  register struct seg *segp;
897 
898  RT_GET_SEG(segp, ap->a_resource);
899  segp->seg_stp = stp;
900  segp->seg_in.hit_dist = in;
901  segp->seg_in.hit_surfno = iplane;
902 
903  segp->seg_out.hit_dist = out;
904  segp->seg_out.hit_surfno = oplane;
905  BU_LIST_INSERT(&(seghead->l), &(segp->l));
906  }
907  return 2; /* HIT */
908 }
909 
910 
911 #define RT_ARB8_SEG_MISS(SEG) (SEG).seg_stp=RT_SOLTAB_NULL
912 /**
913  * This is the Becker vector version
914  */
915 void
916 rt_arb_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
917 /* An array of solid pointers */
918 /* An array of ray pointers */
919 /* array of segs (results returned) */
920 /* Number of ray/object pairs */
921 
922 {
923  register int j, i;
924  register struct arb_specific *arbp;
925  fastf_t dn; /* Direction dot Normal */
926  fastf_t dxbdn;
927  fastf_t s;
928 
929  if (ap) RT_CK_APPLICATION(ap);
930 
931  /* Initialize return values */
932  for (i = 0; i < n; i++) {
933  segp[i].seg_stp = stp[i]; /* Assume hit, if 0 then miss */
934  segp[i].seg_in.hit_dist = -INFINITY; /* used as in */
935  segp[i].seg_in.hit_surfno = -1; /* used as iplane */
936  segp[i].seg_out.hit_dist = INFINITY; /* used as out */
937  segp[i].seg_out.hit_surfno = -1; /* used as oplane */
938 /* segp[i].seg_next = SEG_NULL;*/
939  }
940 
941  /* consider each face */
942  for (j = 0; j < 6; j++) {
943  /* for each ray/arb_face pair */
944  for (i = 0; i < n; i++) {
945  if (stp[i] == 0) continue; /* skip this ray */
946  if (segp[i].seg_stp == 0) continue; /* miss */
947 
948  arbp= (struct arb_specific *) stp[i]->st_specific;
949  if (arbp->arb_nmfaces <= j)
950  continue; /* faces of this ARB are done */
951 
952  dxbdn = VDOT(arbp->arb_face[j].peqn, rp[i]->r_pt) -
953  arbp->arb_face[j].peqn[W];
954  if ((dn = -VDOT(arbp->arb_face[j].peqn, rp[i]->r_dir)) < -SQRT_SMALL_FASTF) {
955  /* exit point, when dir.N < 0. out = min(out, s) */
956  if (segp[i].seg_out.hit_dist > (s = dxbdn/dn)) {
957  segp[i].seg_out.hit_dist = s;
958  segp[i].seg_out.hit_surfno = j;
959  }
960  } else if (dn > SQRT_SMALL_FASTF) {
961  /* entry point, when dir.N > 0. in = max(in, s) */
962  if (segp[i].seg_in.hit_dist < (s = dxbdn/dn)) {
963  segp[i].seg_in.hit_dist = s;
964  segp[i].seg_in.hit_surfno = j;
965  }
966  } else {
967  /* ray is parallel to plane when dir.N == 0.
968  * If it is outside the solid, stop now */
969  if (dxbdn > SQRT_SMALL_FASTF) {
970  RT_ARB8_SEG_MISS(segp[i]); /* MISS */
971  }
972  }
973  if (segp[i].seg_in.hit_dist > segp[i].seg_out.hit_dist) {
974  RT_ARB8_SEG_MISS(segp[i]); /* MISS */
975  }
976  } /* for each ray/arb_face pair */
977  } /* for each arb_face */
978 
979  /*
980  * Validate for each ray/arb_face pair
981  * Segment was initialized as "good" (seg_stp set valid);
982  * that is revoked here on misses.
983  */
984  for (i = 0; i < n; i++) {
985  if (stp[i] == 0) continue; /* skip this ray */
986  if (segp[i].seg_stp == 0) continue; /* missed */
987 
988  if (segp[i].seg_in.hit_surfno == -1 ||
989  segp[i].seg_out.hit_surfno == -1) {
990  RT_ARB8_SEG_MISS(segp[i]); /* MISS */
991  } else if (segp[i].seg_in.hit_dist >= segp[i].seg_out.hit_dist ||
992  segp[i].seg_out.hit_dist >= INFINITY) {
993  RT_ARB8_SEG_MISS(segp[i]); /* MISS */
994  }
995  }
996 }
997 
998 
999 /**
1000  * Given ONE ray distance, return the normal and entry/exit point.
1001  */
1002 void
1003 rt_arb_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
1004 {
1005  register struct arb_specific *arbp =
1006  (struct arb_specific *)stp->st_specific;
1007  register int h;
1008 
1009  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
1010  h = hitp->hit_surfno;
1011  VMOVE(hitp->hit_normal, arbp->arb_face[h].peqn);
1012 }
1013 
1014 
1015 /**
1016  * Return the "curvature" of the ARB face. Pick a principle direction
1017  * orthogonal to normal, and indicate no curvature.
1018  */
1019 void
1020 rt_arb_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
1021 {
1022  if (stp) RT_CK_SOLTAB(stp);
1023 
1024  bn_vec_ortho(cvp->crv_pdir, hitp->hit_normal);
1025  cvp->crv_c1 = cvp->crv_c2 = 0;
1026 }
1027 
1028 
1029 /**
1030  * For a hit on a face of an ARB, return the (u, v) coordinates of the
1031  * hit point. 0 <= u, v <= 1.
1032  *
1033  * u extends along the arb_U direction defined by B-A,
1034  * v extends along the arb_V direction defined by Nx(B-A).
1035  */
1036 void
1037 rt_arb_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
1038 {
1039  register struct arb_specific *arbp =
1040  (struct arb_specific *)stp->st_specific;
1041  struct oface *ofp;
1042  vect_t P_A;
1043  fastf_t r;
1044  vect_t rev_dir;
1045  fastf_t dot_N;
1046  vect_t UV_dir;
1047  fastf_t *norm;
1048  fastf_t min_r_U, min_r_V;
1049 
1050  if (arbp->arb_opt == (struct oface *)0) {
1051  register int ret = 0;
1052  struct rt_db_internal intern;
1053  struct rt_arb_internal *aip;
1054 
1055  if (rt_db_get_internal(&intern, stp->st_dp, ap->a_rt_i->rti_dbip, stp->st_matp, ap->a_resource) < 0) {
1056  bu_log("rt_arb_uv(%s) rt_db_get_internal failure\n",
1057  stp->st_name);
1058  return;
1059  }
1060  RT_CK_DB_INTERNAL(&intern);
1061  aip = (struct rt_arb_internal *)intern.idb_ptr;
1062  RT_ARB_CK_MAGIC(aip);
1063 
1064  /*
1065  * The double check of arb_opt is to avoid the case where
1066  * another processor did the UV setup while this processor was
1067  * waiting in bu_semaphore_acquire().
1068  */
1070  if (arbp->arb_opt == (struct oface *)0) {
1071  ret = rt_arb_setup(stp, aip, ap->a_rt_i, 1);
1072  }
1074 
1075  rt_db_free_internal(&intern);
1076 
1077  if (ret != 0 || arbp->arb_opt == (struct oface *)0) {
1078  bu_log("rt_arb_uv(%s) dynamic setup failure st_specific=%p, optp=%p\n",
1079  stp->st_name,
1080  stp->st_specific, (void *)arbp->arb_opt);
1081  return;
1082  }
1084  }
1085 
1086  ofp = &arbp->arb_opt[hitp->hit_surfno];
1087 
1088  VSUB2(P_A, hitp->hit_point, ofp->arb_UVorig);
1089  /* Flipping v is an artifact of how the faces are built */
1090  uvp->uv_u = VDOT(P_A, ofp->arb_U);
1091  uvp->uv_v = 1.0 - VDOT(P_A, ofp->arb_V);
1092  if (uvp->uv_u < 0 || uvp->uv_v < 0 || uvp->uv_u > 1 || uvp->uv_v > 1) {
1093  bu_log("arb_uv: bad uv=%g, %g\n", uvp->uv_u, uvp->uv_v);
1094  /* Fix it up */
1095  if (uvp->uv_u < 0) uvp->uv_u = (-uvp->uv_u);
1096  if (uvp->uv_v < 0) uvp->uv_v = (-uvp->uv_v);
1097  }
1098  r = ap->a_rbeam + ap->a_diverge * hitp->hit_dist;
1099  min_r_U = r * ofp->arb_Ulen;
1100  min_r_V = r * ofp->arb_Vlen;
1101  VREVERSE(rev_dir, ap->a_ray.r_dir);
1102  norm = &arbp->arb_face[hitp->hit_surfno].peqn[0];
1103  dot_N = VDOT(rev_dir, norm);
1104  VJOIN1(UV_dir, rev_dir, -dot_N, norm);
1105  VUNITIZE(UV_dir);
1106  uvp->uv_du = r * VDOT(UV_dir, ofp->arb_U) / dot_N;
1107  uvp->uv_dv = r * VDOT(UV_dir, ofp->arb_V) / dot_N;
1108  if (uvp->uv_du < 0.0)
1109  uvp->uv_du = -uvp->uv_du;
1110  if (uvp->uv_du < min_r_U)
1111  uvp->uv_du = min_r_U;
1112  if (uvp->uv_dv < 0.0)
1113  uvp->uv_dv = -uvp->uv_dv;
1114  if (uvp->uv_dv < min_r_V)
1115  uvp->uv_dv = min_r_V;
1116 }
1117 
1118 
1119 void
1120 rt_arb_free(register struct soltab *stp)
1121 {
1122  register struct arb_specific *arbp =
1123  (struct arb_specific *)stp->st_specific;
1124 
1125  if (arbp->arb_opt)
1126  bu_free((char *)arbp->arb_opt, "arb_opt");
1127  bu_free((char *)arbp, "arb_specific");
1128 }
1129 
1130 
1131 #define ARB_FACE(vlist_head, arb_pts, a, b, c, d) \
1132  RT_ADD_VLIST(vlist_head, arb_pts[a], BN_VLIST_LINE_MOVE); \
1133  RT_ADD_VLIST(vlist_head, arb_pts[b], BN_VLIST_LINE_DRAW); \
1134  RT_ADD_VLIST(vlist_head, arb_pts[c], BN_VLIST_LINE_DRAW); \
1135  RT_ADD_VLIST(vlist_head, arb_pts[d], BN_VLIST_LINE_DRAW);
1136 
1137 /**
1138  * Plot an ARB by tracing out four "U" shaped contours This draws each
1139  * edge only once.
1140  *
1141  * XXX No checking for degenerate faces is done, but probably should
1142  * be.
1143  */
1144 int
1145 rt_arb_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))
1146 {
1147  point_t *pts;
1148  struct rt_arb_internal *aip;
1149 
1150  BU_CK_LIST_HEAD(vhead);
1151  RT_CK_DB_INTERNAL(ip);
1152  aip = (struct rt_arb_internal *)ip->idb_ptr;
1153  RT_ARB_CK_MAGIC(aip);
1154 
1155  pts = aip->pt;
1156  ARB_FACE(vhead, pts, 0, 1, 2, 3);
1157  ARB_FACE(vhead, pts, 4, 0, 3, 7);
1158  ARB_FACE(vhead, pts, 5, 4, 7, 6);
1159  ARB_FACE(vhead, pts, 1, 5, 6, 2);
1160 
1161  return 0;
1162 }
1163 
1164 
1165 int
1166 rt_arb_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
1167 {
1168  register struct arb_specific *arbp =
1169  (struct arb_specific *)stp->st_specific;
1170  register int i;
1171 
1172  if (arbp == (struct arb_specific *)0) {
1173  bu_log("arb(%s): no faces\n", stp->st_name);
1175  }
1176 
1177  for (i = 0; i < arbp->arb_nmfaces; i++) {
1178  if (bn_hlf_class(arbp->arb_face[i].peqn, min, max, tol) ==
1180  return BN_CLASSIFY_OUTSIDE;
1181  }
1182 
1183  /* FIXME: We need to test for BN_CLASSIFY_INSIDE vs. BN_CLASSIFY_OVERLAPPING! */
1184  return BN_CLASSIFY_UNIMPLEMENTED; /* let the caller assume the worst */
1185 }
1186 
1187 
1188 /**
1189  * Import an ARB8 from the database format to the internal format.
1190  * There are two parts to this: First, the database is presently
1191  * single precision binary floating point. Second, the ARB in the
1192  * database is represented as a vector from the origin to the first
1193  * point, and 7 vectors from the first point to the remaining points.
1194  * In 1979 it seemed like a good idea...
1195  *
1196  * Convert from vector to point notation by rotating each vector and
1197  * adding in the base vector.
1198  */
1199 int
1200 rt_arb_import4(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
1201 {
1202  struct rt_arb_internal *aip;
1203  union record *rp;
1204  register int i;
1205  vect_t work;
1206  fastf_t vec[3*8];
1207 
1208  BU_CK_EXTERNAL(ep);
1209  if (dbip) RT_CK_DBI(dbip);
1210 
1211  rp = (union record *)ep->ext_buf;
1212  /* Check record type */
1213  if (rp->u_id != ID_SOLID) {
1214  bu_log("rt_arb_import4: defective record, id=x%x\n", rp->u_id);
1215  return -1;
1216  }
1217 
1218  RT_CK_DB_INTERNAL(ip);
1219  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1220  ip->idb_type = ID_ARB8;
1221  ip->idb_meth = &OBJ[ID_ARB8];
1222  BU_ALLOC(ip->idb_ptr, struct rt_arb_internal);
1223 
1224  aip = (struct rt_arb_internal *)ip->idb_ptr;
1225  aip->magic = RT_ARB_INTERNAL_MAGIC;
1226 
1227  /* Convert from database to internal format */
1228  flip_fastf_float(vec, rp->s.s_values, 8, dbip->dbi_version < 0 ? 1 : 0);
1229 
1230  /*
1231  * Convert from vector notation (in database) to point notation.
1232  */
1233  if (mat == NULL) mat = bn_mat_identity;
1234  MAT4X3PNT(aip->pt[0], mat, &vec[0]);
1235 
1236  for (i = 1; i < 8; i++) {
1237  VADD2(work, &vec[0*3], &vec[i*3]);
1238  MAT4X3PNT(aip->pt[i], mat, work);
1239  }
1240  return 0; /* OK */
1241 }
1242 
1243 
1244 int
1245 rt_arb_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
1246 {
1247  struct rt_arb_internal *aip;
1248  union record *rec;
1249  register int i;
1250 
1251  RT_CK_DB_INTERNAL(ip);
1252  if (dbip) RT_CK_DBI(dbip);
1253 
1254  if (ip->idb_type != ID_ARB8) return -1;
1255  aip = (struct rt_arb_internal *)ip->idb_ptr;
1256  RT_ARB_CK_MAGIC(aip);
1257 
1258  BU_CK_EXTERNAL(ep);
1259  ep->ext_nbytes = sizeof(union record);
1260  ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "arb external");
1261  rec = (union record *)ep->ext_buf;
1262 
1263  rec->s.s_id = ID_SOLID;
1264  rec->s.s_type = GENARB8;
1265 
1266  /* NOTE: This also converts to dbfloat_t */
1267  VSCALE(&rec->s.s_values[3*0], aip->pt[0], local2mm);
1268  for (i = 1; i < 8; i++) {
1269  VSUB2SCALE(&rec->s.s_values[3*i],
1270  aip->pt[i], aip->pt[0], local2mm);
1271  }
1272  return 0;
1273 }
1274 
1275 
1276 /**
1277  * Import an arb from the db5 format and convert to the internal
1278  * structure. Code duplicated from rt_arb_import4() with db5 help from
1279  * g_ell.c
1280  */
1281 int
1282 rt_arb_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
1283 {
1284  struct rt_arb_internal *aip;
1285  register int i;
1286 
1287  /* must be double for import and export */
1288  double vec[3*8];
1289 
1290  RT_CK_DB_INTERNAL(ip);
1291  BU_CK_EXTERNAL(ep);
1292  if (dbip) RT_CK_DBI(dbip);
1293 
1295 
1296  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1297  ip->idb_type = ID_ARB8;
1298  ip->idb_meth = &OBJ[ID_ARB8];
1299  BU_ALLOC(ip->idb_ptr, struct rt_arb_internal);
1300 
1301  aip = (struct rt_arb_internal *)ip->idb_ptr;
1302  aip->magic = RT_ARB_INTERNAL_MAGIC;
1303 
1304  /* Convert from database (network) to internal (host) format */
1305  bu_cv_ntohd((unsigned char *)vec, ep->ext_buf, 8*3);
1306  if (mat == NULL) mat = bn_mat_identity;
1307  for (i = 0; i < 8; i++) {
1308  MAT4X3PNT(aip->pt[i], mat, &vec[i*3]);
1309  }
1310  return 0; /* OK */
1311 }
1312 
1313 
1314 int
1315 rt_arb_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
1316 {
1317  struct rt_arb_internal *aip;
1318  register int i;
1319 
1320  /* must be double for import and export */
1321  double vec[ELEMENTS_PER_VECT*8];
1322 
1323  RT_CK_DB_INTERNAL(ip);
1324  if (dbip) RT_CK_DBI(dbip);
1325 
1326  if (ip->idb_type != ID_ARB8) return -1;
1327  aip = (struct rt_arb_internal *)ip->idb_ptr;
1328  RT_ARB_CK_MAGIC(aip);
1329 
1330  BU_CK_EXTERNAL(ep);
1331  ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * 8 * ELEMENTS_PER_VECT;
1332  ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "arb external");
1333  for (i = 0; i < 8; i++) {
1334  VSCALE(&vec[i*ELEMENTS_PER_VECT], aip->pt[i], local2mm);
1335  }
1336  bu_cv_htond(ep->ext_buf, (unsigned char *)vec, 8*ELEMENTS_PER_VECT);
1337  return 0;
1338 }
1339 
1340 
1341 /**
1342  * Make human-readable formatted presentation of this solid. First
1343  * line describes type of solid. Additional lines are indented one
1344  * tab, and give parameter values.
1345  */
1346 int
1347 rt_arb_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
1348 {
1349  struct rt_arb_internal *aip = NULL;
1350  char buf[256] = {0};
1351  int i = 0;
1352  int arb_type = -1;
1353  struct bn_tol tmp_tol; /* temporary tolerance */
1354 
1355  if (!str || !ip) return 0;
1356  RT_CK_DB_INTERNAL(ip);
1357  aip = (struct rt_arb_internal *)ip->idb_ptr;
1358  RT_ARB_CK_MAGIC(aip);
1359 
1360  tmp_tol.magic = BN_TOL_MAGIC;
1361  tmp_tol.dist = 0.0001; /* to get old behavior of rt_arb_std_type() */
1362  tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
1363  tmp_tol.perp = 1e-5;
1364  tmp_tol.para = 1 - tmp_tol.perp;
1365 
1366  arb_type = rt_arb_std_type(ip, &tmp_tol);
1367 
1368  if (!arb_type) {
1369 
1370  bu_vls_strcat(str, "ARB8\n");
1371 
1372  /* Use 1-based numbering, to match vertex labels in MGED */
1373  sprintf(buf, "\t1 (%g, %g, %g)\n",
1374  INTCLAMP(aip->pt[0][X] * mm2local),
1375  INTCLAMP(aip->pt[0][Y] * mm2local),
1376  INTCLAMP(aip->pt[0][Z] * mm2local));
1377  bu_vls_strcat(str, buf);
1378 
1379  if (!verbose) return 0;
1380 
1381  for (i = 1; i < 8; i++) {
1382  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1383  INTCLAMP(aip->pt[i][X] * mm2local),
1384  INTCLAMP(aip->pt[i][Y] * mm2local),
1385  INTCLAMP(aip->pt[i][Z] * mm2local));
1386  bu_vls_strcat(str, buf);
1387  }
1388  } else {
1389  sprintf(buf, "ARB%d\n", arb_type);
1390  bu_vls_strcat(str, buf);
1391  switch (arb_type) {
1392  case ARB8:
1393  for (i = 0; i < 8; i++) {
1394  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1395  INTCLAMP(aip->pt[i][X] * mm2local),
1396  INTCLAMP(aip->pt[i][Y] * mm2local),
1397  INTCLAMP(aip->pt[i][Z] * mm2local));
1398  bu_vls_strcat(str, buf);
1399  }
1400  break;
1401  case ARB7:
1402  for (i = 0; i < 7; i++) {
1403  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1404  INTCLAMP(aip->pt[i][X] * mm2local),
1405  INTCLAMP(aip->pt[i][Y] * mm2local),
1406  INTCLAMP(aip->pt[i][Z] * mm2local));
1407  bu_vls_strcat(str, buf);
1408  }
1409  break;
1410  case ARB6:
1411  for (i = 0; i < 5; i++) {
1412  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1413  INTCLAMP(aip->pt[i][X] * mm2local),
1414  INTCLAMP(aip->pt[i][Y] * mm2local),
1415  INTCLAMP(aip->pt[i][Z] * mm2local));
1416  bu_vls_strcat(str, buf);
1417  }
1418  sprintf(buf, "\t6 (%g, %g, %g)\n",
1419  INTCLAMP(aip->pt[6][X] * mm2local),
1420  INTCLAMP(aip->pt[6][Y] * mm2local),
1421  INTCLAMP(aip->pt[6][Z] * mm2local));
1422  bu_vls_strcat(str, buf);
1423  break;
1424  case ARB5:
1425  for (i = 0; i < 5; i++) {
1426  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1427  INTCLAMP(aip->pt[i][X] * mm2local),
1428  INTCLAMP(aip->pt[i][Y] * mm2local),
1429  INTCLAMP(aip->pt[i][Z] * mm2local));
1430  bu_vls_strcat(str, buf);
1431  }
1432  break;
1433  case ARB4:
1434  for (i = 0; i < 3; i++) {
1435  sprintf(buf, "\t%d (%g, %g, %g)\n", i+1,
1436  INTCLAMP(aip->pt[i][X] * mm2local),
1437  INTCLAMP(aip->pt[i][Y] * mm2local),
1438  INTCLAMP(aip->pt[i][Z] * mm2local));
1439  bu_vls_strcat(str, buf);
1440  }
1441  sprintf(buf, "\t4 (%g, %g, %g)\n",
1442  INTCLAMP(aip->pt[4][X] * mm2local),
1443  INTCLAMP(aip->pt[4][Y] * mm2local),
1444  INTCLAMP(aip->pt[4][Z] * mm2local));
1445  bu_vls_strcat(str, buf);
1446  break;
1447  }
1448  }
1449  return 0;
1450 }
1451 
1452 
1453 /**
1454  * Free the storage associated with the rt_db_internal version of this
1455  * solid.
1456  */
1457 void
1459 {
1460  RT_CK_DB_INTERNAL(ip);
1461  bu_free(ip->idb_ptr, "arb ifree");
1462  ip->idb_ptr = (void *)NULL;
1463 }
1464 
1465 
1466 /**
1467  * "Tessellate" an ARB into an NMG data structure. Purely a
1468  * mechanical transformation of one faceted object into another.
1469  *
1470  * Returns -
1471  * -1 failure
1472  * 0 OK. *r points to nmgregion that holds this tessellation.
1473  */
1474 int
1475 rt_arb_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol)
1476 {
1477  struct rt_arb_internal *aip;
1478  struct shell *s;
1479  struct prep_arb pa;
1480  register int i;
1481  struct faceuse *fu[6];
1482  struct vertex *verts[8];
1483  struct vertex **vertp[4];
1484 
1485  RT_CK_DB_INTERNAL(ip);
1486  aip = (struct rt_arb_internal *)ip->idb_ptr;
1487  RT_ARB_CK_MAGIC(aip);
1488 
1489  memset((char *)&pa, 0, sizeof(pa));
1490  pa.pa_doopt = 0; /* no UV stuff */
1491  pa.pa_tol_sq = tol->dist_sq;
1492  if (rt_arb_mk_planes(&pa, aip, "(tess)") < 0) return -2;
1493 
1494  for (i = 0; i < 8; i++)
1495  verts[i] = (struct vertex *)0;
1496 
1497  *r = nmg_mrsv(m); /* Make region, empty shell, vertex */
1498  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
1499 
1500  /* Process each face */
1501  for (i = 0; i < pa.pa_faces; i++) {
1502  if (pa.pa_clockwise[i] != 0) {
1503  /* Counter-Clockwise orientation (CCW) */
1504  vertp[0] = &verts[pa.pa_pindex[0][i]];
1505  vertp[1] = &verts[pa.pa_pindex[1][i]];
1506  vertp[2] = &verts[pa.pa_pindex[2][i]];
1507  if (pa.pa_npts[i] > 3) {
1508  vertp[3] = &verts[pa.pa_pindex[3][i]];
1509  }
1510  } else {
1511  register struct vertex ***vertpp = vertp;
1512  /* Clockwise orientation (CW) */
1513  if (pa.pa_npts[i] > 3) {
1514  *vertpp++ = &verts[pa.pa_pindex[3][i]];
1515  }
1516  *vertpp++ = &verts[pa.pa_pindex[2][i]];
1517  *vertpp++ = &verts[pa.pa_pindex[1][i]];
1518  *vertpp++ = &verts[pa.pa_pindex[0][i]];
1519  }
1520  if (RT_G_DEBUG & DEBUG_ARB8) {
1521  bu_log("face %d, npts=%d, verts %d %d %d %d\n",
1522  i, pa.pa_npts[i],
1523  pa.pa_pindex[0][i], pa.pa_pindex[1][i],
1524  pa.pa_pindex[2][i], pa.pa_pindex[3][i]);
1525  }
1526  if ((fu[i] = nmg_cmface(s, vertp, pa.pa_npts[i])) == 0) {
1527  bu_log("rt_arb_tess(): nmg_cmface() fail on face %d\n", i);
1528  continue;
1529  }
1530  }
1531 
1532  /* Associate vertex geometry */
1533  for (i = 0; i < 8; i++)
1534  if (verts[i]) nmg_vertex_gv(verts[i], aip->pt[i]);
1535 
1536  /* Associate face geometry */
1537  for (i = 0; i < pa.pa_faces; i++) {
1538  /* We already know the plane equations, this is fast */
1539  nmg_face_g(fu[i], pa.pa_face[i].peqn);
1540  }
1541 
1542  /* Mark edges as real */
1543  (void)nmg_mark_edges_real(&s->l.magic);
1544 
1545  /* Compute "geometry" for region and shell */
1546  nmg_region_a(*r, tol);
1547 
1548  /* Some arbs may not be within tolerance, so triangulate faces where needed */
1549  nmg_make_faces_within_tol(s, tol);
1550 
1551  return 0;
1552 }
1553 
1554 
1555 static const fastf_t rt_arb_uvw[5*3] = {
1556  0, 0, 0,
1557  1, 0, 0,
1558  1, 1, 0,
1559  0, 1, 0,
1560  0, 0, 0
1561 };
1562 
1563 
1564 static const int rt_arb_vert_index_scramble[4] = { 0, 1, 3, 2 };
1565 
1566 
1567 /**
1568  * "Tessellate" an ARB into a trimmed-NURB-NMG data structure. Purely
1569  * a mechanical transformation of one faceted object into another.
1570  *
1571  * Depending on the application, it might be beneficial to keep ARBs
1572  * as planar-NMG objects; there is no real benefit to using B-splines
1573  * here, other than uniformity of the conversion for all solids.
1574  *
1575  * Returns -
1576  * -1 failure
1577  * 0 OK. *r points to nmgregion that holds this tessellation.
1578  */
1579 int
1580 rt_arb_tnurb(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct bn_tol *tol)
1581 {
1582  struct rt_arb_internal *aip;
1583  struct shell *s;
1584  struct prep_arb pa;
1585  register int i;
1586  struct faceuse *fu[6];
1587  struct vertex *verts[8];
1588  struct vertex **vertp[4];
1589  struct edgeuse *eu;
1590  struct loopuse *lu;
1591 
1592  RT_CK_DB_INTERNAL(ip);
1593  aip = (struct rt_arb_internal *)ip->idb_ptr;
1594  RT_ARB_CK_MAGIC(aip);
1595 
1596  memset((char *)&pa, 0, sizeof(pa));
1597  pa.pa_doopt = 0; /* no UV stuff */
1598  pa.pa_tol_sq = tol->dist_sq;
1599  if (rt_arb_mk_planes(&pa, aip, "(tnurb)") < 0) return -2;
1600 
1601  for (i = 0; i < 8; i++)
1602  verts[i] = (struct vertex *)0;
1603 
1604  *r = nmg_mrsv(m); /* Make region, empty shell, vertex */
1605  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
1606 
1607  /* Process each face */
1608  for (i = 0; i < pa.pa_faces; i++) {
1609  if (pa.pa_clockwise[i] != 0) {
1610  /* Counter-Clockwise orientation (CCW) */
1611  vertp[0] = &verts[pa.pa_pindex[0][i]];
1612  vertp[1] = &verts[pa.pa_pindex[1][i]];
1613  vertp[2] = &verts[pa.pa_pindex[2][i]];
1614  if (pa.pa_npts[i] > 3) {
1615  vertp[3] = &verts[pa.pa_pindex[3][i]];
1616  }
1617  } else {
1618  register struct vertex ***vertpp = vertp;
1619  /* Clockwise orientation (CW) */
1620  if (pa.pa_npts[i] > 3) {
1621  *vertpp++ = &verts[pa.pa_pindex[3][i]];
1622  }
1623  *vertpp++ = &verts[pa.pa_pindex[2][i]];
1624  *vertpp++ = &verts[pa.pa_pindex[1][i]];
1625  *vertpp++ = &verts[pa.pa_pindex[0][i]];
1626  }
1627  if (RT_G_DEBUG & DEBUG_ARB8) {
1628  bu_log("face %d, npts=%d, verts %d %d %d %d\n",
1629  i, pa.pa_npts[i],
1630  pa.pa_pindex[0][i], pa.pa_pindex[1][i],
1631  pa.pa_pindex[2][i], pa.pa_pindex[3][i]);
1632  }
1633  /* The edges created will be linear, in parameter space...,
1634  * but need to have edge_g_cnurb geometry. */
1635  if ((fu[i] = nmg_cmface(s, vertp, pa.pa_npts[i])) == 0) {
1636  bu_log("rt_arb_tnurb(): nmg_cmface() fail on face %d\n", i);
1637  continue;
1638  }
1639  /* March around the fu's loop assigning uv parameter values */
1640  lu = BU_LIST_FIRST(loopuse, &fu[i]->lu_hd);
1641  NMG_CK_LOOPUSE(lu);
1642  eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
1643  NMG_CK_EDGEUSE(eu);
1644 
1645  /* Loop always has Counter-Clockwise orientation (CCW) */
1646  nmg_vertexuse_a_cnurb(eu->vu_p, &rt_arb_uvw[0*3]);
1647  nmg_vertexuse_a_cnurb(eu->eumate_p->vu_p, &rt_arb_uvw[1*3]);
1648  eu = BU_LIST_NEXT(edgeuse, &eu->l);
1649 
1650  nmg_vertexuse_a_cnurb(eu->vu_p, &rt_arb_uvw[1*3]);
1651  nmg_vertexuse_a_cnurb(eu->eumate_p->vu_p, &rt_arb_uvw[2*3]);
1652  eu = BU_LIST_NEXT(edgeuse, &eu->l);
1653 
1654  nmg_vertexuse_a_cnurb(eu->vu_p, &rt_arb_uvw[2*3]);
1655  if (pa.pa_npts[i] > 3) {
1656  nmg_vertexuse_a_cnurb(eu->eumate_p->vu_p, &rt_arb_uvw[3*3]);
1657 
1658  eu = BU_LIST_NEXT(edgeuse, &eu->l);
1659  nmg_vertexuse_a_cnurb(eu->vu_p, &rt_arb_uvw[3*3]);
1660  }
1661  /* Final eu must end back at the beginning */
1662  nmg_vertexuse_a_cnurb(eu->eumate_p->vu_p, &rt_arb_uvw[0*3]);
1663  }
1664 
1665  /* Associate vertex geometry */
1666  for (i = 0; i < 8; i++)
1667  if (verts[i]) nmg_vertex_gv(verts[i], aip->pt[i]);
1668 
1669  /* Associate face geometry */
1670  for (i = 0; i < pa.pa_faces; i++) {
1671  struct face_g_snurb *fg;
1672  int j;
1673 
1674  /* Let the library allocate all the storage */
1675  nmg_face_g_snurb(fu[i],
1676  2, 2, /* u, v order */
1677  4, 4, /* Number of knots, u, v */
1678  NULL, NULL, /* initial u, v knot vectors */
1679  2, 2, /* n_rows, n_cols */
1680  RT_NURB_MAKE_PT_TYPE(3, RT_NURB_PT_XYZ, RT_NURB_PT_NONRAT),
1681  NULL); /* initial mesh */
1682 
1683  fg = fu[i]->f_p->g.snurb_p;
1684  NMG_CK_FACE_G_SNURB(fg);
1685 
1686  /* Assign surface knot vectors as 0, 0, 1, 1 */
1687  fg->u.knots[0] = fg->u.knots[1] = 0;
1688  fg->u.knots[2] = fg->u.knots[3] = 1;
1689  fg->v.knots[0] = fg->v.knots[1] = 0;
1690  fg->v.knots[2] = fg->v.knots[3] = 1;
1691 
1692  /* Assign surface control points from the corners */
1693  lu = BU_LIST_FIRST(loopuse, &fu[i]->lu_hd);
1694  NMG_CK_LOOPUSE(lu);
1695  eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
1696  NMG_CK_EDGEUSE(eu);
1697 
1698  /* For ctl_points, need 4 verts in order 0, 1, 3, 2 */
1699  for (j = 0; j < pa.pa_npts[i]; j++) {
1700  VMOVE(&fg->ctl_points[rt_arb_vert_index_scramble[j]*3],
1701  eu->vu_p->v_p->vg_p->coord);
1702 
1703  /* Also associate edge geometry (trimming curve) */
1705  eu = BU_LIST_NEXT(edgeuse, &eu->l);
1706  }
1707  if (pa.pa_npts[i] == 3) {
1708  vect_t c_b;
1709  /* Trimming curve describes a triangle ABC on face,
1710  * generate a phantom fourth corner at A + (C-B)
1711  * [3] = [0] + [2] - [1]
1712  */
1713  VSUB2(c_b,
1714  &fg->ctl_points[rt_arb_vert_index_scramble[2]*3],
1715  &fg->ctl_points[rt_arb_vert_index_scramble[1]*3]);
1716  VADD2(&fg->ctl_points[rt_arb_vert_index_scramble[3]*3],
1717  &fg->ctl_points[rt_arb_vert_index_scramble[0]*3],
1718  c_b);
1719  }
1720  }
1721 
1722 
1723  /* Mark edges as real */
1724  (void)nmg_mark_edges_real(&s->l.magic);
1725 
1726  /* Compute "geometry" for region and shell */
1727  nmg_region_a(*r, tol);
1728  return 0;
1729 }
1730 
1731 
1732 /* --- General ARB8 utility routines --- */
1733 
1734 /**
1735  * Takes the planes[] array and intersects the planes to find the
1736  * vertices of a GENARB8. The vertices are stored into arb->pt[].
1737  * This is an analog of rt_arb_calc_planes().
1738  */
1739 int
1740 rt_arb_calc_points(struct rt_arb_internal *arb, int cgtype, const plane_t planes[6], const struct bn_tol *tol)
1741 {
1742  int i;
1743  point_t pt[8];
1744 
1745  RT_ARB_CK_MAGIC(arb);
1746 
1747  /* find new points for entire solid */
1748  for (i = 0; i < 8; i++) {
1749  if (rt_arb_3face_intersect(pt[i], planes, cgtype, i*3) < 0) {
1750  bu_log("rt_arb_calc_points: Intersection of planes fails %d\n", i);
1751  return -1; /* FAIL */
1752  }
1753  }
1754 
1755  /* Move new points to arb tol->dist))*/
1756  for (i = 0; i < 8; i++) {
1757  VMOVE(arb->pt[i], pt[i]);
1758  }
1759 
1760  if (rt_arb_check_points(arb, cgtype, tol) < 0)
1761  return -1;
1762 
1763  return 0; /* success */
1764 }
1765 
1766 
1767 int
1768 rt_arb_check_points(struct rt_arb_internal *arb, int cgtype, const struct bn_tol *tol)
1769 {
1770  register int i;
1771  const short arb8_evm[12][2] = arb8_edge_vertex_mapping;
1772  const short arb7_evm[12][2] = arb7_edge_vertex_mapping;
1773  const short arb5_evm[9][2] = arb5_edge_vertex_mapping;
1774 
1775  switch (cgtype) {
1776  case ARB8:
1777  for (i = 0; i < 12; ++i) {
1778  if (VNEAR_EQUAL(arb->pt[arb8_evm[i][0]],
1779  arb->pt[arb8_evm[i][1]],
1780  tol->dist))
1781  return -1;
1782  }
1783  break;
1784  case ARB7:
1785  for (i = 0; i < 11; ++i) {
1786  if (VNEAR_EQUAL(arb->pt[arb7_evm[i][0]],
1787  arb->pt[arb7_evm[i][1]],
1788  tol->dist))
1789  return -1;
1790  }
1791  break;
1792  case ARB6:
1793  for (i = 0; i < 8; ++i) {
1794  if (VNEAR_EQUAL(arb->pt[local_arb6_edge_vertex_mapping[i][0]],
1795  arb->pt[local_arb6_edge_vertex_mapping[i][1]],
1796  tol->dist))
1797  return -1;
1798  }
1799  break;
1800  case ARB5:
1801  for (i = 0; i < 8; ++i) {
1802  if (VNEAR_EQUAL(arb->pt[arb5_evm[i][0]],
1803  arb->pt[arb5_evm[i][1]],
1804  tol->dist))
1805  return -1;
1806  }
1807  break;
1808  case ARB4:
1809  for (i = 0; i < 6; ++i) {
1810  if (VNEAR_EQUAL(arb->pt[local_arb4_edge_vertex_mapping[i][0]],
1811  arb->pt[local_arb4_edge_vertex_mapping[i][1]],
1812  tol->dist))
1813  return -1;
1814  }
1815  break;
1816  }
1817 
1818  return 0;
1819 }
1820 
1821 
1822 /* planes to define ARB vertices */
1823 static const int rt_arb_planes[5][24] = {
1824  {0, 1, 3, 0, 1, 2, 0, 2, 3, 0, 1, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3}, /* ARB4 */
1825  {0, 1, 4, 0, 1, 2, 0, 2, 3, 0, 3, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4, 1, 2, 4}, /* ARB5 */
1826  {0, 2, 3, 0, 1, 3, 0, 1, 4, 0, 2, 4, 1, 2, 3, 1, 2, 3, 1, 2, 4, 1, 2, 4}, /* ARB6 */
1827  {0, 2, 4, 0, 3, 4, 0, 3, 5, 0, 2, 5, 1, 4, 5, 1, 3, 4, 1, 3, 5, 1, 2, 4}, /* ARB7 */
1828  {0, 2, 4, 0, 3, 4, 0, 3, 5, 0, 2, 5, 1, 2, 4, 1, 3, 4, 1, 3, 5, 1, 2, 5}, /* ARB8 */
1829 };
1830 
1831 
1832 /**
1833  * Finds the intersection point of three faces of an ARB.
1834  *
1835  * Returns -
1836  * 0 success, value is in 'point'
1837  * -1 failure
1838  */
1839 int
1841  point_t point,
1842  const plane_t *planes, /* assumes [6] planes */
1843  int type, /* 4..8 */
1844  int loc)
1845 {
1846  int j;
1847  int i1, i2, i3;
1848 
1849  j = type - 4;
1850 
1851  i1 = rt_arb_planes[j][loc];
1852  i2 = rt_arb_planes[j][loc+1];
1853  i3 = rt_arb_planes[j][loc+2];
1854 
1855  return bn_mkpoint_3planes(point, planes[i1], planes[i2], planes[i3]);
1856 }
1857 
1858 
1859 /**
1860  * Calculate the plane (face) equations for an arb output previously
1861  * went to es_peqn[i].
1862  *
1863  * Returns -
1864  * -1 Failure
1865  * 0 OK
1866  *
1867  * Note -
1868  * This function migrated from mged/edsol.c.
1869  */
1870 int
1871 rt_arb_calc_planes(struct bu_vls *error_msg_ret,
1872  struct rt_arb_internal *arb,
1873  int cgtype,
1874  plane_t planes[6],
1875  const struct bn_tol *tol)
1876 {
1877  register int i, p1, p2, p3;
1878  int type = cgtype - ARB4; /* ARB4 at location 0, ARB5 at 1, etc. */
1879  const int arb_faces[5][24] = rt_arb_faces;
1880 
1881  RT_ARB_CK_MAGIC(arb);
1882  BN_CK_TOL(tol);
1883 
1884  for (i = 0; i < 6; i++) {
1885  if (arb_faces[type][i*4] == -1)
1886  break; /* faces are done */
1887 
1888  p1 = arb_faces[type][i*4];
1889  p2 = arb_faces[type][i*4+1];
1890  p3 = arb_faces[type][i*4+2];
1891 
1892  if (bn_mk_plane_3pts(planes[i],
1893  arb->pt[p1],
1894  arb->pt[p2],
1895  arb->pt[p3],
1896  tol) < 0) {
1897  bu_vls_printf(error_msg_ret, "%d %d%d%d%d (bad face)\n",
1898  i+1, p1+1, p2+1, p3+1, arb_faces[type][i*4+3]+1);
1899  return -1;
1900  }
1901  }
1902 
1903  return 0;
1904 }
1905 
1906 
1907 /**
1908  * Moves an arb edge (end1, end2) with bounding planes bp1 and bp2
1909  * through point "thru". The edge has (non-unit) slope "dir". Note
1910  * that the fact that the normals here point in rather than out makes
1911  * no difference for computing the correct intercepts. After the
1912  * intercepts are found, they should be checked against the other
1913  * faces to make sure that they are always "inside".
1914  */
1915 int
1916 rt_arb_move_edge(struct bu_vls *error_msg_ret,
1917  struct rt_arb_internal *arb,
1918  vect_t thru,
1919  int bp1,
1920  int bp2,
1921  int end1,
1922  int end2,
1923  const vect_t dir,
1924  plane_t planes[6],
1925  const struct bn_tol *tol)
1926 {
1927  fastf_t t1, t2;
1928 
1929  if (bn_isect_line3_plane(&t1, thru, dir, planes[bp1], tol) < 0 ||
1930  bn_isect_line3_plane(&t2, thru, dir, planes[bp2], tol) < 0) {
1931  bu_vls_printf(error_msg_ret, "edge (direction) parallel to face normal\n");
1932  return 1;
1933  }
1934 
1935  RT_ARB_CK_MAGIC(arb);
1936 
1937  VJOIN1(arb->pt[end1], thru, t1, dir);
1938  VJOIN1(arb->pt[end2], thru, t2, dir);
1939 
1940  return 0;
1941 }
1942 
1943 
1944 /**
1945  * An ARB edge is moved by finding the direction of the line
1946  * containing the edge and the 2 "bounding" planes. The new edge is
1947  * found by intersecting the new line location with the bounding
1948  * planes. The two "new" planes thus defined are calculated and the
1949  * affected points are calculated by intersecting planes. This keeps
1950  * ALL faces planar.
1951  *
1952  * Note: This code came from mged/edarb.c (written mostly by Keith
1953  * Applin) and was modified to live here.
1954  *
1955  */
1956 
1957 /* The storage for the "specific" ARB types is :
1958  *
1959  * ARB4 0 1 2 0 3 3 3 3
1960  * ARB5 0 1 2 3 4 4 4 4
1961  * ARB6 0 1 2 3 4 4 5 5
1962  * ARB7 0 1 2 3 4 5 6 4
1963  * ARB8 0 1 2 3 4 5 6 7
1964  */
1965 
1966 /*
1967  * ARB6 0 1 2 3 4 5 5 4
1968  */
1969 
1970 /* Another summary of how the vertices of ARBs are stored:
1971  *
1972  * Vertices: 1 2 3 4 5 6 7 8
1973  * Location----------------------------------------------------------------
1974  * ARB8 0 1 2 3 4 5 6 7
1975  * ARB7 0 1 2 3 4, 7 5 6
1976  * ARB6 0 1 2 3 4, 5 6, 7
1977  * ARB5 0 1 2 3 4, 5, 6, 7
1978  * ARB4 0, 3 1 2 4, 5, 6, 7
1979  */
1980 
1981 
1982 #define RT_ARB_EDIT_EDGE 0
1983 #define RT_ARB_EDIT_POINT 1
1984 #define RT_ARB7_MOVE_POINT_5 11
1985 #define RT_ARB6_MOVE_POINT_5 8
1986 #define RT_ARB6_MOVE_POINT_6 9
1987 #define RT_ARB5_MOVE_POINT_5 8
1988 #define RT_ARB4_MOVE_POINT_4 3
1989 
1990 int
1991 rt_arb_edit(struct bu_vls *error_msg_ret,
1992  struct rt_arb_internal *arb,
1993  int arb_type,
1994  int edit_type,
1995  vect_t pos_model,
1996  plane_t planes[6],
1997  const struct bn_tol *tol)
1998 {
1999  int pt1 = 0, pt2 = 0, bp1, bp2, newp, p1, p2, p3;
2000  const short *edptr; /* pointer to arb edit array */
2001  const short *final; /* location of points to redo */
2002  int i;
2003  const int *iptr;
2004  int edit_class = RT_ARB_EDIT_EDGE;
2005  const short earb8[12][18] = earb8_edit_array;
2006  const short earb7[12][18] = earb7_edit_array;
2007  const short earb6[10][18] = earb6_edit_array;
2008  const short earb5[9][18] = earb5_edit_array;
2009  const short earb4[5][18] = earb4_edit_array;
2010 
2011  RT_ARB_CK_MAGIC(arb);
2012 
2013  /* set the pointer */
2014  switch (arb_type) {
2015  case ARB4:
2016  edptr = &earb4[edit_type][0];
2017  final = &earb4[edit_type][16];
2018 
2019  if (edit_type == RT_ARB4_MOVE_POINT_4)
2020  edit_type = 4;
2021 
2022  edit_class = RT_ARB_EDIT_POINT;
2023 
2024  break;
2025  case ARB5:
2026  edptr = &earb5[edit_type][0];
2027  final = &earb5[edit_type][16];
2028 
2029  if (edit_type == RT_ARB5_MOVE_POINT_5) {
2030  edit_class = RT_ARB_EDIT_POINT;
2031  edit_type = 4;
2032  }
2033 
2034  if (edit_class == RT_ARB_EDIT_POINT) {
2035  edptr = &earb5[8][0];
2036  final = &earb5[8][16];
2037  }
2038 
2039  break;
2040  case ARB6:
2041  edptr = &earb6[edit_type][0];
2042  final = &earb6[edit_type][16];
2043 
2044  if (edit_type == RT_ARB6_MOVE_POINT_5) {
2045  edit_class = RT_ARB_EDIT_POINT;
2046  edit_type = 4;
2047  } else if (edit_type == RT_ARB6_MOVE_POINT_6) {
2048  edit_class = RT_ARB_EDIT_POINT;
2049  edit_type = 6;
2050  }
2051 
2052  if (edit_class == RT_ARB_EDIT_POINT) {
2053  i = 9;
2054  if (edit_type == 4)
2055  i = 8;
2056  edptr = &earb6[i][0];
2057  final = &earb6[i][16];
2058  }
2059 
2060  break;
2061  case ARB7:
2062  edptr = &earb7[edit_type][0];
2063  final = &earb7[edit_type][16];
2064 
2065  if (edit_type == RT_ARB7_MOVE_POINT_5) {
2066  edit_class = RT_ARB_EDIT_POINT;
2067  edit_type = 4;
2068  }
2069 
2070  if (edit_class == RT_ARB_EDIT_POINT) {
2071  edptr = &earb7[11][0];
2072  final = &earb7[11][16];
2073  }
2074 
2075  break;
2076  case ARB8:
2077  edptr = &earb8[edit_type][0];
2078  final = &earb8[edit_type][16];
2079 
2080  break;
2081  default:
2082  bu_vls_printf(error_msg_ret, "rt_arb_edit: unknown ARB type\n");
2083 
2084  return 1;
2085  }
2086 
2087  /* do the arb editing */
2088  if (edit_class == RT_ARB_EDIT_POINT) {
2089  /* moving a point - not an edge */
2090  VMOVE(arb->pt[edit_type], pos_model);
2091  edptr += 4;
2092  } else if (edit_class == RT_ARB_EDIT_EDGE) {
2093  vect_t edge_dir;
2094 
2095  /* moving an edge */
2096  pt1 = *edptr++;
2097  pt2 = *edptr++;
2098 
2099  /* calculate edge direction */
2100  VSUB2(edge_dir, arb->pt[pt2], arb->pt[pt1]);
2101 
2102  if (ZERO(MAGNITUDE(edge_dir)))
2103  goto err;
2104 
2105  /* bounding planes bp1, bp2 */
2106  bp1 = *edptr++;
2107  bp2 = *edptr++;
2108 
2109  /* move the edge */
2110  if (rt_arb_move_edge(error_msg_ret, arb, pos_model, bp1, bp2, pt1, pt2,
2111  edge_dir, planes, tol))
2112  goto err;
2113  }
2114 
2115  /* editing is done - insure planar faces */
2116  /* redo plane eqns that changed */
2117  newp = *edptr++; /* plane to redo */
2118 
2119  if (newp == 9) /* special flag --> redo all the planes */
2120  if (rt_arb_calc_planes(error_msg_ret, arb, arb_type, planes, tol))
2121  goto err;
2122 
2123  if (newp >= 0 && newp < 6) {
2124  for (i = 0; i < 3; i++) {
2125  /* redo this plane (newp), use points p1, p2, p3 */
2126  p1 = *edptr++;
2127  p2 = *edptr++;
2128  p3 = *edptr++;
2129 
2130  if (bn_mk_plane_3pts(planes[newp], arb->pt[p1], arb->pt[p2],
2131  arb->pt[p3], tol))
2132  goto err;
2133 
2134  /* next plane */
2135  if ((newp = *edptr++) == -1 || newp == 8)
2136  break;
2137  }
2138  }
2139 
2140  if (newp == 8) {
2141  /* special...redo next planes using pts defined in faces */
2142  const int arb_faces[5][24] = rt_arb_faces;
2143  for (i = 0; i < 3; i++) {
2144  if ((newp = *edptr++) == -1)
2145  break;
2146 
2147  iptr = &arb_faces[arb_type-4][4*newp];
2148  p1 = *iptr++;
2149  p2 = *iptr++;
2150  p3 = *iptr++;
2151 
2152  if (bn_mk_plane_3pts(planes[newp], arb->pt[p1], arb->pt[p2],
2153  arb->pt[p3], tol))
2154  goto err;
2155  }
2156  }
2157 
2158  /* the changed planes are all redone
2159  * push necessary points back into the planes
2160  */
2161  edptr = final; /* point to the correct location */
2162  for (i = 0; i < 2; i++) {
2163  const plane_t *c_planes = (const plane_t *)planes;
2164 
2165  if ((p1 = *edptr++) == -1)
2166  break;
2167 
2168  /* intersect proper planes to define vertex p1 */
2169 
2170  if (rt_arb_3face_intersect(arb->pt[p1], c_planes, arb_type, p1*3))
2171  goto err;
2172  }
2173 
2174  /* Special case for ARB7: move point 5 .... must
2175  * recalculate plane 2 = 456
2176  */
2177  if (arb_type == ARB7 && edit_class == RT_ARB_EDIT_POINT) {
2178  if (bn_mk_plane_3pts(planes[2], arb->pt[4], arb->pt[5], arb->pt[6], tol))
2179  goto err;
2180  }
2181 
2182  /* carry along any like points */
2183  switch (arb_type) {
2184  case ARB8:
2185  break;
2186  case ARB7:
2187  VMOVE(arb->pt[7], arb->pt[4]);
2188  break;
2189  case ARB6:
2190  VMOVE(arb->pt[5], arb->pt[4]);
2191  VMOVE(arb->pt[7], arb->pt[6]);
2192  break;
2193  case ARB5:
2194  for (i=5; i<8; i++)
2195  VMOVE(arb->pt[i], arb->pt[4]);
2196  break;
2197  case ARB4:
2198  VMOVE(arb->pt[3], arb->pt[0]);
2199  for (i=5; i<8; i++)
2200  VMOVE(arb->pt[i], arb->pt[4]);
2201  break;
2202  }
2203 
2204  if (rt_arb_check_points(arb, arb_type, tol) < 0)
2205  goto err;
2206 
2207  return 0; /* OK */
2208 
2209 err:
2210  /* Error handling */
2211  bu_vls_printf(error_msg_ret, "cannot move edge: %d%d\n", pt1+1, pt2+1);
2212  return 1; /* BAD */
2213 }
2214 
2215 
2216 int
2217 rt_arb_params(struct pc_pc_set * UNUSED(ps), const struct rt_db_internal *ip)
2218 {
2219  RT_CK_DB_INTERNAL(ip);
2220 
2221  return 0; /* OK */
2222 }
2223 
2224 
2225 /**
2226  * compute volume of an arb8 by dividing it into
2227  * 6 arb4 and summing the volumes.
2228  */
2229 void
2230 rt_arb_volume(fastf_t *vol, const struct rt_db_internal *ip)
2231 {
2232  int i, a, b, c, d;
2233  vect_t b_a, c_a, area;
2234  fastf_t arb4_height;
2235  plane_t plane;
2236  struct bn_tol tmp_tol;
2237  struct rt_arb_internal *aip = (struct rt_arb_internal *)ip->idb_ptr;
2238  RT_ARB_CK_MAGIC(aip);
2239 
2240  /* tol struct needed for bn_mk_plane_3pts,
2241  * can't be passed to the function since it
2242  * must fit into the rt_functab interface */
2243  tmp_tol.magic = BN_TOL_MAGIC;
2244  tmp_tol.dist = RT_LEN_TOL;
2245  tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
2246 
2247  for (i = 0; i < 6; i++) {
2248  /* a, b, c = base of the arb4 */
2249  a = farb4[i][0];
2250  b = farb4[i][1];
2251  c = farb4[i][2];
2252  /* d = "top" point of the arb4 */
2253  d = farb4[i][3];
2254 
2255  /* create a plane from a, b, c */
2256  if (bn_mk_plane_3pts(plane, aip->pt[a], aip->pt[b], aip->pt[c], &tmp_tol) < 0) {
2257  continue;
2258  }
2259 
2260  /* height of arb4 is distance from the plane created using the
2261  * points of the base, and the top point 'd' */
2262  arb4_height = fabs(DIST_PT_PLANE(aip->pt[d], plane));
2263 
2264  /* calculate area of arb4 base */
2265  VSUB2(b_a, aip->pt[b], aip->pt[a]);
2266  VSUB2(c_a, aip->pt[c], aip->pt[a]);
2267  VCROSS(area, b_a, c_a);
2268 
2269  *vol += MAGNITUDE(area) * arb4_height;
2270  }
2271  *vol /= 6.0;
2272 }
2273 
2274 
2275 int
2276 rt_arb_get_edge_list(const struct rt_db_internal *ip, const short (*edge_list[])[2])
2277 {
2278  size_t edge_count = 0;
2279  int arb_type;
2280  struct bn_tol tmp_tol;
2281  struct rt_arb_internal *aip = (struct rt_arb_internal *)ip->idb_ptr;
2282  const short arb8_evm[12][2] = arb8_edge_vertex_mapping;
2283  const short arb7_evm[12][2] = arb7_edge_vertex_mapping;
2284  const short arb5_evm[9][2] = arb5_edge_vertex_mapping;
2285  const short arb4_evm[5][2] = arb4_edge_vertex_mapping;
2286 
2287  RT_ARB_CK_MAGIC(aip);
2288 
2289  /* set up tolerance for rt_arb_std_type */
2290  tmp_tol.magic = BN_TOL_MAGIC;
2291  tmp_tol.dist = 0.0001; /* to get old behavior of rt_arb_std_type() */
2292  tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
2293  tmp_tol.perp = 1e-5;
2294  tmp_tol.para = 1 - tmp_tol.perp;
2295 
2296  /* get number of vertices in arb_type */
2297  arb_type = rt_arb_std_type(ip, &tmp_tol);
2298 
2299  switch (arb_type) {
2300  case ARB8:
2301  edge_count = 12;
2302  (*edge_list) = arb8_evm;
2303 
2304  break;
2305  case ARB7:
2306  edge_count = 12;
2307  (*edge_list) = arb7_evm;
2308 
2309  break;
2310  case ARB6:
2311  edge_count = 10;
2312  (*edge_list) = local_arb6_edge_vertex_mapping;
2313 
2314  break;
2315  case ARB5:
2316  edge_count = 9;
2317  (*edge_list) = arb5_evm;
2318 
2319  break;
2320  case ARB4:
2321  edge_count = 5;
2322  (*edge_list) = arb4_evm;
2323 
2324  break;
2325  default:
2326  return edge_count;
2327  }
2328 
2329  return edge_count;
2330 }
2331 
2332 
2333 int
2335  int *vert1,
2336  int *vert2,
2337  const struct rt_db_internal *ip,
2338  const point_t pt2,
2339  const mat_t mat,
2340  fastf_t ptol)
2341 {
2342  int i;
2343  fastf_t dist=MAX_FASTF, tmp_dist;
2344  const short (*edge_list)[2] = {0};
2345  int edge_count = 0;
2346  struct bn_tol tol;
2347  struct rt_arb_internal *aip = (struct rt_arb_internal *)ip->idb_ptr;
2348 
2349  RT_ARB_CK_MAGIC(aip);
2350 
2351  /* first build a list of edges */
2352  edge_count = rt_arb_get_edge_list(ip, &edge_list);
2353  if (edge_count == 0)
2354  return -1;
2355 
2356  /* build a tolerance structure for the bn_dist routine */
2357  tol.magic = BN_TOL_MAGIC;
2358  tol.dist = 0.0;
2359  tol.dist_sq = 0.0;
2360  tol.perp = 0.0;
2361  tol.para = 1.0;
2362 
2363  /* now look for the closest edge */
2364  for (i = 0; i < edge_count; i++) {
2365  point_t p1, p2, pca;
2366  vect_t p1_to_pca, p1_to_p2;
2367  int ret;
2368 
2369  MAT4X3PNT(p1, mat, aip->pt[edge_list[i][0]]);
2370  p1[Z] = 0.0;
2371 
2372  if (edge_list[i][0] == edge_list[i][1]) {
2373  tmp_dist = bn_dist_pt3_pt3(pt2, p1);
2374 
2375  if (tmp_dist < ptol) {
2376  *vert1 = edge_list[i][0] + 1;
2377  *vert2 = *vert1;
2378  *edge = i + 1;
2379 
2380  return 0;
2381  }
2382 
2383  ret = 4;
2384  } else {
2385  MAT4X3PNT(p2, mat, aip->pt[edge_list[i][1]]);
2386  p2[Z] = 0.0;
2387  ret = bn_dist_pt2_lseg2(&tmp_dist, pca, p1, p2, pt2, &tol);
2388  }
2389 
2390  if (ret < 3 || tmp_dist < dist) {
2391  switch (ret) {
2392  case 0:
2393  dist = 0.0;
2394  if (tmp_dist < 0.5) {
2395  *vert1 = edge_list[i][0] + 1;
2396  *vert2 = edge_list[i][1] + 1;
2397  } else {
2398  *vert1 = edge_list[i][1] + 1;
2399  *vert2 = edge_list[i][0] + 1;
2400  }
2401  *edge = i + 1;
2402  break;
2403  case 1:
2404  dist = 0.0;
2405  *vert1 = edge_list[i][0] + 1;
2406  *vert2 = edge_list[i][1] + 1;
2407  *edge = i + 1;
2408  break;
2409  case 2:
2410  dist = 0.0;
2411  *vert1 = edge_list[i][1] + 1;
2412  *vert2 = edge_list[i][0] + 1;
2413  *edge = i + 1;
2414  break;
2415  case 3:
2416  dist = tmp_dist;
2417  *vert1 = edge_list[i][0] + 1;
2418  *vert2 = edge_list[i][1] + 1;
2419  *edge = i + 1;
2420  break;
2421  case 4:
2422  dist = tmp_dist;
2423  *vert1 = edge_list[i][1] + 1;
2424  *vert2 = edge_list[i][0] + 1;
2425  *edge = i + 1;
2426  break;
2427  case 5:
2428  dist = tmp_dist;
2429  V2SUB2(p1_to_pca, pca, p1);
2430  V2SUB2(p1_to_p2, p2, p1);
2431  if (MAG2SQ(p1_to_pca) / MAG2SQ(p1_to_p2) < 0.25) {
2432  *vert1 = edge_list[i][0] + 1;
2433  *vert2 = edge_list[i][1] + 1;
2434  } else {
2435  *vert1 = edge_list[i][1] + 1;
2436  *vert2 = edge_list[i][0] + 1;
2437  }
2438  *edge = i + 1;
2439  break;
2440  }
2441  }
2442  }
2443 
2444  return 0;
2445 }
2446 
2447 
2448 /** @} */
2449 
2450 /*
2451  * Local Variables:
2452  * mode: C
2453  * tab-width: 8
2454  * indent-tabs-mode: t
2455  * c-file-style: "stroustrup"
2456  * End:
2457  * ex: shiftwidth=4 tabstop=8
2458  */
int rt_arb_tnurb(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct bn_tol *tol)
Definition: arb8.c:1580
void rt_pr_soltab(const struct soltab *stp)
char * d_namep
pointer to name string
Definition: raytrace.h:859
struct xray a_ray
Actual ray to be shot.
Definition: raytrace.h:1583
Definition: raytrace.h:800
fastf_t arb_V[3]
Definition: arb8.c:76
fastf_t arb_Ulen
Definition: arb8.c:77
#define RT_LEN_TOL
Definition: raytrace.h:169
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
#define SIZEOF_NETWORK_DOUBLE
Definition: cv.h:48
int bn_isect_line3_plane(fastf_t *dist, const point_t pt, const vect_t dir, const plane_t plane, const struct bn_tol *tol)
struct hit seg_in
IN information.
Definition: raytrace.h:370
void rt_arb_ifree(struct rt_db_internal *ip)
Definition: arb8.c:1458
#define RT_ARB5_MOVE_POINT_5
Definition: arb8.c:1987
int pa_clockwise[6]
Definition: arb8.c:103
Definition: list.h:118
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
#define RT_ARB7_MOVE_POINT_5
Definition: arb8.c:1984
HIDDEN int rt_arb_setup(struct soltab *stp, struct rt_arb_internal *aip, struct rt_i *rtip, int uv_wanted)
Definition: arb8.c:688
#define RT_ARB_EDIT_EDGE
Definition: arb8.c:1982
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
#define BN_CLASSIFY_OUTSIDE
Definition: plane_calc.h:1031
int rt_arb_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
Definition: arb8.c:828
#define BN_CLASSIFY_UNIMPLEMENTED
Definition: plane_calc.h:1028
#define RT_ARB8_SEG_MISS(SEG)
Definition: arb8.c:911
double dist
>= 0
Definition: tol.h:73
void nmg_make_faces_within_tol(struct shell *s, const struct bn_tol *tol)
Definition: nmg_misc.c:8463
#define earb7_edit_array
Definition: arb_edit.h:177
#define RT_ARB4_MOVE_POINT_4
Definition: arb8.c:1988
int arb_nmfaces
Definition: arb8.c:91
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
Definition: arb8.c:98
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
#define ID_ARB8
Generalized ARB. V + 7 vectors.
Definition: raytrace.h:462
if lu s
Definition: nmg_mod.c:3860
Definition: clone.c:90
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
lu
Definition: nmg_mod.c:3855
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
void rt_arb_volume(fastf_t *vol, const struct rt_db_internal *ip)
Definition: arb8.c:2230
Definition: pc.h:108
double dist_sq
dist * dist
Definition: tol.h:74
Definition: raytrace.h:368
void rt_arb_free(register struct soltab *stp)
Definition: arb8.c:1120
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
#define BN_TOL_MAGIC
Definition: magic.h:74
void nmg_face_g(struct faceuse *fu, const fastf_t *p)
Definition: nmg_mk.c:2235
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
#define RT_SLOPPY_DOT_TOL
Definition: arb8.c:70
int pa_npts[6]
Definition: arb8.c:101
int pa_faces
Definition: arb8.c:100
Header file for the BRL-CAD common definitions.
Definition: arb8.c:83
#define earb4_edit_array
Definition: arb_edit.h:359
int rt_arb_import4(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
Definition: arb8.c:1200
matp_t st_matp
solid coords to model space, NULL=identity
Definition: raytrace.h:441
void rt_arb_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
Definition: arb8.c:916
void rt_arb_print(register const struct soltab *stp)
Definition: arb8.c:785
void flip_fastf_float(fastf_t *ff, const dbfloat_t *fp, int n, int flip)
Definition: db_flip.c:74
int bn_mkpoint_3planes(point_t pt, const plane_t a, const plane_t b, const plane_t c)
Given the description of three planes, compute the point of intersection, if any. The direction vecto...
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
Definition: arb8.c:118
void nmg_face_g_snurb(struct faceuse *fu, int u_order, int v_order, int n_u_knots, int n_v_knots, fastf_t *ukv, fastf_t *vkv, int n_rows, int n_cols, int pt_type, fastf_t *mesh)
Definition: nmg_mk.c:2347
void bu_cv_htond(unsigned char *out, const unsigned char *in, size_t count)
#define MAX_FASTF
Definition: defines.h:340
#define rt_arb_faces
Definition: arb_edit.h:65
const struct bu_structparse rt_arb_parse[]
Definition: arb8.c:147
#define HIDDEN
Definition: common.h:86
#define earb5_edit_array
Definition: arb_edit.h:305
NMG_CK_LOOPUSE(lu)
struct bu_list l
Definition: raytrace.h:369
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
int rt_arb_calc_points(struct rt_arb_internal *arb, int cgtype, const plane_t planes[6], const struct bn_tol *tol)
Definition: arb8.c:1740
plane_t peqn
Definition: arb8.c:85
int rt_arb_move_edge(struct bu_vls *error_msg_ret, struct rt_arb_internal *arb, vect_t thru, int bp1, int bp2, int end1, int end2, const vect_t dir, plane_t planes[6], const struct bn_tol *tol)
Definition: arb8.c:1916
int bn_hlf_class(const plane_t half_eqn, const vect_t min, const vect_t max, const struct bn_tol *tol)
Classify a halfspace, specified by its plane equation, against a bounding RPP.
if(share_geom)
Definition: nmg_mod.c:3829
HIDDEN int rt_arb_add_pt(register pointp_t point, const char *title, struct prep_arb *pap, int ptno, const char *name)
Definition: arb8.c:399
int idb_major_type
Definition: raytrace.h:192
int rt_arb_std_type(const struct rt_db_internal *ip, const struct bn_tol *tol)
Definition: arb8.c:317
#define ARB_AO(_t, _a, _i)
Definition: arb8.c:145
Definition: color.c:49
int rt_arb_edit(struct bu_vls *error_msg_ret, struct rt_arb_internal *arb, int arb_type, int edit_type, vect_t pos_model, plane_t planes[6], const struct bn_tol *tol)
Definition: arb8.c:1991
struct rt_i * a_rt_i
this librt instance
Definition: raytrace.h:1588
void * memset(void *s, int c, size_t n)
#define RT_G_DEBUG
Definition: raytrace.h:1718
int pa_doopt
Definition: arb8.c:108
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
int rt_arb_check_points(struct rt_arb_internal *arb, int cgtype, const struct bn_tol *tol)
Definition: arb8.c:1768
int bn_dist_pt2_lseg2(fastf_t *dist_sq, fastf_t pca[2], const point_t a, const point_t b, const point_t p, const struct bn_tol *tol)
Find the distance from a point P to a line segment described by the two endpoints A and B...
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
fastf_t st_bradius
Radius of BOUNDING sphere.
Definition: raytrace.h:434
fastf_t crv_c2
curvature in other direction
Definition: raytrace.h:309
fastf_t a_diverge
slope of beam divergence/mm
Definition: raytrace.h:1600
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
int rt_arb_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: arb8.c:1245
#define V3ARGS(a)
Definition: color.c:56
int rt_arb_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: arb8.c:1475
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
uint8_t * ext_buf
Definition: parse.h:216
Editing operations for arb primitives.
point_t hit_point
DEPRECATED: Intersection point, use VJOIN1 hit_dist.
Definition: raytrace.h:251
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
vect_t pa_center
Definition: arb8.c:99
#define earb6_edit_array
Definition: arb_edit.h:244
Coord * point
Definition: chull3d.cpp:52
struct aface arb_face[6]
Definition: arb8.c:93
#define UNUSED(parameter)
Definition: common.h:239
#define HPRINT(a, b)
Definition: raytrace.h:1882
int nmg_mark_edges_real(const uint32_t *magic_p)
Definition: nmg_misc.c:846
int rt_arb_get_edge_list(const struct rt_db_internal *ip, const short(*edge_list[])[2])
Definition: arb8.c:2276
int rt_arb_3face_intersect(point_t point, const plane_t *planes, int type, int loc)
Definition: arb8.c:1840
goto out
Definition: nmg_mod.c:3846
#define RT_ARB6_MOVE_POINT_5
Definition: arb8.c:1985
fastf_t A[3]
Definition: arb8.c:84
Support for uniform tolerances.
Definition: tol.h:71
const short local_arb6_edge_vertex_mapping[10][2]
Definition: arb8.c:160
#define BN_CK_TOL(_p)
Definition: tol.h:82
int rt_arb_find_e_nearest_pt2(int *edge, int *vert1, int *vert2, const struct rt_db_internal *ip, const point_t pt2, const mat_t mat, fastf_t ptol)
Definition: arb8.c:2334
#define arb8_edge_vertex_mapping
Definition: arb_edit.h:142
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
struct fg_node fg
Definition: chull3d.cpp:80
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
int rt_arb_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: arb8.c:773
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
void nmg_edge_g_cnurb_plinear(struct edgeuse *eu)
Definition: nmg_mk.c:2019
fastf_t arb_U[3]
Definition: arb8.c:75
#define arb4_edge_vertex_mapping
Definition: arb_edit.h:380
fastf_t pa_tol_sq
Definition: arb8.c:107
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
double perp
nearly 0
Definition: tol.h:75
#define ZERO(val)
Definition: units.c:38
#define earb8_edit_array
Definition: arb_edit.h:108
void * idb_ptr
Definition: raytrace.h:195
#define arb5_edge_vertex_mapping
Definition: arb_edit.h:334
double bn_dist_pt3_pt3(const point_t a, const point_t b)
Returns distance between two points.
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
int rt_arb_get_cgtype(int *cgtype, struct rt_arb_internal *arb, const struct bn_tol *tol, register int *uvec, register int *svec)
Definition: arb8.c:203
#define RT_ARB6_MOVE_POINT_6
Definition: arb8.c:1986
struct oface pa_opt[6]
Definition: arb8.c:105
void bu_cv_ntohd(unsigned char *out, const unsigned char *in, size_t count)
uint32_t magic
Definition: tol.h:72
const struct rt_functab OBJ[]
Definition: table.c:159
int rt_arb_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: arb8.c:1145
const short local_arb4_edge_vertex_mapping[6][2]
Definition: arb8.c:174
int pa_pindex[4][6]
Definition: arb8.c:102
void bn_vec_ortho(vect_t out, const vect_t in)
struct db_i * rti_dbip
prt to Database instance struct
Definition: raytrace.h:1774
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
int ai_sub[4]
Definition: arb8.c:120
fastf_t uv_du
delta in u
Definition: raytrace.h:343
int rt_arb_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: arb8.c:1315
Definition: arb8.c:73
fastf_t arb_UVorig[3]
Definition: arb8.c:74
int rt_arb_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
Definition: arb8.c:1282
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
#define ARB_FACE(vlist_head, arb_pts, a, b, c, d)
Definition: arb8.c:1131
Definition: color.c:51
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
fastf_t arb_Vlen
Definition: arb8.c:78
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
#define RT_SEM_MODEL
Definition: raytrace.h:1733
int rt_arb_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: arb8.c:2217
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
struct oface * arb_opt
Definition: arb8.c:92
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
struct aface pa_face[6]
Definition: arb8.c:104
fastf_t a_rbeam
initial beam radius (mm)
Definition: raytrace.h:1599
#define BU_CK_LIST_HEAD(_p)
Definition: list.h:142
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
void rt_arb_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
Definition: arb8.c:1003
struct faceuse * nmg_cmface(struct shell *s, struct vertex ***verts, int n)
Definition: nmg_mod.c:979
int rt_arb_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: arb8.c:1347
void nmg_vertexuse_a_cnurb(struct vertexuse *vu, const fastf_t *uvw)
Definition: nmg_mk.c:1757
HIDDEN int rt_arb_mk_planes(register struct prep_arb *pap, struct rt_arb_internal *aip, const char *name)
Definition: arb8.c:540
void rt_arb_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
Definition: arb8.c:1020
char * ai_title
Definition: arb8.c:119
size_t ext_nbytes
Definition: parse.h:210
int rt_arb_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: arb8.c:661
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
void rt_arb_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: arb8.c:345
void rt_arb_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
Definition: arb8.c:1037
Definition: vls.h:56
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
int rt_arb_calc_planes(struct bu_vls *error_msg_ret, struct rt_arb_internal *arb, int cgtype, plane_t planes[6], const struct bn_tol *tol)
Definition: arb8.c:1871
#define VPRINT(a, b)
Definition: raytrace.h:1881
int bn_mk_plane_3pts(plane_t plane, const point_t a, const point_t b, const point_t c, const struct bn_tol *tol)
#define arb7_edge_vertex_mapping
Definition: arb_edit.h:211
#define RT_ARB_INTERNAL_MAGIC
Definition: magic.h:82
#define BU_LIST_NEXT(structure, hp)
Definition: list.h:316
#define DEBUG_SOLIDS
6 Print prep'ed solids
Definition: raytrace.h:89
int rt_arb_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
Definition: arb8.c:1166
double para
nearly 1
Definition: tol.h:76
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
#define RT_ARB_EDIT_POINT
Definition: arb8.c:1983
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
#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