BRL-CAD
rpc.c
Go to the documentation of this file.
1 /* R P C . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1990-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup primitives */
21 /** @{ */
22 /** @file primitives/rpc/rpc.c
23  *
24  * Intersect a ray with a Right Parabolic Cylinder.
25  *
26  * Algorithm -
27  *
28  * Given V, H, R, and B, there is a set of points on this rpc
29  *
30  * { (x, y, z) | (x, y, z) is on rpc }
31  *
32  * Through a series of Affine Transformations, this set of points will
33  * be transformed into a set of points on an rpc located at the origin
34  * with a rectangular halfwidth R of 1 along the Y axis, a height H of
35  * +1 along the -X axis, a distance B of 1 along the -Z axis between
36  * the vertex V and the tip of the parabola.
37  *
38  *
39  * { (x', y', z') | (x', y', z') is on rpc at origin }
40  *
41  * The transformation from X to X' is accomplished by:
42  *
43  * X' = S(R(X - V))
44  *
45  * where R(X) = (H/(-|H|))
46  * (R/(|R|)) . X
47  * (B/(-|B|))
48  *
49  * and S(X) = (1/|H| 0 0)
50  * (0 1/|R| 0) . X
51  * (0 0 1/|B|)
52  *
53  * To find the intersection of a line with the surface of the rpc,
54  * consider the parametric line L:
55  *
56  * L : { P(n) | P + t(n) . D }
57  *
58  * Call W the actual point of intersection between L and the rpc.
59  * Let W' be the point of intersection between L' and the unit rpc.
60  *
61  * L' : { P'(n) | P' + t(n) . D' }
62  *
63  * W = invR(invS(W')) + V
64  *
65  * Where W' = k D' + P'.
66  *
67  * If Dy' and Dz' are both 0, then there is no hit on the rpc;
68  * but the end plates need checking. If there is now only 1 hit
69  * point, the top plate needs to be checked as well.
70  *
71  * Line L' hits the infinitely long canonical rpc at W' when
72  *
73  * A * k**2 + B * k + C = 0
74  *
75  * where
76  *
77  * A = Dy'**2
78  * B = (2 * Dy' * Py') - Dz'
79  * C = Py'**2 - Pz' - 1
80  * b = |Breadth| = 1.0
81  * h = |Height| = 1.0
82  * r = 1.0
83  *
84  * The quadratic formula yields k (which is constant):
85  *
86  * k = [ -B +/- sqrt(B**2 - 4*A*C)] / (2*A)
87  *
88  * Now, D' = S(R(D))
89  * and P' = S(R(P - V))
90  *
91  * Substituting,
92  *
93  * W = V + invR(invS[ k *(S(R(D))) + S(R(P - V)) ])
94  * = V + invR((k * R(D)) + R(P - V))
95  * = V + k * D + P - V
96  * = k * D + P
97  *
98  * Note that ``k'' is constant, and is the same in the formulations
99  * for both W and W'.
100  *
101  * The hit at ``k'' is a hit on the canonical rpc IFF
102  * -1 <= Wx' <= 0 and -1 <= Wz' <= 0.
103  *
104  * NORMALS. Given the point W on the surface of the rpc, what is the
105  * vector normal to the tangent plane at that point?
106  *
107  * Map W onto the unit rpc, i.e.: W' = S(R(W - V)).
108  *
109  * Plane on unit rpc at W' has a normal vector N' where
110  *
111  * N' = <0, Wy', -.5>.
112  *
113  * The plane transforms back to the tangent plane at W, and this new
114  * plane (on the original rpc) has a normal vector of N, viz:
115  *
116  * N = inverse[ transpose(inverse[ S o R ]) ] (N')
117  *
118  * because if H is perpendicular to plane Q, and matrix M maps from Q
119  * to Q', then inverse[ transpose(M) ] (H) is perpendicular to Q'.
120  * Here, H and Q are in "prime space" with the unit sphere. [Somehow,
121  * the notation here is backwards]. So, the mapping matrix M =
122  * inverse(S o R), because S o R maps from normal space to the unit
123  * sphere.
124  *
125  * N = inverse[ transpose(inverse[ S o R ]) ] (N')
126  * = inverse[ transpose(invR o invS) ] (N')
127  * = inverse[ transpose(invS) o transpose(invR) ] (N')
128  * = inverse[ inverse(S) o R ] (N')
129  * = invR o S (N')
130  *
131  * because inverse(R) = transpose(R), so R = transpose(invR),
132  * and S = transpose(S).
133  *
134  * Note that the normal vector produced above will not have unit
135  * length.
136  *
137  * THE TOP AND END PLATES.
138  *
139  * If Dz' == 0, line L' is parallel to the top plate, so there is no
140  * hit on the top plate. Otherwise, rays intersect the top plate
141  * with k = (0 - Pz')/Dz'. The solution is within the top plate
142  * IFF -1 <= Wx' <= 0 and -1 <= Wy' <= 1
143  *
144  * If Dx' == 0, line L' is parallel to the end plates, so there is no
145  * hit on the end plates. Otherwise, rays intersect the front plate
146  * with k = (0 - Px') / Dx' and the back plate with k = (-1 - Px') / Dx'.
147  *
148  * The solution W' is within an end plate IFF
149  *
150  * Wy'**2 + Wz' <= 1.0 and Wz' <= 1.0
151  *
152  * The normal for a hit on the top plate is -Bunit.
153  * The normal for a hit on the front plate is -Hunit, and
154  * the normal for a hit on the back plate is +Hunit.
155  *
156  */
157 /** @} */
158 
159 #include "common.h"
160 
161 #include <stdlib.h>
162 #include <stddef.h>
163 #include <string.h>
164 #include <math.h>
165 #include "bio.h"
166 
167 #include "bu/cv.h"
168 #include "vmath.h"
169 #include "db.h"
170 #include "nmg.h"
171 #include "rtgeom.h"
172 #include "raytrace.h"
173 
174 #include "../../librt_private.h"
175 
176 static int rpc_is_valid(struct rt_rpc_internal *rpc);
177 
178 struct rpc_specific {
179  point_t rpc_V; /* vector to rpc origin */
180  vect_t rpc_Bunit; /* unit B vector */
181  vect_t rpc_Hunit; /* unit H vector */
182  vect_t rpc_Runit; /* unit vector, B x H */
183  fastf_t rpc_b; /* |B| */
184  fastf_t rpc_inv_rsq; /* 1/(r * r) */
185  mat_t rpc_SoR; /* Scale(Rot(vect)) */
186  mat_t rpc_invRoS; /* invRot(Scale(vect)) */
187 };
188 
189 
190 const struct bu_structparse rt_rpc_parse[] = {
191  { "%f", 3, "V", bu_offsetofarray(struct rt_rpc_internal, rpc_V, fastf_t, X), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
192  { "%f", 3, "H", bu_offsetofarray(struct rt_rpc_internal, rpc_H, fastf_t, X), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
193  { "%f", 3, "B", bu_offsetofarray(struct rt_rpc_internal, rpc_B, fastf_t, X), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
194  { "%f", 1, "r", bu_offsetof(struct rt_rpc_internal, rpc_r), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
195  { {'\0', '\0', '\0', '\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
196 };
197 
198 /**
199  * Calculate the RPP for an RPC
200  */
201 int
202 rt_rpc_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {
203  struct rt_rpc_internal *xip;
204  vect_t rinv, rvect, rv2, working;
205  RT_CK_DB_INTERNAL(ip);
206  xip = (struct rt_rpc_internal *)ip->idb_ptr;
207  RT_RPC_CK_MAGIC(xip);
208 
209  VSETALL((*min), INFINITY);
210  VSETALL((*max), -INFINITY);
211 
212  VCROSS(rvect, xip->rpc_H, xip->rpc_B);
213  VREVERSE(rinv, rvect);
214  VUNITIZE(rvect);
215  VUNITIZE(rinv);
216  VSCALE(rvect, rvect, xip->rpc_r);
217  VSCALE(rinv, rinv, xip->rpc_r);
218 
219  VADD2(working, xip->rpc_V, rvect);
220  VMINMAX((*min), (*max), working);
221 
222  VADD2(working, xip->rpc_V, rinv);
223  VMINMAX((*min), (*max), working);
224 
225  VADD3(working, xip->rpc_V, rvect, xip->rpc_H);
226  VMINMAX((*min), (*max), working);
227 
228  VADD3(working, xip->rpc_V, rinv, xip->rpc_H);
229  VMINMAX((*min), (*max), working);
230 
231  VADD2(rv2, xip->rpc_V, xip->rpc_B);
232 
233  VADD2(working, rv2, rvect);
234  VMINMAX((*min), (*max), working);
235 
236  VADD2(working, rv2, rinv);
237  VMINMAX((*min), (*max), working);
238 
239  VADD3(working, rv2, rvect, xip->rpc_H);
240  VMINMAX((*min), (*max), working);
241 
242  VADD3(working, rv2, rinv, xip->rpc_H);
243  VMINMAX((*min), (*max), working);
244 
245  return 0;
246 }
247 
248 
249 /**
250  * Given a pointer to a GED database record, and a transformation matrix,
251  * determine if this is a valid RPC, and if so, precompute various
252  * terms of the formula.
253  *
254  * Returns -
255  * 0 RPC is OK
256  * !0 Error in description
257  *
258  * Implicit return -
259  * A struct rpc_specific is created, and its address is stored in
260  * stp->st_specific for use by rpc_shot().
261  */
262 int
263 rt_rpc_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
264 {
265  struct rt_rpc_internal *xip;
266  struct rpc_specific *rpc;
267 
268  fastf_t magsq_b, magsq_h, magsq_r;
269  fastf_t mag_b, mag_h, mag_r;
270  mat_t R;
271  mat_t Rinv;
272  mat_t S;
273  vect_t invsq; /* [ 1/(|H|**2), 1/(|R|**2), 1/(|B|**2) ] */
274 
275  RT_CK_DB_INTERNAL(ip);
276 
277  xip = (struct rt_rpc_internal *)ip->idb_ptr;
278  if (!rpc_is_valid(xip)) {
279  return 1;
280  }
281 
282  /* compute |B| |H| */
283  mag_b = sqrt(magsq_b = MAGSQ(xip->rpc_B));
284  mag_h = sqrt(magsq_h = MAGSQ(xip->rpc_H));
285  mag_r = xip->rpc_r;
286  magsq_r = mag_r * mag_r;
287 
288  stp->st_id = ID_RPC; /* set soltab ID */
289  stp->st_meth = &OBJ[ID_RPC];
290 
291  BU_GET(rpc, struct rpc_specific);
292  stp->st_specific = (void *)rpc;
293  rpc->rpc_b = mag_b;
294  rpc->rpc_inv_rsq = 1 / magsq_r;
295 
296  /* make unit vectors in B, H, and BxH directions */
297  VMOVE(rpc->rpc_Hunit, xip->rpc_H);
298  VUNITIZE(rpc->rpc_Hunit);
299  VMOVE(rpc->rpc_Bunit, xip->rpc_B);
300  VUNITIZE(rpc->rpc_Bunit);
301  VCROSS(rpc->rpc_Runit, rpc->rpc_Bunit, rpc->rpc_Hunit);
302 
303  VMOVE(rpc->rpc_V, xip->rpc_V);
304 
305  /* Compute R and Rinv matrices */
306  MAT_IDN(R);
307  VREVERSE(&R[0], rpc->rpc_Hunit);
308  VMOVE(&R[4], rpc->rpc_Runit);
309  VREVERSE(&R[8], rpc->rpc_Bunit);
310  bn_mat_trn(Rinv, R); /* inv of rot mat is trn */
311 
312  /* Compute S */
313  VSET(invsq, 1.0/magsq_h, 1.0/magsq_r, 1.0/magsq_b);
314  MAT_IDN(S);
315  S[ 0] = sqrt(invsq[0]);
316  S[ 5] = sqrt(invsq[1]);
317  S[10] = sqrt(invsq[2]);
318 
319  /* Compute SoR and invRoS */
320  bn_mat_mul(rpc->rpc_SoR, S, R);
321  bn_mat_mul(rpc->rpc_invRoS, Rinv, S);
322 
323  /* Compute bounding sphere and RPP */
324  /* bounding sphere center */
325  VJOIN2(stp->st_center, rpc->rpc_V,
326  mag_h / 2.0, rpc->rpc_Hunit,
327  mag_b / 2.0, rpc->rpc_Bunit);
328  /* bounding radius */
329  stp->st_bradius = 0.5 * sqrt(magsq_h + 4.0*magsq_r + magsq_b);
330  /* approximate bounding radius */
331  stp->st_aradius = stp->st_bradius;
332  /* bounding RPP */
333  if (rt_rpc_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1;
334  return 0; /* OK */
335 }
336 
337 
338 void
339 rt_rpc_print(const struct soltab *stp)
340 {
341  const struct rpc_specific *rpc =
342  (struct rpc_specific *)stp->st_specific;
343 
344  VPRINT("V", rpc->rpc_V);
345  VPRINT("Bunit", rpc->rpc_Bunit);
346  VPRINT("Hunit", rpc->rpc_Hunit);
347  VPRINT("Runit", rpc->rpc_Runit);
348  bn_mat_print("S o R", rpc->rpc_SoR);
349  bn_mat_print("invR o S", rpc->rpc_invRoS);
350 }
351 
352 
353 /* hit_surfno is set to one of these */
354 #define RPC_NORM_BODY (1) /* compute normal */
355 #define RPC_NORM_TOP (2) /* copy tgc_N */
356 #define RPC_NORM_FRT (3) /* copy reverse tgc_N */
357 #define RPC_NORM_BACK (4)
358 
359 /**
360  * Intersect a ray with a rpc.
361  * If an intersection occurs, a struct seg will be acquired
362  * and filled in.
363  *
364  * Returns -
365  * 0 MISS
366  * >0 HIT
367  */
368 int
369 rt_rpc_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
370 {
371  struct rpc_specific *rpc =
372  (struct rpc_specific *)stp->st_specific;
373  vect_t dprime; /* D' */
374  vect_t pprime; /* P' */
375  fastf_t k1, k2; /* distance constants of solution */
376  vect_t xlated; /* translated vector */
377  struct hit hits[3]; /* 2 potential hit points */
378  struct hit *hitp; /* pointer to hit point */
379 
380  hitp = &hits[0];
381 
382  /* out, Mat, vect */
383  MAT4X3VEC(dprime, rpc->rpc_SoR, rp->r_dir);
384  VSUB2(xlated, rp->r_pt, rpc->rpc_V);
385  MAT4X3VEC(pprime, rpc->rpc_SoR, xlated);
386 
387  /* Find roots of the equation, using formula for quadratic */
388  if (!NEAR_ZERO(dprime[Y], RT_PCOEF_TOL)) {
389  fastf_t a, b, c; /* coeffs of polynomial */
390  fastf_t disc; /* disc of radical */
391 
392  a = dprime[Y] * dprime[Y];
393  b = 2.0 * dprime[Y] * pprime[Y] - dprime[Z];
394  c = pprime[Y] * pprime[Y] - pprime[Z] - 1.0;
395  disc = b*b - 4.0 * a * c;
396  if (disc <= 0)
397  goto check_plates;
398  disc = sqrt(disc);
399 
400  k1 = (-b + disc) / (2.0 * a);
401  k2 = (-b - disc) / (2.0 * a);
402 
403  /*
404  * k1 and k2 are potential solutions to intersection with
405  * side. See if they fall in range.
406  */
407  VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */
408  if (hitp->hit_vpriv[X] >= -1.0 && hitp->hit_vpriv[X] <= 0.0
409  && hitp->hit_vpriv[Z] <= 0.0) {
410  hitp->hit_magic = RT_HIT_MAGIC;
411  hitp->hit_dist = k1;
412  hitp->hit_surfno = RPC_NORM_BODY; /* compute N */
413  hitp++;
414  }
415 
416  VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */
417  if (hitp->hit_vpriv[X] >= -1.0 && hitp->hit_vpriv[X] <= 0.0
418  && hitp->hit_vpriv[Z] <= 0.0) {
419  hitp->hit_magic = RT_HIT_MAGIC;
420  hitp->hit_dist = k2;
421  hitp->hit_surfno = RPC_NORM_BODY; /* compute N */
422  hitp++;
423  }
424  } else if (!NEAR_ZERO(dprime[Z], RT_PCOEF_TOL)) {
425  k1 = (pprime[Y] * pprime[Y] - pprime[Z] - 1.0) / dprime[Z];
426  VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */
427  if (hitp->hit_vpriv[X] >= -1.0 && hitp->hit_vpriv[X] <= 0.0
428  && hitp->hit_vpriv[Z] <= 0.0) {
429  hitp->hit_magic = RT_HIT_MAGIC;
430  hitp->hit_dist = k1;
431  hitp->hit_surfno = RPC_NORM_BODY; /* compute N */
432  hitp++;
433  }
434  }
435 
436  /*
437  * Check for hitting the end plates.
438  */
439 
440  check_plates:
441  /* check front and back plates */
442  if (hitp < &hits[2] && !NEAR_ZERO(dprime[X], RT_PCOEF_TOL)) {
443  /* 0 or 1 hits so far, this is worthwhile */
444  k1 = -pprime[X] / dprime[X]; /* front plate */
445  k2 = (-1.0 - pprime[X]) / dprime[X]; /* back plate */
446 
447  VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */
448  if (hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y]
449  - hitp->hit_vpriv[Z] <= 1.0
450  && hitp->hit_vpriv[Z] <= 0.0) {
451  hitp->hit_magic = RT_HIT_MAGIC;
452  hitp->hit_dist = k1;
453  hitp->hit_surfno = RPC_NORM_FRT; /* -H */
454  hitp++;
455  }
456 
457  VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */
458  if (hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y]
459  - hitp->hit_vpriv[Z] <= 1.0
460  && hitp->hit_vpriv[Z] <= 0.0) {
461  hitp->hit_magic = RT_HIT_MAGIC;
462  hitp->hit_dist = k2;
463  hitp->hit_surfno = RPC_NORM_BACK; /* +H */
464  hitp++;
465  }
466  }
467 
468  /* check top plate */
469  if (hitp == &hits[1] && !NEAR_ZERO(dprime[Z], RT_PCOEF_TOL)) {
470  /* 1 hit so far, this is worthwhile */
471  k1 = -pprime[Z] / dprime[Z]; /* top plate */
472 
473  VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */
474  if (hitp->hit_vpriv[X] >= -1.0 && hitp->hit_vpriv[X] <= 0.0
475  && hitp->hit_vpriv[Y] >= -1.0
476  && hitp->hit_vpriv[Y] <= 1.0) {
477  hitp->hit_magic = RT_HIT_MAGIC;
478  hitp->hit_dist = k1;
479  hitp->hit_surfno = RPC_NORM_TOP; /* -B */
480  hitp++;
481  }
482  }
483 
484  if (hitp != &hits[2])
485  return 0; /* MISS */
486 
487  if (hits[0].hit_dist < hits[1].hit_dist) {
488  /* entry is [0], exit is [1] */
489  struct seg *segp;
490 
491  RT_GET_SEG(segp, ap->a_resource);
492  segp->seg_stp = stp;
493  segp->seg_in = hits[0]; /* struct copy */
494  segp->seg_out = hits[1]; /* struct copy */
495  BU_LIST_INSERT(&(seghead->l), &(segp->l));
496  } else {
497  /* entry is [1], exit is [0] */
498  struct seg *segp;
499 
500  RT_GET_SEG(segp, ap->a_resource);
501  segp->seg_stp = stp;
502  segp->seg_in = hits[1]; /* struct copy */
503  segp->seg_out = hits[0]; /* struct copy */
504  BU_LIST_INSERT(&(seghead->l), &(segp->l));
505  }
506  return 2; /* HIT */
507 }
508 
509 
510 /**
511  * Given ONE ray distance, return the normal and entry/exit point.
512  */
513 void
514 rt_rpc_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
515 {
516  vect_t can_normal; /* normal to canonical rpc */
517  struct rpc_specific *rpc =
518  (struct rpc_specific *)stp->st_specific;
519 
520  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
521  switch (hitp->hit_surfno) {
522  case RPC_NORM_BODY:
523  VSET(can_normal, 0.0, hitp->hit_vpriv[Y], -0.5);
524  MAT4X3VEC(hitp->hit_normal, rpc->rpc_invRoS, can_normal);
525  VUNITIZE(hitp->hit_normal);
526  break;
527  case RPC_NORM_TOP:
528  VREVERSE(hitp->hit_normal, rpc->rpc_Bunit);
529  break;
530  case RPC_NORM_FRT:
531  VREVERSE(hitp->hit_normal, rpc->rpc_Hunit);
532  break;
533  case RPC_NORM_BACK:
534  VMOVE(hitp->hit_normal, rpc->rpc_Hunit);
535  break;
536  default:
537  bu_log("rt_rpc_norm: surfno=%d bad\n", hitp->hit_surfno);
538  break;
539  }
540 }
541 
542 
543 /**
544  * Return the curvature of the rpc.
545  */
546 void
547 rt_rpc_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
548 {
549  fastf_t zp1, zp2; /* 1st & 2nd derivatives */
550  struct rpc_specific *rpc =
551  (struct rpc_specific *)stp->st_specific;
552 
553  switch (hitp->hit_surfno) {
554  case RPC_NORM_BODY:
555  /* most nearly flat direction */
556  VMOVE(cvp->crv_pdir, rpc->rpc_Hunit);
557  cvp->crv_c1 = 0;
558  /* k = z'' / (1 + z'^2) ^ 3/2 */
559  zp2 = 2.0 * rpc->rpc_b * rpc->rpc_inv_rsq;
560  zp1 = zp2 * hitp->hit_point[Y];
561  cvp->crv_c2 = zp2 / pow((1 + zp1*zp1), 1.5);
562  break;
563  case RPC_NORM_BACK:
564  case RPC_NORM_FRT:
565  case RPC_NORM_TOP:
566  /* any tangent direction */
567  bn_vec_ortho(cvp->crv_pdir, hitp->hit_normal);
568  cvp->crv_c1 = cvp->crv_c2 = 0;
569  break;
570  }
571 }
572 
573 
574 /**
575  * For a hit on the surface of an rpc, return the (u, v) coordinates
576  * of the hit point, 0 <= u, v <= 1
577  * u = azimuth
578  * v = elevation
579  */
580 void
581 rt_rpc_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp)
582 {
583  struct rpc_specific *rpc = (struct rpc_specific *)stp->st_specific;
584 
585  vect_t work;
586  vect_t pprime;
587  fastf_t len;
588 
589  if (ap) RT_CK_APPLICATION(ap);
590 
591  /*
592  * hit_point is on surface; project back to unit rpc,
593  * creating a vector from vertex to hit point.
594  */
595  VSUB2(work, hitp->hit_point, rpc->rpc_V);
596  MAT4X3VEC(pprime, rpc->rpc_SoR, work);
597 
598  switch (hitp->hit_surfno) {
599  case RPC_NORM_BODY:
600  /* Skin. x, y coordinates define rotation. radius = 1 */
601  len = sqrt(pprime[Y]*pprime[Y] + pprime[Z]*pprime[Z]);
602  uvp->uv_u = acos(pprime[Y]/len) * M_1_PI;
603  uvp->uv_v = -pprime[X]; /* height */
604  break;
605  case RPC_NORM_FRT:
606  case RPC_NORM_BACK:
607  /* end plates - circular mapping, not seamless w/body, top */
608  len = sqrt(pprime[Y]*pprime[Y] + pprime[Z]*pprime[Z]);
609  uvp->uv_u = acos(pprime[Y]/len) * M_1_PI;
610  uvp->uv_v = len; /* rim v = 1 for both plates */
611  break;
612  case RPC_NORM_TOP:
613  /* Simplified next line:
614  uvp->uv_u = 1.0 - (pprime[Y] + 1.0)/2.0; */
615  uvp->uv_u = 0.5 - pprime[Y]/2.0;
616  uvp->uv_v = -pprime[X]; /* height */
617  break;
618  }
619 
620  /* uv_du should be relative to rotation, uv_dv relative to height */
621  uvp->uv_du = uvp->uv_dv = 0;
622 }
623 
624 
625 void
626 rt_rpc_free(struct soltab *stp)
627 {
628  struct rpc_specific *rpc =
629  (struct rpc_specific *)stp->st_specific;
630 
631  BU_PUT(rpc, struct rpc_specific);
632 }
633 
634 /* A canonical parabola in the Y-Z plane has equation z = y^2 / 4p, and opens
635  * toward positive z with vertex at the origin.
636  *
637  * The contour of an rpc in the plane B-R is a parabola with vertex at B,
638  * opening toward -B. We can transform this parabola to get an equivalent
639  * canonical parabola in the Y-Z plane, opening toward positive Z (-B) with
640  * vertex at the origin (B).
641  *
642  * This parabola passes through the point (r, |B|). If we plug the point (r, |B|)
643  * into our canonical equation, we see how p relates to r and |B|:
644  *
645  * |B| = r^2 / 4p
646  * p = (r^2) / (4|B|)
647  */
648 static fastf_t
649 rpc_parabola_p(fastf_t r, fastf_t mag_b)
650 {
651  return (r * r) / (4.0 * mag_b);
652 }
653 
654 static fastf_t
655 rpc_parabola_y(fastf_t p, fastf_t z)
656 {
657  return sqrt(4.0 * p * z);
658 }
659 
660 /* The contour of an rpc in the plane B-R is a parabola with vertex at B,
661  * opening toward -B. We can transform this parabola to get an equivalent
662  * parabola in the Y-Z plane, opening toward positive Z (-B) with vertex at
663  * (0, -|B|).
664  *
665  * The part of this parabola that passes between (0, -|B|) and (r, 0) is
666  * approximated by num_points points (including (0, -|B|) and (r, 0)).
667  *
668  * The constructed point list is returned (NULL returned on error). Because the
669  * above transformation puts the rpc vertex at the origin and the parabola
670  * vertex at (0, -|B|), multiplying the z values by -1 gives corresponding
671  * distances along the rpc breadth vector B.
672  */
673 static struct rt_pt_node *
674 rpc_parabolic_curve(fastf_t mag_b, fastf_t r, int num_points)
675 {
676  int count;
677  struct rt_pt_node *curve;
678 
679  if (num_points < 2) {
680  return NULL;
681  }
682 
683  BU_ALLOC(curve, struct rt_pt_node);
684  BU_ALLOC(curve->next, struct rt_pt_node);
685 
686  curve->next->next = NULL;
687  VSET(curve->p, 0.0, 0.0, -mag_b);
688  VSET(curve->next->p, 0.0, r, 0.0);
689 
690  if (num_points < 3) {
691  return curve;
692  }
693 
694  count = approximate_parabolic_curve(curve, rpc_parabola_p(r, mag_b), num_points - 2);
695 
696  if (count != (num_points - 2)) {
697  return NULL;
698  }
699 
700  return curve;
701 }
702 
703 /* plot half of a parabolic contour curve using the given (r, b) points (pts),
704  * translation along H (rpc_H), and multiplier for r (rscale)
705  */
706 static void
707 rpc_plot_parabolic_curve(
708  struct bu_list *vhead,
709  struct rpc_specific *rpc,
710  struct rt_pt_node *pts,
711  vect_t rpc_H,
712  fastf_t rscale)
713 {
714  vect_t t, Ru, Bu;
715  point_t p;
716  struct rt_pt_node *node;
717 
718  VADD2(t, rpc->rpc_V, rpc_H);
719  VMOVE(Ru, rpc->rpc_Runit);
720  VMOVE(Bu, rpc->rpc_Bunit);
721 
722  VJOIN2(p, t, rscale * pts->p[Y], Ru, -pts->p[Z], Bu);
723  RT_ADD_VLIST(vhead, p, BN_VLIST_LINE_MOVE);
724 
725  node = pts->next;
726  while (node != NULL) {
727  VJOIN2(p, t, rscale * node->p[Y], Ru, -node->p[Z], Bu);
728  RT_ADD_VLIST(vhead, p, BN_VLIST_LINE_DRAW);
729 
730  node = node->next;
731  }
732 }
733 
734 static void
735 rpc_plot_parabolas(
736  struct bu_list *vhead,
737  struct rt_rpc_internal *rpc,
738  struct rt_pt_node *pts)
739 {
740  vect_t rpc_H;
741  struct rpc_specific rpc_s;
742 
743  VMOVE(rpc_s.rpc_V, rpc->rpc_V);
744 
745  VMOVE(rpc_s.rpc_Bunit, rpc->rpc_B);
746  VUNITIZE(rpc_s.rpc_Bunit);
747 
748  VCROSS(rpc_s.rpc_Runit, rpc_s.rpc_Bunit, rpc->rpc_H);
749  VUNITIZE(rpc_s.rpc_Runit);
750 
751  /* plot parabolic contour curve of face containing V */
752  VSETALL(rpc_H, 0.0);
753  rpc_plot_parabolic_curve(vhead, &rpc_s, pts, rpc_H, 1.0);
754  rpc_plot_parabolic_curve(vhead, &rpc_s, pts, rpc_H, -1.0);
755 
756  /* plot parabolic contour curve of opposing face */
757  VMOVE(rpc_H, rpc->rpc_H);
758  rpc_plot_parabolic_curve(vhead, &rpc_s, pts, rpc_H, 1.0);
759  rpc_plot_parabolic_curve(vhead, &rpc_s, pts, rpc_H, -1.0);
760 }
761 
762 static void
763 rpc_plot_curve_connections(
764  struct bu_list *vhead,
765  struct rt_rpc_internal *rpc,
766  int num_connections)
767 {
768  point_t pt;
769  vect_t Yu, Zu;
770  fastf_t mag_Z;
771  fastf_t p, y, z, z_step;
772  int connections_per_half;
773 
774  if (num_connections < 1) {
775  return;
776  }
777 
778  VMOVE(Zu, rpc->rpc_B);
779  VCROSS(Yu, rpc->rpc_H, Zu);
780  VUNITIZE(Yu);
781  VUNITIZE(Zu);
782 
783  mag_Z = MAGNITUDE(rpc->rpc_B);
784 
785  p = rpc_parabola_p(rpc->rpc_r, mag_Z);
786 
787  connections_per_half = 0.5 + num_connections / 2.0;
788  z_step = mag_Z / (connections_per_half + 1.0);
789 
790  for (z = 0.0; z <= mag_Z; z += z_step) {
791  y = rpc_parabola_y(p, mag_Z - z);
792 
793  /* connect faces on one side of the curve */
794  VJOIN2(pt, rpc->rpc_V, z, Zu, -y, Yu);
795  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
796 
797  VADD2(pt, pt, rpc->rpc_H);
798  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
799 
800  /* connect the faces on the other side */
801  VJOIN2(pt, rpc->rpc_V, z, Zu, y, Yu);
802  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
803 
804  VADD2(pt, pt, rpc->rpc_H);
805  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
806  }
807 }
808 
809 static int
810 rpc_curve_points(
811  struct rt_rpc_internal *rpc,
812  const struct rt_view_info *info)
813 {
814  fastf_t height, halfwidth, est_curve_length;
815  point_t p0, p1;
816 
817  height = -MAGNITUDE(rpc->rpc_B);
818  halfwidth = rpc->rpc_r;
819 
820  VSET(p0, 0.0, 0.0, height);
821  VSET(p1, 0.0, halfwidth, 0.0);
822 
823  est_curve_length = 2.0 * DIST_PT_PT(p0, p1);
824 
825  return est_curve_length / info->point_spacing;
826 }
827 
828 int
829 rt_rpc_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info)
830 {
831  point_t p;
832  vect_t rpc_R;
833  int num_curve_points, num_connections;
834  struct rt_rpc_internal *rpc;
835  struct rt_pt_node *pts, *node, *tmp;
836 
837  BU_CK_LIST_HEAD(info->vhead);
838  RT_CK_DB_INTERNAL(ip);
839 
840  rpc = (struct rt_rpc_internal *)ip->idb_ptr;
841  if (!rpc_is_valid(rpc)) {
842  return -2;
843  }
844 
845  num_curve_points = rpc_curve_points(rpc, info);
846 
847  if (num_curve_points < 3) {
848  num_curve_points = 3;
849  }
850 
851  VCROSS(rpc_R, rpc->rpc_B, rpc->rpc_H);
852  VUNITIZE(rpc_R);
853  VSCALE(rpc_R, rpc_R, rpc->rpc_r);
854 
855  pts = rpc_parabolic_curve(MAGNITUDE(rpc->rpc_B), rpc->rpc_r, num_curve_points);
856  rpc_plot_parabolas(info->vhead, rpc, pts);
857 
858  node = pts;
859  while (node != NULL) {
860  tmp = node;
861  node = node->next;
862 
863  bu_free(tmp, "rt_pt_node");
864  }
865 
866  /* connect both halves of the parabolic contours of the opposing faces */
867  num_connections = primitive_curve_count(ip, info);
868  if (num_connections < 2) {
869  num_connections = 2;
870  }
871 
872  rpc_plot_curve_connections(info->vhead, rpc, num_connections);
873 
874  /* plot rectangular face */
875  VADD2(p, rpc->rpc_V, rpc_R);
877 
878  VADD2(p, p, rpc->rpc_H);
880 
881  VJOIN1(p, p, -2.0, rpc_R);
883 
884  VJOIN1(p, p, -1.0, rpc->rpc_H);
886 
887  VJOIN1(p, p, 2.0, rpc_R);
889 
890  return 0;
891 }
892 
893 int
894 rt_rpc_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info))
895 {
896  struct rt_rpc_internal *xip;
897  fastf_t *front;
898  fastf_t *back;
899  fastf_t b, dtol, ntol, rh;
900  int i, n;
901  struct rt_pt_node *old, *pos, *pts;
902  vect_t Bu, Hu, Ru, B, R;
903 
904  BU_CK_LIST_HEAD(vhead);
905  RT_CK_DB_INTERNAL(ip);
906 
907  xip = (struct rt_rpc_internal *)ip->idb_ptr;
908  if (!rpc_is_valid(xip)) {
909  return -2;
910  }
911 
912  /* compute |B| |H| */
913  b = MAGNITUDE(xip->rpc_B); /* breadth */
914  rh = xip->rpc_r; /* rectangular halfwidth */
915 
916  /* make unit vectors in B, H, and BxH directions */
917  VMOVE(Hu, xip->rpc_H);
918  VUNITIZE(Hu);
919  VMOVE(Bu, xip->rpc_B);
920  VUNITIZE(Bu);
921  VCROSS(Ru, Bu, Hu);
922 
923  if (rh < b) {
924  dtol = primitive_get_absolute_tolerance(ttol, 2.0 * rh);
925  } else {
926  dtol = primitive_get_absolute_tolerance(ttol, 2.0 * b);
927  }
928 
929  /* To ensure normal tolerance, remain below this angle */
930  if (ttol->norm > 0.0)
931  ntol = ttol->norm;
932  else
933  /* tolerate everything */
934  ntol = M_PI;
935 
936  /* initial parabola approximation is a single segment */
937  BU_ALLOC(pts, struct rt_pt_node);
938  BU_ALLOC(pts->next, struct rt_pt_node);
939 
940  pts->next->next = NULL;
941  VSET(pts->p, 0.0, -rh, 0.0);
942  VSET(pts->next->p, 0.0, rh, 0.0);
943  /* 2 endpoints in 1st approximation */
944  n = 2;
945  /* recursively break segment 'til within error tolerances */
946  n += rt_mk_parabola(pts, rh, b, dtol, ntol);
947 
948  /* get mem for arrays */
949  front = (fastf_t *)bu_malloc(3*n * sizeof(fastf_t), "fastf_t");
950  back = (fastf_t *)bu_malloc(3*n * sizeof(fastf_t), "fastf_t");
951 
952  /* generate front & back plates in world coordinates */
953  pos = pts;
954  i = 0;
955  while (pos) {
956  /* get corresponding rpc contour point in B-R plane from the parabola
957  * point in the Y-Z plane
958  */
959  VSCALE(R, Ru, pos->p[Y]);
960  VSCALE(B, Bu, -pos->p[Z]);
961  VADD2(&front[i], R, B);
962 
963  /* move to origin vertex origin */
964  VADD2(&front[i], &front[i], xip->rpc_V);
965 
966  /* extrude front to create back plate */
967  VADD2(&back[i], &front[i], xip->rpc_H);
968 
969  i += 3;
970  old = pos;
971  pos = pos->next;
972  bu_free((char *)old, "rt_pt_node");
973  }
974 
975  /* Draw the front */
976  RT_ADD_VLIST(vhead, &front[(n-1)*ELEMENTS_PER_VECT],
978  for (i = 0; i < n; i++) {
979  RT_ADD_VLIST(vhead, &front[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW);
980  }
981 
982  /* Draw the back */
983  RT_ADD_VLIST(vhead, &back[(n-1)*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE);
984  for (i = 0; i < n; i++) {
985  RT_ADD_VLIST(vhead, &back[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW);
986  }
987 
988  /* Draw connections */
989  for (i = 0; i < n; i++) {
990  RT_ADD_VLIST(vhead, &front[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE);
991  RT_ADD_VLIST(vhead, &back[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW);
992  }
993 
994  bu_free((char *)front, "fastf_t");
995  bu_free((char *)back, "fastf_t");
996 
997  return 0;
998 }
999 
1000 
1001 /**
1002  * Approximate a parabola with line segments. The initial single
1003  * segment is broken at the point farthest from the parabola if
1004  * that point is not already within the distance and normal error
1005  * tolerances. The two resulting segments are passed recursively
1006  * to this routine until each segment is within tolerance.
1007  */
1008 int
1009 rt_mk_parabola(struct rt_pt_node *pts, fastf_t r, fastf_t b, fastf_t dtol, fastf_t ntol)
1010 {
1011  fastf_t dist, intr, m, theta0, theta1;
1012  int n;
1013  point_t mpt, p0, p1;
1014  vect_t norm_line, norm_parab;
1015  struct rt_pt_node *newpt;
1016 
1017 #define RPC_TOL .0001
1018  /* endpoints of segment approximating parabola */
1019  VMOVE(p0, pts->p);
1020  VMOVE(p1, pts->next->p);
1021  /* slope and intercept of segment */
1022  m = (p1[Z] - p0[Z]) / (p1[Y] - p0[Y]);
1023  intr = p0[Z] - m * p0[Y];
1024  /* point on parabola with max dist between parabola and line */
1025  mpt[X] = 0.0;
1026  mpt[Y] = (r * r * m) / (2.0 * b);
1027  if (NEAR_ZERO(mpt[Y], RPC_TOL))
1028  mpt[Y] = 0.0;
1029  mpt[Z] = (mpt[Y] * m / 2.0) - b;
1030  if (NEAR_ZERO(mpt[Z], RPC_TOL))
1031  mpt[Z] = 0.0;
1032  /* max distance between that point and line */
1033  dist = fabs(mpt[Z] + b + b + intr) / sqrt(m * m + 1.0);
1034  /* angles between normal of line and of parabola at line endpoints */
1035  VSET(norm_line, m, -1.0, 0.0);
1036  VSET(norm_parab, 2.0 * b / (r * r) * p0[Y], -1.0, 0.0);
1037  VUNITIZE(norm_line);
1038  VUNITIZE(norm_parab);
1039  theta0 = fabs(acos(VDOT(norm_line, norm_parab)));
1040  VSET(norm_parab, 2.0 * b / (r * r) * p1[Y], -1.0, 0.0);
1041  VUNITIZE(norm_parab);
1042  theta1 = fabs(acos(VDOT(norm_line, norm_parab)));
1043  /* split segment at widest point if not within error tolerances */
1044  if (dist > dtol || theta0 > ntol || theta1 > ntol) {
1045  /* split segment */
1046  BU_ALLOC(newpt, struct rt_pt_node);
1047  VMOVE(newpt->p, mpt);
1048  newpt->next = pts->next;
1049  pts->next = newpt;
1050  /* keep track of number of pts added */
1051  n = 1;
1052  /* recurse on first new segment */
1053  n += rt_mk_parabola(pts, r, b, dtol, ntol);
1054  /* recurse on second new segment */
1055  n += rt_mk_parabola(newpt, r, b, dtol, ntol);
1056  } else
1057  n = 0;
1058  return n;
1059 }
1060 
1061 
1062 /**
1063  * Returns -
1064  * -1 failure
1065  * 0 OK. *r points to nmgregion that holds this tessellation.
1066  */
1067 int
1068 rt_rpc_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
1069 {
1070  int i, j, n;
1071  fastf_t b, *back, *front, rh;
1072  fastf_t dtol, ntol;
1073  vect_t Bu, Hu, Ru;
1074  mat_t R;
1075  mat_t invR;
1076  struct rt_rpc_internal *xip;
1077  struct rt_pt_node *old, *pos, *pts;
1078  struct shell *s;
1079  struct faceuse **outfaceuses;
1080  struct vertex **vfront, **vback, **vtemp, *vertlist[4];
1081  vect_t *norms;
1082  fastf_t r_sq_over_b;
1083 
1084  NMG_CK_MODEL(m);
1085  BN_CK_TOL(tol);
1086  RT_CK_TESS_TOL(ttol);
1087 
1088  RT_CK_DB_INTERNAL(ip);
1089 
1090  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1091  if (!rpc_is_valid(xip)) {
1092  return -2;
1093  }
1094 
1095  /* compute |B| |H| */
1096  b = MAGNITUDE(xip->rpc_B); /* breadth */
1097  rh = xip->rpc_r; /* rectangular halfwidth */
1098 
1099  /* make unit vectors in B, H, and BxH directions */
1100  VMOVE(Hu, xip->rpc_H);
1101  VUNITIZE(Hu);
1102  VMOVE(Bu, xip->rpc_B);
1103  VUNITIZE(Bu);
1104  VCROSS(Ru, Bu, Hu);
1105 
1106  /* Compute R and Rinv matrices */
1107  MAT_IDN(R);
1108  VREVERSE(&R[0], Hu);
1109  VMOVE(&R[4], Ru);
1110  VREVERSE(&R[8], Bu);
1111  bn_mat_trn(invR, R); /* inv of rot mat is trn */
1112 
1113  if (rh < b) {
1114  dtol = primitive_get_absolute_tolerance(ttol, 2.0 * rh);
1115  } else {
1116  dtol = primitive_get_absolute_tolerance(ttol, 2.0 * b);
1117  }
1118 
1119  /* To ensure normal tolerance, remain below this angle */
1120  if (ttol->norm > 0.0)
1121  ntol = ttol->norm;
1122  else
1123  /* tolerate everything */
1124  ntol = M_PI;
1125 
1126  /* initial parabola approximation is a single segment */
1127  BU_ALLOC(pts, struct rt_pt_node);
1128  BU_ALLOC(pts->next, struct rt_pt_node);
1129 
1130  pts->next->next = NULL;
1131  VSET(pts->p, 0.0, -rh, 0.0);
1132  VSET(pts->next->p, 0.0, rh, 0.0);
1133  /* 2 endpoints in 1st approximation */
1134  n = 2;
1135  /* recursively break segment 'til within error tolerances */
1136  n += rt_mk_parabola(pts, rh, b, dtol, ntol);
1137 
1138  /* get mem for arrays */
1139  front = (fastf_t *)bu_malloc(3*n * sizeof(fastf_t), "fastf_t");
1140  back = (fastf_t *)bu_malloc(3*n * sizeof(fastf_t), "fastf_t");
1141  norms = (vect_t *)bu_calloc(n, sizeof(vect_t), "rt_rpc_tess: norms");
1142  vfront = (struct vertex **)bu_malloc((n+1) * sizeof(struct vertex *), "vertex *");
1143  vback = (struct vertex **)bu_malloc((n+1) * sizeof(struct vertex *), "vertex *");
1144  vtemp = (struct vertex **)bu_malloc((n+1) * sizeof(struct vertex *), "vertex *");
1145  outfaceuses = (struct faceuse **)bu_malloc((n+2) * sizeof(struct faceuse *), "faceuse *");
1146 
1147  /* generate front & back plates in world coordinates */
1148  r_sq_over_b = rh * rh / b;
1149  pos = pts;
1150  i = 0;
1151  j = 0;
1152  while (pos) {
1153  vect_t tmp_norm;
1154 
1155  VSET(tmp_norm, 0.0, 2.0 * pos->p[Y], -r_sq_over_b);
1156  MAT4X3VEC(norms[j], invR, tmp_norm);
1157  VUNITIZE(norms[j]);
1158  /* rotate back to original position */
1159  MAT4X3VEC(&front[i], invR, pos->p);
1160  /* move to origin vertex origin */
1161  VADD2(&front[i], &front[i], xip->rpc_V);
1162  /* extrude front to create back plate */
1163  VADD2(&back[i], &front[i], xip->rpc_H);
1164  i += 3;
1165  j++;
1166  old = pos;
1167  pos = pos->next;
1168  bu_free((char *)old, "rt_pt_node");
1169  }
1170 
1171  *r = nmg_mrsv(m); /* Make region, empty shell, vertex */
1172  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
1173 
1174  for (i=0; i<n; i++) {
1175  vfront[i] = vtemp[i] = (struct vertex *)0;
1176  }
1177 
1178  /* Front face topology. Verts are considered to go CCW */
1179  outfaceuses[0] = nmg_cface(s, vfront, n);
1180 
1181  (void)nmg_mark_edges_real(&outfaceuses[0]->l.magic);
1182 
1183  /* Back face topology. Verts must go in opposite dir (CW) */
1184  outfaceuses[1] = nmg_cface(s, vtemp, n);
1185 
1186  (void)nmg_mark_edges_real(&outfaceuses[1]->l.magic);
1187 
1188  for (i=0; i<n; i++) vback[i] = vtemp[n-1-i];
1189 
1190  /* Duplicate [0] as [n] to handle loop end condition, below */
1191  vfront[n] = vfront[0];
1192  vback[n] = vback[0];
1193 
1194  /* Build topology for all the rectangular side faces (n of them)
1195  * connecting the front and back faces.
1196  * increasing indices go towards counter-clockwise (CCW).
1197  */
1198  for (i=0; i<n; i++) {
1199  vertlist[0] = vfront[i]; /* from top, */
1200  vertlist[1] = vback[i]; /* straight down, */
1201  vertlist[2] = vback[i+1]; /* to left, */
1202  vertlist[3] = vfront[i+1]; /* straight up. */
1203  outfaceuses[2+i] = nmg_cface(s, vertlist, 4);
1204  }
1205 
1206  (void)nmg_mark_edges_real(&outfaceuses[n+1]->l.magic);
1207 
1208  for (i=0; i<n; i++) {
1209  NMG_CK_VERTEX(vfront[i]);
1210  NMG_CK_VERTEX(vback[i]);
1211  }
1212 
1213  /* Associate the vertex geometry, CCW */
1214  for (i=0; i<n; i++) {
1215  nmg_vertex_gv(vfront[i], &front[3*(i)]);
1216  }
1217  for (i=0; i<n; i++) {
1218  nmg_vertex_gv(vback[i], &back[3*(i)]);
1219  }
1220 
1221  /* Associate the face geometry */
1222  for (i=0; i < n+2; i++) {
1223  if (nmg_fu_planeeqn(outfaceuses[i], tol) < 0) {
1224  /* free mem */
1225  bu_free((char *)front, "fastf_t");
1226  bu_free((char *)back, "fastf_t");
1227  bu_free((char*)vfront, "vertex *");
1228  bu_free((char*)vback, "vertex *");
1229  bu_free((char*)vtemp, "vertex *");
1230  bu_free((char*)outfaceuses, "faceuse *");
1231 
1232  return -1; /* FAIL */
1233  }
1234  }
1235 
1236  /* Associate vertexuse normals */
1237  for (i=0; i<n; i++) {
1238  struct vertexuse *vu;
1239  struct faceuse *fu;
1240  vect_t rev_norm;
1241 
1242  VREVERSE(rev_norm, norms[i]);
1243 
1244  /* do "front" vertices */
1245  NMG_CK_VERTEX(vfront[i]);
1246  for (BU_LIST_FOR(vu, vertexuse, &vfront[i]->vu_hd)) {
1247  NMG_CK_VERTEXUSE(vu);
1248  fu = nmg_find_fu_of_vu(vu);
1249  NMG_CK_FACEUSE(fu);
1250  if (fu->f_p == outfaceuses[0]->f_p ||
1251  fu->f_p == outfaceuses[1]->f_p ||
1252  fu->f_p == outfaceuses[n+1]->f_p)
1253  continue; /* skip flat faces */
1254 
1255  if (fu->orientation == OT_SAME)
1256  nmg_vertexuse_nv(vu, norms[i]);
1257  else if (fu->orientation == OT_OPPOSITE)
1258  nmg_vertexuse_nv(vu, rev_norm);
1259  }
1260 
1261  /* and "back" vertices */
1262  NMG_CK_VERTEX(vback[i]);
1263  for (BU_LIST_FOR(vu, vertexuse, &vback[i]->vu_hd)) {
1264  NMG_CK_VERTEXUSE(vu);
1265  fu = nmg_find_fu_of_vu(vu);
1266  NMG_CK_FACEUSE(fu);
1267  if (fu->f_p == outfaceuses[0]->f_p ||
1268  fu->f_p == outfaceuses[1]->f_p ||
1269  fu->f_p == outfaceuses[n+1]->f_p)
1270  continue; /* skip flat faces */
1271 
1272  if (fu->orientation == OT_SAME)
1273  nmg_vertexuse_nv(vu, norms[i]);
1274  else if (fu->orientation == OT_OPPOSITE)
1275  nmg_vertexuse_nv(vu, rev_norm);
1276  }
1277  }
1278 
1279  /* Glue the edges of different outward pointing face uses together */
1280  nmg_gluefaces(outfaceuses, n+2, tol);
1281 
1282  /* Compute "geometry" for region and shell */
1283  nmg_region_a(*r, tol);
1284 
1285  /* free mem */
1286  bu_free((char *)front, "fastf_t");
1287  bu_free((char *)back, "fastf_t");
1288  bu_free((char*)vfront, "vertex *");
1289  bu_free((char*)vback, "vertex *");
1290  bu_free((char*)vtemp, "vertex *");
1291  bu_free((char*)outfaceuses, "faceuse *");
1292 
1293  return 0;
1294 }
1295 
1296 
1297 /**
1298  * Import an RPC from the database format to the internal format.
1299  * Apply modeling transformations as well.
1300  */
1301 int
1302 rt_rpc_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
1303 {
1304  struct rt_rpc_internal *xip;
1305  union record *rp;
1306  vect_t v1, v2, v3;
1307 
1308  if (dbip) RT_CK_DBI(dbip);
1309 
1310  BU_CK_EXTERNAL(ep);
1311  rp = (union record *)ep->ext_buf;
1312  /* Check record type */
1313  if (rp->u_id != ID_SOLID) {
1314  bu_log("rt_rpc_import4: defective record\n");
1315  return -1;
1316  }
1317 
1318  RT_CK_DB_INTERNAL(ip);
1319  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1320  ip->idb_type = ID_RPC;
1321  ip->idb_meth = &OBJ[ID_RPC];
1322  BU_ALLOC(ip->idb_ptr, struct rt_rpc_internal);
1323 
1324  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1325  xip->rpc_magic = RT_RPC_INTERNAL_MAGIC;
1326 
1327  /* Warning: type conversion */
1328  if (mat == NULL) mat = bn_mat_identity;
1329 
1330  if (dbip->dbi_version < 0) {
1331  flip_fastf_float(v1, &rp->s.s_values[0*3], 1, 1);
1332  flip_fastf_float(v2, &rp->s.s_values[1*3], 1, 1);
1333  flip_fastf_float(v3, &rp->s.s_values[2*3], 1, 1);
1334  } else {
1335  VMOVE(v1, &rp->s.s_values[0*3]);
1336  VMOVE(v2, &rp->s.s_values[1*3]);
1337  VMOVE(v3, &rp->s.s_values[2*3]);
1338  }
1339 
1340  MAT4X3PNT(xip->rpc_V, mat, v1);
1341  MAT4X3VEC(xip->rpc_H, mat, v2);
1342  MAT4X3VEC(xip->rpc_B, mat, v3);
1343 
1344  if (dbip->dbi_version < 0) {
1345  v1[X] = flip_dbfloat(rp->s.s_values[3*3+0]);
1346  } else {
1347  v1[X] = rp->s.s_values[3*3+0];
1348  }
1349 
1350  xip->rpc_r = v1[X] / mat[15];
1351 
1352  if (xip->rpc_r <= SMALL_FASTF) {
1353  bu_log("rt_rpc_import4: r is zero\n");
1354  bu_free((char *)ip->idb_ptr, "rt_rpc_import4: ip->idp_ptr");
1355  return -1;
1356  }
1357 
1358  return 0; /* OK */
1359 }
1360 
1361 
1362 /**
1363  * The name is added by the caller, in the usual place.
1364  */
1365 int
1366 rt_rpc_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
1367 {
1368  struct rt_rpc_internal *xip;
1369  union record *rpc;
1370  fastf_t f, mag_b, mag_h;
1371 
1372  if (dbip) RT_CK_DBI(dbip);
1373 
1374  RT_CK_DB_INTERNAL(ip);
1375  if (ip->idb_type != ID_RPC) return -1;
1376  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1377  RT_RPC_CK_MAGIC(xip);
1378 
1379  BU_CK_EXTERNAL(ep);
1380  ep->ext_nbytes = sizeof(union record);
1381  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "rpc external");
1382  rpc = (union record *)ep->ext_buf;
1383 
1384  rpc->s.s_id = ID_SOLID;
1385  rpc->s.s_type = RPC;
1386 
1387  mag_b = MAGNITUDE(xip->rpc_B);
1388  mag_h = MAGNITUDE(xip->rpc_H);
1389 
1390  if (mag_b < RT_LEN_TOL || mag_h < RT_LEN_TOL || xip->rpc_r < RT_LEN_TOL) {
1391  bu_log("rt_rpc_export4: not all dimensions positive!\n");
1392  return -1;
1393  }
1394 
1395  f = VDOT(xip->rpc_B, xip->rpc_H) / (mag_b * mag_h);
1396  if (!NEAR_ZERO(f, RT_DOT_TOL)) {
1397  bu_log("rt_rpc_export4: B and H are not perpendicular! (dot = %g)\n", f);
1398  return -1;
1399  }
1400 
1401  /* Warning: type conversion */
1402  VSCALE(&rpc->s.s_values[0*3], xip->rpc_V, local2mm);
1403  VSCALE(&rpc->s.s_values[1*3], xip->rpc_H, local2mm);
1404  VSCALE(&rpc->s.s_values[2*3], xip->rpc_B, local2mm);
1405  rpc->s.s_values[3*3] = xip->rpc_r * local2mm;
1406 
1407  return 0;
1408 }
1409 
1410 
1411 /**
1412  * Import an RPC from the database format to the internal format.
1413  * Apply modeling transformations as well.
1414  */
1415 int
1416 rt_rpc_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
1417 {
1418  struct rt_rpc_internal *xip;
1419 
1420  /* must be double for import and export */
1421  double vec[10];
1422 
1423  if (dbip) RT_CK_DBI(dbip);
1424 
1425  BU_CK_EXTERNAL(ep);
1427 
1428  RT_CK_DB_INTERNAL(ip);
1429  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
1430  ip->idb_type = ID_RPC;
1431  ip->idb_meth = &OBJ[ID_RPC];
1432  BU_ALLOC(ip->idb_ptr, struct rt_rpc_internal);
1433 
1434  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1435  xip->rpc_magic = RT_RPC_INTERNAL_MAGIC;
1436 
1437  /* Convert from database (network) to internal (host) format */
1438  bu_cv_ntohd((unsigned char *)vec, ep->ext_buf, 10);
1439 
1440  /* Apply modeling transformations */
1441  if (mat == NULL) mat = bn_mat_identity;
1442  MAT4X3PNT(xip->rpc_V, mat, &vec[0*3]);
1443  MAT4X3VEC(xip->rpc_H, mat, &vec[1*3]);
1444  MAT4X3VEC(xip->rpc_B, mat, &vec[2*3]);
1445  xip->rpc_r = vec[3*3] / mat[15];
1446 
1447  if (xip->rpc_r <= SMALL_FASTF) {
1448  bu_log("rt_rpc_import4: r is zero\n");
1449  bu_free((char *)ip->idb_ptr, "rt_rpc_import4: ip->idp_ptr");
1450  return -1;
1451  }
1452 
1453  return 0; /* OK */
1454 }
1455 
1456 
1457 /**
1458  * The name is added by the caller, in the usual place.
1459  */
1460 int
1461 rt_rpc_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
1462 {
1463  struct rt_rpc_internal *xip;
1464  fastf_t f, mag_b, mag_h;
1465 
1466  /* must be double for import and export */
1467  double vec[10];
1468 
1469  if (dbip) RT_CK_DBI(dbip);
1470 
1471  RT_CK_DB_INTERNAL(ip);
1472  if (ip->idb_type != ID_RPC) return -1;
1473  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1474  RT_RPC_CK_MAGIC(xip);
1475 
1476  BU_CK_EXTERNAL(ep);
1477  ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * 10;
1478  ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "rpc external");
1479 
1480  mag_b = MAGNITUDE(xip->rpc_B);
1481  mag_h = MAGNITUDE(xip->rpc_H);
1482 
1483  if (mag_b < RT_LEN_TOL || mag_h < RT_LEN_TOL || xip->rpc_r < RT_LEN_TOL) {
1484  bu_log("rt_rpc_export4: not all dimensions positive!\n");
1485  return -1;
1486  }
1487 
1488  f = VDOT(xip->rpc_B, xip->rpc_H) / (mag_b * mag_h);
1489  if (!NEAR_ZERO(f, RT_DOT_TOL)) {
1490  bu_log("rt_rpc_export4: B and H are not perpendicular! (dot = %g)\n", f);
1491  return -1;
1492  }
1493 
1494  /* scale 'em into local buffer */
1495  VSCALE(&vec[0*3], xip->rpc_V, local2mm);
1496  VSCALE(&vec[1*3], xip->rpc_H, local2mm);
1497  VSCALE(&vec[2*3], xip->rpc_B, local2mm);
1498  vec[3*3] = xip->rpc_r * local2mm;
1499 
1500  /* Convert from internal (host) to database (network) format */
1501  bu_cv_htond(ep->ext_buf, (unsigned char *)vec, 10);
1502 
1503  return 0;
1504 }
1505 
1506 
1507 /**
1508  * Make human-readable formatted presentation of this solid.
1509  * First line describes type of solid.
1510  * Additional lines are indented one tab, and give parameter values.
1511  */
1512 int
1513 rt_rpc_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
1514 {
1515  struct rt_rpc_internal *xip =
1516  (struct rt_rpc_internal *)ip->idb_ptr;
1517  char buf[256];
1518 
1519  RT_RPC_CK_MAGIC(xip);
1520  bu_vls_strcat(str, "Right Parabolic Cylinder (RPC)\n");
1521 
1522  if (!verbose)
1523  return 0;
1524 
1525  sprintf(buf, "\tV (%g, %g, %g)\n",
1526  INTCLAMP(xip->rpc_V[X] * mm2local),
1527  INTCLAMP(xip->rpc_V[Y] * mm2local),
1528  INTCLAMP(xip->rpc_V[Z] * mm2local));
1529  bu_vls_strcat(str, buf);
1530 
1531  sprintf(buf, "\tB (%g, %g, %g) mag=%g\n",
1532  INTCLAMP(xip->rpc_B[X] * mm2local),
1533  INTCLAMP(xip->rpc_B[Y] * mm2local),
1534  INTCLAMP(xip->rpc_B[Z] * mm2local),
1535  INTCLAMP(MAGNITUDE(xip->rpc_B) * mm2local));
1536  bu_vls_strcat(str, buf);
1537 
1538  sprintf(buf, "\tH (%g, %g, %g) mag=%g\n",
1539  INTCLAMP(xip->rpc_H[X] * mm2local),
1540  INTCLAMP(xip->rpc_H[Y] * mm2local),
1541  INTCLAMP(xip->rpc_H[Z] * mm2local),
1542  INTCLAMP(MAGNITUDE(xip->rpc_H) * mm2local));
1543  bu_vls_strcat(str, buf);
1544 
1545  sprintf(buf, "\tr=%g\n", INTCLAMP(xip->rpc_r * mm2local));
1546  bu_vls_strcat(str, buf);
1547 
1548  return 0;
1549 }
1550 
1551 
1552 /**
1553  * Free the storage associated with the rt_db_internal version of this solid.
1554  */
1555 void
1557 {
1558  struct rt_rpc_internal *xip;
1559 
1560  RT_CK_DB_INTERNAL(ip);
1561 
1562  xip = (struct rt_rpc_internal *)ip->idb_ptr;
1563  RT_RPC_CK_MAGIC(xip);
1564  xip->rpc_magic = 0; /* sanity */
1565 
1566  bu_free((char *)xip, "rpc ifree");
1567  ip->idb_ptr = ((void *)0); /* sanity */
1568 }
1569 
1570 
1571 int
1572 rt_rpc_params(struct pc_pc_set *UNUSED(ps), const struct rt_db_internal *ip)
1573 {
1574  if (ip) RT_CK_DB_INTERNAL(ip);
1575 
1576  return 0; /* OK */
1577 }
1578 
1579 
1580 void
1581 rt_rpc_volume(fastf_t *vol, const struct rt_db_internal *ip)
1582 {
1583  fastf_t mag_h, mag_b, mag_r;
1584  struct rt_rpc_internal *xip = (struct rt_rpc_internal *)ip->idb_ptr;
1585  RT_RPC_CK_MAGIC(xip);
1586 
1587  mag_h = MAGNITUDE(xip->rpc_H);
1588  mag_b = MAGNITUDE(xip->rpc_B);
1589  mag_r = xip->rpc_r;
1590 
1591  *vol = 4.0/3.0 * mag_b * mag_r * mag_h;
1592 }
1593 
1594 
1595 void
1596 rt_rpc_centroid(point_t *cent, const struct rt_db_internal *ip)
1597 {
1598  struct rt_rpc_internal *xip = (struct rt_rpc_internal *)ip->idb_ptr;
1599  RT_RPC_CK_MAGIC(xip);
1600 
1601  /* centroid of a parabolic section is
1602  * 0.4 * h where h is a vector from
1603  * the base to the vertex of the parabola */
1604  VJOIN1(*cent, xip->rpc_V, 0.4, xip->rpc_B);
1605 
1606  /* cent now stores the centroid of the
1607  * parabolic section representing the base
1608  * of the rpc */
1609  VJOIN1(*cent, *cent, 0.5, xip->rpc_H);
1610 }
1611 
1612 
1613 void
1614 rt_rpc_surf_area(fastf_t *area, const struct rt_db_internal *ip)
1615 {
1616  fastf_t area_base, area_shell, area_rect;
1617  fastf_t mag_b, mag_r, mag_h;
1618  fastf_t magsq_b, magsq_r;
1619  struct rt_rpc_internal *xip = (struct rt_rpc_internal *)ip->idb_ptr;
1620  RT_RPC_CK_MAGIC(xip);
1621 
1622  mag_h = MAGNITUDE(xip->rpc_H);
1623  magsq_b = MAGSQ(xip->rpc_B);
1624  mag_r = xip->rpc_r;
1625  mag_b = sqrt(magsq_b);
1626  magsq_r = mag_r * mag_r;
1627 
1628  area_base = 4.0/3.0 * mag_b * mag_r;
1629 
1630  area_shell = 0.5 * sqrt(magsq_r + 4.0 * magsq_b) + 0.25 * magsq_r /
1631  mag_b * asinh(2.0 * mag_b / mag_r);
1632  area_shell *= 2.0;
1633 
1634  area_rect = 2.0 * mag_r * mag_h;
1635 
1636  *area = 2.0 * area_base + area_rect + area_shell;
1637 }
1638 
1639 static int
1640 rpc_is_valid(struct rt_rpc_internal *rpc)
1641 {
1642  fastf_t mag_h, mag_b, cos_angle_bh;
1643  vect_t rpc_H, rpc_B;
1644 
1645  RT_RPC_CK_MAGIC(rpc);
1646 
1647  VMOVE(rpc_H, rpc->rpc_H);
1648  mag_h = MAGNITUDE(rpc_H);
1649 
1650  VMOVE(rpc_B, rpc->rpc_B);
1651  mag_b = MAGNITUDE(rpc_B);
1652 
1653  /* Check for |H| > 0, |B| > 0, |R| > 0 */
1654  if (NEAR_ZERO(mag_h, RT_LEN_TOL)
1655  || NEAR_ZERO(mag_b, RT_LEN_TOL)
1656  || NEAR_ZERO(rpc->rpc_r, RT_LEN_TOL))
1657  {
1658  return 0;
1659  }
1660 
1661  /* check B and H are orthogonal */
1662  cos_angle_bh = VDOT(rpc_B, rpc_H) / (mag_b * mag_h);
1663  if (!NEAR_ZERO(cos_angle_bh, RT_DOT_TOL)) {
1664  return 0;
1665  }
1666 
1667  return 1;
1668 }
1669 
1670 /*
1671  * Local Variables:
1672  * mode: C
1673  * tab-width: 8
1674  * indent-tabs-mode: t
1675  * c-file-style: "stroustrup"
1676  * End:
1677  * ex: shiftwidth=4 tabstop=8
1678  */
fastf_t rpc_b
Definition: rpc.c:183
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
Definition: raytrace.h:800
void rt_rpc_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
Definition: rpc.c:547
ustring back
#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
void rt_rpc_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp)
Definition: rpc.c:581
#define SIZEOF_NETWORK_DOUBLE
Definition: cv.h:48
struct faceuse * nmg_cface(struct shell *s, struct vertex **verts, int n)
Definition: nmg_mod.c:1130
struct hit seg_in
IN information.
Definition: raytrace.h:370
Definition: list.h:118
int nmg_fu_planeeqn(struct faceuse *fu, const struct bn_tol *tol)
Definition: nmg_mod.c:1311
int rt_rpc_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: rpc.c:1416
#define RT_DOT_TOL
Definition: raytrace.h:170
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
void rt_rpc_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
Definition: rpc.c:514
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
#define RPC_TOL
if lu s
Definition: nmg_mod.c:3860
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
#define M_PI
Definition: fft.h:35
Definition: pc.h:108
Definition: raytrace.h:368
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
void rt_rpc_surf_area(fastf_t *area, const struct rt_db_internal *ip)
Definition: rpc.c:1614
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
#define SMALL_FASTF
Definition: defines.h:342
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
int rt_rpc_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: rpc.c:1302
Header file for the BRL-CAD common definitions.
void nmg_vertexuse_nv(struct vertexuse *vu, const fastf_t *norm)
Definition: nmg_mk.c:1719
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
void bu_cv_htond(unsigned char *out, const unsigned char *in, size_t count)
#define RPC_NORM_BACK
Definition: rpc.c:357
struct bu_list l
Definition: raytrace.h:369
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
if(share_geom)
Definition: nmg_mod.c:3829
int idb_major_type
Definition: raytrace.h:192
Definition: color.c:49
void rt_rpc_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: rpc.c:1596
#define RPC_NORM_TOP
Definition: rpc.c:355
vect_t hit_vpriv
PRIVATE vector for xxx_*()
Definition: raytrace.h:253
struct bu_list * vhead
Definition: raytrace.h:1926
#define RT_ADD_VLIST(hd, pnt, draw)
Definition: raytrace.h:1865
int rt_rpc_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: rpc.c:263
void bn_mat_print(const char *title, const mat_t m)
Definition: mat.c:81
int rt_rpc_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
Definition: rpc.c:369
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
#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
int rt_rpc_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: rpc.c:894
mat_t rpc_invRoS
Definition: rpc.c:186
#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
fastf_t primitive_get_absolute_tolerance(const struct rt_tess_tol *ttol, fastf_t rel_to_abs)
#define RPC_NORM_FRT
Definition: rpc.c:356
void rt_rpc_volume(fastf_t *vol, const struct rt_db_internal *ip)
Definition: rpc.c:1581
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
#define RT_CK_TESS_TOL(_p)
Definition: raytrace.h:184
uint8_t * ext_buf
Definition: parse.h:216
fastf_t rpc_inv_rsq
Definition: rpc.c:184
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
int rt_mk_parabola(struct rt_pt_node *pts, fastf_t r, fastf_t b, fastf_t dtol, fastf_t ntol)
Definition: rpc.c:1009
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
void rt_rpc_free(struct soltab *stp)
Definition: rpc.c:626
struct hit seg_out
OUT information.
Definition: raytrace.h:371
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
#define RT_RPC_INTERNAL_MAGIC
Definition: magic.h:107
fastf_t flip_dbfloat(dbfloat_t d)
Definition: db_flip.c:58
void bn_mat_trn(mat_t om, const mat_t im)
#define UNUSED(parameter)
Definition: common.h:239
int nmg_mark_edges_real(const uint32_t *magic_p)
Definition: nmg_misc.c:846
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
void bn_mat_mul(mat_t o, const mat_t a, const mat_t b)
struct faceuse * nmg_find_fu_of_vu(const struct vertexuse *vu)
Definition: nmg_info.c:304
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
#define bu_offsetofarray(_t, _a, _d, _i)
Definition: parse.h:65
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
int rt_rpc_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: rpc.c:1068
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
vect_t rpc_Hunit
Definition: rpc.c:181
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
struct rt_pt_node * next
ptr to next pt
Definition: raytrace.h:1912
fastf_t primitive_curve_count(struct rt_db_internal *ip, const struct rt_view_info *info)
int rt_rpc_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: rpc.c:1572
#define bu_offsetof(_t, _m)
Definition: parse.h:64
point_t rpc_V
Definition: rpc.c:179
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
fastf_t point_spacing
Definition: raytrace.h:1934
void * idb_ptr
Definition: raytrace.h:195
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
const struct bu_structparse rt_rpc_parse[]
Definition: rpc.c:190
point_t st_min
min X, Y, Z of bounding RPP
Definition: raytrace.h:437
int rt_rpc_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: rpc.c:1366
void bu_cv_ntohd(unsigned char *out, const unsigned char *in, size_t count)
const struct rt_functab OBJ[]
Definition: table.c:159
void bn_vec_ortho(vect_t out, const vect_t in)
#define R
Definition: msr.c:55
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
fastf_t uv_du
delta in u
Definition: raytrace.h:343
point_t p
a point
Definition: raytrace.h:1911
int rt_rpc_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: rpc.c:1461
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
Definition: color.c:51
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
ustring front
double norm
normal tol
Definition: raytrace.h:182
vect_t rpc_Bunit
Definition: rpc.c:180
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
void rt_rpc_ifree(struct rt_db_internal *ip)
Definition: rpc.c:1556
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_rpc_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: rpc.c:1513
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
void nmg_gluefaces(struct faceuse **fulist, int n, const struct bn_tol *tol)
Definition: nmg_mod.c:1408
int rt_rpc_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info)
Definition: rpc.c:829
const struct rt_functab * st_meth
pointer to per-solid methods
Definition: raytrace.h:428
#define RT_PCOEF_TOL
Definition: raytrace.h:171
void rt_rpc_print(const struct soltab *stp)
Definition: rpc.c:339
#define ID_RPC
Right Parabolic Cylinder.
Definition: raytrace.h:475
int st_id
Solid ident.
Definition: raytrace.h:431
size_t ext_nbytes
Definition: parse.h:210
vect_t rpc_Runit
Definition: rpc.c:182
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
Definition: vls.h:56
int rt_rpc_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: rpc.c:202
double fastf_t
Definition: defines.h:300
#define VPRINT(a, b)
Definition: raytrace.h:1881
#define RPC_NORM_BODY
Definition: rpc.c:354
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
int approximate_parabolic_curve(struct rt_pt_node *pts, fastf_t p, int num_new_points)
mat_t rpc_SoR
Definition: rpc.c:185
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
#define RT_HIT_MAGIC
Definition: magic.h:161
void nmg_region_a(struct nmgregion *r, const struct bn_tol *tol)
Definition: nmg_mk.c:2557