BRL-CAD
pipe.c
Go to the documentation of this file.
1 /* P I P E . 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/pipe/pipe.c
23  *
24  * Intersect a ray with a pipe solid.
25  *
26  */
27 /** @} */
28 
29 #include "common.h"
30 
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <string.h>
35 
36 #include <float.h>
37 #include <math.h>
38 #include "bnetwork.h"
39 
40 #include "tcl.h"
41 
42 #include "bu/cv.h"
43 #include "vmath.h"
44 
45 #include "bn.h"
46 #include "db.h"
47 #include "nmg.h"
48 #include "rtgeom.h"
49 #include "raytrace.h"
50 #include "wdb.h"
51 #include "../../librt_private.h"
52 
53 
54 struct id_pipe {
55  struct bu_list l;
57 };
58 
59 
60 struct lin_pipe {
61  struct bu_list l;
63  vect_t pipe_V; /* start point for pipe section */
64  vect_t pipe_H; /* unit vector in direction of pipe section */
65  fastf_t pipe_ribase, pipe_ritop; /* base and top inner radii */
66  fastf_t pipe_ribase_sq, pipe_ritop_sq; /* inner radii squared */
67  fastf_t pipe_ridiff_sq, pipe_ridiff; /* difference between top and base inner radii */
68  fastf_t pipe_rodiff_sq, pipe_rodiff; /* difference between top and base outer radii */
69  fastf_t pipe_robase, pipe_rotop; /* base and top outer radii */
70  fastf_t pipe_robase_sq, pipe_rotop_sq; /* outer radii squared */
71  fastf_t pipe_len; /* length of pipe segment */
72  mat_t pipe_SoR; /* Scale and rotate */
73  mat_t pipe_invRoS; /* inverse rotation and scale */
74  point_t pipe_min;
75  point_t pipe_max;
76 };
77 
78 
79 struct bend_pipe {
80  struct bu_list l;
82  fastf_t bend_radius; /* distance from bend_v to center of pipe */
83  fastf_t bend_or; /* outer radius */
84  fastf_t bend_ir; /* inner radius */
85  mat_t bend_invR; /* inverse rotation matrix */
86  mat_t bend_SoR; /* Scale and rotate */
87  point_t bend_V; /* Center of bend */
88  point_t bend_start; /* Start of bend */
89  point_t bend_end; /* End of bend */
90  fastf_t bend_alpha_i; /* ratio of inner radius to bend radius */
91  fastf_t bend_alpha_o; /* ratio of outer radius to bend radius */
92  fastf_t bend_angle; /* Angle that bend goes through */
93  vect_t bend_ra; /* unit vector in plane of bend (points toward start from bend_V) */
94  vect_t bend_rb; /* unit vector in plane of bend (normal to bend_ra) */
95  vect_t bend_endNorm; /* unit vector normal to end plane */
96  vect_t bend_startNorm; /* unit vector normal to start plane */
97  vect_t bend_N; /* unit vector normal to plane of bend */
98  point_t bend_bound_center; /* center of bounding sphere */
99  fastf_t bend_bound_radius_sq; /* square of bounding sphere radius */
100 };
101 
102 
103 /* two orthogonal unit vectors that define an orientation */
105  vect_t v1;
106  vect_t v2;
107 };
108 
109 
110 /* A plotted circle defined by a center point, an orientation at that point,
111  * and a radius.
112  */
113 struct pipe_circle {
114  point_t center;
117 };
118 
119 
120 struct pipe_segment {
121  struct wdb_pipept *cur;
124  point_t last_drawn;
126 };
127 
128 
129 struct pipe_bend {
132  vect_t bend_normal;
133  point_t bend_start;
134  point_t bend_end;
136 };
137 
138 
139 #define PIPE_CONNECTING_ARCS 4 /* number of connecting arcs to draw between points */
140 #define PIPE_CIRCLE_SEGS 16 /* number of segments used to plot a circle */
141 
142 #define PIPE_LINEAR_OUTER_BODY 1
143 #define PIPE_LINEAR_INNER_BODY 2
144 #define PIPE_LINEAR_TOP 3
145 #define PIPE_LINEAR_BASE 4
146 #define PIPE_BEND_OUTER_BODY 5
147 #define PIPE_BEND_INNER_BODY 6
148 #define PIPE_BEND_BASE 7
149 #define PIPE_BEND_TOP 8
150 #define PIPE_RADIUS_CHANGE 9
151 
152 #define RT_PIPE_MAXHITS 128
153 
154 static fastf_t
155 pipe_seg_bend_angle(const struct pipe_segment *seg)
156 {
157  struct wdb_pipept *prevpt, *curpt, *nextpt;
158  fastf_t dot, rad_between_segments, supplementary_angle;
159  vect_t cur_to_prev, cur_to_next;
160 
161  curpt = seg->cur;
162  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
163  nextpt = BU_LIST_NEXT(wdb_pipept, &curpt->l);
164 
165  VSUB2(cur_to_prev, prevpt->pp_coord, curpt->pp_coord);
166  VSUB2(cur_to_next, nextpt->pp_coord, curpt->pp_coord);
167  VUNITIZE(cur_to_prev);
168  VUNITIZE(cur_to_next);
169 
170  dot = VDOT(cur_to_prev, cur_to_next);
171  rad_between_segments = acos(VDOT(cur_to_prev, cur_to_next));
172 
173  /* handle the cases where acos returned NaN because floating point fuzz
174  * caused dot to be slightly outside the valid [-1.0, 1.0] range
175  */
176  if (isnan(rad_between_segments)) {
177  if (dot >= 1.0) {
178  rad_between_segments = acos(1.0);
179  } else if (dot <= -1.0) {
180  rad_between_segments = acos(-1.0);
181  }
182  }
183 
184  supplementary_angle = M_PI - rad_between_segments;
185 
186  return supplementary_angle;
187 }
188 
189 
190 static fastf_t
191 pipe_seg_dist_to_bend_endpoint(const struct pipe_segment *seg)
192 {
193  fastf_t bend_angle, dist_to_bend_end;
194 
195  /* The fewer the radians between the segments, the more the bend is
196  * pushed away from cur and toward prev and next.
197  *
198  * (rad < pi/2) => (dist > bendradius)
199  * (rad = pi/2) => (dist = bendradius)
200  * (rad > pi/2) => (dist < bendradius)
201  */
202  bend_angle = pipe_seg_bend_angle(seg);
203  dist_to_bend_end = seg->cur->pp_bendradius * tan(bend_angle / 2.0);
204 
205  return dist_to_bend_end;
206 }
207 
208 
209 static void
210 pipe_seg_bend_normal(vect_t norm, const struct pipe_segment *seg)
211 {
212  vect_t cur_to_prev, cur_to_next;
213  struct wdb_pipept *prevpt, *curpt, *nextpt;
214 
215  curpt = seg->cur;
216  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
217  nextpt = BU_LIST_NEXT(wdb_pipept, &curpt->l);
218 
219  VSUB2(cur_to_prev, prevpt->pp_coord, curpt->pp_coord);
220  VSUB2(cur_to_next, nextpt->pp_coord, curpt->pp_coord);
221  VCROSS(norm, cur_to_prev, cur_to_next);
222  VUNITIZE(norm);
223 }
224 
225 
226 static struct pipe_orientation
227 pipe_orient_from_normal(const vect_t norm)
228 {
229  struct pipe_orientation orient;
230 
231  bn_vec_ortho(orient.v1, norm);
232  VCROSS(orient.v2, norm, orient.v1);
233  VUNITIZE(orient.v2);
234 
235  return orient;
236 }
237 
238 
239 static struct pipe_segment *
240 pipe_seg_first(struct rt_pipe_internal *pipeobj)
241 {
242  struct bu_list *seghead;
243  struct pipe_segment *first_seg = NULL;
244  struct wdb_pipept *pt_1, *pt_2;
245  vect_t cur_to_next;
246 
247  RT_PIPE_CK_MAGIC(pipeobj);
248 
249  /* no points */
250  if (BU_LIST_IS_EMPTY(&pipeobj->pipe_segs_head)) {
251  return NULL;
252  }
253 
254  seghead = &pipeobj->pipe_segs_head;
255  pt_1 = BU_LIST_FIRST(wdb_pipept, seghead);
256  pt_2 = BU_LIST_NEXT(wdb_pipept, &pt_1->l);
257 
258  /* only one point */
259  if (BU_LIST_IS_HEAD(&pt_2->l, seghead)) {
260  return NULL;
261  }
262 
263  BU_GET(first_seg, struct pipe_segment);
264  first_seg->pipe_segs_head = seghead;
265  first_seg->cur = pt_1;
266 
267  VSUB2(cur_to_next, pt_2->pp_coord, pt_1->pp_coord);
268  first_seg->orient = pipe_orient_from_normal(cur_to_next);
269 
270  return first_seg;
271 }
272 
273 
274 static void
275 pipe_seg_advance(struct pipe_segment *seg)
276 {
277  seg->cur = BU_LIST_NEXT(wdb_pipept, &seg->cur->l);
278 }
279 
280 
281 static int
282 pipe_seg_is_last(const struct pipe_segment *seg)
283 {
284  struct wdb_pipept *nextpt;
285 
286  nextpt = BU_LIST_NEXT(wdb_pipept, &seg->cur->l);
287  if (BU_LIST_IS_HEAD(nextpt, seg->pipe_segs_head)) {
288  return 1;
289  }
290 
291  return 0;
292 }
293 
294 
295 static int
296 pipe_seg_is_bend(const struct pipe_segment *seg)
297 {
298  vect_t cur_to_prev, cur_to_next, norm;
299  struct wdb_pipept *prevpt, *curpt, *nextpt;
300  fastf_t dist_to_bend_end;
301 
302  curpt = seg->cur;
303  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
304  nextpt = BU_LIST_NEXT(wdb_pipept, &curpt->l);
305 
306  VSUB2(cur_to_prev, prevpt->pp_coord, curpt->pp_coord);
307  VSUB2(cur_to_next, nextpt->pp_coord, curpt->pp_coord);
308  VCROSS(norm, cur_to_prev, cur_to_next);
309  VUNITIZE(cur_to_prev);
310  VUNITIZE(cur_to_next);
311 
312  dist_to_bend_end = pipe_seg_dist_to_bend_endpoint(seg);
313 
314  /* in the extreme cases where the interior angle between the adjacent
315  * segments is nearly 0 or pi radians, the points are considered
316  * collinear
317  */
318  if (isinf(dist_to_bend_end)
319  || NEAR_ZERO(dist_to_bend_end, SQRT_SMALL_FASTF)
320  || VNEAR_ZERO(norm, SQRT_SMALL_FASTF))
321  {
322  return 0;
323  }
324 
325  return 1;
326 }
327 
328 
329 HIDDEN int
331  struct bu_list *head,
332  fastf_t *bend_center, fastf_t *bend_start, fastf_t *bend_end,
333  fastf_t bend_radius, fastf_t bend_angle,
334  fastf_t od, fastf_t id,
335  fastf_t prev_od, fastf_t next_od,
336  point_t *min, point_t *max)
337 {
338  struct bend_pipe *bp;
339  vect_t to_start, to_end;
340  mat_t R;
341  point_t work;
342  fastf_t f;
343  fastf_t max_od;
344  fastf_t max_or;
345  fastf_t max_r;
346 
347  BU_GET(bp, struct bend_pipe);
348 
349  bp->pipe_is_bend = 1;
350  bp->bend_or = od * 0.5;
351  bp->bend_ir = id * 0.5;
352 
353  VMOVE(bp->bend_start, bend_start);
354  VMOVE(bp->bend_end, bend_end);
355  VMOVE(bp->bend_V, bend_center);
356  VSUB2(to_start, bend_start, bend_center);
357  bp->bend_radius = bend_radius;
358  VSUB2(to_end, bend_end, bend_center);
359  VSCALE(bp->bend_ra, to_start, 1.0 / bp->bend_radius);
360  VCROSS(bp->bend_N, to_start, to_end);
361  VUNITIZE(bp->bend_N);
362  VCROSS(bp->bend_rb, bp->bend_N, bp->bend_ra);
363  VCROSS(bp->bend_startNorm, bp->bend_ra, bp->bend_N);
364  VCROSS(bp->bend_endNorm, bp->bend_N, to_end);
365  VUNITIZE(bp->bend_endNorm);
366 
367  bp->bend_angle = bend_angle;
368 
369  /* angle goes from 0.0 at start to some angle less than PI */
370  if (bp->bend_angle >= M_PI) {
371  bu_log("Error: rt_pipe_prep: Bend section bends through more than 180 degrees\n");
372  return 1;
373  }
374 
375  bp->bend_alpha_i = bp->bend_ir / bp->bend_radius;
376  bp->bend_alpha_o = bp->bend_or / bp->bend_radius;
377 
378  MAT_IDN(R);
379  VMOVE(&R[0], bp->bend_ra);
380  VMOVE(&R[4], bp->bend_rb);
381  VMOVE(&R[8], bp->bend_N);
382 
383  if (bn_mat_inverse(bp->bend_invR, R) == 0) {
384  BU_PUT(bp, struct bend_pipe);
385  return 0; /* there is nothing to bend, that's OK */
386  }
387 
388 
389  MAT_COPY(bp->bend_SoR, R);
390  bp->bend_SoR[15] *= bp->bend_radius;
391 
392  /* bounding box for entire torus */
393  /* include od of previous and next segment
394  * to allow for discontinuous radii
395  */
396  max_od = od;
397  if (prev_od > max_od) {
398  max_od = prev_od;
399  }
400  if (next_od > max_od) {
401  max_od = next_od;
402  }
403  max_or = max_od / 2.0;
404  max_r = bend_radius + max_or;
405 
406  VBLEND2(bp->bend_bound_center, 0.5, bend_start, 0.5, bend_end);
407  bp->bend_bound_radius_sq = max_r * sin(bend_angle / 2.0);
409  bp->bend_bound_radius_sq += max_or * max_or;
410  f = sqrt(bp->bend_bound_radius_sq);
411  VMOVE(work, bp->bend_bound_center);
412  work[X] -= f;
413  work[Y] -= f;
414  work[Z] -= f;
415  VMINMAX(*min, *max, work);
416  VMOVE(work, bp->bend_bound_center);
417  work[X] += f;
418  work[Y] += f;
419  work[Z] += f;
420  VMINMAX(*min, *max, work);
421 
422  if (head) {
423  BU_LIST_INSERT(head, &bp->l);
424  } else {
425  BU_PUT(bp, struct bend_pipe);
426  }
427 
428  return 0;
429 
430 }
431 
432 
433 HIDDEN void
435  struct bu_list *head,
436  fastf_t *pt1, fastf_t id1, fastf_t od1,
437  fastf_t *pt2, fastf_t id2, fastf_t od2,
438  point_t *min,
439  point_t *max)
440 {
441  struct lin_pipe *lp;
442  mat_t R;
443  mat_t Rinv;
444  mat_t S;
445  point_t work;
446  vect_t seg_ht;
447  vect_t v1, v2;
448 
449  BU_GET(lp, struct lin_pipe);
450 
451  VMOVE(lp->pipe_V, pt1);
452 
453  VSUB2(seg_ht, pt2, pt1);
454  lp->pipe_ribase = id1 / 2.0;
455  lp->pipe_ribase_sq = lp->pipe_ribase * lp->pipe_ribase;
456  lp->pipe_ritop = id2 / 2.0;
457  lp->pipe_ritop_sq = lp->pipe_ritop * lp->pipe_ritop;
458  lp->pipe_robase = od1 / 2.0;
459  lp->pipe_robase_sq = lp->pipe_robase * lp->pipe_robase;
460  lp->pipe_rotop = od2 / 2.0;
461  lp->pipe_rotop_sq = lp->pipe_rotop * lp->pipe_rotop;
462  lp->pipe_ridiff = lp->pipe_ritop - lp->pipe_ribase;
463  lp->pipe_ridiff_sq = lp->pipe_ridiff * lp->pipe_ridiff;
464  lp->pipe_rodiff = lp->pipe_rotop - lp->pipe_robase;
465  lp->pipe_rodiff_sq = lp->pipe_rodiff * lp->pipe_rodiff;
466  lp->pipe_is_bend = 0;
467 
468  lp->pipe_len = MAGNITUDE(seg_ht);
469  VSCALE(seg_ht, seg_ht, 1.0 / lp->pipe_len);
470  VMOVE(lp->pipe_H, seg_ht);
471  bn_vec_ortho(v1, seg_ht);
472  VCROSS(v2, seg_ht, v1);
473 
474  /* build R matrix */
475  MAT_IDN(R);
476  VMOVE(&R[0], v1);
477  VMOVE(&R[4], v2);
478  VMOVE(&R[8], seg_ht);
479 
480  /* Rinv is transpose */
481  bn_mat_trn(Rinv, R);
482 
483  /* Build Scale matrix */
484  MAT_IDN(S);
485  S[10] = 1.0 / lp->pipe_len;
486 
487  /* Compute SoR and invRoS */
488  bn_mat_mul(lp->pipe_SoR, S, R);
489  bn_mat_mul(lp->pipe_invRoS, Rinv, S);
490 
491  VSETALL(lp->pipe_min, INFINITY);
492  VSETALL(lp->pipe_max, -INFINITY);
493 
494  VJOIN2(work, pt1, od1, v1, od1, v2);
495  VMINMAX(*min, *max, work);
496  VMINMAX(lp->pipe_min, lp->pipe_max, work);
497  VJOIN2(work, pt1, -od1, v1, od1, v2);
498  VMINMAX(*min, *max, work);
499  VMINMAX(lp->pipe_min, lp->pipe_max, work);
500  VJOIN2(work, pt1, od1, v1, -od1, v2);
501  VMINMAX(*min, *max, work);
502  VMINMAX(lp->pipe_min, lp->pipe_max, work);
503  VJOIN2(work, pt1, -od1, v1, -od1, v2);
504  VMINMAX(*min, *max, work);
505  VMINMAX(lp->pipe_min, lp->pipe_max, work);
506 
507  VJOIN2(work, pt2, od2, v1, od2, v2);
508  VMINMAX(*min, *max, work);
509  VMINMAX(lp->pipe_min, lp->pipe_max, work);
510  VJOIN2(work, pt2, -od2, v1, od2, v2);
511  VMINMAX(*min, *max, work);
512  VMINMAX(lp->pipe_min, lp->pipe_max, work);
513  VJOIN2(work, pt2, od2, v1, -od2, v2);
514  VMINMAX(*min, *max, work);
515  VMINMAX(lp->pipe_min, lp->pipe_max, work);
516  VJOIN2(work, pt2, -od2, v1, -od2, v2);
517  VMINMAX(*min, *max, work);
518  VMINMAX(lp->pipe_min, lp->pipe_max, work);
519 
520  if (head) {
521  BU_LIST_INSERT(head, &lp->l);
522  } else {
523  bu_free(lp, "free pipe bb lp segment");
524  }
525 }
526 
527 
528 HIDDEN void
529 pipe_elements_calculate(struct bu_list *elements_head, struct rt_db_internal *ip, point_t *min, point_t *max)
530 {
531  struct rt_pipe_internal *pip;
532  struct wdb_pipept *pp1, *pp2, *pp3;
533  point_t curr_pt;
534  fastf_t curr_id, curr_od;
535 
536 
537  RT_CK_DB_INTERNAL(ip);
538  pip = (struct rt_pipe_internal *)ip->idb_ptr;
539  RT_PIPE_CK_MAGIC(pip);
540 
541  VSETALL(*min, INFINITY);
542  VSETALL(*max, -INFINITY);
543 
544  if (BU_LIST_IS_EMPTY(&(pip->pipe_segs_head))) {
545  return;
546  }
547 
548  pp1 = BU_LIST_FIRST(wdb_pipept, &(pip->pipe_segs_head));
549  pp2 = BU_LIST_NEXT(wdb_pipept, &pp1->l);
550  if (BU_LIST_IS_HEAD(&pp2->l, &(pip->pipe_segs_head))) {
551  return;
552  }
553  pp3 = BU_LIST_NEXT(wdb_pipept, &pp2->l);
554  if (BU_LIST_IS_HEAD(&pp3->l, &(pip->pipe_segs_head))) {
555  pp3 = (struct wdb_pipept *)NULL;
556  }
557 
558  VSETALL((*min), INFINITY);
559  VSETALL((*max), -INFINITY);
560 
561  VMOVE(curr_pt, pp1->pp_coord);
562  curr_od = pp1->pp_od;
563  curr_id = pp1->pp_id;
564  while (1) {
565  vect_t n1, n2;
566  vect_t norm;
567  vect_t v1;
568  vect_t diff;
569  fastf_t angle;
570  fastf_t dist_to_bend;
571  point_t bend_start, bend_end, bend_center;
572 
573  VSUB2(n1, curr_pt, pp2->pp_coord);
574  if (VNEAR_ZERO(n1, RT_LEN_TOL)) {
575  /* duplicate point, skip to next point */
576  goto next_pt;
577  }
578 
579  if (!pp3) {
580  /* last segment */
581  rt_linear_pipe_prep(elements_head, curr_pt, curr_id, curr_od, pp2->pp_coord, pp2->pp_id, pp2->pp_od, min, max);
582  break;
583  }
584 
585  VSUB2(n2, pp3->pp_coord, pp2->pp_coord);
586  VCROSS(norm, n1, n2);
587  VUNITIZE(n1);
588  VUNITIZE(n2);
589  angle = M_PI - acos(VDOT(n1, n2));
590  dist_to_bend = pp2->pp_bendradius * tan(angle / 2.0);
591  if (isnan(dist_to_bend) || VNEAR_ZERO(norm, SQRT_SMALL_FASTF) || NEAR_ZERO(dist_to_bend, SQRT_SMALL_FASTF)) {
592  /* points are collinear, treat as a linear segment */
593  rt_linear_pipe_prep(elements_head, curr_pt, curr_id, curr_od,
594  pp2->pp_coord, pp2->pp_id, pp2->pp_od, min, max);
595  VMOVE(curr_pt, pp2->pp_coord);
596  goto next_pt;
597  }
598 
599  VJOIN1(bend_start, pp2->pp_coord, dist_to_bend, n1);
600  VJOIN1(bend_end, pp2->pp_coord, dist_to_bend, n2);
601 
602  VUNITIZE(norm);
603 
604  /* linear section */
605  VSUB2(diff, curr_pt, bend_start);
606  if (MAGNITUDE(diff) <= RT_LEN_TOL) {
607  /* do not make linear sections that are too small to raytrace */
608  VMOVE(bend_start, curr_pt);
609  } else {
610  rt_linear_pipe_prep(elements_head, curr_pt, curr_id, curr_od,
611  bend_start, pp2->pp_id, pp2->pp_od, min, max);
612  }
613 
614  /* and bend section */
615  VCROSS(v1, n1, norm);
616  VJOIN1(bend_center, bend_start, -pp2->pp_bendradius, v1);
617  rt_bend_pipe_prep(elements_head, bend_center, bend_start, bend_end, pp2->pp_bendradius, angle,
618  pp2->pp_od, pp2->pp_id, pp1->pp_od, pp3->pp_od, min, max);
619 
620  VMOVE(curr_pt, bend_end);
621  next_pt:
622  if (!pp3) {
623  break;
624  }
625  curr_id = pp2->pp_id;
626  curr_od = pp2->pp_od;
627  pp1 = pp2;
628  pp2 = pp3;
629  pp3 = BU_LIST_NEXT(wdb_pipept, &pp3->l);
630  if (BU_LIST_IS_HEAD(&pp3->l, &(pip->pipe_segs_head))) {
631  pp3 = (struct wdb_pipept *)NULL;
632  }
633  }
634 }
635 
636 
637 HIDDEN void
639 {
640  if (head != 0) {
641  struct id_pipe *p;
642 
643  while (BU_LIST_WHILE(p, id_pipe, head)) {
644  BU_LIST_DEQUEUE(&(p->l));
645  if (p->pipe_is_bend) {
646  BU_PUT(p, struct lin_pipe);
647  } else {
648  BU_PUT(p, struct bend_pipe);
649  }
650  }
651  }
652 }
653 
654 
655 /**
656  * Calculate a bounding RPP for a pipe
657  */
658 int
660  struct rt_db_internal *ip,
661  point_t *min,
662  point_t *max,
663  const struct bn_tol *UNUSED(tol))
664 {
665  pipe_elements_calculate(NULL, ip, min, max);
666  return 0;
667 }
668 
669 
670 /**
671  * Given a pointer to a GED database record, and a transformation
672  * matrix, determine if this is a valid pipe solid, and if so,
673  * precompute various terms of the formula.
674  *
675  * Returns -
676  * 0 if pipe solid is OK
677  * !0 if there is an error in the description
678  *
679  * Implicit return -
680  * A struct bu_list is created, and its address is stored in
681  * stp->st_specific for use by pipe_shot().
682  */
683 int
684 rt_pipe_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
685 {
686  struct bu_list *head;
687  fastf_t dx, dy, dz, f;
688 
689  if (rtip) {
690  RT_CK_RTI(rtip);
691  }
692 
693  BU_GET(head, struct bu_list);
694  BU_LIST_INIT(head);
695 
696  pipe_elements_calculate(head, ip, &(stp->st_min), &(stp->st_max));
697 
698  stp->st_specific = (void *)head;
699 
700  VSET(stp->st_center,
701  (stp->st_max[X] + stp->st_min[X]) / 2,
702  (stp->st_max[Y] + stp->st_min[Y]) / 2,
703  (stp->st_max[Z] + stp->st_min[Z]) / 2);
704 
705  dx = (stp->st_max[X] - stp->st_min[X]) / 2;
706  f = dx;
707  dy = (stp->st_max[Y] - stp->st_min[Y]) / 2;
708  if (dy > f) {
709  f = dy;
710  }
711  dz = (stp->st_max[Z] - stp->st_min[Z]) / 2;
712  if (dz > f) {
713  f = dz;
714  }
715  stp->st_aradius = f;
716  stp->st_bradius = sqrt(dx * dx + dy * dy + dz * dz);
717 
718  return 0;
719 }
720 
721 
722 void
723 rt_pipe_print(const struct soltab *stp)
724 {
725  struct bu_list *head = (struct bu_list *)stp->st_specific;
726 
727  if (!head) {
728  return;
729  }
730 }
731 
732 
733 void
734 rt_pipept_print(const struct wdb_pipept *pipept, double mm2local)
735 {
736  point_t p1;
737 
738  bu_log("Pipe Vertex:\n");
739  VSCALE(p1, pipept->pp_coord, mm2local);
740  bu_log("\tat (%g %g %g)\n", V3ARGS(p1));
741  bu_log("\tbend radius = %g\n", pipept->pp_bendradius * mm2local);
742  if (pipept->pp_id > 0.0) {
743  bu_log("\tod=%g, id=%g\n",
744  pipept->pp_od * mm2local,
745  pipept->pp_id * mm2local);
746  } else {
747  bu_log("\tod=%g\n", pipept->pp_od * mm2local);
748  }
749 }
750 
751 
752 void
754  struct bu_vls *vp,
755  int seg_no,
756  const struct rt_db_internal *ip,
757  double mm2local)
758 {
759  struct rt_pipe_internal *pint;
760  struct wdb_pipept *pipept;
761  int seg_count = 0;
762  char buf[256];
763  point_t p1;
764 
765  pint = (struct rt_pipe_internal *)ip->idb_ptr;
766  RT_PIPE_CK_MAGIC(pint);
767 
768  pipept = BU_LIST_FIRST(wdb_pipept, &pint->pipe_segs_head);
769  while (++seg_count != seg_no && BU_LIST_NOT_HEAD(&pipept->l, &pint->pipe_segs_head)) {
770  pipept = BU_LIST_NEXT(wdb_pipept, &pipept->l);
771  }
772 
773 
774  sprintf(buf, "Pipe Vertex:\n");
775  bu_vls_strcat(vp, buf);
776  VSCALE(p1, pipept->pp_coord, mm2local);
777  sprintf(buf, "\tat (%g %g %g)\n", V3ARGS(p1));
778  bu_vls_strcat(vp, buf);
779  sprintf(buf, "\tbend radius = %g\n", pipept->pp_bendradius * mm2local);
780  bu_vls_strcat(vp, buf);
781  if (pipept->pp_id > 0.0) {
782  sprintf(buf, "\tod=%g, id=%g\n",
783  pipept->pp_od * mm2local,
784  pipept->pp_id * mm2local);
785  } else {
786  sprintf(buf, "\tod=%g\n", pipept->pp_od * mm2local);
787  }
788  bu_vls_strcat(vp, buf);
789 }
790 
791 
792 /**
793  * Check for hits on surfaces created by discontinuous radius changes
794  * from one pipe segment to the next. Can only happen when one segment
795  * is a bend, because linear segments handle different radii at each
796  * end. Bend segments must have constant radii . These surfaces are
797  * normal to the flow of the pipe.
798  */
799 HIDDEN void
801  struct xray *rp,
802  point_t center,
803  vect_t norm,
804  fastf_t or1_sq, fastf_t ir1_sq,
805  fastf_t or2_sq, fastf_t ir2_sq,
806  struct hit *hits,
807  int *hit_count,
808  int seg_no,
809  struct soltab *stp)
810 {
811  fastf_t dist_to_plane;
812  fastf_t norm_dist;
813  fastf_t slant_factor;
814  fastf_t t_tmp;
815  point_t hit_pt;
816  fastf_t radius_sq;
817 
818  /* calculate intersection with plane at center (with normal "norm") */
819  dist_to_plane = VDOT(norm, center);
820  norm_dist = dist_to_plane - VDOT(norm, rp->r_pt);
821  slant_factor = VDOT(norm, rp->r_dir);
822  if (!ZERO(slant_factor)) {
823  vect_t to_center;
824  struct hit *hitp;
825 
826  t_tmp = norm_dist / slant_factor;
827  VJOIN1(hit_pt, rp->r_pt, t_tmp, rp->r_dir);
828  VSUB2(to_center, center, hit_pt);
829  radius_sq = MAGSQ(to_center);
830 
831  /* where the radius ranges overlap, there is no hit */
832  if (radius_sq <= or1_sq && radius_sq >= ir1_sq &&
833  radius_sq <= or2_sq && radius_sq >= ir2_sq) {
834  return;
835  }
836 
837  /* if we are within one of the radius ranges, we have a hit */
838  if ((radius_sq <= or2_sq && radius_sq >= ir2_sq) ||
839  (radius_sq <= or1_sq && radius_sq >= ir1_sq)) {
840  hitp = &hits[*hit_count];
841  hitp->hit_magic = RT_HIT_MAGIC;
842  hitp->hit_dist = t_tmp;
843  hitp->hit_surfno = seg_no * 10 + PIPE_RADIUS_CHANGE;
844 
845  /* within first range, use norm, otherwise reverse */
846  if (radius_sq <= or1_sq && radius_sq >= ir1_sq) {
847  VMOVE(hitp->hit_normal, norm);
848  } else {
849  VREVERSE(hitp->hit_normal, norm);
850  }
851  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
852  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
853  return;
854  }
855  }
856  }
857 }
858 
859 
860 /**
861  * check if a ray passes within a bounding sphere
862  */
863 int
864 rt_in_sph(struct xray *rp, point_t center, fastf_t radius_sq)
865 {
866  vect_t toCenter;
867  vect_t toPCA;
868  fastf_t dist_sq;
869 
870  VSUB2(toCenter, center, rp->r_pt);
871  VCROSS(toPCA, toCenter, rp->r_dir);
872  dist_sq = MAGSQ(toPCA);
873 
874  if (dist_sq <= radius_sq) {
875  return 1;
876  } else {
877  return 0;
878  }
879 }
880 
881 
882 HIDDEN void
884  struct soltab *stp,
885  struct xray *rp,
886  struct bend_pipe *bp,
887  struct hit *hits,
888  int *hit_count,
889  int seg_no)
890 {
891  vect_t dprime; /* D' */
892  vect_t pprime; /* P' */
893  vect_t work; /* temporary vector */
894  bn_poly_t C; /* The final equation */
895  bn_complex_t val[4]; /* The complex roots */
896  int j;
897 
898  int root_count = 0;
899  bn_poly_t A, Asqr;
900  bn_poly_t X2_Y2; /* X**2 + Y**2 */
901  vect_t cor_pprime; /* new ray origin */
902  fastf_t cor_proj;
903  fastf_t or_sq; /* outside radius squared */
904  fastf_t ir_sq; /* inside radius squared */
905  fastf_t or2_sq; /* outside radius squared (from adjacent seg) */
906  fastf_t ir2_sq; /* inside radius squared (from adjacent seg) */
907  int parallel; /* set to one when ray is parallel to plane of bend */
908  fastf_t dist = 0; /* distance between ray and plane of bend */
909  fastf_t tmp;
910  struct id_pipe *prev;
911  struct id_pipe *next;
912 
913  or_sq = bp->bend_or * bp->bend_or;
914  ir_sq = bp->bend_ir * bp->bend_ir;
915 
916  tmp = VDOT(rp->r_dir, bp->bend_N);
917  if (NEAR_ZERO(tmp, 0.0000005)) {
918  /* ray is parallel to plane of bend */
919  parallel = 1;
920  dist = fabs(VDOT(rp->r_pt, bp->bend_N) -
921  VDOT(bp->bend_V, bp->bend_N));
922 
923  if (dist > bp->bend_or) {
924  /* ray is more than outer radius away from plane of bend */
925  goto check_discont_radii;
926  }
927  } else {
928  parallel = 0;
929  }
930 
931  /* Convert vector into the space of the unit torus */
932  MAT4X3VEC(dprime, bp->bend_SoR, rp->r_dir);
933  VUNITIZE(dprime);
934 
935  VSUB2(work, rp->r_pt, bp->bend_V);
936  MAT4X3VEC(pprime, bp->bend_SoR, work);
937 
938  /* normalize distance from torus. substitute corrected pprime
939  * which contains a translation along ray direction to closest
940  * approach to vertex of torus. Translating ray origin along
941  * direction of ray to closest pt. to origin of solid's coordinate
942  * system, new ray origin is 'cor_pprime'.
943  */
944  cor_proj = VDOT(pprime, dprime);
945  VSCALE(cor_pprime, dprime, cor_proj);
946  VSUB2(cor_pprime, pprime, cor_pprime);
947 
948  /*
949  * Given a line and a ratio, alpha, finds the equation of the unit
950  * torus in terms of the variable 't'.
951  *
952  * The equation for the torus is:
953  *
954  * [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*(X**2 + Y**2) = 0
955  *
956  * First, find X, Y, and Z in terms of 't' for this line, then
957  * substitute them into the equation above.
958  *
959  * Wx = Dx*t + Px
960  *
961  * Wx**2 = Dx**2 * t**2 + 2 * Dx * Px + Px**2
962  * [0] [1] [2] dgr=2
963  */
964  X2_Y2.dgr = 2;
965  X2_Y2.cf[0] = dprime[X] * dprime[X] + dprime[Y] * dprime[Y];
966  X2_Y2.cf[1] = 2.0 * (dprime[X] * cor_pprime[X] +
967  dprime[Y] * cor_pprime[Y]);
968  X2_Y2.cf[2] = cor_pprime[X] * cor_pprime[X] +
969  cor_pprime[Y] * cor_pprime[Y];
970 
971  /* A = X2_Y2 + Z2 */
972  A.dgr = 2;
973  A.cf[0] = X2_Y2.cf[0] + dprime[Z] * dprime[Z];
974  A.cf[1] = X2_Y2.cf[1] + 2.0 * dprime[Z] * cor_pprime[Z];
975  A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
976  1.0 - bp->bend_alpha_o * bp->bend_alpha_o;
977 
978  /* Inline expansion of (void) bn_poly_mul(&Asqr, &A, &A) */
979  /* Both polys have degree two */
980  Asqr.dgr = 4;
981  Asqr.cf[0] = A.cf[0] * A.cf[0];
982  Asqr.cf[1] = A.cf[0] * A.cf[1] + A.cf[1] * A.cf[0];
983  Asqr.cf[2] = A.cf[0] * A.cf[2] + A.cf[1] * A.cf[1] + A.cf[2] * A.cf[0];
984  Asqr.cf[3] = A.cf[1] * A.cf[2] + A.cf[2] * A.cf[1];
985  Asqr.cf[4] = A.cf[2] * A.cf[2];
986 
987  /* Inline expansion of bn_poly_scale(&X2_Y2, 4.0) and
988  * bn_poly_sub(&C, &Asqr, &X2_Y2).
989  */
990  C.dgr = 4;
991  C.cf[0] = Asqr.cf[0];
992  C.cf[1] = Asqr.cf[1];
993  C.cf[2] = Asqr.cf[2] - X2_Y2.cf[0] * 4.0;
994  C.cf[3] = Asqr.cf[3] - X2_Y2.cf[1] * 4.0;
995  C.cf[4] = Asqr.cf[4] - X2_Y2.cf[2] * 4.0;
996 
997  /* It is known that the equation is 4th order. Therefore, if the
998  * root finder returns other than 4 roots, error.
999  */
1000  if ((root_count = rt_poly_roots(&C, val, stp->st_dp->d_namep)) != 4) {
1001  if (root_count > 0) {
1002  bu_log("pipe: rt_poly_roots() 4!=%d\n", root_count);
1003  bn_pr_roots(stp->st_name, val, root_count);
1004  } else if (root_count < 0) {
1005  static int reported = 0;
1006  bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
1007  if (!reported) {
1008  VPRINT("while shooting from:\t", rp->r_pt);
1009  VPRINT("while shooting at:\t", rp->r_dir);
1010  bu_log("Additional pipe convergence failure details will be suppressed.\n");
1011  reported = 1;
1012  }
1013  }
1014  goto check_discont_radii; /* MISSED */
1015  }
1016 
1017  /* Only real roots indicate an intersection in real space.
1018  *
1019  * Look at each root returned; if the imaginary part is zero or
1020  * sufficiently close, then use the real part as one value of 't'
1021  * for the intersections
1022  */
1023  for (j = 0 ; j < 4; j++) {
1024  if (NEAR_ZERO(val[j].im, 0.0001)) {
1025  struct hit *hitp;
1026  fastf_t normalized_dist;
1027  fastf_t distance;
1028  point_t hit_pt;
1029  vect_t to_hit;
1030  fastf_t angle;
1031 
1032  normalized_dist = val[j].re - cor_proj;
1033  distance = normalized_dist * bp->bend_radius;
1034 
1035  /* check if this hit is within bend angle */
1036  VJOIN1(hit_pt, rp->r_pt, distance, rp->r_dir);
1037  VSUB2(to_hit, hit_pt, bp->bend_V);
1038  angle = atan2(VDOT(to_hit, bp->bend_rb), VDOT(to_hit, bp->bend_ra));
1039  if (angle < 0.0) {
1040  angle += M_2PI;
1041  }
1042  if (angle <= bp->bend_angle) {
1043  hitp = &hits[*hit_count];
1044  hitp->hit_magic = RT_HIT_MAGIC;
1045  hitp->hit_dist = distance;
1046  VJOIN1(hitp->hit_vpriv, pprime, normalized_dist, dprime);
1047  hitp->hit_surfno = seg_no * 10 + PIPE_BEND_OUTER_BODY;
1048 
1049  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1050  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1051  return;
1052  }
1053  }
1054  }
1055  }
1056 
1057  if (bp->bend_alpha_i <= 0.0) {
1058  goto check_discont_radii; /* no inner torus */
1059  }
1060 
1061  if (parallel && dist > bp->bend_ir) {
1062  /* ray is parallel to plane of bend and more than inner radius away */
1063  goto check_discont_radii;
1064  }
1065 
1066  /* Now do inner torus */
1067  A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
1068  1.0 - bp->bend_alpha_i * bp->bend_alpha_i;
1069 
1070  /* Inline expansion of (void) bn_poly_mul(&Asqr, &A, &A) */
1071  /* Both polys have degree two */
1072  Asqr.dgr = 4;
1073  Asqr.cf[0] = A.cf[0] * A.cf[0];
1074  Asqr.cf[1] = A.cf[0] * A.cf[1] + A.cf[1] * A.cf[0];
1075  Asqr.cf[2] = A.cf[0] * A.cf[2] + A.cf[1] * A.cf[1] + A.cf[2] * A.cf[0];
1076  Asqr.cf[3] = A.cf[1] * A.cf[2] + A.cf[2] * A.cf[1];
1077  Asqr.cf[4] = A.cf[2] * A.cf[2];
1078 
1079  /* Inline expansion of bn_poly_scale(&X2_Y2, 4.0) and
1080  * bn_poly_sub(&C, &Asqr, &X2_Y2).
1081  */
1082  C.dgr = 4;
1083  C.cf[0] = Asqr.cf[0];
1084  C.cf[1] = Asqr.cf[1];
1085  C.cf[2] = Asqr.cf[2] - X2_Y2.cf[0] * 4.0;
1086  C.cf[3] = Asqr.cf[3] - X2_Y2.cf[1] * 4.0;
1087  C.cf[4] = Asqr.cf[4] - X2_Y2.cf[2] * 4.0;
1088 
1089  /* It is known that the equation is 4th order. Therefore,
1090  * if the root finder returns other than 4 roots, error.
1091  */
1092  if ((root_count = rt_poly_roots(&C, val, stp->st_dp->d_namep)) != 4) {
1093  if (root_count > 0) {
1094  bu_log("tor: rt_poly_roots() 4!=%d\n", root_count);
1095  bn_pr_roots(stp->st_name, val, root_count);
1096  } else if (root_count < 0) {
1097  static int reported = 0;
1098  bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
1099  if (!reported) {
1100  VPRINT("while shooting from:\t", rp->r_pt);
1101  VPRINT("while shooting at:\t", rp->r_dir);
1102  bu_log("Additional pipe convergence failure details will be suppressed.\n");
1103  reported = 1;
1104  }
1105  }
1106  goto check_discont_radii; /* MISSED */
1107  }
1108 
1109  /* Only real roots indicate an intersection in real space.
1110  *
1111  * Look at each root returned; if the imaginary part is zero or
1112  * sufficiently close, then use the real part as one value of 't'
1113  * for the intersections
1114  */
1115  for (j = 0, root_count = 0; j < 4; j++) {
1116  if (NEAR_ZERO(val[j].im, 0.0001)) {
1117  struct hit *hitp;
1118  fastf_t normalized_dist;
1119  fastf_t distance;
1120  point_t hit_pt;
1121  vect_t to_hit;
1122  fastf_t angle;
1123 
1124  normalized_dist = val[j].re - cor_proj;
1125  distance = normalized_dist * bp->bend_radius;
1126 
1127  /* check if this hit is within bend angle */
1128  VJOIN1(hit_pt, rp->r_pt, distance, rp->r_dir);
1129  VSUB2(to_hit, hit_pt, bp->bend_V);
1130  angle = atan2(VDOT(to_hit, bp->bend_rb), VDOT(to_hit, bp->bend_ra));
1131  if (angle < 0.0) {
1132  angle += M_2PI;
1133  }
1134  if (angle <= bp->bend_angle) {
1135  hitp = &hits[*hit_count];
1136  hitp->hit_magic = RT_HIT_MAGIC;
1137  hitp->hit_dist = distance;
1138  VJOIN1(hitp->hit_vpriv, pprime, normalized_dist, dprime);
1139  hitp->hit_surfno = seg_no * 10 + PIPE_BEND_INNER_BODY;
1140 
1141  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1142  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1143  return;
1144  }
1145  }
1146  }
1147  }
1148 
1149 
1150 check_discont_radii:
1151  /* check for surfaces created by discontinuous changes in radii */
1152  prev = BU_LIST_BACK(id_pipe, &bp->l);
1153  if (prev->l.magic != BU_LIST_HEAD_MAGIC) {
1154  if (prev->pipe_is_bend) {
1155  /* do not process previous bend
1156  * struct bend_pipe *bend = (struct bend_pipe *)prev;
1157  * or2_sq = bend->bend_or*bend->bend_or;
1158  * ir2_sq = bend->bend_ir*bend->bend_ir; */
1159  or2_sq = or_sq;
1160  ir2_sq = ir_sq;
1161  } else {
1162  struct lin_pipe *lin = (struct lin_pipe *)prev;
1163  or2_sq = lin->pipe_rotop_sq;
1164  ir2_sq = lin->pipe_ritop_sq;
1165  if (!NEAR_EQUAL(or_sq, or2_sq, RT_LEN_TOL) ||
1166  !NEAR_EQUAL(ir_sq, ir2_sq, RT_LEN_TOL)) {
1168  or_sq, ir_sq, or2_sq, ir2_sq, hits, hit_count, seg_no, stp);
1169  }
1170  }
1171  }
1172 
1173  next = BU_LIST_NEXT(id_pipe, &bp->l);
1174  if (next->l.magic != BU_LIST_HEAD_MAGIC) {
1175  if (next->pipe_is_bend) {
1176  struct bend_pipe *bend = (struct bend_pipe *)next;
1177  or2_sq = bend->bend_or * bend->bend_or;
1178  ir2_sq = bend->bend_ir * bend->bend_ir;
1179  if (!NEAR_EQUAL(or_sq, or2_sq, RT_LEN_TOL) ||
1180  !NEAR_EQUAL(ir_sq, ir2_sq, RT_LEN_TOL)) {
1182  or_sq, ir_sq, or2_sq, ir2_sq, hits, hit_count, seg_no, stp);
1183  }
1184  } else {
1185  struct lin_pipe *lin = (struct lin_pipe *)next;
1186  or2_sq = lin->pipe_robase_sq;
1187  ir2_sq = lin->pipe_ribase_sq;
1188  if (!NEAR_EQUAL(or_sq, or2_sq, RT_LEN_TOL) ||
1189  !NEAR_EQUAL(ir_sq, ir2_sq, RT_LEN_TOL)) {
1191  or_sq, ir_sq, or2_sq, ir2_sq, hits, hit_count, seg_no, stp);
1192  }
1193  }
1194  }
1195 
1196 
1197  return;
1198 
1199 }
1200 
1201 
1202 HIDDEN void
1204  struct soltab *stp,
1205  struct xray *rp,
1206  struct lin_pipe *lp,
1207  struct hit *hits,
1208  int *hit_count,
1209  int seg_no)
1210 {
1211  struct hit *hitp;
1212  point_t work_pt;
1213  point_t ray_start;
1214  vect_t ray_dir;
1215  double t_tmp;
1216  double a, b, c;
1217  double descrim;
1218 
1219  if (lp->pipe_is_bend) {
1220  bu_log("linear_pipe_shot called for pipe bend\n");
1221  bu_bomb("linear_pipe_shot\n");
1222  }
1223 
1224  /* transform ray start point */
1225  VSUB2(work_pt, rp->r_pt, lp->pipe_V);
1226  MAT4X3VEC(ray_start, lp->pipe_SoR, work_pt);
1227 
1228  /* rotate ray direction */
1229  MAT4X3VEC(ray_dir, lp->pipe_SoR, rp->r_dir);
1230 
1231  /* Intersect with outer sides */
1232  a = ray_dir[X] * ray_dir[X]
1233  + ray_dir[Y] * ray_dir[Y]
1234  - ray_dir[Z] * ray_dir[Z] * lp->pipe_rodiff_sq;
1235  b = 2.0 * (ray_start[X] * ray_dir[X]
1236  + ray_start[Y] * ray_dir[Y]
1237  - ray_start[Z] * ray_dir[Z] * lp->pipe_rodiff_sq
1238  - ray_dir[Z] * lp->pipe_robase * lp->pipe_rodiff);
1239  c = ray_start[X] * ray_start[X]
1240  + ray_start[Y] * ray_start[Y]
1241  - lp->pipe_robase * lp->pipe_robase
1242  - ray_start[Z] * ray_start[Z] * lp->pipe_rodiff_sq
1243  - 2.0 * ray_start[Z] * lp->pipe_robase * lp->pipe_rodiff;
1244 
1245  descrim = b * b - 4.0 * a * c;
1246 
1247  if (descrim > 0.0) {
1248  fastf_t sqrt_descrim;
1249  point_t hit_pt;
1250 
1251  sqrt_descrim = sqrt(descrim);
1252 
1253  t_tmp = (-b - sqrt_descrim) / (2.0 * a);
1254  VJOIN1(hit_pt, ray_start, t_tmp, ray_dir);
1255  if (hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0) {
1256  hitp = &hits[*hit_count];
1257  hitp->hit_magic = RT_HIT_MAGIC;
1258  hitp->hit_dist = t_tmp;
1259  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_OUTER_BODY;
1260  VMOVE(hitp->hit_vpriv, hit_pt);
1261  hitp->hit_vpriv[Z] = (-lp->pipe_robase - hit_pt[Z] * lp->pipe_rodiff) *
1262  lp->pipe_rodiff;
1263 
1264  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1265  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1266  return;
1267  }
1268  }
1269 
1270  t_tmp = (-b + sqrt_descrim) / (2.0 * a);
1271  VJOIN1(hit_pt, ray_start, t_tmp, ray_dir);
1272  if (hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0) {
1273  hitp = &hits[*hit_count];
1274  hitp->hit_magic = RT_HIT_MAGIC;
1275  hitp->hit_dist = t_tmp;
1276  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_OUTER_BODY;
1277  VMOVE(hitp->hit_vpriv, hit_pt);
1278  hitp->hit_vpriv[Z] = (-lp->pipe_robase - hit_pt[Z] * lp->pipe_rodiff) *
1279  lp->pipe_rodiff;
1280 
1281  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1282  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1283  return;
1284  }
1285  }
1286  }
1287 
1288  if (lp->pipe_ribase > 0.0 || lp->pipe_ritop > 0.0) {
1289  /* Intersect with inner sides */
1290 
1291  a = ray_dir[X] * ray_dir[X]
1292  + ray_dir[Y] * ray_dir[Y]
1293  - ray_dir[Z] * ray_dir[Z] * lp->pipe_ridiff_sq;
1294  b = 2.0 * (ray_start[X] * ray_dir[X]
1295  + ray_start[Y] * ray_dir[Y]
1296  - ray_start[Z] * ray_dir[Z] * lp->pipe_ridiff_sq
1297  - ray_dir[Z] * lp->pipe_ribase * lp->pipe_ridiff);
1298  c = ray_start[X] * ray_start[X]
1299  + ray_start[Y] * ray_start[Y]
1300  - lp->pipe_ribase * lp->pipe_ribase
1301  - ray_start[Z] * ray_start[Z] * lp->pipe_ridiff_sq
1302  - 2.0 * ray_start[Z] * lp->pipe_ribase * lp->pipe_ridiff;
1303 
1304  descrim = b * b - 4.0 * a * c;
1305 
1306  if (descrim > 0.0) {
1307  fastf_t sqrt_descrim;
1308  point_t hit_pt;
1309 
1310  sqrt_descrim = sqrt(descrim);
1311 
1312  t_tmp = (-b - sqrt_descrim) / (2.0 * a);
1313  VJOIN1(hit_pt, ray_start, t_tmp, ray_dir);
1314  if (hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0) {
1315  hitp = &hits[*hit_count];
1316  hitp->hit_magic = RT_HIT_MAGIC;
1317  hitp->hit_dist = t_tmp;
1318  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_INNER_BODY;
1319  VMOVE(hitp->hit_vpriv, hit_pt);
1320  hitp->hit_vpriv[Z] = (-lp->pipe_ribase - hit_pt[Z] * lp->pipe_ridiff) *
1321  lp->pipe_ridiff;
1322 
1323  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1324  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1325  return;
1326  }
1327  }
1328 
1329  t_tmp = (-b + sqrt_descrim) / (2.0 * a);
1330  VJOIN1(hit_pt, ray_start, t_tmp, ray_dir);
1331  if (hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0) {
1332  hitp = &hits[*hit_count];
1333  hitp->hit_magic = RT_HIT_MAGIC;
1334  hitp->hit_dist = t_tmp;
1335  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_INNER_BODY;
1336  VMOVE(hitp->hit_vpriv, hit_pt);
1337  hitp->hit_vpriv[Z] = (-lp->pipe_ribase - hit_pt[Z] * lp->pipe_ridiff) *
1338  lp->pipe_ridiff;
1339 
1340  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1341  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1342  return;
1343  }
1344  }
1345  }
1346  }
1347 
1348 }
1349 
1350 
1351 HIDDEN void
1353  struct soltab *stp,
1354  struct xray *rp,
1355  struct id_pipe *id_p,
1356  struct hit *hits,
1357  int *hit_count,
1358  int seg_no)
1359 {
1360  point_t hit_pt;
1361  fastf_t t_tmp;
1362  fastf_t radius_sq;
1363  struct hit *hitp;
1364 
1365  if (!id_p->pipe_is_bend) {
1366  struct lin_pipe *lin = (struct lin_pipe *)(&id_p->l);
1367  fastf_t dist_to_plane;
1368  fastf_t norm_dist;
1369  fastf_t slant_factor;
1370 
1371  dist_to_plane = VDOT(lin->pipe_H, lin->pipe_V);
1372  norm_dist = dist_to_plane - VDOT(lin->pipe_H, rp->r_pt);
1373  slant_factor = VDOT(lin->pipe_H, rp->r_dir);
1374  if (!ZERO(slant_factor)) {
1375  vect_t to_center;
1376 
1377  t_tmp = norm_dist / slant_factor;
1378  VJOIN1(hit_pt, rp->r_pt, t_tmp, rp->r_dir);
1379  VSUB2(to_center, lin->pipe_V, hit_pt);
1380  radius_sq = MAGSQ(to_center);
1381  if (radius_sq <= lin->pipe_robase_sq && radius_sq >= lin->pipe_ribase_sq) {
1382  hitp = &hits[*hit_count];
1383  hitp->hit_magic = RT_HIT_MAGIC;
1384  hitp->hit_dist = t_tmp;
1385  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_BASE;
1386 
1387  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1388  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1389  return;
1390  }
1391  }
1392  }
1393  } else if (id_p->pipe_is_bend) {
1394  struct bend_pipe *bend = (struct bend_pipe *)(&id_p->l);
1395  fastf_t dist_to_plane;
1396  fastf_t norm_dist;
1397  fastf_t slant_factor;
1398 
1399  dist_to_plane = VDOT(bend->bend_rb, bend->bend_start);
1400  norm_dist = dist_to_plane - VDOT(bend->bend_rb, rp->r_pt);
1401  slant_factor = VDOT(bend->bend_rb, rp->r_dir);
1402 
1403  if (!ZERO(slant_factor)) {
1404  vect_t to_center;
1405 
1406  t_tmp = norm_dist / slant_factor;
1407  VJOIN1(hit_pt, rp->r_pt, t_tmp, rp->r_dir);
1408  VSUB2(to_center, bend->bend_start, hit_pt);
1409  radius_sq = MAGSQ(to_center);
1410  if (radius_sq <= bend->bend_or * bend->bend_or && radius_sq >= bend->bend_ir * bend->bend_ir) {
1411  hitp = &hits[*hit_count];
1412  hitp->hit_magic = RT_HIT_MAGIC;
1413  hitp->hit_dist = t_tmp;
1414  hitp->hit_surfno = seg_no * 10 + PIPE_BEND_BASE;
1415 
1416  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1417  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1418  return;
1419  }
1420  }
1421  }
1422  }
1423 }
1424 
1425 
1426 HIDDEN void
1428  struct soltab *stp,
1429  struct xray *rp,
1430  struct id_pipe *id_p,
1431  struct hit *hits,
1432  int *hit_count,
1433  int seg_no)
1434 {
1435  point_t hit_pt;
1436  fastf_t t_tmp;
1437  fastf_t radius_sq;
1438  struct hit *hitp;
1439 
1440  if (!id_p->pipe_is_bend) {
1441  struct lin_pipe *lin = (struct lin_pipe *)(&id_p->l);
1442  point_t top;
1443  fastf_t dist_to_plane;
1444  fastf_t norm_dist;
1445  fastf_t slant_factor;
1446 
1447  VJOIN1(top, lin->pipe_V, lin->pipe_len, lin->pipe_H);
1448  dist_to_plane = VDOT(lin->pipe_H, top);
1449  norm_dist = dist_to_plane - VDOT(lin->pipe_H, rp->r_pt);
1450  slant_factor = VDOT(lin->pipe_H, rp->r_dir);
1451  if (!ZERO(slant_factor)) {
1452  vect_t to_center;
1453 
1454  t_tmp = norm_dist / slant_factor;
1455  VJOIN1(hit_pt, rp->r_pt, t_tmp, rp->r_dir);
1456  VSUB2(to_center, top, hit_pt);
1457  radius_sq = MAGSQ(to_center);
1458  if (radius_sq <= lin->pipe_rotop_sq && radius_sq >= lin->pipe_ritop_sq) {
1459  hitp = &hits[*hit_count];
1460  hitp->hit_magic = RT_HIT_MAGIC;
1461  hitp->hit_dist = t_tmp;
1462  hitp->hit_surfno = seg_no * 10 + PIPE_LINEAR_TOP;
1463 
1464  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1465  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1466  return;
1467  }
1468  }
1469  }
1470  } else if (id_p->pipe_is_bend) {
1471  struct bend_pipe *bend = (struct bend_pipe *)(&id_p->l);
1472  vect_t to_end;
1473  vect_t plane_norm;
1474  fastf_t dist_to_plane;
1475  fastf_t norm_dist;
1476  fastf_t slant_factor;
1477 
1478  VSUB2(to_end, bend->bend_end, bend->bend_V);
1479  VCROSS(plane_norm, to_end, bend->bend_N);
1480  VUNITIZE(plane_norm);
1481 
1482  dist_to_plane = VDOT(plane_norm, bend->bend_end);
1483  norm_dist = dist_to_plane - VDOT(plane_norm, rp->r_pt);
1484  slant_factor = VDOT(plane_norm, rp->r_dir);
1485 
1486  if (!ZERO(slant_factor)) {
1487  vect_t to_center;
1488 
1489  t_tmp = norm_dist / slant_factor;
1490  VJOIN1(hit_pt, rp->r_pt, t_tmp, rp->r_dir);
1491  VSUB2(to_center, bend->bend_end, hit_pt);
1492  radius_sq = MAGSQ(to_center);
1493  if (radius_sq <= bend->bend_or * bend->bend_or && radius_sq >= bend->bend_ir * bend->bend_ir) {
1494  hitp = &hits[*hit_count];
1495  hitp->hit_magic = RT_HIT_MAGIC;
1496  hitp->hit_dist = t_tmp;
1497  hitp->hit_surfno = seg_no * 10 + PIPE_BEND_TOP;
1498 
1499  if ((*hit_count)++ >= RT_PIPE_MAXHITS) {
1500  bu_log("Too many hits (%d) on primitive (%s)\n", *hit_count, stp->st_dp->d_namep);
1501  return;
1502  }
1503  }
1504  }
1505  }
1506 }
1507 
1508 
1509 HIDDEN void
1511  struct hit *hit,
1512  int *nh,
1513  struct xray *rp,
1514  struct soltab *stp)
1515 {
1516  struct hit *hitp;
1517  struct hit *next_hit;
1518  int hitNo = 0;
1519 
1520  /* delete duplicate hits */
1521  while (hitNo < ((*nh) - 1)) {
1522  hitp = &hit[hitNo];
1523  next_hit = &hit[hitNo + 1];
1524 
1525  if (NEAR_EQUAL(hitp->hit_dist, next_hit->hit_dist, stp->st_rtip->rti_tol.dist) &&
1526  hitp->hit_surfno == next_hit->hit_surfno) {
1527  int i;
1528  for (i = hitNo ; i < (*nh-2) ; i++) {
1529  hit[i] = hit[i + 2];
1530  }
1531  (*nh)=(*nh)-2;
1532  } else {
1533  hitNo++;
1534  }
1535  }
1536 
1537  if ((*nh) == 1) {
1538  (*nh) = 0;
1539  return;
1540  }
1541 
1542  if ((*nh) == 0 || (*nh) == 2) {
1543  return;
1544  }
1545 
1546  hitNo = 0;
1547  while (hitNo < ((*nh) - 1)) {
1548  int hitNoPlus = hitNo + 1;
1549  /* struct hit *first = &hit[hitNo]; */
1550  struct hit *second = &hit[hitNoPlus];
1551 
1552  /* keep first entrance hit, eliminate all successive entrance hits */
1553  while (hitNoPlus < (*nh) && VDOT(second->hit_normal, rp->r_dir) < 0.0) {
1554  int j;
1555  for (j = hitNoPlus ; j < ((*nh) - 1) ; j++) {
1556  hit[j] = hit[j + 1];
1557  }
1558  (*nh)--;
1559  second = &hit[hitNoPlus];
1560  }
1561 
1562  /* second is now an exit hit at hit[hitNoPlus] */
1563 
1564  /* move to next hit */
1565  hitNoPlus++;
1566  if (hitNoPlus >= (*nh)) {
1567  break;
1568  }
1569 
1570  /* set second to the next hit */
1571  second = &hit[hitNoPlus];
1572 
1573  /* eliminate all exit hits (except the last one) till we find another entrance hit */
1574  while (hitNoPlus < (*nh) && VDOT(second->hit_normal, rp->r_dir) > 0.0) {
1575  int j;
1576  for (j = hitNoPlus - 1 ; j < ((*nh) - 1) ; j++) {
1577  hit[j] = hit[j + 1];
1578  }
1579  (*nh)--;
1580  second = &hit[hitNoPlus];
1581  }
1582  hitNo = hitNoPlus;
1583  }
1584 }
1585 
1586 
1587 /**
1588  * Given ONE ray distance, return the normal and entry/exit point.
1589  */
1590 void
1591 rt_pipe_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
1592 {
1593  struct bu_list *head = (struct bu_list *)stp->st_specific;
1594  struct id_pipe *pipe_id;
1595  struct lin_pipe *pipe_lin;
1596  struct bend_pipe *pipe_bend;
1597  fastf_t w;
1598  vect_t work;
1599  vect_t work1;
1600  int segno;
1601  int i;
1602 
1603  segno = hitp->hit_surfno / 10;
1604 
1605  pipe_id = BU_LIST_FIRST(id_pipe, head);
1606  for (i = 1; i < segno; i++) {
1607  pipe_id = BU_LIST_NEXT(id_pipe, &pipe_id->l);
1608  }
1609 
1610  pipe_lin = (struct lin_pipe *)pipe_id;
1611  pipe_bend = (struct bend_pipe *)pipe_id;
1612 
1613  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
1614  switch (hitp->hit_surfno % 10) {
1615  case PIPE_LINEAR_TOP:
1616  VMOVE(hitp->hit_normal, pipe_lin->pipe_H);
1617  break;
1618  case PIPE_LINEAR_BASE:
1619  VREVERSE(hitp->hit_normal, pipe_lin->pipe_H);
1620  break;
1622  MAT4X3VEC(hitp->hit_normal, pipe_lin->pipe_invRoS, hitp->hit_vpriv);
1623  VUNITIZE(hitp->hit_normal);
1624  break;
1626  MAT4X3VEC(hitp->hit_normal, pipe_lin->pipe_invRoS, hitp->hit_vpriv);
1627  VUNITIZE(hitp->hit_normal);
1628  VREVERSE(hitp->hit_normal, hitp->hit_normal);
1629  break;
1630  case PIPE_BEND_OUTER_BODY:
1631  w = hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
1632  hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] +
1633  hitp->hit_vpriv[Z] * hitp->hit_vpriv[Z] +
1634  1.0 - pipe_bend->bend_alpha_o * pipe_bend->bend_alpha_o;
1635  VSET(work,
1636  (w - 2.0) * hitp->hit_vpriv[X],
1637  (w - 2.0) * hitp->hit_vpriv[Y],
1638  w * hitp->hit_vpriv[Z]);
1639  VUNITIZE(work);
1640  MAT3X3VEC(hitp->hit_normal, pipe_bend->bend_invR, work);
1641  break;
1642  case PIPE_BEND_INNER_BODY:
1643  w = hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
1644  hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] +
1645  hitp->hit_vpriv[Z] * hitp->hit_vpriv[Z] +
1646  1.0 - pipe_bend->bend_alpha_i * pipe_bend->bend_alpha_i;
1647  VSET(work,
1648  (w - 2.0) * hitp->hit_vpriv[X],
1649  (w - 2.0) * hitp->hit_vpriv[Y],
1650  w * hitp->hit_vpriv[Z]);
1651  VUNITIZE(work);
1652  MAT3X3VEC(work1, pipe_bend->bend_invR, work);
1653  VREVERSE(hitp->hit_normal, work1);
1654  break;
1655  case PIPE_BEND_BASE:
1656  VREVERSE(hitp->hit_normal, pipe_bend->bend_rb);
1657  break;
1658  case PIPE_BEND_TOP:
1659  VSUB2(work, pipe_bend->bend_end, pipe_bend->bend_V);
1660  VCROSS(hitp->hit_normal, pipe_bend->bend_N, work);
1661  VUNITIZE(hitp->hit_normal);
1662  break;
1663  case PIPE_RADIUS_CHANGE:
1664  break; /* already have normal */
1665  default:
1666  bu_log("rt_pipe_norm: Unrecognized surfno (%d)\n", hitp->hit_surfno);
1667  break;
1668  }
1669 }
1670 
1671 
1672 /**
1673  * Intersect a ray with a pipe. If an intersection occurs, a struct
1674  * seg will be acquired and filled in.
1675  *
1676  * Returns -
1677  * 0 MISS
1678  * >0 HIT
1679  */
1680 int
1682  struct soltab *stp,
1683  struct xray *rp,
1684  struct application *ap,
1685  struct seg *seghead)
1686 {
1687  struct bu_list *head = (struct bu_list *)stp->st_specific;
1688  struct id_pipe *pipe_id;
1689  struct seg *segp;
1690  struct hit hits[RT_PIPE_MAXHITS];
1691  int total_hits = 0;
1692  int seg_no;
1693  int i;
1694 
1695  pipe_start_shot(stp, rp, BU_LIST_FIRST(id_pipe, head), hits, &total_hits, 1);
1696  seg_no = 0;
1697  for (BU_LIST_FOR(pipe_id, id_pipe, head)) {
1698  seg_no++;
1699  }
1700  pipe_end_shot(stp, rp, BU_LIST_LAST(id_pipe, head), hits, &total_hits, seg_no);
1701 
1702  seg_no = 0;
1703  for (BU_LIST_FOR(pipe_id, id_pipe, head)) {
1704  seg_no++;
1705 
1706  if (!pipe_id->pipe_is_bend) {
1707  struct lin_pipe *lin = (struct lin_pipe *)pipe_id;
1708  if (!rt_in_rpp(rp, ap->a_inv_dir, lin->pipe_min, lin->pipe_max)) {
1709  continue;
1710  }
1711  linear_pipe_shot(stp, rp, lin, hits, &total_hits, seg_no);
1712  } else {
1713  struct bend_pipe *bend = (struct bend_pipe *)pipe_id;
1714  if (!rt_in_sph(rp, bend->bend_bound_center, bend->bend_bound_radius_sq)) {
1715  continue;
1716  }
1717  bend_pipe_shot(stp, rp, bend, hits, &total_hits, seg_no);
1718  }
1719  }
1720  if (!total_hits) {
1721  return 0;
1722  }
1723 
1724  /* calculate hit points and normals */
1725  for (i = 0 ; i < total_hits ; i++) {
1726  rt_pipe_norm(&hits[i], stp, rp);
1727  }
1728 
1729  /* sort the hits */
1730  rt_hitsort(hits, total_hits);
1731 
1732  /* eliminate duplicate hits */
1733  rt_pipe_elim_dups(hits, &total_hits, rp, stp);
1734 
1735  /* Build segments */
1736  if (total_hits % 2) {
1737  bu_log("rt_pipe_shot: bad number of hits on solid %s (%d)\n", stp->st_dp->d_namep, total_hits);
1738  bu_log("Ignoring this solid for this ray\n");
1739  bu_log("\tray start = (%e %e %e), ray dir = (%e %e %e)\n", V3ARGS(rp->r_pt), V3ARGS(rp->r_dir));
1740  for (i = 0 ; i < total_hits ; i++) {
1741  point_t hit_pt;
1742 
1743  bu_log("#%d, dist = %g, surfno=%d\n", i, hits[i].hit_dist, hits[i].hit_surfno);
1744  VJOIN1(hit_pt, rp->r_pt, hits[i].hit_dist, rp->r_dir);
1745  bu_log("\t(%g %g %g)\n", V3ARGS(hit_pt));
1746  }
1747 
1748  return 0;
1749  }
1750 
1751  for (i = 0 ; i < total_hits ; i += 2) {
1752  RT_GET_SEG(segp, ap->a_resource);
1753 
1754  segp->seg_stp = stp;
1755  segp->seg_in = hits[i];
1756  segp->seg_out = hits[i + 1];
1757 
1758  BU_LIST_INSERT(&(seghead->l), &(segp->l));
1759  }
1760 
1761 
1762  if (total_hits) {
1763  return 1; /* HIT */
1764  } else {
1765  return 0; /* MISS */
1766  }
1767 }
1768 
1769 
1770 /**
1771  * Return the curvature of the pipe.
1772  */
1773 void
1774 rt_pipe_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
1775 {
1776  if (!cvp || !hitp) {
1777  return;
1778  }
1779  if (stp) {
1780  RT_CK_SOLTAB(stp);
1781  }
1782 
1783  cvp->crv_c1 = cvp->crv_c2 = 0;
1784 
1785  /* any tangent direction */
1786  bn_vec_ortho(cvp->crv_pdir, hitp->hit_normal);
1787 }
1788 
1789 
1790 /**
1791  * For a hit on the surface of an pipe, return the (u, v) coordinates
1792  * of the hit point, 0 <= u, v <= 1.
1793  * u = azimuth
1794  * v = elevation
1795  */
1796 void
1798  struct application *ap,
1799  struct soltab *stp,
1800  struct hit *hitp,
1801  struct uvcoord *uvp)
1802 {
1803  if (!ap || !stp || !hitp || !uvp) {
1804  return;
1805  }
1806 }
1807 
1808 
1809 void
1810 rt_pipe_free(struct soltab *stp)
1811 {
1812  if (stp != NULL) {
1813  pipe_elements_free((struct bu_list *)stp->st_specific);
1814  BU_PUT(stp->st_specific, struct bu_list);
1815  }
1816 }
1817 
1818 
1819 static int
1820 pipe_circle_segments(const struct rt_view_info *info, fastf_t radius)
1821 {
1822  int num_segments;
1823 
1824  num_segments = M_2PI * radius / info->point_spacing;
1825 
1826  if (num_segments < 5) {
1827  num_segments = 5;
1828  }
1829 
1830  return num_segments;
1831 }
1832 
1833 
1834 static int
1835 pipe_bend_segments(
1836  const struct rt_view_info *info,
1837  const struct pipe_bend *bend)
1838 {
1839  int num_segments;
1840  fastf_t arc_length;
1841 
1842  arc_length = (bend->bend_angle * M_1_2PI) * bend->bend_circle.radius;
1843  num_segments = arc_length / info->point_spacing;
1844 
1845  if (num_segments < 3) {
1846  num_segments = 3;
1847  }
1848 
1849  return num_segments;
1850 }
1851 
1852 
1853 static int
1854 pipe_connecting_arcs(
1855  struct rt_pipe_internal *pipeobj,
1856  const struct rt_view_info *info)
1857 {
1858  int dcount, num_arcs;
1859  struct pipe_segment *cur_seg;
1860  fastf_t avg_diameter, avg_circumference;
1861 
1862  RT_PIPE_CK_MAGIC(pipeobj);
1863  BU_CK_LIST_HEAD(info->vhead);
1864 
1865  cur_seg = pipe_seg_first(pipeobj);
1866  if (cur_seg == NULL) {
1867  return 0;
1868  }
1869 
1870  dcount = 0;
1871  avg_diameter = 0.0;
1872  while (!pipe_seg_is_last(cur_seg)) {
1873  avg_diameter += cur_seg->cur->pp_od;
1874  ++dcount;
1875 
1876  if (cur_seg->cur->pp_id > 0.0) {
1877  avg_diameter += cur_seg->cur->pp_id;
1878  ++dcount;
1879  }
1880 
1881  pipe_seg_advance(cur_seg);
1882  }
1883 
1884  avg_diameter += cur_seg->cur->pp_od;
1885  ++dcount;
1886 
1887  if (cur_seg->cur->pp_id > 0.0) {
1888  avg_diameter += cur_seg->cur->pp_id;
1889  ++dcount;
1890  }
1891 
1892  avg_diameter /= (double)dcount;
1893 
1894  BU_PUT(cur_seg, struct pipe_segment);
1895 
1896  avg_circumference = M_PI * avg_diameter;
1897  num_arcs = avg_circumference / info->curve_spacing;
1898 
1899  if (num_arcs < 4) {
1900  num_arcs = 4;
1901  }
1902 
1903  return num_arcs;
1904 }
1905 
1906 
1907 /**
1908  * Draw a pipe circle using a given number of segments.
1909  */
1910 static void
1911 draw_pipe_circle(
1912  struct bu_list *vhead,
1913  const struct pipe_circle *circle,
1914  int num_segments)
1915 {
1916  vect_t axis_a, axis_b;
1917 
1918  VSCALE(axis_a, circle->orient.v1, circle->radius);
1919  VSCALE(axis_b, circle->orient.v2, circle->radius);
1920 
1921  plot_ellipse(vhead, circle->center, axis_a, axis_b, num_segments);
1922 }
1923 
1924 
1925 /**
1926  * Draws the specified number of connecting lines between the start and end
1927  * circles, which are expected to be parallel (i.e. have the same orientation).
1928  */
1929 static void
1930 draw_pipe_parallel_circle_connections(
1931  struct bu_list *vhead,
1932  const struct pipe_circle *start,
1933  const struct pipe_circle *end,
1934  int num_lines)
1935 {
1936  int i;
1937  point_t pt;
1938  fastf_t radian, radian_step;
1939  vect_t start_a, start_b, end_a, end_b;
1940 
1941  BU_CK_LIST_HEAD(vhead);
1942 
1943  radian_step = M_2PI / num_lines;
1944 
1945  VSCALE(start_a, start->orient.v1, start->radius);
1946  VSCALE(start_b, start->orient.v2, start->radius);
1947  VSCALE(end_a, end->orient.v1, end->radius);
1948  VSCALE(end_b, end->orient.v2, end->radius);
1949 
1950  radian = 0.0;
1951  for (i = 0; i < num_lines; ++i) {
1952  ellipse_point_at_radian(pt, start->center, start_a, start_b, radian);
1953  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
1954 
1955  ellipse_point_at_radian(pt, end->center, end_a, end_b, radian);
1956  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
1957 
1958  radian += radian_step;
1959  }
1960 }
1961 
1962 
1963 static void
1964 draw_pipe_connect_points_linearly(
1965  struct bu_list *vhead,
1966  const struct wdb_pipept *startpt,
1967  const struct wdb_pipept *endpt,
1968  const struct pipe_orientation *orient,
1969  int num_connections)
1970 {
1971  struct pipe_circle start_circle, end_circle;
1972 
1973  start_circle.orient = end_circle.orient = *orient; /* struct copy */
1974 
1975  VMOVE(start_circle.center, startpt->pp_coord);
1976  VMOVE(end_circle.center, endpt->pp_coord);
1977 
1978  /* connect outer circles */
1979  start_circle.radius = startpt->pp_od / 2.0;
1980  end_circle.radius = endpt->pp_od / 2.0;
1981  draw_pipe_parallel_circle_connections(vhead, &start_circle, &end_circle,
1982  num_connections);
1983 
1984  /* connect inner circles */
1985  if (startpt->pp_id > 0.0 && endpt->pp_id > 0.0) {
1986  start_circle.radius = startpt->pp_id / 2.0;
1987  end_circle.radius = endpt->pp_id / 2.0;
1988  draw_pipe_parallel_circle_connections(vhead, &start_circle, &end_circle,
1989  num_connections);
1990  }
1991 }
1992 
1993 
1994 static void
1995 draw_pipe_linear_seg(
1996  struct bu_list *vhead,
1997  struct pipe_segment *seg)
1998 {
1999  struct wdb_pipept startpt, endpt;
2000 
2001  endpt = *seg->cur;
2002  startpt = *BU_LIST_PREV(wdb_pipept, &seg->cur->l);
2003  VMOVE(startpt.pp_coord, seg->last_drawn);
2004 
2005  draw_pipe_connect_points_linearly(vhead, &startpt, &endpt, &seg->orient,
2006  seg->connecting_arcs);
2007 
2008  VMOVE(seg->last_drawn, endpt.pp_coord);
2009 }
2010 
2011 
2012 /**
2013  * Using the specified number of segments, draw the shortest arc on the given
2014  * circle which starts at (center + radius * v1) and ends at (arc_end).
2015  */
2016 HIDDEN void
2018  struct bu_list *vhead,
2019  struct pipe_circle arc_circle,
2020  const point_t arc_end,
2021  int num_segments)
2022 {
2023  int i;
2024  point_t pt;
2025  vect_t center_to_start, center_to_end, axis_a, axis_b;
2026  fastf_t radians_from_start_to_end, radian, radian_step;
2027 
2028  BU_CK_LIST_HEAD(vhead);
2029 
2030  VSCALE(axis_a, arc_circle.orient.v1, arc_circle.radius);
2031  VSCALE(axis_b, arc_circle.orient.v2, arc_circle.radius);
2032  VMOVE(center_to_start, arc_circle.orient.v1);
2033  VSUB2(center_to_end, arc_end, arc_circle.center);
2034  VUNITIZE(center_to_end);
2035 
2036  radians_from_start_to_end = acos(VDOT(center_to_start, center_to_end));
2037  radian_step = radians_from_start_to_end / num_segments;
2038 
2039  ellipse_point_at_radian(pt, arc_circle.center, axis_a, axis_b, 0.0);
2040  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
2041 
2042  radian = radian_step;
2043  for (i = 0; i < num_segments; ++i) {
2044  ellipse_point_at_radian(pt, arc_circle.center, axis_a, axis_b, radian);
2045  RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
2046 
2047  radian += radian_step;
2048  }
2049 }
2050 
2051 
2052 static void
2053 pipe_seg_bend(struct pipe_bend *out_bend, const struct pipe_segment *seg)
2054 {
2055  fastf_t dist_to_bend_end;
2056  vect_t cur_to_prev, cur_to_next;
2057  struct wdb_pipept *prevpt, *curpt, *nextpt;
2058 
2059  out_bend->pipe_circle.orient = seg->orient;
2060  out_bend->bend_angle = pipe_seg_bend_angle(seg);
2061  pipe_seg_bend_normal(out_bend->bend_normal, seg);
2062 
2063  curpt = seg->cur;
2064  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
2065  nextpt = BU_LIST_NEXT(wdb_pipept, &curpt->l);
2066 
2067  VSUB2(cur_to_prev, prevpt->pp_coord, curpt->pp_coord);
2068  VSUB2(cur_to_next, nextpt->pp_coord, curpt->pp_coord);
2069  VUNITIZE(cur_to_prev);
2070  VUNITIZE(cur_to_next);
2071 
2072  dist_to_bend_end = pipe_seg_dist_to_bend_endpoint(seg);
2073  VJOIN1(out_bend->bend_start, curpt->pp_coord, dist_to_bend_end, cur_to_prev);
2074  VJOIN1(out_bend->bend_end, curpt->pp_coord, dist_to_bend_end, cur_to_next);
2075 
2076  out_bend->bend_circle.radius = curpt->pp_bendradius;
2077  VCROSS(out_bend->bend_circle.orient.v1, cur_to_prev, out_bend->bend_normal);
2078  VCROSS(out_bend->bend_circle.orient.v2, out_bend->bend_circle.orient.v1,
2079  out_bend->bend_normal);
2080  VJOIN1(out_bend->bend_circle.center, out_bend->bend_start, -out_bend->bend_circle.radius,
2081  out_bend->bend_circle.orient.v1);
2082 }
2083 
2084 
2085 static struct pipe_orientation
2086 draw_pipe_connect_circular_segs(
2087  struct bu_list *vhead,
2088  const struct pipe_bend *bend,
2089  int num_arcs,
2090  int segs_per_arc)
2091 {
2092  int i;
2093  mat_t rot_mat;
2094  struct pipe_circle arc_circle;
2095  struct pipe_orientation end_orient;
2096  point_t bend_center, bend_start, bend_end, pipe_pt, arc_start, arc_end;
2097  vect_t bend_norm, center_to_start;
2098  vect_t pipe_axis_a, pipe_axis_b, pipe_r, end_pipe_r;
2099  fastf_t pipe_radius, bend_circle_offset, radian_step, radian;
2100 
2101  BU_CK_LIST_HEAD(vhead);
2102 
2103  /* short names */
2104  VMOVE(bend_center, bend->bend_circle.center);
2105  VMOVE(bend_norm, bend->bend_normal);
2106  VMOVE(bend_start, bend->bend_start);
2107  VMOVE(bend_end, bend->bend_end);
2108 
2109  pipe_radius = bend->pipe_circle.radius;
2110  VSCALE(pipe_axis_a, bend->pipe_circle.orient.v1, pipe_radius);
2111  VSCALE(pipe_axis_b, bend->pipe_circle.orient.v2, pipe_radius);
2112 
2113  /* calculate matrix to rotate vectors around the bend */
2114  {
2115  vect_t reverse_norm;
2116  VREVERSE(reverse_norm, bend_norm);
2117  bn_mat_arb_rot(rot_mat, bend_center, reverse_norm, bend->bend_angle);
2118  }
2119 
2120  arc_circle.orient = bend->bend_circle.orient;
2121 
2122  radian_step = M_2PI / num_arcs;
2123  radian = 0.0;
2124  for (i = 0; i < num_arcs; ++i) {
2125  /* get a vector from the pipe center (bend start) to a point on the
2126  * pipe circle
2127  */
2128  ellipse_point_at_radian(pipe_pt, bend_start, pipe_axis_a, pipe_axis_b,
2129  radian);
2130  VSUB2(pipe_r, pipe_pt, bend_start);
2131 
2132  /* Project the pipe vector onto the bend circle normal to get an
2133  * offset from the bend circle plane. Move that distance along the
2134  * bend circle normal to find the center of the arc circle.
2135  */
2136  bend_circle_offset = VDOT(pipe_r, bend_norm);
2137  VJOIN1(arc_circle.center, bend_center, bend_circle_offset, bend_norm);
2138 
2139  /* rotate the vector around the bend to its final position */
2140  MAT4X3VEC(end_pipe_r, rot_mat, pipe_r);
2141 
2142  /* draw an arc between the start and end positions of the pipe vector */
2143  VADD2(arc_start, bend_start, pipe_r);
2144  VADD2(arc_end, bend_end, end_pipe_r);
2145  VSUB2(center_to_start, arc_start, arc_circle.center);
2146  arc_circle.radius = MAGNITUDE(center_to_start);
2147  draw_pipe_arc(vhead, arc_circle, arc_end, segs_per_arc);
2148 
2149  radian += radian_step;
2150  }
2151 
2152  /* return the final orientation of the pipe circle */
2153  MAT4X3VEC(end_pipe_r, rot_mat, bend->pipe_circle.orient.v1);
2154  VMOVE(end_orient.v1, end_pipe_r);
2155 
2156  MAT4X3VEC(end_pipe_r, rot_mat, bend->pipe_circle.orient.v2);
2157  VMOVE(end_orient.v2, end_pipe_r);
2158 
2159  return end_orient;
2160 }
2161 
2162 
2163 static void
2164 draw_pipe_circular_seg(struct bu_list *vhead, struct pipe_segment *seg)
2165 {
2166  struct pipe_bend bend;
2167  struct wdb_pipept *prevpt, *curpt, startpt, endpt;
2168 
2169  pipe_seg_bend(&bend, seg);
2170 
2171  curpt = seg->cur;
2172  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
2173 
2174  /* draw linear segment to start of bend */
2175  startpt = *prevpt;
2176  endpt = *curpt;
2177  VMOVE(startpt.pp_coord, seg->last_drawn);
2178  VMOVE(endpt.pp_coord, bend.bend_start);
2179 
2180  draw_pipe_connect_points_linearly(vhead, &startpt, &endpt, &seg->orient,
2182 
2183  VMOVE(seg->last_drawn, bend.bend_start);
2184 
2185  /* draw circular bend */
2186  bend.pipe_circle.radius = curpt->pp_od / 2.0;
2187  seg->orient = draw_pipe_connect_circular_segs(vhead, &bend,
2189 
2190  if (prevpt->pp_id > 0.0 && curpt->pp_id > 0.0) {
2191  bend.pipe_circle.radius = curpt->pp_id / 2.0;
2192  seg->orient = draw_pipe_connect_circular_segs(vhead, &bend,
2194  }
2195 
2196  VMOVE(seg->last_drawn, bend.bend_end);
2197 }
2198 
2199 
2200 static void
2201 draw_pipe_circular_seg_adaptive(
2202  struct bu_list *vhead,
2203  struct pipe_segment *seg,
2204  const struct rt_view_info *info)
2205 {
2206  int num_segments;
2207  struct pipe_bend bend;
2208  struct wdb_pipept *prevpt, *curpt, startpt, endpt;
2209 
2210  pipe_seg_bend(&bend, seg);
2211 
2212  curpt = seg->cur;
2213  prevpt = BU_LIST_PREV(wdb_pipept, &curpt->l);
2214 
2215  /* draw linear segment to start of bend */
2216  startpt = *prevpt;
2217  endpt = *curpt;
2218  VMOVE(startpt.pp_coord, seg->last_drawn);
2219  VMOVE(endpt.pp_coord, bend.bend_start);
2220 
2221  draw_pipe_connect_points_linearly(vhead, &startpt, &endpt, &seg->orient,
2222  seg->connecting_arcs);
2223 
2224  VMOVE(seg->last_drawn, bend.bend_start);
2225 
2226  /* draw circular bend */
2227  bend.pipe_circle.radius = curpt->pp_od / 2.0;
2228  num_segments = pipe_bend_segments(info, &bend);
2229  seg->orient = draw_pipe_connect_circular_segs(vhead, &bend,
2230  seg->connecting_arcs, num_segments);
2231 
2232  if (prevpt->pp_id > 0.0 && curpt->pp_id > 0.0) {
2233  bend.pipe_circle.radius = curpt->pp_id / 2.0;
2234  num_segments = pipe_bend_segments(info, &bend);
2235  seg->orient = draw_pipe_connect_circular_segs(vhead, &bend,
2236  seg->connecting_arcs, num_segments);
2237  }
2238 
2239  VMOVE(seg->last_drawn, bend.bend_end);
2240 }
2241 
2242 
2243 static void
2244 draw_pipe_end(struct bu_list *vhead, struct pipe_segment *seg)
2245 {
2246  struct wdb_pipept *endpt;
2247  struct pipe_circle pipe_circle;
2248 
2249  endpt = seg->cur;
2250 
2251  VMOVE(pipe_circle.center, endpt->pp_coord);
2252  pipe_circle.orient = seg->orient;
2253 
2254  /* draw outer circle */
2255  pipe_circle.radius = endpt->pp_od / 2.0;
2256  draw_pipe_circle(vhead, &pipe_circle, PIPE_CIRCLE_SEGS);
2257 
2258  /* draw inner circle */
2259  if (endpt->pp_id > 0.0) {
2260  pipe_circle.radius = endpt->pp_id / 2.0;
2261  draw_pipe_circle(vhead, &pipe_circle, PIPE_CIRCLE_SEGS);
2262  }
2263 
2264  VMOVE(seg->last_drawn, endpt->pp_coord);
2265 }
2266 
2267 
2268 static void
2269 draw_pipe_end_adaptive(
2270  struct bu_list *vhead,
2271  struct pipe_segment *seg,
2272  const struct rt_view_info *info)
2273 {
2274  int num_segments;
2275  struct wdb_pipept *endpt;
2276  struct pipe_circle pipe_circle;
2277 
2278  endpt = seg->cur;
2279 
2280  VMOVE(pipe_circle.center, endpt->pp_coord);
2281  pipe_circle.orient = seg->orient;
2282 
2283  /* draw outer circle */
2284  pipe_circle.radius = endpt->pp_od / 2.0;
2285  num_segments = pipe_circle_segments(info, pipe_circle.radius);
2286  draw_pipe_circle(vhead, &pipe_circle, num_segments);
2287 
2288  /* draw inner circle */
2289  if (endpt->pp_id > 0.0) {
2290  pipe_circle.radius = endpt->pp_id / 2.0;
2291  num_segments = pipe_circle_segments(info, pipe_circle.radius);
2292  draw_pipe_circle(vhead, &pipe_circle, num_segments);
2293  }
2294 
2295  VMOVE(seg->last_drawn, endpt->pp_coord);
2296 }
2297 
2298 
2299 int
2301  struct rt_db_internal *ip,
2302  const struct rt_view_info *info)
2303 {
2304  struct rt_pipe_internal *pipeobj;
2305  struct pipe_segment *cur_seg;
2306 
2307  BU_CK_LIST_HEAD(info->vhead);
2308  RT_CK_DB_INTERNAL(ip);
2309  pipeobj = (struct rt_pipe_internal *)ip->idb_ptr;
2310  RT_PIPE_CK_MAGIC(pipeobj);
2311 
2312  cur_seg = pipe_seg_first(pipeobj);
2313  if (cur_seg == NULL) {
2314  return 0;
2315  }
2316 
2317  cur_seg->connecting_arcs = pipe_connecting_arcs(pipeobj, info);
2318 
2319  draw_pipe_end_adaptive(info->vhead, cur_seg, info);
2320  pipe_seg_advance(cur_seg);
2321 
2322  while (!pipe_seg_is_last(cur_seg)) {
2323  if (pipe_seg_is_bend(cur_seg)) {
2324  draw_pipe_circular_seg_adaptive(info->vhead, cur_seg, info);
2325  } else {
2326  draw_pipe_linear_seg(info->vhead, cur_seg);
2327  }
2328 
2329  pipe_seg_advance(cur_seg);
2330  }
2331 
2332  draw_pipe_linear_seg(info->vhead, cur_seg);
2333  draw_pipe_end_adaptive(info->vhead, cur_seg, info);
2334 
2335  BU_PUT(cur_seg, struct pipe_segment);
2336 
2337  return 0;
2338 }
2339 
2340 
2341 int
2343  struct bu_list *vhead,
2344  struct rt_db_internal *ip,
2345  const struct rt_tess_tol *UNUSED(ttol),
2346  const struct bn_tol *UNUSED(tol),
2347  const struct rt_view_info *UNUSED(info))
2348 {
2349  struct rt_pipe_internal *pip;
2350  struct pipe_segment *cur_seg;
2351 
2352  BU_CK_LIST_HEAD(vhead);
2353  RT_CK_DB_INTERNAL(ip);
2354  pip = (struct rt_pipe_internal *)ip->idb_ptr;
2355  RT_PIPE_CK_MAGIC(pip);
2356 
2357  cur_seg = pipe_seg_first(pip);
2358  if (cur_seg == NULL) {
2359  return 0;
2360  }
2361 
2363 
2364  draw_pipe_end(vhead, cur_seg);
2365  pipe_seg_advance(cur_seg);
2366 
2367  while (!pipe_seg_is_last(cur_seg)) {
2368  if (pipe_seg_is_bend(cur_seg)) {
2369  draw_pipe_circular_seg(vhead, cur_seg);
2370  } else {
2371  draw_pipe_linear_seg(vhead, cur_seg);
2372  }
2373 
2374  pipe_seg_advance(cur_seg);
2375  }
2376 
2377  draw_pipe_linear_seg(vhead, cur_seg);
2378  draw_pipe_end(vhead, cur_seg);
2379 
2380  BU_PUT(cur_seg, struct pipe_segment);
2381 
2382  return 0;
2383 }
2384 
2385 
2386 HIDDEN void
2388  struct wdb_pipept *pipept,
2389  int arc_segs,
2390  double sin_del,
2391  double cos_del,
2392  struct vertex ***outer_loop,
2393  struct vertex ***inner_loop,
2394  fastf_t *r1,
2395  fastf_t *r2,
2396  struct shell *s,
2397  const struct bn_tol *tol)
2398 {
2399  struct faceuse *fu;
2400  struct loopuse *lu;
2401  struct edgeuse *eu;
2402  struct wdb_pipept *next;
2403  point_t pt;
2404  fastf_t orad;
2405  fastf_t irad;
2406  fastf_t x, y, xnew, ynew;
2407  vect_t n;
2408  int i;
2409 
2410  NMG_CK_SHELL(s);
2411  BN_CK_TOL(tol);
2412 
2413  next = BU_LIST_NEXT(wdb_pipept, &pipept->l);
2414 
2415  VSUB2(n, pipept->pp_coord, next->pp_coord);
2416  VUNITIZE(n);
2417  bn_vec_ortho(r1, n);
2418  VCROSS(r2, n, r1);
2419 
2420  orad = pipept->pp_od / 2.0;
2421  irad = pipept->pp_id / 2.0;
2422 
2423  if (orad <= tol->dist) {
2424  return;
2425  }
2426 
2427  if (irad > orad) {
2428  bu_log("Inner radius larger than outer radius at start of pipe solid\n");
2429  return;
2430  }
2431 
2432  if (NEAR_EQUAL(irad, orad , tol->dist)) {
2433  return;
2434  }
2435 
2436 
2437  fu = nmg_cface(s, *outer_loop, arc_segs);
2438 
2439  x = orad;
2440  y = 0.0;
2441  i = (-1);
2442  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
2443  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2444  VJOIN2(pt, pipept->pp_coord, x, r1, y, r2);
2445  (*outer_loop)[++i] = eu->vu_p->v_p;
2446  nmg_vertex_gv(eu->vu_p->v_p, pt);
2447  xnew = x * cos_del - y * sin_del;
2448  ynew = x * sin_del + y * cos_del;
2449  x = xnew;
2450  y = ynew;
2451  }
2452 
2453  if (irad > tol->dist) {
2454  struct edgeuse *new_eu;
2455  struct vertexuse *vu;
2456 
2457  /* create a loop of a single vertex using the first vertex from the inner loop */
2458  lu = nmg_mlv(&fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE);
2459 
2460  vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
2461  eu = nmg_meonvu(vu);
2462  (*inner_loop)[0] = eu->vu_p->v_p;
2463 
2464  x = irad;
2465  y = 0.0;
2466  VJOIN2(pt, pipept->pp_coord, x, r1, y, r2);
2467  nmg_vertex_gv((*inner_loop)[0], pt);
2468  /* split edges in loop for each vertex in inner loop */
2469  for (i = 1; i < arc_segs; i++) {
2470  new_eu = nmg_eusplit((struct vertex *)NULL, eu, 0);
2471  (*inner_loop)[i] = new_eu->vu_p->v_p;
2472  xnew = x * cos_del - y * sin_del;
2473  ynew = x * sin_del + y * cos_del;
2474  x = xnew;
2475  y = ynew;
2476  VJOIN2(pt, pipept->pp_coord, x, r1, y, r2);
2477  nmg_vertex_gv((*inner_loop)[i], pt);
2478  }
2479  } else if (next->pp_id > tol->dist) {
2480  struct vertexuse *vu;
2481 
2482  /* make a loop of a single vertex in this face */
2483  lu = nmg_mlv(&fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE);
2484  vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
2485 
2486  nmg_vertex_gv(vu->v_p, pipept->pp_coord);
2487  }
2488 
2489  if (nmg_calc_face_g(fu)) {
2490  bu_bomb("tesselate_pipe_start: nmg_calc_face_g failed\n");
2491  }
2492 
2493  for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
2494  NMG_CK_LOOPUSE(lu);
2495 
2496  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) {
2497  continue;
2498  }
2499 
2500  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2501  NMG_CK_EDGEUSE(eu);
2502  eu->e_p->is_real = 1;
2503  }
2504  }
2505 }
2506 
2507 
2508 HIDDEN void
2510  fastf_t *start_pt, fastf_t orad, fastf_t irad,
2511  fastf_t *end_pt, fastf_t end_orad, fastf_t end_irad,
2512  int arc_segs,
2513  double sin_del,
2514  double cos_del,
2515  struct vertex ***outer_loop,
2516  struct vertex ***inner_loop,
2517  fastf_t *r1,
2518  fastf_t *r2,
2519  struct shell *s,
2520  const struct bn_tol *tol)
2521 {
2522  struct vertex **new_outer_loop;
2523  struct vertex **new_inner_loop;
2524  struct vertex **verts[3];
2525  struct faceuse *fu;
2526  vect_t *norms;
2527  vect_t n;
2528  fastf_t slope;
2529  fastf_t seg_len;
2530  int i, j;
2531 
2532  NMG_CK_SHELL(s);
2533  BN_CK_TOL(tol);
2534 
2535  norms = (vect_t *)bu_calloc(arc_segs, sizeof(vect_t), "tesselate_pipe_linear: new normals");
2536 
2537  if (end_orad > tol->dist) {
2538  new_outer_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
2539  "tesselate_pipe_linear: new_outer_loop");
2540  } else {
2541  new_outer_loop = (struct vertex **)NULL;
2542  }
2543 
2544  if (end_irad > tol->dist) {
2545  new_inner_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
2546  "tesselate_pipe_linear: new_inner_loop");
2547  } else {
2548  new_inner_loop = (struct vertex **)NULL;
2549  }
2550 
2551  VSUB2(n, end_pt, start_pt);
2552  seg_len = MAGNITUDE(n);
2553  VSCALE(n, n, 1.0 / seg_len);
2554  slope = (orad - end_orad) / seg_len;
2555 
2556  if (orad > tol->dist && end_orad > tol->dist) {
2557  point_t pt;
2558  fastf_t x, y, xnew, ynew;
2559  struct faceuse *fu_prev = (struct faceuse *)NULL;
2560 
2561  x = 1.0;
2562  y = 0.0;
2563  VCOMB2(norms[0], x, r1, y, r2);
2564  VJOIN1(norms[0], norms[0], slope, n);
2565  VUNITIZE(norms[0]);
2566  for (i = 0; i < arc_segs; i++) {
2567  j = i + 1;
2568  if (j == arc_segs) {
2569  j = 0;
2570  }
2571 
2572  VJOIN2(pt, end_pt, x * end_orad, r1, y * end_orad, r2);
2573  xnew = x * cos_del - y * sin_del;
2574  ynew = x * sin_del + y * cos_del;
2575  x = xnew;
2576  y = ynew;
2577  if (i < arc_segs - 1) {
2578  VCOMB2(norms[j], x, r1, y, r2);
2579  VJOIN1(norms[j], norms[j], slope, n);
2580  VUNITIZE(norms[j]);
2581  }
2582 
2583  if (fu_prev) {
2584  nmg_vertex_gv(new_outer_loop[i], pt);
2585  if (nmg_calc_face_g(fu_prev)) {
2586  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2587  nmg_kfu(fu_prev);
2588  } else {
2589  /* assign vertexuse normals */
2590  struct loopuse *lu;
2591  struct edgeuse *eu;
2592 
2593  NMG_CK_FACEUSE(fu_prev);
2594 
2595  if (fu_prev->orientation != OT_SAME) {
2596  fu_prev = fu_prev->fumate_p;
2597  }
2598 
2599  lu = BU_LIST_FIRST(loopuse, &fu_prev->lu_hd);
2600 
2601  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2602  vect_t reverse_norm;
2603  struct edgeuse *eu_opp_use;
2604 
2605  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2606  if (eu->vu_p->v_p == new_outer_loop[i - 1]) {
2607  nmg_vertexuse_nv(eu->vu_p, norms[i - 1]);
2608  VREVERSE(reverse_norm, norms[i - 1]);
2609  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2610  } else if (eu->vu_p->v_p == (*outer_loop)[i - 1]) {
2611  nmg_vertexuse_nv(eu->vu_p, norms[i - 1]);
2612  VREVERSE(reverse_norm, norms[i - 1]);
2613  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2614  } else if (eu->vu_p->v_p == new_outer_loop[i]) {
2615  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2616  VREVERSE(reverse_norm, norms[i]);
2617  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2618  } else if (eu->vu_p->v_p == (*outer_loop)[i]) {
2619  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2620  VREVERSE(reverse_norm, norms[i]);
2621  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2622  } else {
2623  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2624  bu_log("\ti=%d, arc_segs=%d, fu_prev = %p\n", i, arc_segs, (void *)fu_prev);
2625  }
2626  }
2627  }
2628  }
2629 
2630  verts[0] = &(*outer_loop)[j];
2631  verts[1] = &(*outer_loop)[i];
2632  verts[2] = &new_outer_loop[i];
2633 
2634  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
2635  bu_log("tesselate_pipe_linear: failed to make outer face #%d orad=%g, end_orad=%g\n",
2636  i, orad , end_orad);
2637  continue;
2638  }
2639  if (!new_outer_loop[i]->vg_p) {
2640  nmg_vertex_gv(new_outer_loop[i], pt);
2641  }
2642 
2643  if (nmg_calc_face_g(fu)) {
2644  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2645  nmg_kfu(fu);
2646  } else {
2647  /* assign vertexuse normals */
2648  struct loopuse *lu;
2649  struct edgeuse *eu;
2650 
2651  NMG_CK_FACEUSE(fu);
2652 
2653  if (fu->orientation != OT_SAME) {
2654  fu = fu->fumate_p;
2655  }
2656 
2657  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
2658 
2659  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2660  vect_t reverse_norm;
2661  struct edgeuse *eu_opp_use;
2662 
2663  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2664  if (eu->vu_p->v_p == (*outer_loop)[0]) {
2665  nmg_vertexuse_nv(eu->vu_p, norms[0]);
2666  VREVERSE(reverse_norm, norms[0]);
2667  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2668  } else if (eu->vu_p->v_p == new_outer_loop[i]) {
2669  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2670  VREVERSE(reverse_norm, norms[i]);
2671  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2672  } else if (eu->vu_p->v_p == (*outer_loop)[i]) {
2673  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2674  VREVERSE(reverse_norm, norms[i]);
2675  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2676  } else if (eu->vu_p->v_p == (*outer_loop)[j]) {
2677  nmg_vertexuse_nv(eu->vu_p, norms[j]);
2678  VREVERSE(reverse_norm, norms[j]);
2679  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2680  } else {
2681  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2682  bu_log("\ti=%d, arc_segs=%d, fu = %p\n", i, arc_segs, (void *)fu);
2683  }
2684  }
2685  }
2686 
2687  verts[1] = verts[2];
2688  verts[2] = &new_outer_loop[j];
2689 
2690  if ((fu_prev = nmg_cmface(s, verts, 3)) == NULL) {
2691  bu_log("tesselate_pipe_linear: failed to make outer face #%d orad=%g, end_orad=%g\n",
2692  i, orad , end_orad);
2693  continue;
2694  }
2695  if (i == arc_segs - 1) {
2696  if (nmg_calc_face_g(fu_prev)) {
2697  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2698  nmg_kfu(fu_prev);
2699  }
2700  }
2701  }
2702  bu_free((char *)(*outer_loop), "tesselate_pipe_bend: outer_loop");
2703  *outer_loop = new_outer_loop;
2704  } else if (orad > tol->dist && end_orad <= tol->dist) {
2705  struct vertex *v = (struct vertex *)NULL;
2706 
2707  VSUB2(norms[0], (*outer_loop)[0]->vg_p->coord, start_pt);
2708  VJOIN1(norms[0], norms[0], slope * orad , n);
2709  VUNITIZE(norms[0]);
2710  for (i = 0; i < arc_segs; i++) {
2711  j = i + 1;
2712  if (j == arc_segs) {
2713  j = 0;
2714  }
2715 
2716  verts[0] = &(*outer_loop)[j];
2717  verts[1] = &(*outer_loop)[i];
2718  verts[2] = &v;
2719 
2720  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
2721  bu_log("tesselate_pipe_linear: failed to make outer face #%d orad=%g, end_orad=%g\n",
2722  i, orad , end_orad);
2723  continue;
2724  }
2725  if (i == 0) {
2726  nmg_vertex_gv(v, end_pt);
2727  }
2728 
2729  if (i < arc_segs - 1) {
2730  VSUB2(norms[j], (*outer_loop)[j]->vg_p->coord, start_pt);
2731  VJOIN1(norms[j], norms[j], slope * orad , n);
2732  VUNITIZE(norms[j]);
2733  }
2734 
2735  if (nmg_calc_face_g(fu)) {
2736  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2737  nmg_kfu(fu);
2738  } else {
2739  struct loopuse *lu;
2740  struct edgeuse *eu;
2741  struct edgeuse *eu_opp_use;
2742  vect_t reverse_norm;
2743 
2744  NMG_CK_FACEUSE(fu);
2745  if (fu->orientation != OT_SAME) {
2746  fu = fu->fumate_p;
2747  }
2748 
2749  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
2750  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2751  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2752  if (eu->vu_p->v_p == (*outer_loop)[i]) {
2753  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2754  VREVERSE(reverse_norm, norms[i]);
2755  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2756  } else if (eu->vu_p->v_p == (*outer_loop)[j]) {
2757  nmg_vertexuse_nv(eu->vu_p, norms[j]);
2758  VREVERSE(reverse_norm, norms[j]);
2759  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2760  } else if (eu->vu_p->v_p == v) {
2761  vect_t tmp_norm;
2762  VBLEND2(tmp_norm, 0.5, norms[i], 0.5, norms[j]);
2763  VUNITIZE(tmp_norm);
2764  nmg_vertexuse_nv(eu->vu_p, tmp_norm);
2765  VREVERSE(reverse_norm, tmp_norm);
2766  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2767  } else {
2768  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2769  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
2770  }
2771  }
2772  }
2773  }
2774 
2775  bu_free((char *)(*outer_loop), "tesselate_pipe_linear: outer_loop");
2776  outer_loop[0] = &v;
2777  } else if (orad <= tol->dist && end_orad > tol->dist) {
2778  point_t pt, pt_next;
2779  fastf_t x, y, xnew, ynew;
2780 
2781  x = 1.0;
2782  y = 0.0;
2783  VCOMB2(norms[0], x, r1, y, r2);
2784  VJOIN1(pt_next, end_pt, end_orad, norms[0]);
2785  VJOIN1(norms[0], norms[0], slope, n);
2786  VUNITIZE(norms[0]);
2787  for (i = 0; i < arc_segs; i++) {
2788  j = i + 1;
2789  if (j == arc_segs) {
2790  j = 0;
2791  }
2792 
2793  VMOVE(pt, pt_next);
2794  xnew = x * cos_del - y * sin_del;
2795  ynew = x * sin_del + y * cos_del;
2796  x = xnew;
2797  y = ynew;
2798  if (i < j) {
2799  VCOMB2(norms[j], x, r1, y, r2);
2800  VJOIN1(pt_next, end_pt, end_orad, norms[j]);
2801  VJOIN1(norms[j], norms[j], slope, n);
2802  VUNITIZE(norms[j]);
2803  }
2804 
2805  verts[0] = &(*outer_loop)[0];
2806  verts[1] = &new_outer_loop[i];
2807  verts[2] = &new_outer_loop[j];
2808 
2809  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
2810  bu_log("tesselate_pipe_linear: failed to make outer face #%d orad=%g, end_orad=%g\n",
2811  i, orad , end_orad);
2812  continue;
2813  }
2814  if (!(*outer_loop)[0]->vg_p) {
2815  nmg_vertex_gv((*outer_loop)[0], start_pt);
2816  }
2817  if (!new_outer_loop[i]->vg_p) {
2818  nmg_vertex_gv(new_outer_loop[i], pt);
2819  }
2820  if (!new_outer_loop[j]->vg_p) {
2821  nmg_vertex_gv(new_outer_loop[j], pt_next);
2822  }
2823  if (nmg_calc_face_g(fu)) {
2824  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2825  nmg_kfu(fu);
2826  } else {
2827  struct loopuse *lu;
2828  struct edgeuse *eu;
2829  struct edgeuse *eu_opp_use;
2830  vect_t reverse_norm;
2831 
2832  NMG_CK_FACEUSE(fu);
2833  if (fu->orientation != OT_SAME) {
2834  fu = fu->fumate_p;
2835  }
2836 
2837  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
2838  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2839  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2840  if (eu->vu_p->v_p == new_outer_loop[i]) {
2841  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2842  VREVERSE(reverse_norm, norms[i]);
2843  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2844  } else if (eu->vu_p->v_p == new_outer_loop[j]) {
2845  nmg_vertexuse_nv(eu->vu_p, norms[j]);
2846  VREVERSE(reverse_norm, norms[j]);
2847  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2848  } else if (eu->vu_p->v_p == (*outer_loop)[0]) {
2849  vect_t tmp_norm;
2850  VBLEND2(tmp_norm, 0.5, norms[i], 0.5, norms[j]);
2851  VUNITIZE(tmp_norm);
2852  nmg_vertexuse_nv(eu->vu_p, tmp_norm);
2853  VREVERSE(reverse_norm, tmp_norm);
2854  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2855  } else {
2856  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2857  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
2858  }
2859  }
2860  }
2861  }
2862  bu_free((char *)(*outer_loop), "tesselate_pipe_linear: outer_loop");
2863  *outer_loop = new_outer_loop;
2864  }
2865 
2866  slope = (irad - end_irad) / seg_len;
2867 
2868  if (irad > tol->dist && end_irad > tol->dist) {
2869  point_t pt;
2870  fastf_t x, y, xnew, ynew;
2871  struct faceuse *fu_prev = (struct faceuse *)NULL;
2872 
2873  x = 1.0;
2874  y = 0.0;
2875  VCOMB2(norms[0], -x, r1, -y, r2);
2876  VJOIN1(norms[0], norms[0], -slope, n);
2877  VUNITIZE(norms[0]);
2878  for (i = 0; i < arc_segs; i++) {
2879  j = i + 1;
2880  if (j == arc_segs) {
2881  j = 0;
2882  }
2883 
2884  VJOIN2(pt, end_pt, x * end_irad, r1, y * end_irad, r2);
2885  xnew = x * cos_del - y * sin_del;
2886  ynew = x * sin_del + y * cos_del;
2887  x = xnew;
2888  y = ynew;
2889  if (i < arc_segs - 1) {
2890  VCOMB2(norms[j], -x, r1, -y, r2);
2891  VJOIN1(norms[j], norms[j], -slope, n);
2892  VUNITIZE(norms[j]);
2893  }
2894 
2895  if (fu_prev) {
2896  nmg_vertex_gv(new_inner_loop[i], pt);
2897  if (nmg_calc_face_g(fu_prev)) {
2898  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2899  nmg_kfu(fu_prev);
2900  } else {
2901  /* assign vertexuse normals */
2902  struct loopuse *lu;
2903  struct edgeuse *eu;
2904 
2905  NMG_CK_FACEUSE(fu_prev);
2906 
2907  if (fu_prev->orientation != OT_SAME) {
2908  fu_prev = fu_prev->fumate_p;
2909  }
2910 
2911  lu = BU_LIST_FIRST(loopuse, &fu_prev->lu_hd);
2912 
2913  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2914  vect_t reverse_norm;
2915  struct edgeuse *eu_opp_use;
2916 
2917  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2918  if (eu->vu_p->v_p == new_inner_loop[i - 1]) {
2919  nmg_vertexuse_nv(eu->vu_p, norms[i - 1]);
2920  VREVERSE(reverse_norm, norms[i - 1]);
2921  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2922  } else if (eu->vu_p->v_p == (*inner_loop)[i - 1]) {
2923  nmg_vertexuse_nv(eu->vu_p, norms[i - 1]);
2924  VREVERSE(reverse_norm, norms[i - 1]);
2925  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2926  } else if (eu->vu_p->v_p == new_inner_loop[i]) {
2927  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2928  VREVERSE(reverse_norm, norms[i]);
2929  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2930  } else if (eu->vu_p->v_p == (*inner_loop)[i]) {
2931  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2932  VREVERSE(reverse_norm, norms[i]);
2933  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2934  } else {
2935  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2936  bu_log("\ti=%d, arc_segs=%d, fu_prev = %p\n", i, arc_segs, (void *)fu_prev);
2937  }
2938  }
2939  }
2940  }
2941 
2942  verts[0] = &(*inner_loop)[j];
2943  verts[1] = &new_inner_loop[i];
2944  verts[2] = &(*inner_loop)[i];
2945 
2946  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
2947  bu_log("tesselate_pipe_linear: failed to make inner face #%d irad=%g, end_irad=%g\n",
2948  i, irad, end_irad);
2949  continue;
2950  }
2951  if (!new_inner_loop[i]->vg_p) {
2952  nmg_vertex_gv(new_inner_loop[i], pt);
2953  }
2954 
2955  if (nmg_calc_face_g(fu)) {
2956  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
2957  nmg_kfu(fu);
2958  } else {
2959  /* assign vertexuse normals */
2960  struct loopuse *lu;
2961  struct edgeuse *eu;
2962 
2963  NMG_CK_FACEUSE(fu);
2964 
2965  if (fu->orientation != OT_SAME) {
2966  fu = fu->fumate_p;
2967  }
2968 
2969  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
2970 
2971  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
2972  vect_t reverse_norm;
2973  struct edgeuse *eu_opp_use;
2974 
2975  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
2976  if (eu->vu_p->v_p == (*inner_loop)[0]) {
2977  nmg_vertexuse_nv(eu->vu_p, norms[0]);
2978  VREVERSE(reverse_norm, norms[0]);
2979  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2980  } else if (eu->vu_p->v_p == new_inner_loop[i]) {
2981  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2982  VREVERSE(reverse_norm, norms[i]);
2983  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2984  } else if (eu->vu_p->v_p == (*inner_loop)[i]) {
2985  nmg_vertexuse_nv(eu->vu_p, norms[i]);
2986  VREVERSE(reverse_norm, norms[i]);
2987  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2988  } else if (eu->vu_p->v_p == (*inner_loop)[j]) {
2989  nmg_vertexuse_nv(eu->vu_p, norms[j]);
2990  VREVERSE(reverse_norm, norms[j]);
2991  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
2992  } else {
2993  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
2994  bu_log("\ti=%d, arc_segs=%d, fu = %p\n", i, arc_segs, (void *)fu);
2995  }
2996  }
2997  }
2998 
2999  verts[2] = verts[0];
3000  verts[0] = verts[1];
3001  verts[1] = verts[2];
3002  if (i == arc_segs - 1) {
3003  verts[2] = &new_inner_loop[0];
3004  } else {
3005  verts[2] = &new_inner_loop[j];
3006  }
3007  if ((fu_prev = nmg_cmface(s, verts, 3)) == NULL) {
3008  bu_log("tesselate_pipe_linear: failed to make inner face #%d irad=%g, end_irad=%g\n",
3009  i, irad, end_irad);
3010  continue;
3011  }
3012  if (i == arc_segs - 1) {
3013  if (nmg_calc_face_g(fu_prev)) {
3014  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
3015  nmg_kfu(fu_prev);
3016  }
3017  }
3018 
3019  }
3020  bu_free((char *)(*inner_loop), "tesselate_pipe_bend: inner_loop");
3021  *inner_loop = new_inner_loop;
3022  } else if (irad > tol->dist && end_irad <= tol->dist) {
3023  struct vertex *v = (struct vertex *)NULL;
3024 
3025  VSUB2(norms[0], (*inner_loop)[0]->vg_p->coord, start_pt);
3026  VJOIN1(norms[0], norms[0], -slope * irad, n);
3027  VUNITIZE(norms[0]);
3028  VREVERSE(norms[0], norms[0]);
3029  for (i = 0; i < arc_segs; i++) {
3030  j = i + 1;
3031  if (j == arc_segs) {
3032  j = 0;
3033  }
3034 
3035  verts[0] = &(*inner_loop)[i];
3036  verts[1] = &(*inner_loop)[j];
3037  verts[2] = &v;
3038 
3039  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3040  bu_log("tesselate_pipe_linear: failed to make inner face #%d irad=%g, end_irad=%g\n",
3041  i, irad, end_irad);
3042  continue;
3043  }
3044  if (i == 0) {
3045  nmg_vertex_gv(v, end_pt);
3046  }
3047 
3048  if (i < arc_segs - 1) {
3049  VSUB2(norms[j], (*inner_loop)[j]->vg_p->coord, start_pt);
3050  VJOIN1(norms[j], norms[j], -slope * irad, n);
3051  VUNITIZE(norms[j]);
3052  VREVERSE(norms[j], norms[j]);
3053  }
3054 
3055  if (nmg_calc_face_g(fu)) {
3056  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
3057  nmg_kfu(fu);
3058  } else {
3059  struct loopuse *lu;
3060  struct edgeuse *eu;
3061  struct edgeuse *eu_opp_use;
3062  vect_t reverse_norm;
3063 
3064  NMG_CK_FACEUSE(fu);
3065  if (fu->orientation != OT_SAME) {
3066  fu = fu->fumate_p;
3067  }
3068 
3069  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3070  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3071  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3072  if (eu->vu_p->v_p == (*inner_loop)[i]) {
3073  nmg_vertexuse_nv(eu->vu_p, norms[i]);
3074  VREVERSE(reverse_norm, norms[i]);
3075  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3076  } else if (eu->vu_p->v_p == (*inner_loop)[j]) {
3077  nmg_vertexuse_nv(eu->vu_p, norms[j]);
3078  VREVERSE(reverse_norm, norms[j]);
3079  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3080  } else if (eu->vu_p->v_p == v) {
3081  vect_t tmp_norm;
3082  VBLEND2(tmp_norm, 0.5, norms[i], 0.5, norms[j]);
3083  VUNITIZE(tmp_norm);
3084  nmg_vertexuse_nv(eu->vu_p, tmp_norm);
3085  VREVERSE(reverse_norm, tmp_norm);
3086  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3087  } else {
3088  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3089  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3090  }
3091  }
3092  }
3093  }
3094 
3095  bu_free((char *)(*inner_loop), "tesselate_pipe_linear: inner_loop");
3096  inner_loop[0] = &v;
3097  } else if (irad <= tol->dist && end_irad > tol->dist) {
3098  point_t pt, pt_next;
3099  fastf_t x, y, xnew, ynew;
3100 
3101  x = 1.0;
3102  y = 0.0;
3103  VCOMB2(norms[0], -x, r1, -y, r2);
3104  VJOIN1(pt_next, end_pt, -end_irad, norms[0]);
3105  VJOIN1(norms[0], norms[0], -slope, n);
3106  VUNITIZE(norms[0]);
3107  for (i = 0; i < arc_segs; i++) {
3108  j = i + 1;
3109  if (j == arc_segs) {
3110  j = 0;
3111  }
3112 
3113  VMOVE(pt, pt_next);
3114  xnew = x * cos_del - y * sin_del;
3115  ynew = x * sin_del + y * cos_del;
3116  x = xnew;
3117  y = ynew;
3118  if (i < j) {
3119  VCOMB2(norms[j], -x, r1, -y, r2);
3120  VJOIN1(pt_next, end_pt, -end_irad, norms[j]);
3121  VJOIN1(norms[j], norms[j], -slope, n);
3122  VUNITIZE(norms[j]);
3123  }
3124 
3125  verts[0] = &new_inner_loop[j];
3126  verts[1] = &new_inner_loop[i];
3127  verts[2] = &(*inner_loop)[0];
3128 
3129  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3130  bu_log("tesselate_pipe_linear: failed to make inner face #%d irad=%g, end_irad=%g\n",
3131  i, irad, end_irad);
3132  continue;
3133  }
3134  if (!(*inner_loop)[0]->vg_p) {
3135  nmg_vertex_gv((*inner_loop)[0], start_pt);
3136  }
3137  if (!new_inner_loop[i]->vg_p) {
3138  nmg_vertex_gv(new_inner_loop[i], pt);
3139  }
3140  if (!new_inner_loop[j]->vg_p) {
3141  nmg_vertex_gv(new_inner_loop[j], pt_next);
3142  }
3143  if (nmg_calc_face_g(fu)) {
3144  bu_log("tesselate_pipe_linear: nmg_calc_face_g failed\n");
3145  nmg_kfu(fu);
3146  } else {
3147  struct loopuse *lu;
3148  struct edgeuse *eu;
3149  struct edgeuse *eu_opp_use;
3150  vect_t reverse_norm;
3151 
3152  NMG_CK_FACEUSE(fu);
3153  if (fu->orientation != OT_SAME) {
3154  fu = fu->fumate_p;
3155  }
3156 
3157  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3158  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3159  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3160  if (eu->vu_p->v_p == new_inner_loop[i]) {
3161  nmg_vertexuse_nv(eu->vu_p, norms[i]);
3162  VREVERSE(reverse_norm, norms[i]);
3163  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3164  } else if (eu->vu_p->v_p == new_inner_loop[j]) {
3165  nmg_vertexuse_nv(eu->vu_p, norms[j]);
3166  VREVERSE(reverse_norm, norms[j]);
3167  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3168  } else if (eu->vu_p->v_p == (*inner_loop)[0]) {
3169  vect_t tmp_norm;
3170  VBLEND2(tmp_norm, 0.5, norms[i], 0.5, norms[j]);
3171  VUNITIZE(tmp_norm);
3172  nmg_vertexuse_nv(eu->vu_p, tmp_norm);
3173  VREVERSE(reverse_norm, tmp_norm);
3174  nmg_vertexuse_nv(eu_opp_use->vu_p, reverse_norm);
3175  } else {
3176  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3177  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3178  }
3179  }
3180  }
3181  }
3182  bu_free((char *)(*inner_loop), "tesselate_pipe_linear: inner_loop");
3183  *inner_loop = new_inner_loop;
3184  }
3185  bu_free((char *)norms, "tesselate_linear_pipe: norms");
3186 }
3187 
3188 
3189 HIDDEN void
3191  fastf_t *bend_start,
3192  fastf_t *bend_end,
3193  fastf_t *bend_center,
3194  fastf_t orad,
3195  fastf_t irad,
3196  int arc_segs,
3197  double sin_del,
3198  double cos_del,
3199  struct vertex ***outer_loop,
3200  struct vertex ***inner_loop,
3201  fastf_t *start_r1,
3202  fastf_t *start_r2,
3203  struct shell *s,
3204  const struct bn_tol *tol,
3205  const struct rt_tess_tol *ttol)
3206 {
3207  struct vertex **new_outer_loop = NULL;
3208  struct vertex **new_inner_loop = NULL;
3209  struct vert_root *vertex_tree = NULL;
3210  struct vertex **vertex_array = NULL;
3211  fastf_t bend_radius;
3212  fastf_t bend_angle;
3213  fastf_t x, y, xnew, ynew;
3214  fastf_t delta_angle;
3215  mat_t rot;
3216  vect_t b1;
3217  vect_t b2;
3218  vect_t r1, r2;
3219  vect_t r1_tmp, r2_tmp;
3220  vect_t bend_norm;
3221  vect_t to_start;
3222  vect_t to_end;
3223  vect_t norm;
3224  point_t origin;
3225  point_t center;
3226  point_t old_center;
3227  int bend_segs = 1; /* minimum number of edges along bend */
3228  int bend_seg;
3229  int tol_segs;
3230  int i, j, k;
3231 
3232  NMG_CK_SHELL(s);
3233  BN_CK_TOL(tol);
3234  RT_CK_TESS_TOL(ttol);
3235  vertex_tree = create_vert_tree();
3236 
3237  VMOVE(r1, start_r1);
3238  VMOVE(r2, start_r2);
3239 
3240  /* Calculate vector b1, unit vector in direction from
3241  * bend center to start point
3242  */
3243  VSUB2(to_start, bend_start, bend_center);
3244  bend_radius = MAGNITUDE(to_start);
3245  VSCALE(b1, to_start, 1.0 / bend_radius);
3246 
3247  /* bend_norm is normal to plane of bend */
3248  VSUB2(to_end, bend_end, bend_center);
3249  VCROSS(bend_norm, b1, to_end);
3250  VUNITIZE(bend_norm);
3251 
3252  /* b1, b2, and bend_norm form a RH coord, system */
3253  VCROSS(b2, bend_norm, b1);
3254 
3255  bend_angle = atan2(VDOT(to_end, b2), VDOT(to_end, b1));
3256  if (bend_angle < 0.0) {
3257  bend_angle += M_2PI;
3258  }
3259 
3260  /* calculate number of segments to use along bend */
3261  if (ttol->abs > 0.0 && ttol->abs < bend_radius + orad) {
3262  tol_segs = ceil(bend_angle / (2.0 * acos(1.0 - ttol->abs / (bend_radius + orad))));
3263  if (tol_segs > bend_segs) {
3264  bend_segs = tol_segs;
3265  }
3266  }
3267  if (ttol->rel > 0.0) {
3268  tol_segs = ceil(bend_angle / (2.0 * acos(1.0 - ttol->rel)));
3269  if (tol_segs > bend_segs) {
3270  bend_segs = tol_segs;
3271  }
3272  }
3273  if (ttol->norm > 0.0) {
3274  tol_segs = ceil(bend_angle / (2.0 * ttol->norm));
3275  if (tol_segs > bend_segs) {
3276  bend_segs = tol_segs;
3277  }
3278  }
3279 
3280  /* add starting loops to the vertex tree */
3281  vertex_array = (struct vertex **)bu_calloc((bend_segs + 1) * arc_segs, sizeof(struct vertex *), "vertex array in pipe.c");
3282  for (i = 0 ; i < arc_segs ; i++) {
3283  struct vertex *v = (*outer_loop)[i];
3284  struct vertex_g *vg = v->vg_p;
3285  j = Add_vert(vg->coord[X], vg->coord[Y], vg->coord[Z], vertex_tree, tol->dist_sq);
3286  vertex_array[j] = v;
3287  }
3288 
3289  delta_angle = bend_angle / (fastf_t)(bend_segs);
3290 
3291  VSETALL(origin, 0.0);
3292  bn_mat_arb_rot(rot, origin, bend_norm, delta_angle);
3293 
3294  VMOVE(old_center, bend_start);
3295  for (bend_seg = 0; bend_seg < bend_segs; bend_seg++) {
3296 
3297  new_outer_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
3298  "tesselate_pipe_bend(): new_outer_loop");
3299 
3300  MAT4X3VEC(r1_tmp, rot, r1);
3301  MAT4X3VEC(r2_tmp, rot, r2);
3302  VMOVE(r1, r1_tmp);
3303  VMOVE(r2, r2_tmp);
3304 
3305  VSUB2(r1_tmp, old_center, bend_center);
3306  MAT4X3PNT(r2_tmp, rot, r1_tmp);
3307  VADD2(center, r2_tmp, bend_center);
3308 
3309  x = orad;
3310  y = 0.0;
3311  for (i = 0; i < arc_segs; i++) {
3312  struct faceuse *fu;
3313  struct vertex **verts[3];
3314  point_t pt;
3315 
3316  j = i + 1;
3317  if (j == arc_segs) {
3318  j = 0;
3319  }
3320 
3321  VJOIN2(pt, center, x, r1, y, r2);
3322  k = Add_vert(pt[X], pt[Y], pt[Z], vertex_tree, tol->dist_sq);
3323 
3324  verts[0] = &(*outer_loop)[j];
3325  verts[1] = &(*outer_loop)[i];
3326  verts[2] = &new_outer_loop[i];
3327 
3328  if (i != j && j != k && i != k) {
3329  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3330  bu_log("tesselate_pipe_bend(): nmg_cmface failed\n");
3331  bu_bomb("tesselate_pipe_bend\n");
3332  }
3333  if (!new_outer_loop[i]->vg_p) {
3334  nmg_vertex_gv(new_outer_loop[i], pt);
3335  }
3336  if (nmg_calc_face_g(fu)) {
3337  bu_log("tesselate_pipe_bend: nmg_calc_face_g failed\n");
3338  nmg_kfu(fu);
3339  } else {
3340  struct loopuse *lu;
3341  struct edgeuse *eu;
3342 
3343  vertex_array[k] = new_outer_loop[i];
3344 
3345  NMG_CK_FACEUSE(fu);
3346  if (fu->orientation != OT_SAME) {
3347  fu = fu->fumate_p;
3348  }
3349 
3350  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3351  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3352  struct edgeuse *eu_opp_use;
3353 
3354  NMG_CK_EDGEUSE(eu);
3355  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3356 
3357  if (eu->vu_p->v_p == (*outer_loop)[j]) {
3358  VSUB2(norm, (*outer_loop)[j]->vg_p->coord, old_center);
3359  VUNITIZE(norm);
3360  nmg_vertexuse_nv(eu->vu_p, norm);
3361  VREVERSE(norm, norm);
3362  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3363  } else if (eu->vu_p->v_p == (*outer_loop)[i]) {
3364  VSUB2(norm, (*outer_loop)[i]->vg_p->coord, old_center);
3365  VUNITIZE(norm);
3366  nmg_vertexuse_nv(eu->vu_p, norm);
3367  VREVERSE(norm, norm);
3368  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3369  } else if (eu->vu_p->v_p == new_outer_loop[i]) {
3370  VSUB2(norm, new_outer_loop[i]->vg_p->coord, center);
3371  VUNITIZE(norm);
3372  nmg_vertexuse_nv(eu->vu_p, norm);
3373  VREVERSE(norm, norm);
3374  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3375  } else {
3376  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3377  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3378  }
3379  }
3380  }
3381  } else {
3382  verts[2] = &vertex_array[k];
3383  new_outer_loop[i] = vertex_array[k];
3384  }
3385 
3386  xnew = x * cos_del - y * sin_del;
3387  ynew = x * sin_del + y * cos_del;
3388  x = xnew;
3389  y = ynew;
3390 
3391  VJOIN2(pt, center, x, r1, y, r2);
3392  k = Add_vert(pt[X], pt[Y], pt[Z], vertex_tree, tol->dist_sq);
3393 
3394  verts[1] = verts[2];
3395  verts[2] = &new_outer_loop[j];
3396 
3397  if (i != j && j != k && i != k) {
3398  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3399  bu_log("tesselate_pipe_bend(): nmg_cmface failed\n");
3400  bu_bomb("tesselate_pipe_bend\n");
3401  }
3402  if (!(*verts[2])->vg_p) {
3403  nmg_vertex_gv(*verts[2], pt);
3404  }
3405  if (nmg_calc_face_g(fu)) {
3406  bu_log("tesselate_pipe_bend: nmg_calc_face_g failed\n");
3407  nmg_kfu(fu);
3408  } else {
3409  struct loopuse *lu;
3410  struct edgeuse *eu;
3411 
3412  vertex_array[k] = new_outer_loop[j];
3413 
3414  NMG_CK_FACEUSE(fu);
3415  if (fu->orientation != OT_SAME) {
3416  fu = fu->fumate_p;
3417  }
3418 
3419  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3420  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3421  struct edgeuse *eu_opp_use;
3422 
3423  NMG_CK_EDGEUSE(eu);
3424  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3425 
3426  if (eu->vu_p->v_p == (*outer_loop)[j]) {
3427  VSUB2(norm, (*outer_loop)[j]->vg_p->coord, old_center);
3428  VUNITIZE(norm);
3429  nmg_vertexuse_nv(eu->vu_p, norm);
3430  VREVERSE(norm, norm);
3431  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3432  } else if (eu->vu_p->v_p == new_outer_loop[i]) {
3433  VSUB2(norm, new_outer_loop[i]->vg_p->coord, center);
3434  VUNITIZE(norm);
3435  nmg_vertexuse_nv(eu->vu_p, norm);
3436  VREVERSE(norm, norm);
3437  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3438  } else if (eu->vu_p->v_p == new_outer_loop[j]) {
3439  VSUB2(norm, new_outer_loop[j]->vg_p->coord, center);
3440  VUNITIZE(norm);
3441  nmg_vertexuse_nv(eu->vu_p, norm);
3442  VREVERSE(norm, norm);
3443  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3444  } else {
3445  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3446  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3447  }
3448  }
3449  }
3450  } else {
3451  verts[2] = &vertex_array[k];
3452  new_outer_loop[j] = vertex_array[k];
3453  }
3454  }
3455 
3456  bu_free((char *)(*outer_loop), "tesselate_pipe_bend: outer_loop");
3457  *outer_loop = new_outer_loop;
3458  VMOVE(old_center, center);
3459  }
3460 
3461  /* release resources, sanity */
3462  free_vert_tree(vertex_tree);
3463  bu_free((char *)vertex_array, "vertex array in pipe.c");
3464  vertex_tree = NULL;
3465  vertex_array = NULL;
3466 
3467  if (irad <= tol->dist) {
3468  VMOVE(start_r1, r1);
3469  VMOVE(start_r2, r2);
3470  return;
3471  }
3472 
3473  VMOVE(r1, start_r1);
3474  VMOVE(r2, start_r2);
3475 
3476  VMOVE(old_center, bend_start);
3477  for (bend_seg = 0; bend_seg < bend_segs; bend_seg++) {
3478 
3479  new_inner_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
3480  "tesselate_pipe_bend(): new_inner_loop");
3481 
3482  MAT4X3VEC(r1_tmp, rot, r1);
3483  MAT4X3VEC(r2_tmp, rot, r2);
3484  VMOVE(r1, r1_tmp);
3485  VMOVE(r2, r2_tmp);
3486 
3487  VSUB2(r1_tmp, old_center, bend_center);
3488  MAT4X3PNT(r2_tmp, rot, r1_tmp);
3489  VADD2(center, r2_tmp, bend_center);
3490 
3491  x = irad;
3492  y = 0.0;
3493  for (i = 0; i < arc_segs; i++) {
3494  struct faceuse *fu;
3495  struct vertex **verts[3];
3496  point_t pt;
3497 
3498  j = i + 1;
3499  if (j == arc_segs) {
3500  j = 0;
3501  }
3502 
3503  VJOIN2(pt, center, x, r1, y, r2);
3504  verts[0] = &(*inner_loop)[i];
3505  verts[1] = &(*inner_loop)[j];
3506  verts[2] = &new_inner_loop[i];
3507 
3508  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3509  bu_log("tesselate_pipe_bend(): nmg_cmface failed\n");
3510  bu_bomb("tesselate_pipe_bend\n");
3511  }
3512  if (!new_inner_loop[i]->vg_p) {
3513  nmg_vertex_gv(new_inner_loop[i], pt);
3514  }
3515  if (nmg_calc_face_g(fu)) {
3516  bu_log("tesselate_pipe_bend: nmg_calc_face_g failed\n");
3517  nmg_kfu(fu);
3518  } else {
3519  struct loopuse *lu;
3520  struct edgeuse *eu;
3521 
3522  NMG_CK_FACEUSE(fu);
3523  if (fu->orientation != OT_SAME) {
3524  fu = fu->fumate_p;
3525  }
3526 
3527  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3528  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3529  struct edgeuse *eu_opp_use;
3530 
3531  NMG_CK_EDGEUSE(eu);
3532  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3533 
3534  if (eu->vu_p->v_p == (*inner_loop)[j]) {
3535  VSUB2(norm, old_center, (*inner_loop)[j]->vg_p->coord);
3536  VUNITIZE(norm);
3537  nmg_vertexuse_nv(eu->vu_p, norm);
3538  VREVERSE(norm, norm);
3539  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3540  } else if (eu->vu_p->v_p == (*inner_loop)[i]) {
3541  VSUB2(norm, old_center, (*inner_loop)[i]->vg_p->coord);
3542  VUNITIZE(norm);
3543  nmg_vertexuse_nv(eu->vu_p, norm);
3544  VREVERSE(norm, norm);
3545  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3546  } else if (eu->vu_p->v_p == new_inner_loop[i]) {
3547  VSUB2(norm, center, new_inner_loop[i]->vg_p->coord);
3548  VUNITIZE(norm);
3549  nmg_vertexuse_nv(eu->vu_p, norm);
3550  VREVERSE(norm, norm);
3551  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3552  } else {
3553  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3554  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3555  }
3556  }
3557  }
3558 
3559  xnew = x * cos_del - y * sin_del;
3560  ynew = x * sin_del + y * cos_del;
3561  x = xnew;
3562  y = ynew;
3563  VJOIN2(pt, center, x, r1, y, r2);
3564 
3565  verts[0] = verts[2];
3566  verts[2] = &new_inner_loop[j];
3567 
3568  if ((fu = nmg_cmface(s, verts, 3)) == NULL) {
3569  bu_log("tesselate_pipe_bend(): nmg_cmface failed\n");
3570  bu_bomb("tesselate_pipe_bend\n");
3571  }
3572  if (!(*verts[2])->vg_p) {
3573  nmg_vertex_gv(*verts[2], pt);
3574  }
3575  if (nmg_calc_face_g(fu)) {
3576  bu_log("tesselate_pipe_bend: nmg_calc_face_g failed\n");
3577  nmg_kfu(fu);
3578  } else {
3579  struct loopuse *lu;
3580  struct edgeuse *eu;
3581 
3582  NMG_CK_FACEUSE(fu);
3583  if (fu->orientation != OT_SAME) {
3584  fu = fu->fumate_p;
3585  }
3586 
3587  lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
3588  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3589  struct edgeuse *eu_opp_use;
3590 
3591  NMG_CK_EDGEUSE(eu);
3592  eu_opp_use = BU_LIST_PNEXT_CIRC(edgeuse, &eu->eumate_p->l);
3593 
3594  if (eu->vu_p->v_p == (*inner_loop)[j]) {
3595  VSUB2(norm, old_center, (*inner_loop)[j]->vg_p->coord);
3596  VUNITIZE(norm);
3597  nmg_vertexuse_nv(eu->vu_p, norm);
3598  VREVERSE(norm, norm);
3599  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3600  } else if (eu->vu_p->v_p == new_inner_loop[i]) {
3601  VSUB2(norm, center, new_inner_loop[i]->vg_p->coord);
3602  VUNITIZE(norm);
3603  nmg_vertexuse_nv(eu->vu_p, norm);
3604  VREVERSE(norm, norm);
3605  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3606  } else if (eu->vu_p->v_p == new_inner_loop[j]) {
3607  VSUB2(norm, center, new_inner_loop[j]->vg_p->coord);
3608  VUNITIZE(norm);
3609  nmg_vertexuse_nv(eu->vu_p, norm);
3610  VREVERSE(norm, norm);
3611  nmg_vertexuse_nv(eu_opp_use->vu_p, norm);
3612  } else {
3613  bu_log("No vu_normal assigned at (%g %g %g)\n", V3ARGS(eu->vu_p->v_p->vg_p->coord));
3614  bu_log("\ti=%d, j=%d, arc_segs=%d, fu = %p\n", i, j, arc_segs, (void *)fu);
3615  }
3616  }
3617  }
3618  }
3619  bu_free((char *)(*inner_loop), "tesselate_pipe_bend: inner_loop");
3620  *inner_loop = new_inner_loop;
3621  VMOVE(old_center, center);
3622  }
3623  VMOVE(start_r1, r1);
3624  VMOVE(start_r2, r2);
3625 }
3626 
3627 
3628 HIDDEN void
3630  struct wdb_pipept *pipept,
3631  int arc_segs,
3632  struct vertex ***outer_loop,
3633  struct vertex ***inner_loop,
3634  struct shell *s,
3635  const struct bn_tol *tol)
3636 {
3637  struct wdb_pipept *prev;
3638  struct faceuse *fu;
3639  struct loopuse *lu;
3640 
3641  NMG_CK_SHELL(s);
3642  BN_CK_TOL(tol);
3643 
3644  if (pipept->pp_od <= tol->dist) {
3645  return;
3646  }
3647 
3648  if (NEAR_EQUAL(pipept->pp_od, pipept->pp_id, tol->dist)) {
3649  return;
3650  }
3651 
3652  if ((fu = nmg_cface(s, *outer_loop, arc_segs)) == NULL) {
3653  bu_log("tesselate_pipe_end(): nmg_cface failed\n");
3654  return;
3655  }
3656  fu = fu->fumate_p;
3657  if (nmg_calc_face_g(fu)) {
3658  bu_log("tesselate_pipe_end: nmg_calc_face_g failed\n");
3659  nmg_kfu(fu);
3660  return;
3661  }
3662 
3663  prev = BU_LIST_PREV(wdb_pipept, &pipept->l);
3664 
3665  if (pipept->pp_id > tol->dist) {
3666  struct vertex **verts;
3667  int i;
3668 
3669  verts = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
3670  "tesselate_pipe_end: verts");
3671  for (i = 0; i < arc_segs; i++) {
3672  verts[i] = (*inner_loop)[i];
3673  }
3674 
3675  fu = nmg_add_loop_to_face(s, fu, verts, arc_segs, OT_OPPOSITE);
3676 
3677  bu_free((char *)verts, "tesselate_pipe_end: verts");
3678  } else if (prev->pp_id > tol->dist) {
3679  struct vertexuse *vu;
3680 
3681  /* make a loop of a single vertex in this face */
3682  lu = nmg_mlv(&fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE);
3683  vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
3684 
3685  nmg_vertex_gv(vu->v_p, pipept->pp_coord);
3686  }
3687 
3688  for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
3689  struct edgeuse *eu;
3690 
3691  NMG_CK_LOOPUSE(lu);
3692 
3693  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) {
3694  continue;
3695  }
3696 
3697  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
3698  NMG_CK_EDGEUSE(eu);
3699  eu->e_p->is_real = 1;
3700  }
3701  }
3702 }
3703 
3704 
3705 /**
3706  * XXXX Still needs vertexuse normals!
3707  */
3708 int
3710  struct nmgregion **r,
3711  struct model *m,
3712  struct rt_db_internal *ip,
3713  const struct rt_tess_tol *ttol,
3714  const struct bn_tol *tol)
3715 {
3716  struct wdb_pipept *pp1;
3717  struct wdb_pipept *pp2;
3718  struct wdb_pipept *pp3;
3719  point_t curr_pt;
3720  struct shell *s;
3721  struct rt_pipe_internal *pip;
3722  int arc_segs = 6; /* minimum number of segments for a circle */
3723  int tol_segs;
3724  fastf_t max_diam = 0.0;
3725  fastf_t pipe_size;
3726  fastf_t curr_od, curr_id;
3727  double delta_angle;
3728  double sin_del;
3729  double cos_del;
3730  point_t min_pt;
3731  point_t max_pt;
3732  vect_t min_to_max;
3733  vect_t r1, r2;
3734  struct vertex **outer_loop;
3735  struct vertex **inner_loop;
3736 
3737  RT_CK_DB_INTERNAL(ip);
3738  pip = (struct rt_pipe_internal *)ip->idb_ptr;
3739  RT_PIPE_CK_MAGIC(pip);
3740 
3741  BN_CK_TOL(tol);
3742  RT_CK_TESS_TOL(ttol);
3743  NMG_CK_MODEL(m);
3744 
3745  *r = (struct nmgregion *)NULL;
3746 
3747  if (BU_LIST_IS_EMPTY(&pip->pipe_segs_head)) {
3748  return 0; /* nothing to tesselate */
3749  }
3750 
3751  pp1 = BU_LIST_FIRST(wdb_pipept, &pip->pipe_segs_head);
3752 
3753  VMOVE(min_pt, pp1->pp_coord);
3754  VMOVE(max_pt, pp1->pp_coord);
3755 
3756  /* find max diameter */
3757  for (BU_LIST_FOR(pp1, wdb_pipept, &pip->pipe_segs_head)) {
3758  if (pp1->pp_od > SMALL_FASTF && pp1->pp_od > max_diam) {
3759  max_diam = pp1->pp_od;
3760  }
3761 
3762  VMINMAX(min_pt, max_pt, pp1->pp_coord);
3763  }
3764 
3765  if (max_diam <= tol->dist) {
3766  return 0; /* nothing to tesselate */
3767  }
3768 
3769  /* calculate pipe size for relative tolerance */
3770  VSUB2(min_to_max, max_pt, min_pt);
3771  pipe_size = MAGNITUDE(min_to_max);
3772 
3773  /* calculate number of segments for circles */
3774  if (ttol->abs > SMALL_FASTF && ttol->abs * 2.0 < max_diam) {
3775  tol_segs = ceil(M_PI / acos(1.0 - 2.0 * ttol->abs / max_diam));
3776  if (tol_segs > arc_segs) {
3777  arc_segs = tol_segs;
3778  }
3779  }
3780  if (ttol->rel > SMALL_FASTF && 2.0 * ttol->rel * pipe_size < max_diam) {
3781  tol_segs = ceil(M_PI / acos(1.0 - 2.0 * ttol->rel * pipe_size / max_diam));
3782  if (tol_segs > arc_segs) {
3783  arc_segs = tol_segs;
3784  }
3785  }
3786  if (ttol->norm > SMALL_FASTF) {
3787  tol_segs = ceil(M_PI / ttol->norm);
3788  if (tol_segs > arc_segs) {
3789  arc_segs = tol_segs;
3790  }
3791  }
3792 
3793  *r = nmg_mrsv(m);
3794  s = BU_LIST_FIRST(shell, &(*r)->s_hd);
3795 
3796  outer_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
3797  "rt_pipe_tess: outer_loop");
3798  inner_loop = (struct vertex **)bu_calloc(arc_segs, sizeof(struct vertex *),
3799  "rt_pipe_tess: inner_loop");
3800  delta_angle = M_2PI / (double)arc_segs;
3801  sin_del = sin(delta_angle);
3802  cos_del = cos(delta_angle);
3803 
3804  pp1 = BU_LIST_FIRST(wdb_pipept, &(pip->pipe_segs_head));
3805  tesselate_pipe_start(pp1, arc_segs, sin_del, cos_del,
3806  &outer_loop, &inner_loop, r1, r2, s, tol);
3807 
3808  pp2 = BU_LIST_NEXT(wdb_pipept, &pp1->l);
3809  if (BU_LIST_IS_HEAD(&pp2->l, &(pip->pipe_segs_head))) {
3810  return 0;
3811  }
3812  pp3 = BU_LIST_NEXT(wdb_pipept, &pp2->l);
3813  if (BU_LIST_IS_HEAD(&pp3->l, &(pip->pipe_segs_head))) {
3814  pp3 = (struct wdb_pipept *)NULL;
3815  }
3816 
3817  VMOVE(curr_pt, pp1->pp_coord);
3818  curr_od = pp1->pp_od;
3819  curr_id = pp1->pp_id;
3820  while (1) {
3821  vect_t n1, n2;
3822  vect_t norm;
3823  vect_t v1;
3824  fastf_t angle;
3825  fastf_t dist_to_bend;
3826  point_t bend_start, bend_end, bend_center;
3827 
3828  if (!pp3) {
3829  /* last segment */
3830  tesselate_pipe_linear(curr_pt, curr_od / 2.0, curr_id / 2.0,
3831  pp2->pp_coord, pp2->pp_od / 2.0, pp2->pp_id / 2.0,
3832  arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol);
3833  break;
3834  }
3835 
3836  VSUB2(n1, curr_pt, pp2->pp_coord);
3837  if (VNEAR_ZERO(n1, VUNITIZE_TOL)) {
3838  /* duplicate point, skip to next point */
3839  goto next_pt;
3840  }
3841 
3842  VSUB2(n2, pp3->pp_coord, pp2->pp_coord);
3843  VCROSS(norm, n1, n2);
3844  if (VNEAR_ZERO(norm, VUNITIZE_TOL)) {
3845  /* points are collinear, treat as a linear segment */
3846  tesselate_pipe_linear(curr_pt, curr_od / 2.0, curr_id / 2.0,
3847  pp2->pp_coord, pp2->pp_od / 2.0, pp2->pp_id / 2.0,
3848  arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol);
3849 
3850  VMOVE(curr_pt, pp2->pp_coord);
3851  curr_id = pp2->pp_id;
3852  curr_od = pp2->pp_od;
3853  goto next_pt;
3854  }
3855 
3856  VUNITIZE(n1);
3857  VUNITIZE(n2);
3858  VUNITIZE(norm);
3859 
3860  /* linear section */
3861  angle = M_PI - acos(VDOT(n1, n2));
3862  dist_to_bend = pp2->pp_bendradius * tan(angle / 2.0);
3863  VJOIN1(bend_start, pp2->pp_coord, dist_to_bend, n1);
3864  tesselate_pipe_linear(curr_pt, curr_od / 2.0, curr_id / 2.0,
3865  bend_start, pp2->pp_od / 2.0, pp2->pp_id / 2.0,
3866  arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol);
3867 
3868  /* and bend section */
3869  VJOIN1(bend_end, pp2->pp_coord, dist_to_bend, n2);
3870  VCROSS(v1, n1, norm);
3871  VJOIN1(bend_center, bend_start, -pp2->pp_bendradius, v1);
3872  tesselate_pipe_bend(bend_start, bend_end, bend_center, curr_od / 2.0, curr_id / 2.0,
3873  arc_segs, sin_del, cos_del, &outer_loop, &inner_loop,
3874  r1, r2, s, tol, ttol);
3875 
3876  VMOVE(curr_pt, bend_end);
3877  curr_id = pp2->pp_id;
3878  curr_od = pp2->pp_od;
3879  next_pt:
3880  pp1 = pp2;
3881  pp2 = pp3;
3882  pp3 = BU_LIST_NEXT(wdb_pipept, &pp3->l);
3883  if (BU_LIST_IS_HEAD(&pp3->l, &(pip->pipe_segs_head))) {
3884  pp3 = (struct wdb_pipept *)NULL;
3885  }
3886  }
3887 
3888  tesselate_pipe_end(pp2, arc_segs, &outer_loop, &inner_loop, s, tol);
3889 
3890  bu_free((char *)outer_loop, "rt_pipe_tess: outer_loop");
3891  bu_free((char *)inner_loop, "rt_pipe_tess: inner_loop");
3892 
3893  nmg_rebound(m, tol);
3894  nmg_edge_fuse(&s->l.magic, tol);
3895 
3896  return 0;
3897 }
3898 
3899 
3900 int
3902  struct rt_db_internal *ip,
3903  const struct bu_external *ep,
3904  const fastf_t *mat,
3905  const struct db_i *dbip)
3906 {
3907  struct exported_pipept *exp_pipept;
3908  struct wdb_pipept *ptp;
3909  struct wdb_pipept tmp;
3910  struct rt_pipe_internal *pip;
3911  union record *rp;
3912 
3913  /* must be double for import and export */
3914  double scan[ELEMENTS_PER_VECT];
3915 
3916  if (dbip) {
3917  RT_CK_DBI(dbip);
3918  }
3919 
3920  BU_CK_EXTERNAL(ep);
3921  rp = (union record *)ep->ext_buf;
3922  /* Check record type */
3923  if (rp->u_id != DBID_PIPE) {
3924  bu_log("rt_pipe_import4: defective record\n");
3925  return -1;
3926  }
3927 
3928  RT_CK_DB_INTERNAL(ip);
3929  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
3930  ip->idb_type = ID_PIPE;
3931  ip->idb_meth = &OBJ[ID_PIPE];
3932  BU_ALLOC(ip->idb_ptr, struct rt_pipe_internal);
3933 
3934  pip = (struct rt_pipe_internal *)ip->idb_ptr;
3935  pip->pipe_magic = RT_PIPE_INTERNAL_MAGIC;
3936  pip->pipe_count = ntohl(*(uint32_t *)rp->pwr.pwr_pt_count);
3937 
3938  /*
3939  * Walk the array of segments in reverse order, allocating a
3940  * linked list of segments in internal format, using exactly the
3941  * same structures as libwdb.
3942  */
3943  BU_LIST_INIT(&pip->pipe_segs_head);
3944  if (mat == NULL) {
3945  mat = bn_mat_identity;
3946  }
3947  for (exp_pipept = &rp->pwr.pwr_data[pip->pipe_count - 1]; exp_pipept >= &rp->pwr.pwr_data[0]; exp_pipept--) {
3948  bu_cv_ntohd((unsigned char *)&scan[0], exp_pipept->epp_id, 1);
3949  tmp.pp_id = scan[0]; /* convert double to fastf_t */
3950 
3951  bu_cv_ntohd((unsigned char *)&scan[1], exp_pipept->epp_od, 1);
3952  tmp.pp_od = scan[1]; /* convert double to fastf_t */
3953 
3954  bu_cv_ntohd((unsigned char *)&scan[2], exp_pipept->epp_bendradius, 1);
3955  tmp.pp_bendradius = scan[2]; /* convert double to fastf_t */
3956 
3957  bu_cv_ntohd((unsigned char *)scan, exp_pipept->epp_coord, ELEMENTS_PER_VECT);
3958  VMOVE(tmp.pp_coord, scan); /* convert double to fastf_t */
3959 
3960  /* Apply modeling transformations */
3961  BU_ALLOC(ptp, struct wdb_pipept);
3962  ptp->l.magic = WDB_PIPESEG_MAGIC;
3963  MAT4X3PNT(ptp->pp_coord, mat, tmp.pp_coord);
3964  ptp->pp_id = tmp.pp_id / mat[15];
3965  ptp->pp_od = tmp.pp_od / mat[15];
3966  ptp->pp_bendradius = tmp.pp_bendradius / mat[15];
3967  BU_LIST_APPEND(&pip->pipe_segs_head, &ptp->l);
3968  }
3969 
3970  return 0; /* OK */
3971 }
3972 
3973 
3974 int
3976  struct bu_external *ep,
3977  const struct rt_db_internal *ip,
3978  double local2mm,
3979  const struct db_i *dbip)
3980 {
3981  struct rt_pipe_internal *pip;
3982  struct bu_list *headp;
3983  struct exported_pipept *epp;
3984  struct wdb_pipept *ppt;
3985  struct wdb_pipept tmp;
3986  int count;
3987  int ngran;
3988  int nbytes;
3989  union record *rec;
3990 
3991  if (dbip) {
3992  RT_CK_DBI(dbip);
3993  }
3994 
3995  RT_CK_DB_INTERNAL(ip);
3996  pip = (struct rt_pipe_internal *)ip->idb_ptr;
3997  RT_PIPE_CK_MAGIC(pip);
3998 
3999  if (pip->pipe_segs_head.magic == 0) {
4000  return -1; /* no segments provided, empty pipe is bogus */
4001  }
4002  headp = &pip->pipe_segs_head;
4003 
4004  /* Count number of points */
4005  count = 0;
4006  for (BU_LIST_FOR(ppt, wdb_pipept, headp)) {
4007  count++;
4008  }
4009 
4010  if (count < 1) {
4011  return -4; /* Not enough for 1 pipe! */
4012  }
4013 
4014  /* Determine how many whole granules will be required */
4015  nbytes = sizeof(struct pipewire_rec) +
4016  (count - 1) * sizeof(struct exported_pipept);
4017  ngran = (nbytes + sizeof(union record) - 1) / sizeof(union record);
4018 
4019  BU_CK_EXTERNAL(ep);
4020  ep->ext_nbytes = ngran * sizeof(union record);
4021  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "pipe external");
4022  rec = (union record *)ep->ext_buf;
4023 
4024  rec->pwr.pwr_id = DBID_PIPE;
4025  *(uint32_t *)rec->pwr.pwr_count = htonl(ngran - 1); /* # EXTRA grans */
4026  *(uint32_t *)rec->pwr.pwr_pt_count = htonl(count);
4027 
4028  /* Convert the pipe segments to external form */
4029  epp = &rec->pwr.pwr_data[0];
4030  for (BU_LIST_FOR(ppt, wdb_pipept, headp), epp++) {
4031  double scan[ELEMENTS_PER_POINT];
4032 
4033  /* Convert from user units to mm */
4034  VSCALE(tmp.pp_coord, ppt->pp_coord, local2mm);
4035  tmp.pp_id = ppt->pp_id * local2mm;
4036  tmp.pp_od = ppt->pp_od * local2mm;
4037  tmp.pp_bendradius = ppt->pp_bendradius * local2mm;
4038 
4039 
4040  VMOVE(scan, tmp.pp_coord); /* convert fastf_t to double */
4041  bu_cv_htond(epp->epp_coord, (unsigned char *)scan, ELEMENTS_PER_POINT);
4042 
4043  scan[0] = tmp.pp_id; /* convert fastf_t to double */
4044  bu_cv_htond(epp->epp_id, (unsigned char *)&scan[0], 1);
4045 
4046  scan[1] = tmp.pp_od; /* convert fastf_t to double */
4047  bu_cv_htond(epp->epp_od, (unsigned char *)&scan[1], 1);
4048 
4049  scan[2] = tmp.pp_bendradius; /* convert fastf_t to double */
4050  bu_cv_htond(epp->epp_bendradius, (unsigned char *)&scan[2], 1);
4051  }
4052 
4053  return 0;
4054 }
4055 
4056 
4057 int
4059  struct rt_db_internal *ip,
4060  const struct bu_external *ep,
4061  const fastf_t *mat,
4062  const struct db_i *dbip)
4063 {
4064  struct wdb_pipept *ptp;
4065  struct rt_pipe_internal *pip;
4066 
4067  /* must be double for import and export */
4068  double *vec;
4069 
4070  size_t total_count;
4071  int double_count;
4072  int byte_count;
4073  unsigned long pipe_count;
4074  int i;
4075 
4076  if (dbip) {
4077  RT_CK_DBI(dbip);
4078  }
4079  BU_CK_EXTERNAL(ep);
4080 
4081  pipe_count = ntohl(*(uint32_t *)ep->ext_buf);
4082  double_count = pipe_count * 6;
4083  byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
4084  total_count = 4 + byte_count;
4085  BU_ASSERT_LONG(ep->ext_nbytes, == , total_count);
4086 
4087  RT_CK_DB_INTERNAL(ip);
4088  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
4089  ip->idb_type = ID_PIPE;
4090  ip->idb_meth = &OBJ[ID_PIPE];
4091  BU_ALLOC(ip->idb_ptr, struct rt_pipe_internal);
4092 
4093  pip = (struct rt_pipe_internal *)ip->idb_ptr;
4094  pip->pipe_magic = RT_PIPE_INTERNAL_MAGIC;
4095  pip->pipe_count = pipe_count;
4096 
4097  vec = (double *)bu_malloc(byte_count, "rt_pipe_import5: vec");
4098 
4099  /* Convert from database (network) to internal (host) format */
4100  bu_cv_ntohd((unsigned char *)vec, (unsigned char *)ep->ext_buf + 4, double_count);
4101 
4102  /*
4103  * Walk the array of segments in reverse order, allocating a
4104  * linked list of segments in internal format, using exactly the
4105  * same structures as libwdb.
4106  */
4107  BU_LIST_INIT(&pip->pipe_segs_head);
4108  if (mat == NULL) {
4109  mat = bn_mat_identity;
4110  }
4111  for (i = 0; i < double_count; i += 6) {
4112  /* Apply modeling transformations */
4113  BU_ALLOC(ptp, struct wdb_pipept);
4114  ptp->l.magic = WDB_PIPESEG_MAGIC;
4115  MAT4X3PNT(ptp->pp_coord, mat, &vec[i]);
4116  ptp->pp_id = vec[i + 3] / mat[15];
4117  ptp->pp_od = vec[i + 4] / mat[15];
4118  ptp->pp_bendradius = vec[i + 5] / mat[15];
4119  BU_LIST_INSERT(&pip->pipe_segs_head, &ptp->l);
4120  }
4121 
4122  bu_free((void *)vec, "rt_pipe_import5: vec");
4123  return 0; /* OK */
4124 }
4125 
4126 
4127 int
4128 rt_pipe_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
4129 {
4130  struct rt_pipe_internal *pip;
4131  struct bu_list *headp;
4132  struct wdb_pipept *ppt;
4133  int total_count;
4134  int double_count;
4135  int byte_count;
4136  unsigned long pipe_count;
4137  int i = 0;
4138 
4139  /* must be double for import and export */
4140  double *vec;
4141 
4142  if (dbip) {
4143  RT_CK_DBI(dbip);
4144  }
4145 
4146  RT_CK_DB_INTERNAL(ip);
4147  pip = (struct rt_pipe_internal *)ip->idb_ptr;
4148  RT_PIPE_CK_MAGIC(pip);
4149 
4150  if (pip->pipe_segs_head.magic == 0) {
4151  return -1; /* no segments provided, empty pipe is bogus */
4152  }
4153  headp = &pip->pipe_segs_head;
4154 
4155  /* Count number of points */
4156  pipe_count = 0;
4157  for (BU_LIST_FOR(ppt, wdb_pipept, headp)) {
4158  pipe_count++;
4159  }
4160 
4161  if (pipe_count <= 1) {
4162  return -4; /* Not enough for 1 pipe! */
4163  }
4164 
4165  double_count = pipe_count * 6;
4166  byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
4167  total_count = 4 + byte_count;
4168  vec = (double *)bu_malloc(byte_count, "rt_pipe_export5: vec");
4169 
4170  BU_CK_EXTERNAL(ep);
4171  ep->ext_nbytes = total_count;
4172  ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "pipe external");
4173 
4174  *(uint32_t *)ep->ext_buf = htonl(pipe_count);
4175 
4176  /* Convert the pipe segments to external form */
4177  for (BU_LIST_FOR(ppt, wdb_pipept, headp), i += 6) {
4178  /* Convert from user units to mm */
4179  VSCALE(&vec[i], ppt->pp_coord, local2mm);
4180  vec[i + 3] = ppt->pp_id * local2mm;
4181  vec[i + 4] = ppt->pp_od * local2mm;
4182  vec[i + 5] = ppt->pp_bendradius * local2mm;
4183  }
4184 
4185  /* Convert from internal (host) to database (network) format */
4186  bu_cv_htond((unsigned char *)ep->ext_buf + 4, (unsigned char *)vec, double_count);
4187 
4188  bu_free((void *)vec, "rt_pipe_export5: vec");
4189  return 0;
4190 }
4191 
4192 
4193 /**
4194  * Make human-readable formatted presentation of this solid. First
4195  * line describes type of solid. Additional lines are indented one
4196  * tab, and give parameter values.
4197  */
4198 int
4200  struct bu_vls *str,
4201  const struct rt_db_internal *ip,
4202  int verbose,
4203  double mm2local)
4204 {
4205  struct rt_pipe_internal *pip;
4206  struct wdb_pipept *ptp;
4207  char buf[256];
4208  int segno = 0;
4209 
4210  RT_CK_DB_INTERNAL(ip);
4211  pip = (struct rt_pipe_internal *)ip->idb_ptr;
4212  RT_PIPE_CK_MAGIC(pip);
4213 
4214  sprintf(buf, "pipe with %d points\n", pip->pipe_count);
4215  bu_vls_strcat(str, buf);
4216 
4217  if (!verbose) {
4218  return 0;
4219  }
4220 
4221  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4222  sprintf(buf, "\t%d ", segno++);
4223  bu_vls_strcat(str, buf);
4224  sprintf(buf, "\tbend radius = %g", INTCLAMP(ptp->pp_bendradius * mm2local));
4225  bu_vls_strcat(str, buf);
4226  sprintf(buf, " od=%g", INTCLAMP(ptp->pp_od * mm2local));
4227  bu_vls_strcat(str, buf);
4228  if (ptp->pp_id > 0) {
4229  sprintf(buf, ", id = %g", INTCLAMP(ptp->pp_id * mm2local));
4230  bu_vls_strcat(str, buf);
4231  }
4232  bu_vls_strcat(str, "\n");
4233 
4234  sprintf(buf, "\t at=(%g, %g, %g)\n",
4235  INTCLAMP(ptp->pp_coord[X] * mm2local),
4236  INTCLAMP(ptp->pp_coord[Y] * mm2local),
4237  INTCLAMP(ptp->pp_coord[Z] * mm2local));
4238  bu_vls_strcat(str, buf);
4239 
4240  }
4241 
4242  return 0;
4243 }
4244 
4245 
4246 /**
4247  * Free the storage associated with the rt_db_internal version of this solid.
4248  */
4249 void
4251 {
4252  struct rt_pipe_internal *pip;
4253  struct wdb_pipept *ptp;
4254 
4255  RT_CK_DB_INTERNAL(ip);
4256  pip = (struct rt_pipe_internal *)ip->idb_ptr;
4257  RT_PIPE_CK_MAGIC(pip);
4258 
4259  if (pip->pipe_segs_head.magic != 0) {
4260  while (BU_LIST_WHILE(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4261  BU_LIST_DEQUEUE(&(ptp->l));
4262  bu_free((char *)ptp, "wdb_pipept");
4263  }
4264  }
4265  bu_free(ip->idb_ptr, "pipe ifree");
4266  ip->idb_ptr = ((void *)0);
4267 }
4268 
4269 
4270 /**
4271  * Check pipe solid. Bend radius must be at least as large as the
4272  * outer radius. All bends must have constant diameters. No
4273  * consecutive LINEAR sections without BENDS unless the LINEAR
4274  * sections are collinear. Inner diameter must be less than outer
4275  * diameter.
4276  */
4277 int
4278 rt_pipe_ck(const struct bu_list *headp)
4279 {
4280  int error_count = 0;
4281  struct wdb_pipept *cur, *prev, *next;
4282  fastf_t old_bend_dist = 0.0;
4283  fastf_t new_bend_dist;
4284  fastf_t v2_len = 0.0;
4285 
4286  prev = BU_LIST_FIRST(wdb_pipept, headp);
4287 
4288  if (prev->pp_id >= prev->pp_od) {
4289  bu_log("Inner diameter (%gmm) has to be less than outer diameter (%gmm)\n",
4290  prev->pp_id, prev->pp_od);
4291  error_count++;
4292  }
4293 
4294  if (prev->pp_bendradius < prev->pp_od * 0.5) {
4295  bu_log("Bend radius (%gmm) is less than outer radius at (%g %g %g)\n",
4296  prev->pp_bendradius, V3ARGS(prev->pp_coord));
4297  error_count++;
4298  }
4299 
4300  cur = BU_LIST_NEXT(wdb_pipept, &prev->l);
4301  next = BU_LIST_NEXT(wdb_pipept, &cur->l);
4302  while (BU_LIST_NOT_HEAD(&next->l, headp)) {
4303  vect_t v1, v2, norm;
4304  fastf_t v1_len;
4305  fastf_t angle;
4306  fastf_t local_vdot;
4307 
4308  if (cur->pp_id >= cur->pp_od) {
4309  bu_log("Inner diameter (%gmm) has to be less than outer diameter (%gmm)\n",
4310  cur->pp_id, cur->pp_od);
4311  error_count++;
4312  }
4313 
4314  if (cur->pp_bendradius < cur->pp_od * 0.5) {
4315  bu_log("Bend radius (%gmm) is less than outer radius at (%g %g %g)\n",
4316  cur->pp_bendradius, V3ARGS(cur->pp_coord));
4317  error_count++;
4318  }
4319 
4320  VSUB2(v1, prev->pp_coord, cur->pp_coord);
4321  v1_len = MAGNITUDE(v1);
4322  VUNITIZE(v1);
4323 
4324  VSUB2(v2, next->pp_coord, cur->pp_coord);
4325  v2_len = MAGNITUDE(v2);
4326  VUNITIZE(v2);
4327 
4328  VCROSS(norm, v1, v2);
4329  if (VNEAR_ZERO(norm, SQRT_SMALL_FASTF)) {
4330  new_bend_dist = 0.0;
4331  goto next_pt;
4332  }
4333 
4334  local_vdot = VDOT(v1, v2);
4335  /* protect against fuzzy overflow/underflow, clamp unitized
4336  * vectors in order to prevent acos() from throwing an
4337  * exception (or crashing).
4338  */
4339  CLAMP(local_vdot, -1.0, 1.0);
4340 
4341  angle = M_PI - acos(local_vdot);
4342  new_bend_dist = cur->pp_bendradius * tan(angle / 2.0);
4343 
4344  if (new_bend_dist + old_bend_dist > v1_len) {
4345  fastf_t vdot;
4346  error_count++;
4347  bu_log("Bend radii (%gmm) at (%g %g %g) and (%gmm) at (%g %g %g) are too large\n",
4348  prev->pp_bendradius, V3ARGS(prev->pp_coord),
4349  cur->pp_bendradius, V3ARGS(cur->pp_coord));
4350  bu_log("for pipe segment between (%g %g %g) and (%g %g %g)\n",
4351  V3ARGS(prev->pp_coord), V3ARGS(cur->pp_coord));
4352  bu_log("failed test: %g + %g > %g\n", new_bend_dist, old_bend_dist, v1_len);
4353  vdot = VDOT(v1, v2);
4354  bu_log("angle(%g) = M_PI(%g) - acos(VDOT(v1, v2)(%g))(%g)\n", angle, M_PI, vdot, acos(vdot));
4355  bu_log("v1: (%g %g %g)\n", V3ARGS(v1));
4356  bu_log("v2: (%g %g %g)\n", V3ARGS(v2));
4357  }
4358  next_pt:
4359  old_bend_dist = new_bend_dist;
4360  prev = cur;
4361  cur = next;
4362  next = BU_LIST_NEXT(wdb_pipept, &cur->l);
4363  }
4364 
4365  if (cur->pp_id >= cur->pp_od) {
4366  bu_log("Inner diameter (%gmm) has to be less than outer diameter (%gmm)\n",
4367  cur->pp_id, cur->pp_od);
4368  error_count++;
4369  }
4370 
4371  if (old_bend_dist > v2_len) {
4372  error_count++;
4373  bu_log("last segment (%g %g %g) to (%g %g %g) is too short to allow\n",
4374  V3ARGS(prev->pp_coord), V3ARGS(cur->pp_coord));
4375  bu_log("bend radius of %gmm\n", prev->pp_bendradius);
4376  }
4377  return error_count;
4378 }
4379 
4380 
4381 /**
4382  * Examples -
4383  * db get name V# => get coordinates for vertex #
4384  * db get name I# => get inner radius for vertex #
4385  * db get name O# => get outer radius for vertex #
4386  * db get name R# => get bendradius for vertex #
4387  * db get name P# => get all data for vertex #
4388  * db get name N ==> get number of vertices
4389  */
4390 int
4392  struct bu_vls *logstr,
4393  const struct rt_db_internal *intern,
4394  const char *attr)
4395 {
4396  struct rt_pipe_internal *pip = (struct rt_pipe_internal *)intern->idb_ptr;
4397  struct wdb_pipept *ptp;
4398  int seg_no;
4399  int num_segs = 0;
4400 
4401  RT_PIPE_CK_MAGIC(pip);
4402 
4403  /* count segments */
4404  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4405  num_segs++;
4406  }
4407 
4408  if (attr == (char *)NULL) {
4409  bu_vls_strcat(logstr, "pipe");
4410 
4411  seg_no = 0;
4412  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4413  bu_vls_printf(logstr, " V%d { %.25G %.25G %.25G } O%d %.25G I%d %.25G R%d %.25G",
4414  seg_no, V3ARGS(ptp->pp_coord),
4415  seg_no, ptp->pp_od,
4416  seg_no, ptp->pp_id,
4417  seg_no, ptp->pp_bendradius);
4418  seg_no++;
4419  }
4420  } else if (attr[0] == 'N') {
4421  bu_vls_printf(logstr, "%d", num_segs);
4422  } else {
4423  int curr_seg = 0;
4424 
4425  seg_no = atoi(&attr[1]);
4426  if (seg_no < 0 || seg_no >= num_segs) {
4427  bu_vls_printf(logstr, "segment number out of range (0 - %d)", num_segs - 1);
4428  return BRLCAD_ERROR;
4429  }
4430 
4431  /* find the desired vertex */
4432  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4433  if (curr_seg == seg_no) {
4434  break;
4435  }
4436  curr_seg++;
4437  }
4438 
4439  switch (attr[0]) {
4440  case 'V':
4441  bu_vls_printf(logstr, "%.25G %.25G %.25G", V3ARGS(ptp->pp_coord));
4442  break;
4443  case 'I':
4444  bu_vls_printf(logstr, "%.25G", ptp->pp_id);
4445  break;
4446  case 'O':
4447  bu_vls_printf(logstr, "%.25G", ptp->pp_od);
4448  break;
4449  case 'R':
4450  bu_vls_printf(logstr, "%.25G", ptp->pp_bendradius);
4451  break;
4452  case 'P':
4453  bu_vls_printf(logstr, " V%d { %.25G %.25G %.25G } I%d %.25G O%d %.25G R%d %.25G",
4454  seg_no, V3ARGS(ptp->pp_coord),
4455  seg_no, ptp->pp_id,
4456  seg_no, ptp->pp_od,
4457  seg_no, ptp->pp_bendradius);
4458  break;
4459  default:
4460  bu_vls_printf(logstr, "unrecognized attribute (%c), choices are V, I, O, R, or P", attr[0]);
4461  return BRLCAD_ERROR;
4462  }
4463  }
4464 
4465  return BRLCAD_OK;
4466 }
4467 
4468 
4469 int
4471  struct bu_vls *logstr,
4472  struct rt_db_internal *intern,
4473  int argc,
4474  const char **argv)
4475 {
4476  struct rt_pipe_internal *pip;
4477  struct wdb_pipept *ptp;
4478  Tcl_Obj *obj, *list;
4479  int seg_no;
4480  int num_segs;
4481  int curr_seg;
4482  fastf_t tmp;
4483  char *v_str;
4484 
4485 
4486  RT_CK_DB_INTERNAL(intern);
4487  pip = (struct rt_pipe_internal *)intern->idb_ptr;
4488  RT_PIPE_CK_MAGIC(pip);
4489 
4490  while (argc >= 2) {
4491 
4492  /* count vertices */
4493  num_segs = 0;
4494  if (pip->pipe_segs_head.forw) {
4495  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4496  num_segs++;
4497  }
4498  } else {
4499  BU_LIST_INIT(&pip->pipe_segs_head);
4500  }
4501 
4502  if (!isdigit((int)argv[0][1])) {
4503  bu_vls_printf(logstr, "no vertex number specified");
4504  return BRLCAD_ERROR;
4505  }
4506 
4507  seg_no = atoi(&argv[0][1]);
4508  if (seg_no == num_segs) {
4509  struct wdb_pipept *new_pt;
4510 
4511  BU_ALLOC(new_pt, struct wdb_pipept);
4512  if (num_segs > 0) {
4513  ptp = BU_LIST_LAST(wdb_pipept, &pip->pipe_segs_head);
4514  *new_pt = *ptp; /* struct copy */
4515  BU_LIST_INSERT(&pip->pipe_segs_head, &new_pt->l);
4516  ptp = new_pt;
4517  } else {
4518  VSETALL(new_pt->pp_coord, 0.0);
4519  new_pt->pp_id = 0.0;
4520  new_pt->pp_od = 10.0;
4521  new_pt->pp_bendradius = 20.0;
4522  BU_LIST_INSERT(&pip->pipe_segs_head, &new_pt->l);
4523  ptp = new_pt;
4524  }
4525  num_segs++;
4526  }
4527  if (seg_no < 0 || seg_no >= num_segs) {
4528  bu_vls_printf(logstr, "vertex number out of range");
4529  return BRLCAD_ERROR;
4530  }
4531 
4532  /* get the specified vertex */
4533  curr_seg = 0;
4534  for (BU_LIST_FOR(ptp, wdb_pipept, &pip->pipe_segs_head)) {
4535  if (curr_seg == seg_no) {
4536  break;
4537  }
4538  curr_seg++;
4539  }
4540 
4541 
4542  switch (argv[0][0]) {
4543  case 'V':
4544  obj = Tcl_NewStringObj(argv[1], -1);
4545  list = Tcl_NewListObj(0, NULL);
4546  Tcl_ListObjAppendList(brlcad_interp, list, obj);
4547  v_str = Tcl_GetStringFromObj(list, NULL);
4548  while (isspace((int)*v_str)) {
4549  v_str++;
4550  }
4551  if (*v_str == '\0') {
4552  bu_vls_printf(logstr, "incomplete vertex specification");
4553  Tcl_DecrRefCount(list);
4554  return BRLCAD_ERROR;
4555  }
4556  ptp->pp_coord[0] = atof(v_str);
4557  v_str = bu_next_token(v_str);
4558  if (*v_str == '\0') {
4559  bu_vls_printf(logstr, "incomplete vertex specification");
4560  Tcl_DecrRefCount(list);
4561  return BRLCAD_ERROR;
4562  }
4563  ptp->pp_coord[1] = atof(v_str);
4564  v_str = bu_next_token(v_str);
4565  if (*v_str == '\0') {
4566  bu_vls_printf(logstr, "incomplete vertex specification");
4567  Tcl_DecrRefCount(list);
4568  return BRLCAD_ERROR;
4569  }
4570  ptp->pp_coord[2] = atof(v_str);
4571  Tcl_DecrRefCount(list);
4572  break;
4573  case 'I':
4574  ptp->pp_id = atof(argv[1]);
4575  break;
4576  case 'O':
4577  tmp = atof(argv[1]);
4578  if (tmp <= 0.0) {
4579  bu_vls_printf(logstr, "outer diameter cannot be 0.0 or less");
4580  return BRLCAD_ERROR;
4581  }
4582  ptp->pp_od = tmp;
4583  break;
4584  case 'R':
4585  ptp->pp_bendradius = atof(argv[1]);
4586  break;
4587  default:
4588  bu_vls_printf(logstr, "unrecognized attribute, choices are V, I, O, or R");
4589  return BRLCAD_ERROR;
4590  }
4591 
4592  argc -= 2;
4593  argv += 2;
4594  }
4595 
4596  return (rt_pipe_ck(&pip->pipe_segs_head) == 0) ? TCL_OK : BRLCAD_ERROR;
4597 }
4598 
4599 
4600 int
4601 rt_pipe_params(struct pc_pc_set *UNUSED(ps), const struct rt_db_internal *ip)
4602 {
4603  if (ip) {
4604  RT_CK_DB_INTERNAL(ip);
4605  }
4606 
4607  return 0; /* OK */
4608 }
4609 
4610 
4611 void
4613 {
4614  struct bu_list head;
4615  point_t min, max;
4616  struct id_pipe *p;
4617  fastf_t len_sq;
4618  struct lin_pipe *lin;
4619  struct bend_pipe *bend;
4620  fastf_t prev_ir, prev_or, start_ir, start_or, end_ir, end_or, tmpval;
4621  point_t last_end, first_start;
4622  vect_t *end_normal, *start_normal;
4623  int connected;
4624  char overlap;
4625 
4626  BU_LIST_INIT(&head);
4627 
4628  pipe_elements_calculate(&head, ip, &min, &max);
4629 
4630  /* The following calculation establishes if the last pipe segment
4631  * is in fact connected to the first one. The last end point is
4632  * checked to be equal to the first start point, and the normals
4633  * are checked to be either 0 or 180 degree to each other: abs(dot product) == 1.
4634  * If the first/last segments are connected, the starting/ending
4635  * surfaces will cancel each other where overlapping.
4636  */
4637  p = BU_LIST_LAST(id_pipe, &head);
4638  if (!p->pipe_is_bend) {
4639  lin = (struct lin_pipe *)p;
4640  prev_ir = lin->pipe_ritop;
4641  prev_or = lin->pipe_rotop;
4642  VJOIN1(last_end, lin->pipe_V, lin->pipe_len, lin->pipe_H);
4643  end_normal = &(lin->pipe_H);
4644  } else {
4645  bend = (struct bend_pipe *)p;
4646  prev_ir = bend->bend_ir;
4647  prev_or = bend->bend_or;
4648  VMOVE(last_end, bend->bend_end);
4649  end_normal = &(bend->bend_endNorm);
4650  }
4651 
4652  p = BU_LIST_FIRST(id_pipe, &head);
4653  if (!p->pipe_is_bend) {
4654  lin = (struct lin_pipe *)p;
4655  VMOVE(first_start, lin->pipe_V);
4656  start_normal = &(lin->pipe_H);
4657  } else {
4658  bend = (struct bend_pipe *)p;
4659  VMOVE(first_start, bend->bend_start);
4660  start_normal = &(bend->bend_startNorm);
4661  }
4662 
4663  connected = VNEAR_EQUAL(first_start, last_end, RT_LEN_TOL)
4664  && NEAR_EQUAL(fabs(VDOT(*start_normal, *end_normal)), 1.0, RT_DOT_TOL);
4665 
4666  *area = 0;
4667  /* The the total surface area is calculated as a sum of the areas for:
4668  * + outer lateral pipe surface;
4669  * + inner lateral pipe surface;
4670  * + unconnected/non-overlapping cross-section surface at the ends of the pipe segments;
4671  */
4672  for (BU_LIST_FOR(p, id_pipe, &head)) {
4673  if (!p->pipe_is_bend) {
4674  lin = (struct lin_pipe *)p;
4675  /* Lateral Surface Area = PI * (r_base + r_top) * sqrt(pipe_len^2 + (r_base-r_top)^2) */
4676  len_sq = lin->pipe_len * lin->pipe_len;
4677  *area += M_PI * (lin->pipe_robase + lin->pipe_rotop)
4678  * (sqrt(len_sq + lin->pipe_rodiff_sq) /* outer surface */
4679  + sqrt(len_sq + lin->pipe_ridiff_sq)); /* inner surface */
4680  start_or = lin->pipe_robase;
4681  start_ir = lin->pipe_ribase;
4682  end_or = lin->pipe_rotop;
4683  end_ir = lin->pipe_ritop;
4684  } else {
4685  bend = (struct bend_pipe *)p;
4686  /* Torus Surface Area = 4 * PI^2 * r_bend * r_pipe
4687  * Bend Surface Area = torus_area * (bend_angle / (2*PI))
4688  * = 2 * PI * bend_angle * r_bend * r_pipe
4689  * Inner + Outer Area = 2 * PI * bend_angle * r_bend * (r_outer + r_inner)
4690  */
4691  *area += M_2PI * bend->bend_angle * bend->bend_radius * (bend->bend_ir + bend->bend_or);
4692  start_or = end_or = bend->bend_or;
4693  start_ir = end_ir = bend->bend_ir;
4694  }
4695  if (connected) {
4696  overlap = 0;
4697  /* For the case of equality we consider only the start overlapping,
4698  * to not have both start and prev report an overlap at the same time.
4699  * This way we have simplified cases to handle, as overlaps will always
4700  * come in pairs, and some pairs can be excluded too.
4701  */
4702  if (start_ir >= prev_ir && start_ir <= prev_or) {
4703  overlap += 1;
4704  }
4705  if (start_or >= prev_ir && start_or <= prev_or) {
4706  overlap += 2;
4707  }
4708  if (prev_ir > start_ir && prev_ir < start_or) {
4709  overlap += 4;
4710  }
4711  if (prev_or > start_ir && prev_or < start_or) {
4712  overlap += 8;
4713  }
4714  /* Overlaps are expected always in pairs, so the sum of the set digits should be always 2 */
4715  switch (overlap) {
4716  case 0: /* no overlap between the cross sections, the areas are both added, nothing to fix */
4717  break;
4718  case 3: /* start cross section contained completely by the prev cross section; we swap start_ir with prev_or */
4719  case 9: /* section between start_ir and prev_or overlap; we swap them */
4720  case 12: /* prev cross section contained completely by the start cross section; we swap start_ir with prev_or */
4721  tmpval = start_ir;
4722  start_ir = prev_or;
4723  prev_or = tmpval;
4724  break;
4725  case 6: /* section between prev_ir and start_or overlap; we swap them */
4726  tmpval = prev_ir;
4727  prev_ir = start_or;
4728  start_or = tmpval;
4729  break;
4730  default:
4731  bu_log("rt_pipe_surf_area: Unexpected cross-section overlap code: (%d)\n", overlap);
4732  break;
4733  }
4734  } else {
4735  /* not connected, both areas are added regardless of overlaps */
4736  /* this can happen only on the first segment, and all further segments will be connected: */
4737  connected = 1;
4738  }
4739  tmpval = 0;
4740  /* start cross section */
4741  if (!NEAR_EQUAL(start_or, start_ir, RT_LEN_TOL)) {
4742  tmpval += (start_or + start_ir) * (start_or - start_ir);
4743  }
4744  /* previous end cross section */
4745  if (!NEAR_EQUAL(start_or, start_ir, RT_LEN_TOL)) {
4746  tmpval += (prev_or + prev_ir) * (prev_or - prev_ir);
4747  }
4748  *area += M_PI * tmpval;
4749  prev_or = end_or;
4750  prev_ir = end_ir;
4751  }
4752 
4753  pipe_elements_free(&head);
4754 
4755 }
4756 
4757 
4758 HIDDEN void
4759 pipe_elem_volume_and_centroid(struct id_pipe *p, fastf_t *vol, point_t *cent)
4760 {
4761  fastf_t crt_vol, cs;
4762  point_t cp;
4763 
4764  /* Note: the centroid is premultiplied with the corresponding partial volume ! */
4765  if (!p->pipe_is_bend) {
4766  struct lin_pipe *lin = (struct lin_pipe *)p;
4767  /* Volume = PI * (r_base*r_base + r_top*r_top + r_base*r_top) * pipe_len / 3 */
4768  crt_vol = M_PI * lin->pipe_len / 3
4769  * (lin->pipe_robase*lin->pipe_robase + lin->pipe_robase*lin->pipe_rotop + lin->pipe_rotop*lin->pipe_rotop
4770  - lin->pipe_ribase*lin->pipe_ribase - lin->pipe_ribase*lin->pipe_ritop - lin->pipe_ritop*lin->pipe_ritop);
4771  *vol += crt_vol;
4772 
4773  if (cent != NULL) {
4774  /* centroid coefficient from the middle-point of the base
4775  * (premultiplied with the volume):
4776  * cbase = 1/12 * PI * pipe_len * pipe_len * (3*rtop^2 + 2*rtop*rbase + rbase^2)
4777  */
4778  cs = M_PI * lin->pipe_len * lin->pipe_len / 12.0
4779  * (3*(lin->pipe_rotop + lin->pipe_ritop)*(lin->pipe_rotop - lin->pipe_ritop)
4780  + 2*(lin->pipe_robase*lin->pipe_rotop - lin->pipe_ribase*lin->pipe_ritop)
4781  + (lin->pipe_robase + lin->pipe_ribase)*(lin->pipe_robase - lin->pipe_ribase));
4782  VCOMB2(cp, crt_vol, lin->pipe_V, cs, lin->pipe_H);
4783  VADD2(*cent, *cent, cp);
4784  }
4785  } else {
4786  struct bend_pipe *bend = (struct bend_pipe *)p;
4787  /* Torus Volume = 2 * PI^2 * r_bend * r_pipe^2
4788  * Bend Volume = torus_area * (bend_angle / (2*PI))
4789  * = PI * bend_angle * r_bend * r_pipe^2
4790  * Mass Volume = Displacement Volume - Inner Volume = PI * bend_angle * r_bend * (r_outer^2 - r_inner^2)
4791  */
4792  crt_vol = M_PI * bend->bend_angle * bend->bend_radius * (bend->bend_or + bend->bend_ir) * (bend->bend_or - bend->bend_ir);
4793  *vol += crt_vol;
4794 
4795  if (cent != NULL) {
4796  /* The centroid sits on the line between bend_V and the
4797  * middle point of bend_start, at distance
4798  * cos(bend->bend_angle/4)*bend->bend_radius */
4799  VCOMB2(cp, 0.5, bend->bend_start, 0.5, bend->bend_end);
4800  VSUB2(cp, cp, bend->bend_V);
4801  VUNITIZE(cp);
4802  cs = crt_vol * cos(bend->bend_angle/4) * bend->bend_radius;
4803  VCOMB2(cp, crt_vol, bend->bend_V, cs, cp);
4804  VADD2(*cent, *cent, cp);
4805  }
4806  }
4807 }
4808 
4809 
4810 void
4812 {
4813  struct bu_list head;
4814  point_t min, max;
4815  struct id_pipe *p;
4816 
4817  BU_LIST_INIT(&head);
4818 
4819  pipe_elements_calculate(&head, ip, &min, &max);
4820 
4821  *vol = 0;
4822  for (BU_LIST_FOR(p, id_pipe, &head)) {
4823  pipe_elem_volume_and_centroid(p, vol, NULL);
4824  }
4825 
4826  pipe_elements_free(&head);
4827 }
4828 
4829 
4830 void
4831 rt_pipe_centroid(point_t *cent, struct rt_db_internal *ip)
4832 {
4833  struct bu_list head;
4834  point_t min, max;
4835  struct id_pipe *p;
4836  fastf_t vol;
4837 
4838  BU_LIST_INIT(&head);
4839 
4840  pipe_elements_calculate(&head, ip, &min, &max);
4841 
4842  VSETALL(*cent, 0);
4843  vol = 0;
4844 
4845  for (BU_LIST_FOR(p, id_pipe, &head)) {
4846  pipe_elem_volume_and_centroid(p, &vol, cent);
4847  }
4848  VSCALE(*cent, *cent, 1/vol);
4849  pipe_elements_free(&head);
4850 }
4851 
4852 
4853 /*
4854  * Local Variables:
4855  * mode: C
4856  * tab-width: 8
4857  * indent-tabs-mode: t
4858  * c-file-style: "stroustrup"
4859  * End:
4860  * ex: shiftwidth=4 tabstop=8
4861  */
Definition: db_flip.c:35
#define BU_LIST_PNEXT_CIRC(structure, p)
Definition: list.h:442
char * d_namep
pointer to name string
Definition: raytrace.h:859
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
Definition: raytrace.h:800
fastf_t cf[BN_MAX_POLY_DEGREE+1]
Definition: poly.h:50
uint32_t hit_magic
Definition: raytrace.h:249
struct bu_list l
Definition: pipe.c:61
#define NMG_EDGEUSE_MAGIC
Definition: magic.h:120
mat_t bend_SoR
Definition: pipe.c:86
#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
vect_t bend_ra
Definition: pipe.c:93
#define SIZEOF_NETWORK_DOUBLE
Definition: cv.h:48
int nmg_edge_fuse(const uint32_t *magic_p, const struct bn_tol *tol)
Definition: nmg_fuse.c:1062
int rt_pipe_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: pipe.c:3901
struct faceuse * nmg_cface(struct shell *s, struct vertex **verts, int n)
Definition: nmg_mod.c:1130
fastf_t C[2 *MAX_CNT+1][2 *MAX_CNT+1]
Definition: dsp_brep.cpp:38
Definition: list.h:118
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
point_t bend_end
Definition: pipe.c:134
#define BU_LIST_LAST(structure, hp)
Definition: list.h:306
#define RT_DOT_TOL
Definition: raytrace.h:170
int nmg_kfu(struct faceuse *fu1)
Definition: nmg_mk.c:1207
int rt_pipe_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: pipe.c:4199
#define ID_PIPE
Pipe (wire) solid.
Definition: raytrace.h:473
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
vect_t bend_rb
Definition: pipe.c:94
double dist
>= 0
Definition: tol.h:73
int pipe_is_bend
Definition: pipe.c:81
vect_t crv_pdir
Principle direction.
Definition: raytrace.h:307
const mat_t bn_mat_identity
Matrix and vector functionality.
Definition: mat.c:46
point_t bend_end
Definition: pipe.c:89
if lu s
Definition: nmg_mod.c:3860
fastf_t pipe_robase
Definition: pipe.c:69
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
lu
Definition: nmg_mod.c:3855
#define VSET(a, b, c, d)
Definition: color.c:53
int rt_pipe_ck(const struct bu_list *headp)
Definition: pipe.c:4278
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
void bn_pr_roots(const char *title, const struct bn_complex roots[], int n)
HIDDEN void bend_pipe_shot(struct soltab *stp, struct xray *rp, struct bend_pipe *bp, struct hit *hits, int *hit_count, int seg_no)
Definition: pipe.c:883
mat_t pipe_SoR
Definition: pipe.c:72
#define PIPE_CONNECTING_ARCS
Definition: pipe.c:139
#define BU_LIST_IS_EMPTY(hp)
Definition: list.h:295
#define M_PI
Definition: fft.h:35
Definition: pc.h:108
double dist_sq
dist * dist
Definition: tol.h:74
void rt_hitsort(struct hit h[], int nh)
Definition: raytrace.h:368
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
Definition: pipe.c:60
struct pipe_orientation orient
Definition: pipe.c:123
fastf_t pipe_rotop
Definition: pipe.c:69
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
#define PIPE_CIRCLE_SEGS
Definition: pipe.c:140
fastf_t pipe_ritop
Definition: pipe.c:65
#define SMALL_FASTF
Definition: defines.h:342
#define PIPE_LINEAR_TOP
Definition: pipe.c:144
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
void rt_pipe_ifree(struct rt_db_internal *ip)
Definition: pipe.c:4250
#define PIPE_LINEAR_OUTER_BODY
Definition: pipe.c:142
void nmg_rebound(struct model *m, const struct bn_tol *tol)
Definition: nmg_misc.c:2072
Header file for the BRL-CAD common definitions.
int bn_mat_inverse(mat_t output, const mat_t input)
void nmg_vertexuse_nv(struct vertexuse *vu, const fastf_t *norm)
Definition: nmg_mk.c:1719
int rt_pipe_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: pipe.c:3709
Definition: poly.h:47
void free_vert_tree(struct vert_root *tree_root)
Routine to free a vertex tree and all associated dynamic memory.
Definition: vert_tree.c:155
#define BU_LIST_APPEND(old, new)
Definition: list.h:197
#define PIPE_BEND_TOP
Definition: pipe.c:149
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
struct vert_root * create_vert_tree(void)
routine to create a vertex tree.
Definition: vert_tree.c:80
point_t pipe_min
Definition: pipe.c:74
HIDDEN void pipe_elem_volume_and_centroid(struct id_pipe *p, fastf_t *vol, point_t *cent)
Definition: pipe.c:4759
int rt_in_rpp(struct xray *rp, const fastf_t *invdir, const fastf_t *min, const fastf_t *max)
void bu_cv_htond(unsigned char *out, const unsigned char *in, size_t count)
point_t bend_bound_center
Definition: pipe.c:98
fastf_t bend_radius
Definition: pipe.c:82
int rt_pipe_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: pipe.c:2342
HIDDEN int rt_bend_pipe_prep(struct bu_list *head, fastf_t *bend_center, fastf_t *bend_start, fastf_t *bend_end, fastf_t bend_radius, fastf_t bend_angle, fastf_t od, fastf_t id, fastf_t prev_od, fastf_t next_od, point_t *min, point_t *max)
Definition: pipe.c:330
fastf_t bend_angle
Definition: pipe.c:92
int rt_pipe_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
Definition: pipe.c:1681
#define HIDDEN
Definition: common.h:86
int nmg_calc_face_g(struct faceuse *fu)
Definition: nmg_misc.c:1786
#define PIPE_BEND_OUTER_BODY
Definition: pipe.c:146
NMG_CK_LOOPUSE(lu)
fastf_t bend_alpha_i
Definition: pipe.c:90
struct bu_list l
Definition: raytrace.h:369
fastf_t curve_spacing
Definition: raytrace.h:1940
double re
real part
Definition: complex.h:40
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
void rt_pipe_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
Definition: pipe.c:1591
double rel
rel dist tol
Definition: raytrace.h:181
int rt_pipe_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: pipe.c:3975
if(share_geom)
Definition: nmg_mod.c:3829
int idb_major_type
Definition: raytrace.h:192
size_t dgr
Definition: poly.h:49
Definition: color.c:49
point_t center
Definition: pipe.c:114
point_t bend_start
Definition: pipe.c:88
int connecting_arcs
Definition: pipe.c:125
HIDDEN void tesselate_pipe_linear(fastf_t *start_pt, fastf_t orad, fastf_t irad, fastf_t *end_pt, fastf_t end_orad, fastf_t end_irad, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, fastf_t *r1, fastf_t *r2, struct shell *s, const struct bn_tol *tol)
Definition: pipe.c:2509
#define BU_LIST_IS_HEAD(p, hp)
Definition: list.h:322
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
vect_t a_inv_dir
filled in by rt_shootray(), inverse of ray direction cosines
Definition: raytrace.h:1614
void rt_pipe_volume(fastf_t *vol, struct rt_db_internal *ip)
Definition: pipe.c:4811
#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
point_t bend_start
Definition: pipe.c:133
fastf_t crv_c2
curvature in other direction
Definition: raytrace.h:309
int Add_vert(double x, double y, double z, struct vert_root *tree_root, fastf_t local_tol_sq)
Routine to add a vertex to the current list of part vertices. The array is re-alloc'd if needed...
Definition: vert_tree.c:181
Definition: pipe.c:54
fastf_t pipe_ribase
Definition: pipe.c:65
#define BN_VLIST_LINE_MOVE
Definition: vlist.h:82
fastf_t bend_angle
Definition: pipe.c:135
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
vect_t bend_normal
Definition: pipe.c:132
#define V3ARGS(a)
Definition: color.c:56
vect_t pipe_V
Definition: pipe.c:63
vect_t bend_endNorm
Definition: pipe.c:95
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
#define RT_CK_TESS_TOL(_p)
Definition: raytrace.h:184
struct loopuse * nmg_mlv(uint32_t *magic, struct vertex *v, int orientation)
Definition: nmg_mk.c:571
#define BRLCAD_OK
Definition: defines.h:71
unsigned char * bp
Definition: rot.c:56
uint8_t * ext_buf
Definition: parse.h:216
static void top()
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
int pipe_is_bend
Definition: pipe.c:62
fastf_t pipe_rodiff_sq
Definition: pipe.c:68
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
struct faceuse * nmg_add_loop_to_face(struct shell *s, struct faceuse *fu, struct vertex **verts, int n, int dir)
Definition: nmg_mod.c:1211
#define SQRT_SMALL_FASTF
Definition: defines.h:346
void rt_pipe_free(struct soltab *stp)
Definition: pipe.c:1810
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
mat_t pipe_invRoS
Definition: pipe.c:73
fastf_t pipe_len
Definition: pipe.c:71
struct bu_list * pipe_segs_head
Definition: pipe.c:122
fastf_t pipe_robase_sq
Definition: pipe.c:70
void bn_mat_trn(mat_t om, const mat_t im)
char * bu_next_token(char *str)
Definition: parse.c:2469
#define UNUSED(parameter)
Definition: common.h:239
HIDDEN void pipe_elements_free(struct bu_list *head)
Definition: pipe.c:638
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
int rt_pipe_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
Definition: pipe.c:4391
void bn_mat_mul(mat_t o, const mat_t a, const mat_t b)
Vertex tree support Routines to manage a binary search tree of vertices.
Definition: vert_tree.h:50
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
mat_t bend_invR
Definition: pipe.c:85
#define BU_LIST_FIRST_MAGIC(hp)
Definition: list.h:416
vect_t bend_N
Definition: pipe.c:97
struct bu_list l
Definition: pipe.c:55
int rt_pipe_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: pipe.c:4601
uint32_t magic
Magic # for mem id/check.
Definition: list.h:119
struct edgeuse * nmg_meonvu(struct vertexuse *vu)
Definition: nmg_mk.c:800
HIDDEN void pipe_end_shot(struct soltab *stp, struct xray *rp, struct id_pipe *id_p, struct hit *hits, int *hit_count, int seg_no)
Definition: pipe.c:1427
#define BU_LIST_WHILE(p, structure, hp)
Definition: list.h:410
fastf_t pipe_ridiff_sq
Definition: pipe.c:67
struct pipe_circle pipe_circle
Definition: pipe.c:130
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
point_t pipe_max
Definition: pipe.c:75
void rt_pipe_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp)
Definition: pipe.c:1797
int rt_pipe_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: pipe.c:659
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
HIDDEN const double cs
Definition: sh_prj.c:617
#define RT_PIPE_MAXHITS
Definition: pipe.c:152
#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
#define PIPE_BEND_INNER_BODY
Definition: pipe.c:147
#define ZERO(val)
Definition: units.c:38
#define BU_LIST_INIT(_hp)
Definition: list.h:148
struct bu_list l
Definition: pipe.c:80
void * idb_ptr
Definition: raytrace.h:195
vect_t bend_startNorm
Definition: pipe.c:96
int overlap(struct application *ap, struct partition *pp, struct region *reg1, struct region *reg2, struct partition *hp)
Definition: gqa.c:843
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_in_sph(struct xray *rp, point_t center, fastf_t radius_sq)
Definition: pipe.c:864
HIDDEN void pipe_elements_calculate(struct bu_list *elements_head, struct rt_db_internal *ip, point_t *min, point_t *max)
Definition: pipe.c:529
int rt_pipe_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
Definition: pipe.c:4058
point_t bend_V
Definition: pipe.c:87
void bu_cv_ntohd(unsigned char *out, const unsigned char *in, size_t count)
Definition: pipe.c:79
const struct rt_functab OBJ[]
Definition: table.c:159
int rt_poly_roots(bn_poly_t *eqn, bn_complex_t roots[], const char *name)
#define PIPE_LINEAR_BASE
Definition: pipe.c:145
#define PIPE_BEND_BASE
Definition: pipe.c:148
HIDDEN void discont_radius_shot(struct xray *rp, point_t center, vect_t norm, fastf_t or1_sq, fastf_t ir1_sq, fastf_t or2_sq, fastf_t ir2_sq, struct hit *hits, int *hit_count, int seg_no, struct soltab *stp)
Definition: pipe.c:800
#define WDB_PIPESEG_MAGIC
Definition: magic.h:214
void rt_pipe_centroid(point_t *cent, struct rt_db_internal *ip)
Definition: pipe.c:4831
void bn_vec_ortho(vect_t out, const vect_t in)
void rt_pipe_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
Definition: pipe.c:1774
fastf_t bend_bound_radius_sq
Definition: pipe.c:99
HIDDEN void tesselate_pipe_end(struct wdb_pipept *pipept, int arc_segs, struct vertex ***outer_loop, struct vertex ***inner_loop, struct shell *s, const struct bn_tol *tol)
Definition: pipe.c:3629
#define R
Definition: msr.c:55
vect_t v1
Definition: pipe.c:105
void rt_pipe_print(const struct soltab *stp)
Definition: pipe.c:723
double abs
absolute dist tol
Definition: raytrace.h:180
void rt_pipept_print(const struct wdb_pipept *pipept, double mm2local)
Definition: pipe.c:734
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
HIDDEN void tesselate_pipe_start(struct wdb_pipept *pipept, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, fastf_t *r1, fastf_t *r2, struct shell *s, const struct bn_tol *tol)
Definition: pipe.c:2387
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 rt_pipe_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv)
Definition: pipe.c:4470
#define BU_LIST_BACK(structure, hp)
Definition: list.h:308
HIDDEN void rt_pipe_elim_dups(struct hit *hit, int *nh, struct xray *rp, struct soltab *stp)
Definition: pipe.c:1510
HIDDEN void pipe_start_shot(struct soltab *stp, struct xray *rp, struct id_pipe *id_p, struct hit *hits, int *hit_count, int seg_no)
Definition: pipe.c:1352
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
#define A
Definition: msr.c:51
int rt_pipe_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: pipe.c:684
Definition: color.c:51
struct pipe_circle bend_circle
Definition: pipe.c:131
void plot_ellipse(struct bu_list *vhead, const vect_t t, const vect_t a, const vect_t b, int num_points)
double norm
normal tol
Definition: raytrace.h:182
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
struct rt_i * st_rtip
"up" pointer to rt_i
Definition: raytrace.h:429
vect_t pipe_H
Definition: pipe.c:64
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
fastf_t bend_alpha_o
Definition: pipe.c:91
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
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
NMG_CK_SHELL(s)
int rt_pipe_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: pipe.c:4128
struct faceuse * nmg_cmface(struct shell *s, struct vertex ***verts, int n)
Definition: nmg_mod.c:979
fastf_t pipe_ribase_sq
Definition: pipe.c:66
#define PIPE_RADIUS_CHANGE
Definition: pipe.c:150
Complex numbers.
Definition: complex.h:39
HIDDEN void draw_pipe_arc(struct bu_list *vhead, struct pipe_circle arc_circle, const point_t arc_end, int num_segments)
Definition: pipe.c:2017
#define BU_LIST_DEQUEUE(cur)
Definition: list.h:209
size_t ext_nbytes
Definition: parse.h:210
void ellipse_point_at_radian(point_t result, const vect_t center, const vect_t axis_a, const vect_t axis_b, fastf_t radian)
#define BU_LIST_HEAD_MAGIC
Definition: magic.h:56
fastf_t bend_ir
Definition: pipe.c:84
fastf_t pipe_rotop_sq
Definition: pipe.c:70
fastf_t pipe_ritop_sq
Definition: pipe.c:66
#define PIPE_LINEAR_INNER_BODY
Definition: pipe.c:143
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
int rt_pipe_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info)
Definition: pipe.c:2300
Definition: vls.h:56
HIDDEN void rt_linear_pipe_prep(struct bu_list *head, fastf_t *pt1, fastf_t id1, fastf_t od1, fastf_t *pt2, fastf_t id2, fastf_t od2, point_t *min, point_t *max)
Definition: pipe.c:434
fastf_t radius
Definition: pipe.c:115
#define BRLCAD_ERROR
Definition: defines.h:72
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
point_t last_drawn
Definition: pipe.c:124
double fastf_t
Definition: defines.h:300
int pipe_is_bend
Definition: pipe.c:56
#define VPRINT(a, b)
Definition: raytrace.h:1881
struct wdb_pipept * cur
Definition: pipe.c:121
#define BU_LIST_NEXT(structure, hp)
Definition: list.h:316
#define BU_LIST_NOT_HEAD(p, hp)
Definition: list.h:324
void rt_pipe_surf_area(fastf_t *area, struct rt_db_internal *ip)
Definition: pipe.c:4612
Tcl_Interp * brlcad_interp
Definition: tcl.c:41
HIDDEN void tesselate_pipe_bend(fastf_t *bend_start, fastf_t *bend_end, fastf_t *bend_center, fastf_t orad, fastf_t irad, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, fastf_t *start_r1, fastf_t *start_r2, struct shell *s, const struct bn_tol *tol, const struct rt_tess_tol *ttol)
Definition: pipe.c:3190
fastf_t pipe_rodiff
Definition: pipe.c:68
#define BU_LIST_PREV(structure, hp)
Definition: list.h:310
void bn_mat_arb_rot(mat_t m, const point_t pt, const vect_t dir, const fastf_t ang)
Definition: mat.c:987
HIDDEN void linear_pipe_shot(struct soltab *stp, struct xray *rp, struct lin_pipe *lp, struct hit *hits, int *hit_count, int seg_no)
Definition: pipe.c:1203
Definition: color.c:50
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
vect_t v2
Definition: pipe.c:106
void rt_vls_pipept(struct bu_vls *vp, int seg_no, const struct rt_db_internal *ip, double mm2local)
Definition: pipe.c:753
fastf_t bend_or
Definition: pipe.c:83
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
#define RT_PIPE_INTERNAL_MAGIC
Definition: magic.h:104
#define RT_HIT_MAGIC
Definition: magic.h:161
struct pipe_orientation orient
Definition: pipe.c:116
fastf_t pipe_ridiff
Definition: pipe.c:67