BRL-CAD
extrude.c
Go to the documentation of this file.
1 /* E X T R U D 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/extrude/extrude.c
23  *
24  * Provide support for solids of extrusion.
25  *
26  */
27 
28 #include "common.h"
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <math.h>
33 #include <string.h>
34 #include "bnetwork.h"
35 
36 #include "tcl.h"
37 #include "bu/cv.h"
38 #include "bu/debug.h"
39 #include "vmath.h"
40 #include "db.h"
41 #include "nmg.h"
42 #include "rtgeom.h"
43 #include "raytrace.h"
44 #include "nurb.h"
45 
46 #include "../../librt_private.h"
47 
48 
49 extern int seg_to_vlist(struct bu_list *vhead, const struct rt_tess_tol *ttol, point_t V,
50  vect_t u_vec, vect_t v_vec, struct rt_sketch_internal *sketch_ip, void *seg);
51 
52 extern void rt_sketch_surf_area(fastf_t *area, const struct rt_db_internal *ip);
53 extern void rt_sketch_centroid(point_t *cent, const struct rt_db_internal *ip);
54 
56  mat_t rot, irot; /* rotation and translation to get extrusion vector in +z direction with V at origin */
57  vect_t unit_h; /* unit vector in direction of extrusion vector */
58  vect_t u_vec; /* u vector rotated and projected */
59  vect_t v_vec; /* v vector rotated and projected */
60  fastf_t uv_scale; /* length of original, untransformed u_vec */
61  vect_t rot_axis; /* axis of rotation for rotation matrix */
62  vect_t perp; /* vector in pl1_rot plane and normal to rot_axis */
63  plane_t pl1, pl2; /* plane equations of the top and bottom planes (not rotated) */
64  plane_t pl1_rot; /* pl1 rotated by rot */
65  point_t *verts; /* sketch vertices projected onto a plane normal to extrusion vector */
66  struct rt_curve crv; /* copy of the referenced curve */
67 };
68 
69 
70 static struct bn_tol extr_tol = {
71  /* a fake tolerance structure for the intersection routines */
73  RT_LEN_TOL,
74  RT_LEN_TOL*RT_LEN_TOL,
75  0.0,
76  1.0
77 };
78 
79 
80 #define MAX_HITS 64
81 
82 /* defines for surf_no in the hit struct (a negative surf_no indicates an exit point) */
83 #define TOP_FACE 1 /* extruded face */
84 #define BOTTOM_FACE 2 /* face in uv-plane */
85 #define LINE_SEG 3
86 #define CARC_SEG 4
87 #define NURB_SEG 5
88 #define BEZIER_SEG 6
89 
90 /* defines for loop classification */
91 #define UNKNOWN 0
92 #define A_IN_B 1
93 #define B_IN_A 2
94 #define DISJOINT 3
95 
96 #define LOOPA 1
97 #define LOOPB 2
98 
99 /**
100  * Calculate a bounding RPP for an extruded sketch
101  */
102 int
103 rt_extrude_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
104 {
105  struct rt_extrude_internal *eip;
106  struct extrude_specific extr;
107  struct rt_sketch_internal *skt;
108  vect_t tmp, xyz[3];
109  fastf_t tmp_f, ldir[3];
110  size_t i, j;
111  size_t vert_count;
112  size_t curr_vert;
113 
114  eip = (struct rt_extrude_internal *)ip->idb_ptr;
115  RT_EXTRUDE_CK_MAGIC(eip);
116  skt = eip->skt;
117  RT_SKETCH_CK_MAGIC(skt);
118 
119  /* make sure the sketch is valid */
120  if (rt_check_curve(&skt->curve, skt, 1)) {
121  bu_log("ERROR: referenced sketch (%s) is bad!\n",
122  eip->sketch_name);
123  return -1;
124  }
125 
126  memset(&extr, 0, sizeof(struct extrude_specific));
127 
128  VMOVE(extr.unit_h, eip->h);
129  VUNITIZE(extr.unit_h);
130 
131  /* the length of the u_vec is used for scaling radii of circular
132  * arcs the u_vec and the v_vec must have the same length
133  */
134  extr.uv_scale = MAGNITUDE(eip->u_vec);
135 
136  /* build a transformation matrix to rotate extrusion vector to
137  * z-axis
138  */
139  VSET(tmp, 0, 0, 1);
140  bn_mat_fromto(extr.rot, eip->h, tmp, tol);
141 
142  /* and translate to origin */
143  extr.rot[MDX] = -VDOT(eip->V, &extr.rot[0]);
144  extr.rot[MDY] = -VDOT(eip->V, &extr.rot[4]);
145  extr.rot[MDZ] = -VDOT(eip->V, &extr.rot[8]);
146 
147  /* and save the inverse */
148  bn_mat_inv(extr.irot, extr.rot);
149 
150  /* calculate plane equations of top and bottom planes */
151  VCROSS(extr.pl1, eip->u_vec, eip->v_vec);
152  VUNITIZE(extr.pl1);
153  extr.pl1[W] = VDOT(extr.pl1, eip->V);
154  VMOVE(extr.pl2, extr.pl1);
155  VADD2(tmp, eip->V, eip->h);
156  extr.pl2[W] = VDOT(extr.pl2, tmp);
157 
158  vert_count = skt->vert_count;
159  /* count how many additional vertices we will need for arc centers */
160  for (i = 0; i < skt->curve.count; i++) {
161  struct carc_seg *csg=(struct carc_seg *)skt->curve.segment[i];
162 
163  if (csg->magic != CURVE_CARC_MAGIC)
164  continue;
165 
166  if (csg->radius <= 0.0)
167  continue;
168 
169  vert_count++;
170  }
171 
172  /* apply the rotation matrix to all the vertices, and start
173  * bounding box calculation
174  */
175  if (vert_count) {
176  extr.verts = (point_t *)bu_calloc(vert_count, sizeof(point_t),
177  "extr.verts");
178  }
179  VSETALL((*min), INFINITY);
180  VSETALL((*max), -INFINITY);
181 
182  for (i = 0; i < skt->vert_count; i++) {
183  VJOIN2(tmp, eip->V, skt->verts[i][0], eip->u_vec, skt->verts[i][1], eip->v_vec);
184  VMINMAX((*min), (*max), tmp);
185  MAT4X3PNT(extr.verts[i], extr.rot, tmp);
186  VADD2(tmp, tmp, eip->h);
187  VMINMAX((*min), (*max), tmp);
188  }
189  curr_vert = skt->vert_count;
190 
191  /* and the u, v vectors */
192  MAT4X3VEC(extr.u_vec, extr.rot, eip->u_vec);
193  MAT4X3VEC(extr.v_vec, extr.rot, eip->v_vec);
194 
195  /* calculate the rotated pl1 */
196  VCROSS(extr.pl1_rot, extr.u_vec, extr.v_vec);
197  VUNITIZE(extr.pl1_rot);
198  extr.pl1_rot[W] = VDOT(extr.pl1_rot, extr.verts[0]);
199 
200  VSET(tmp, 0, 0, 1);
201  tmp_f = VDOT(tmp, extr.unit_h);
202  if (tmp_f < 0.0)
203  tmp_f = -tmp_f;
204  tmp_f -= 1.0;
205  if (NEAR_ZERO(tmp_f, SQRT_SMALL_FASTF)) {
206  VSET(extr.rot_axis, 1.0, 0.0, 0.0);
207  VSET(extr.perp, 0.0, 1.0, 0.0);
208  } else {
209  VCROSS(extr.rot_axis, tmp, extr.unit_h);
210  VUNITIZE(extr.rot_axis);
211  if (MAGNITUDE(extr.rot_axis) < SQRT_SMALL_FASTF) {
212  VSET(extr.rot_axis, 1.0, 0.0, 0.0);
213  VSET(extr.perp, 0.0, 1.0, 0.0);
214  } else {
215  VCROSS(extr.perp, extr.rot_axis, extr.pl1_rot);
216  VUNITIZE(extr.perp);
217  }
218  }
219 
220  /* copy the curve */
221  rt_copy_curve(&extr.crv, &skt->curve);
222 
223  VSET(xyz[X], 1, 0, 0);
224  VSET(xyz[Y], 0, 1, 0);
225  VSET(xyz[Z], 0, 0, 1);
226 
227  for (i=X; i<=Z; i++) {
228  VCROSS(tmp, extr.unit_h, xyz[i]);
229  ldir[i] = MAGNITUDE(tmp);
230  }
231 
232  /* if any part of the curve is a circular arc, the arc may extend
233  * beyond the listed vertices
234  */
235  for (i = 0; i < skt->curve.count; i++) {
236  struct carc_seg *csg=(struct carc_seg *)skt->curve.segment[i];
237  struct carc_seg *csg_extr=(struct carc_seg *)extr.crv.segment[i];
238  point_t center;
239 
240  if (csg->magic != CURVE_CARC_MAGIC)
241  continue;
242 
243  if (csg->radius <= 0.0) {
244  /* full circle */
245  point_t start;
246  fastf_t radius;
247 
248  csg_extr->center = csg->end;
249  VJOIN2(start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec);
250  VJOIN2(center, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec);
251  VSUB2(tmp, start, center);
252  radius = MAGNITUDE(tmp);
253  csg_extr->radius = -radius; /* need the correct magnitude for normal calculation */
254 
255  for (j=X; j<=Z; j++) {
256  tmp_f = radius * ldir[j];
257  VJOIN1(tmp, center, tmp_f, xyz[j]);
258  VMINMAX((*min), (*max), tmp);
259  VADD2(tmp, tmp, eip->h);
260  VMINMAX((*min), (*max), tmp);
261 
262  VJOIN1(tmp, center, -tmp_f, xyz[j]);
263  VMINMAX((*min), (*max), tmp);
264  VADD2(tmp, tmp, eip->h);
265  VMINMAX((*min), (*max), tmp);
266  }
267  } else {
268  /* circular arc */
269  point_t start, end, mid;
270  vect_t s_to_m;
271  vect_t bisector;
272  fastf_t dist;
273  fastf_t magsq_s2m;
274 
275  VJOIN2(start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec);
276  VJOIN2(end, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec);
277  VBLEND2(mid, 0.5, start, 0.5, end);
278  VSUB2(s_to_m, mid, start);
279  VCROSS(bisector, extr.pl1, s_to_m);
280  VUNITIZE(bisector);
281  magsq_s2m = MAGSQ(s_to_m);
282  csg_extr->radius = csg->radius * extr.uv_scale;
283  if (magsq_s2m > csg_extr->radius*csg_extr->radius) {
284  fastf_t max_radius;
285 
286  max_radius = sqrt(magsq_s2m);
287  if (NEAR_EQUAL(max_radius, csg_extr->radius, RT_LEN_TOL)) {
288  csg_extr->radius = max_radius;
289  } else {
290  bu_log("Impossible radius for circular arc in extrusion - is %g, cannot be more than %g!\n",
291  csg_extr->radius, sqrt(magsq_s2m));
292  bu_log("Difference is %g\n", max_radius - csg->radius);
293  return -1;
294  }
295  }
296  dist = sqrt(csg_extr->radius*csg_extr->radius - magsq_s2m);
297 
298  /* save arc center */
299  if (csg->center_is_left) {
300  VJOIN1(center, mid, dist, bisector);
301  } else {
302  VJOIN1(center, mid, -dist, bisector);
303  }
304  MAT4X3PNT(extr.verts[curr_vert], extr.rot, center);
305  csg_extr->center = curr_vert;
306  curr_vert++;
307 
308  for (j=X; j<=Z; j++) {
309  tmp_f = csg_extr->radius * ldir[j];
310  VJOIN1(tmp, center, tmp_f, xyz[j]);
311  VMINMAX((*min), (*max), tmp);
312  VADD2(tmp, tmp, eip->h);
313  VMINMAX((*min), (*max), tmp);
314 
315  VJOIN1(tmp, center, -tmp_f, xyz[j]);
316  VMINMAX((*min), (*max), tmp);
317  VADD2(tmp, tmp, eip->h);
318  VMINMAX((*min), (*max), tmp);
319  }
320  }
321  }
322 
323  if (extr.verts)
324  bu_free((char *)extr.verts, "extrude->verts");
325  rt_curve_free(&(extr.crv));
326 
327  return 0; /* OK */
328 }
329 
330 
331 /**
332  * Calculate the volume of an extruded object
333  */
334 void
335 rt_extrude_volume(fastf_t *vol, const struct rt_db_internal *ip)
336 {
337  struct rt_extrude_internal *eip;
338  struct rt_sketch_internal *skt;
339  struct rt_db_internal db_skt;
340  fastf_t area;
341  fastf_t h_norm;
342  fastf_t u_norm;
343  fastf_t v_norm;
344  eip = (struct rt_extrude_internal *)ip->idb_ptr;
345  RT_EXTRUDE_CK_MAGIC(eip);
346  skt = eip->skt;
347  RT_SKETCH_CK_MAGIC(skt);
348 
349  RT_DB_INTERNAL_INIT(&db_skt);
350  db_skt.idb_ptr = (void *)skt;
351 
352  rt_sketch_surf_area(&area, &db_skt);
353 
354  h_norm = MAGNITUDE(eip->h);
355  u_norm = MAGNITUDE(eip->u_vec);
356  v_norm = MAGNITUDE(eip->v_vec);
357 
358  *vol = area * h_norm * u_norm * v_norm;
359 }
360 
361 
362 /**
363  * Given a pointer to a GED database record, and a transformation
364  * matrix, determine if this is a valid EXTRUDE, and if so, precompute
365  * various terms of the formula.
366  *
367  * Returns -
368  * 0 EXTRUDE is OK
369  * !0 Error in description
370  *
371  * Implicit return -
372  * A struct extrude_specific is created, and its address is stored in
373  * stp->st_specific for use by extrude_shot().
374  */
375 int
376 rt_extrude_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
377 {
378  struct rt_extrude_internal *eip;
379  struct extrude_specific *extr;
380  struct rt_sketch_internal *skt;
381  vect_t tmp, xyz[3];
382  fastf_t tmp_f, ldir[3];
383  size_t i, j;
384  size_t vert_count;
385  size_t curr_vert;
386 
387  if (rtip) RT_CK_RTI(rtip);
388 
389  eip = (struct rt_extrude_internal *)ip->idb_ptr;
390  RT_EXTRUDE_CK_MAGIC(eip);
391  skt = eip->skt;
392  RT_SKETCH_CK_MAGIC(skt);
393 
394  /* make sure the sketch is valid */
395  if (rt_check_curve(&skt->curve, skt, 1)) {
396  bu_log("ERROR: referenced sketch (%s) is bad!\n",
397  eip->sketch_name);
398  return -1;
399  }
400 
401  BU_GET(extr, struct extrude_specific);
402  stp->st_specific = (void *)extr;
403 
404  VMOVE(extr->unit_h, eip->h);
405  VUNITIZE(extr->unit_h);
406 
407  /* the length of the u_vec is used for scaling radii of circular
408  * arcs the u_vec and the v_vec must have the same length
409  */
410  extr->uv_scale = MAGNITUDE(eip->u_vec);
411 
412  /* build a transformation matrix to rotate extrusion vector to
413  * z-axis
414  */
415  VSET(tmp, 0, 0, 1);
416  bn_mat_fromto(extr->rot, eip->h, tmp, &rtip->rti_tol);
417 
418  /* and translate to origin */
419  extr->rot[MDX] = -VDOT(eip->V, &extr->rot[0]);
420  extr->rot[MDY] = -VDOT(eip->V, &extr->rot[4]);
421  extr->rot[MDZ] = -VDOT(eip->V, &extr->rot[8]);
422 
423  /* and save the inverse */
424  bn_mat_inv(extr->irot, extr->rot);
425 
426  /* calculate plane equations of top and bottom planes */
427  VCROSS(extr->pl1, eip->u_vec, eip->v_vec);
428  VUNITIZE(extr->pl1);
429  extr->pl1[W] = VDOT(extr->pl1, eip->V);
430  VMOVE(extr->pl2, extr->pl1);
431  VADD2(tmp, eip->V, eip->h);
432  extr->pl2[W] = VDOT(extr->pl2, tmp);
433 
434  vert_count = skt->vert_count;
435  /* count how many additional vertices we will need for arc centers */
436  for (i = 0; i < skt->curve.count; i++) {
437  struct carc_seg *csg=(struct carc_seg *)skt->curve.segment[i];
438 
439  if (csg->magic != CURVE_CARC_MAGIC)
440  continue;
441 
442  if (csg->radius <= 0.0)
443  continue;
444 
445  vert_count++;
446  }
447 
448  /* apply the rotation matrix to all the vertices, and start
449  * bounding box calculation
450  */
451  if (vert_count) {
452  extr->verts = (point_t *)bu_calloc(vert_count, sizeof(point_t),
453  "extr->verts");
454  }
455  VSETALL(stp->st_min, INFINITY);
456  VSETALL(stp->st_max, -INFINITY);
457 
458  for (i = 0; i < skt->vert_count; i++) {
459  VJOIN2(tmp, eip->V, skt->verts[i][0], eip->u_vec, skt->verts[i][1], eip->v_vec);
460  VMINMAX(stp->st_min, stp->st_max, tmp);
461  MAT4X3PNT(extr->verts[i], extr->rot, tmp);
462  VADD2(tmp, tmp, eip->h);
463  VMINMAX(stp->st_min, stp->st_max, tmp);
464  }
465  curr_vert = skt->vert_count;
466 
467  /* and the u, v vectors */
468  MAT4X3VEC(extr->u_vec, extr->rot, eip->u_vec);
469  MAT4X3VEC(extr->v_vec, extr->rot, eip->v_vec);
470 
471  /* calculate the rotated pl1 */
472  VCROSS(extr->pl1_rot, extr->u_vec, extr->v_vec);
473  VUNITIZE(extr->pl1_rot);
474  extr->pl1_rot[W] = VDOT(extr->pl1_rot, extr->verts[0]);
475 
476  VSET(tmp, 0, 0, 1);
477  tmp_f = VDOT(tmp, extr->unit_h);
478  if (tmp_f < 0.0)
479  tmp_f = -tmp_f;
480  tmp_f -= 1.0;
481  if (NEAR_ZERO(tmp_f, SQRT_SMALL_FASTF)) {
482  VSET(extr->rot_axis, 1.0, 0.0, 0.0);
483  VSET(extr->perp, 0.0, 1.0, 0.0);
484  } else {
485  VCROSS(extr->rot_axis, tmp, extr->unit_h);
486  VUNITIZE(extr->rot_axis);
487  if (MAGNITUDE(extr->rot_axis) < SQRT_SMALL_FASTF) {
488  VSET(extr->rot_axis, 1.0, 0.0, 0.0);
489  VSET(extr->perp, 0.0, 1.0, 0.0);
490  } else {
491  VCROSS(extr->perp, extr->rot_axis, extr->pl1_rot);
492  VUNITIZE(extr->perp);
493  }
494  }
495 
496  /* copy the curve */
497  rt_copy_curve(&extr->crv, &skt->curve);
498 
499  VSET(xyz[X], 1, 0, 0);
500  VSET(xyz[Y], 0, 1, 0);
501  VSET(xyz[Z], 0, 0, 1);
502 
503  for (i=X; i<=Z; i++) {
504  VCROSS(tmp, extr->unit_h, xyz[i]);
505  ldir[i] = MAGNITUDE(tmp);
506  }
507 
508  /* if any part of the curve is a circular arc, the arc may extend
509  * beyond the listed vertices
510  */
511  for (i = 0; i < skt->curve.count; i++) {
512  struct carc_seg *csg=(struct carc_seg *)skt->curve.segment[i];
513  struct carc_seg *csg_extr=(struct carc_seg *)extr->crv.segment[i];
514  point_t center;
515 
516  if (csg->magic != CURVE_CARC_MAGIC)
517  continue;
518 
519  if (csg->radius <= 0.0) {
520  /* full circle */
521  point_t start;
522  fastf_t radius;
523 
524  csg_extr->center = csg->end;
525  VJOIN2(start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec);
526  VJOIN2(center, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec);
527  VSUB2(tmp, start, center);
528  radius = MAGNITUDE(tmp);
529  csg_extr->radius = -radius; /* need the correct magnitude for normal calculation */
530 
531  for (j=X; j<=Z; j++) {
532  tmp_f = radius * ldir[j];
533  VJOIN1(tmp, center, tmp_f, xyz[j]);
534  VMINMAX(stp->st_min, stp->st_max, tmp);
535  VADD2(tmp, tmp, eip->h);
536  VMINMAX(stp->st_min, stp->st_max, tmp);
537 
538  VJOIN1(tmp, center, -tmp_f, xyz[j]);
539  VMINMAX(stp->st_min, stp->st_max, tmp);
540  VADD2(tmp, tmp, eip->h);
541  VMINMAX(stp->st_min, stp->st_max, tmp);
542  }
543  } else {
544  /* circular arc */
545  point_t start, end, mid;
546  vect_t s_to_m;
547  vect_t bisector;
548  fastf_t dist;
549  fastf_t magsq_s2m;
550 
551  VJOIN2(start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec);
552  VJOIN2(end, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec);
553  VBLEND2(mid, 0.5, start, 0.5, end);
554  VSUB2(s_to_m, mid, start);
555  VCROSS(bisector, extr->pl1, s_to_m);
556  VUNITIZE(bisector);
557  magsq_s2m = MAGSQ(s_to_m);
558  csg_extr->radius = csg->radius * extr->uv_scale;
559  if (magsq_s2m > csg_extr->radius*csg_extr->radius) {
560  fastf_t max_radius;
561 
562  max_radius = sqrt(magsq_s2m);
563  if (NEAR_EQUAL(max_radius, csg_extr->radius, RT_LEN_TOL)) {
564  csg_extr->radius = max_radius;
565  } else {
566  bu_log("Impossible radius for circular arc in extrusion (%s), is %g, cannot be more than %g!\n",
567  stp->st_dp->d_namep, csg_extr->radius, sqrt(magsq_s2m));
568  bu_log("Difference is %g\n", max_radius - csg->radius);
569  return -1;
570  }
571  }
572  dist = sqrt(csg_extr->radius*csg_extr->radius - magsq_s2m);
573 
574  /* save arc center */
575  if (csg->center_is_left) {
576  VJOIN1(center, mid, dist, bisector);
577  } else {
578  VJOIN1(center, mid, -dist, bisector);
579  }
580  MAT4X3PNT(extr->verts[curr_vert], extr->rot, center);
581  csg_extr->center = curr_vert;
582  curr_vert++;
583 
584  for (j=X; j<=Z; j++) {
585  tmp_f = csg_extr->radius * ldir[j];
586  VJOIN1(tmp, center, tmp_f, xyz[j]);
587  VMINMAX(stp->st_min, stp->st_max, tmp);
588  VADD2(tmp, tmp, eip->h);
589  VMINMAX(stp->st_min, stp->st_max, tmp);
590 
591  VJOIN1(tmp, center, -tmp_f, xyz[j]);
592  VMINMAX(stp->st_min, stp->st_max, tmp);
593  VADD2(tmp, tmp, eip->h);
594  VMINMAX(stp->st_min, stp->st_max, tmp);
595  }
596  }
597  }
598 
599  VBLEND2(stp->st_center, 0.5, stp->st_min, 0.5, stp->st_max);
600  VSUB2(tmp, stp->st_max, stp->st_min);
601  stp->st_aradius = 0.5 * MAGNITUDE(tmp);
602  stp->st_bradius = stp->st_aradius;
603 
604  return 0; /* OK */
605 }
606 
607 
608 void
609 rt_extrude_print(const struct soltab *stp)
610 {
611  struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
612 
613  VPRINT("u vector", extr->u_vec);
614  VPRINT("v vector", extr->v_vec);
615  VPRINT("h vector", extr->unit_h);
616  bn_mat_print("rotation matrix", extr->rot);
617  bn_mat_print("inverse rotation matrix", extr->irot);
618 }
619 
620 
621 static int
622 get_quadrant(fastf_t *v, fastf_t *local_x, fastf_t *local_y, fastf_t *vx, fastf_t *vy)
623 {
624 
625  *vx = V2DOT(v, local_x);
626  *vy = V2DOT(v, local_y);
627 
628  if (*vy >= 0.0) {
629  if (*vx >= 0.0)
630  return 1;
631  else
632  return 2;
633  } else {
634  if (*vx >= 0.0)
635  return 4;
636  else
637  return 3;
638  }
639 }
640 
641 
642 /*
643  * TODO: seems appropriate to make this into a proper libbn function
644  */
645 static int
646 isect_line2_ellipse(vect2d_t dist, const vect2d_t ray_start, const vect2d_t ray_dir, const vect2d_t center, const vect2d_t ra, const vect2d_t rb)
647 {
648  fastf_t a, b, c;
649  point2d_t pmc;
650  fastf_t pmcda, pmcdb;
651  fastf_t ra_sq, rb_sq;
652  fastf_t ra_4, rb_4;
653  fastf_t dda, ddb;
654  fastf_t disc;
655 
656  V2SUB2(pmc, ray_start, center);
657  pmcda = V2DOT(pmc, ra);
658  pmcdb = V2DOT(pmc, rb);
659  ra_sq = V2DOT(ra, ra);
660  ra_4 = ra_sq * ra_sq;
661  rb_sq = V2DOT(rb, rb);
662  rb_4 = rb_sq * rb_sq;
663  if (ra_4 <= SMALL_FASTF || rb_4 <= SMALL_FASTF) {
664  bu_log("ray (%g %g) -> (%g %g), semi-axes = (%g %g) and (%g %g), center = (%g %g)\n",
665  V2ARGS(ray_start), V2ARGS(ray_dir), V2ARGS(ra), V2ARGS(rb), V2ARGS(center));
666  bu_bomb("ERROR: isect_line2_ellipse: semi-axis length is too small!\n");
667  }
668 
669  dda = V2DOT(ray_dir, ra);
670  ddb = V2DOT(ray_dir, rb);
671 
672  a = dda*dda/ra_4 + ddb*ddb/rb_4;
673  b = 2.0 * (pmcda*dda/ra_4 + pmcdb*ddb/rb_4);
674  c = pmcda*pmcda/ra_4 + pmcdb*pmcdb/rb_4 - 1.0;
675 
676  disc = b*b - 4.0*a*c;
677  if (disc < 0.0)
678  return 0;
679 
680  if (disc <= SMALL_FASTF) {
681  dist[0] = -b/(2.0*a);
682  return 1;
683  }
684 
685  dist[0] = (-b - sqrt(disc)) / (2.0*a);
686  dist[1] = (-b + sqrt(disc)) / (2.0*a);
687  return 2;
688 }
689 
690 
691 /*
692  * TODO: seems appropriate to make this into a proper libbn function
693  */
694 static int
695 isect_line_earc(vect2d_t dist, const vect_t ray_start, const vect_t ray_dir, const vect_t center, const vect_t ra, const vect_t rb, const vect_t norm, const vect_t start, const vect_t end, int orientation)
696 
697 
698  /* 0 -> ccw, !0 -> cw */
699 {
700  int i;
701  int dist_count;
702  vect_t local_x, local_y, local_z;
703  fastf_t vx, vy;
704  fastf_t ex, ey;
705  fastf_t sx, sy;
706  int quad_start, quad_end, quad_pt;
707  point2d_t to_pt, pt;
708 
709  dist_count = isect_line2_ellipse(dist, ray_start, ray_dir, center, ra, rb);
710 
711  if (dist_count == 0)
712  return 0;
713 
714  if (orientation) {
715  VREVERSE(local_z, norm);
716  } else {
717  VMOVE(local_z, norm);
718  }
719 
720  VMOVE(local_x, ra);
721 
722  VCROSS(local_y, local_z, local_x);
723 
724  V2SUB2(to_pt, end, center);
725  quad_end = get_quadrant(to_pt, local_x, local_y, &ex, &ey);
726  V2SUB2(to_pt, start, center);
727  quad_start = get_quadrant(to_pt, local_x, local_y, &sx, &sy);
728 
729  i = 0;
730  while (i < dist_count) {
731  int omit;
732 
733  omit = 0;
734  V2JOIN1(pt, ray_start, dist[i], ray_dir);
735  V2SUB2(to_pt, pt, center);
736  quad_pt = get_quadrant(to_pt, local_x, local_y, &vx, &vy);
737 
738  if (quad_start < quad_end) {
739  if (quad_pt > quad_end)
740  omit = 1;
741  else if (quad_pt < quad_start)
742  omit = 1;
743  else if (quad_pt == quad_end) {
744  switch (quad_pt) {
745  case 1:
746  case 2:
747  if (vx < ex)
748  omit = 1;
749  break;
750  case 3:
751  case 4:
752  if (vx > ex)
753  omit = 1;
754  break;
755  }
756  } else if (quad_pt == quad_start) {
757  switch (quad_pt) {
758  case 1:
759  case 2:
760  if (vx > sx)
761  omit = 1;
762  break;
763  case 3:
764  case 4:
765  if (vx < sx)
766  omit = 1;
767  break;
768  }
769  }
770  } else if (quad_start > quad_end) {
771  if (quad_pt > quad_end && quad_pt < quad_start)
772  omit = 1;
773  else if (quad_pt == quad_end) {
774  switch (quad_pt) {
775  case 1:
776  case 2:
777  if (vx < ex)
778  omit = 1;
779  break;
780  case 3:
781  case 4:
782  if (vx > ex)
783  omit = 1;
784  break;
785  }
786  } else if (quad_pt == quad_start) {
787  switch (quad_pt) {
788  case 1:
789  case 2:
790  if (vx > sx)
791  omit = 1;
792  break;
793  case 3:
794  case 4:
795  if (vx < sx)
796  omit = 1;
797  break;
798  }
799  }
800  } else {
801  /* quad_start == quad_end */
802  if (quad_pt != quad_start)
803  omit = 1;
804  else {
805  switch (quad_pt) {
806  case 1:
807  case 2:
808  if (vx < ex || vx > sx)
809  omit = 1;
810  break;
811  case 3:
812  case 4:
813  if (vx > ex || vx < sx)
814  omit = 1;
815  break;
816  }
817  }
818  }
819  if (omit) {
820  if (i == 0)
821  dist[0] = dist[1];
822  dist_count--;
823  } else {
824  i++;
825  }
826  }
827 
828  return dist_count;
829 }
830 
831 
832 /**
833  * Intersect a ray with a extrude. If an intersection occurs, a
834  * struct seg will be acquired and filled in.
835  *
836  * Returns -
837  * 0 MISS
838  * >0 HIT
839  */
840 int
841 rt_extrude_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
842 {
843  struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
844  size_t i, j, k;
845  long counter;
846  fastf_t dist_top, dist_bottom, to_bottom = 0;
847  vect2d_t dist = V2INIT_ZERO;
848  fastf_t dot_pl1, dir_dot_z;
849  point_t tmp, tmp2;
850  point_t ray_start; /* 2D */
851  vect_t ray_dir, ray_dir_unit; /* 2D */
852  struct rt_curve *crv;
853  struct hit hits[MAX_HITS];
854  fastf_t dists_before[MAX_HITS];
855  fastf_t dists_after[MAX_HITS];
856  fastf_t *dists=NULL;
857  size_t dist_count = 0;
858  size_t hit_count = 0;
859  size_t hits_before_bottom = 0, hits_after_top = 0;
860  int code;
861  int check_inout = 0;
862  int top_face=TOP_FACE, bot_face=BOTTOM_FACE;
863  int surfno= -42;
864  int free_dists = 0;
865  point2d_t *verts;
866  point2d_t *intercept;
867  point2d_t *normal = NULL;
868  point2d_t ray_perp;
869  vect_t ra = VINIT_ZERO; /* 2D */
870  vect_t rb = VINIT_ZERO; /* 2D */
871 
872  crv = &extr->crv;
873 
874  /* intersect with top and bottom planes */
875  dot_pl1 = VDOT(rp->r_dir, extr->pl1);
876  if (ZERO(dot_pl1)) {
877  /* ray is parallel to top and bottom faces */
878  dist_bottom = DIST_PT_PLANE(rp->r_pt, extr->pl1);
879  dist_top = DIST_PT_PLANE(rp->r_pt, extr->pl2);
880  if (dist_bottom < 0.0 && dist_top < 0.0)
881  return 0;
882  if (dist_bottom > 0.0 && dist_top > 0.0)
883  return 0;
884  dist_bottom = -MAX_FASTF;
885  dist_top = MAX_FASTF;
886  } else {
887  dist_bottom = -DIST_PT_PLANE(rp->r_pt, extr->pl1)/dot_pl1;
888  to_bottom = dist_bottom; /* need to remember this */
889  dist_top = -DIST_PT_PLANE(rp->r_pt, extr->pl2)/dot_pl1; /* pl1 and pl2 are parallel */
890  if (dist_bottom > dist_top) {
891  fastf_t tmp1;
892 
893  tmp1 = dist_bottom;
894  dist_bottom = dist_top;
895  dist_top = tmp1;
897  bot_face = TOP_FACE;
898  }
899  }
900 
901  /* rotate ray */
902  MAT4X3PNT(ray_start, extr->rot, rp->r_pt);
903  MAT4X3VEC(ray_dir, extr->rot, rp->r_dir);
904 
905  dir_dot_z = ray_dir[Z];
906  if (dir_dot_z < 0.0)
907  dir_dot_z = -dir_dot_z;
908 
909  /* Previously using SMALL_FASTF. A tolerance of dist_sq is
910  * also too small (i.e. 1.0-16); using dist. There were cases
911  * where dir_dot_z was very close to 1.0, but not close enough
912  * to switch to using u vector as the ray direction and yet still
913  * close enough to cause a miss when there should have been a hit.
914  */
915  if (NEAR_EQUAL(dir_dot_z, 1.0, extr_tol.dist)) {
916  /* ray is parallel to extrusion vector set mode to just count
917  * intersections for Jordan Theorem
918  */
919  check_inout = 1;
920 
921  /* set the ray start to the intersection of the original ray
922  * and the base plane
923  */
924  VJOIN1(tmp, rp->r_pt, to_bottom, rp->r_dir);
925  MAT4X3PNT(ray_start, extr->rot, tmp);
926 
927  /* use the u vector as the ray direction */
928  VMOVE(ray_dir, extr->u_vec);
929  }
930 
931  /* intersect with projected curve */
932  for (i = 0; i < crv->count; i++) {
933  uint32_t *lng=(uint32_t *)crv->segment[i];
934  struct line_seg *lsg;
935  struct carc_seg *csg=NULL;
936  struct bezier_seg *bsg=NULL;
937  fastf_t diff;
938 
939  free_dists = 0;
940  switch (*lng) {
941  case CURVE_LSEG_MAGIC:
942  lsg = (struct line_seg *)lng;
943  VSUB2(tmp, extr->verts[lsg->end], extr->verts[lsg->start]);
944  VMOVE(tmp2, extr->verts[lsg->start]);
945  code = bn_isect_line2_line2(dist, ray_start, ray_dir, tmp2, tmp, &extr_tol);
946 
947  if (code < 1)
948  continue;
949 
950  if (dist[1] > 1.0 || dist[1] < 0.0)
951  continue;
952 
953  dists = dist;
954  dist_count = 1;
955  surfno = LINE_SEG;
956  break;
957  case CURVE_CARC_MAGIC:
958  /* circular arcs become elliptical arcs when projected
959  * in the XY-plane
960  */
961  csg = (struct carc_seg *)lng;
962  {
963  fastf_t radius;
964  point_t center = VINIT_ZERO;
965 
966  if (csg->radius <= 0.0) {
967  /* full circle */
968  radius = -csg->radius;
969 
970  /* build the ellipse, this actually builds a
971  * circle in 3D, but the intersection routine
972  * only uses the X and Y components
973  */
974  VSCALE(ra, extr->rot_axis, radius);
975  VSCALE(rb, extr->perp, radius);
976 
977  VSET(center, extr->verts[csg->end][X], extr->verts[csg->end][Y], 0.0);
978  dist_count = isect_line2_ellipse(dist, ray_start, ray_dir, center, ra, rb);
979  MAT4X3PNT(tmp, extr->irot, extr->verts[csg->end]); /* used later in hit->vpriv */
980  } else {
981  VSCALE(ra, extr->rot_axis, csg->radius);
982  VSCALE(rb, extr->perp, csg->radius);
983  VSET(center, extr->verts[csg->center][X], extr->verts[csg->center][Y], 0.0);
984  dist_count = isect_line_earc(dist, ray_start, ray_dir, center, ra, rb, extr->pl1_rot, extr->verts[csg->start], extr->verts[csg->end], csg->orientation);
985  MAT4X3PNT(tmp, extr->irot, extr->verts[csg->center]); /* used later in hit->vpriv */
986  }
987  }
988  if (dist_count < 1)
989  continue;
990 
991  dists = dist;
992  surfno = CARC_SEG;
993  break;
994 
995  case CURVE_BEZIER_MAGIC:
996  bsg = (struct bezier_seg *)lng;
997  verts = (point2d_t *)bu_calloc(bsg->degree + 1, sizeof(point2d_t), "Bezier verts");
998  for (j = 0; j <= (size_t)bsg->degree; j++) {
999  V2MOVE(verts[j], extr->verts[bsg->ctl_points[j]]);
1000  }
1001 
1002  V2MOVE(ray_dir_unit, ray_dir);
1003  diff = sqrt(MAG2SQ(ray_dir));
1004 
1005  ray_dir_unit[X] /= diff;
1006  ray_dir_unit[Y] /= diff;
1007  ray_dir_unit[Z] = 0.0;
1008  ray_perp[X] = ray_dir[Y];
1009  ray_perp[Y] = -ray_dir[X];
1010 
1011  dist_count = bezier_roots(verts, bsg->degree, &intercept, &normal, ray_start, ray_dir_unit, ray_perp, 0, extr_tol.dist);
1012  if (dist_count) {
1013  free_dists = 1;
1014  dists = (fastf_t *)bu_calloc(dist_count, sizeof(fastf_t), "dists (Bezier)");
1015  for (j = 0; j < dist_count; j++) {
1016  point2d_t to_pt;
1017  V2SUB2(to_pt, intercept[j], ray_start);
1018  dists[j] = V2DOT(to_pt, ray_dir_unit) / diff;
1019  }
1020  bu_free((char *)intercept, "Bezier intercept");
1021  surfno = BEZIER_SEG;
1022  }
1023 
1024  bu_free((char *)verts, "Bezier verts");
1025  break;
1026 
1027  case CURVE_NURB_MAGIC:
1028  break;
1029  default:
1030  bu_log("Unrecognized segment type in sketch referenced by extrusion (%s)\n",stp->st_dp->d_namep);
1031  bu_bomb("Unrecognized segment type in sketch\n");
1032  break;
1033  }
1034 
1035  /* eliminate duplicate hit distances */
1036  for (j = 0; j < hit_count; j++) {
1037  k = 0;
1038  while (k < dist_count) {
1039  diff = dists[k] - hits[j].hit_dist;
1040  if (NEAR_ZERO(diff, extr_tol.dist)) {
1041  size_t n;
1042  for (n=k; n<dist_count-1; n++) {
1043  dists[n] = dists[n+1];
1044  if (*lng == CURVE_BEZIER_MAGIC) {
1045  V2MOVE(normal[n], normal[n+1]);
1046  }
1047  }
1048  dist_count--;
1049  } else {
1050  k++;
1051  }
1052  }
1053  }
1054 
1055  /* eliminate duplicate hits below the bottom plane of the
1056  * extrusion
1057  */
1058  for (j = 0; j < hits_before_bottom; j++) {
1059  k = 0;
1060  while (k < dist_count) {
1061  diff = dists[k] - dists_before[j];
1062  if (NEAR_ZERO(diff, extr_tol.dist)) {
1063  size_t n;
1064  for (n=k; n<dist_count-1; n++) {
1065  dists[n] = dists[n+1];
1066  if (*lng == CURVE_BEZIER_MAGIC) {
1067  V2MOVE(normal[n], normal[n+1]);
1068  }
1069  }
1070  dist_count--;
1071  } else {
1072  k++;
1073  }
1074  }
1075  }
1076 
1077  /* eliminate duplicate hits above the top plane of the
1078  * extrusion
1079  */
1080  for (j = 0; j < hits_after_top; j++) {
1081  k = 0;
1082  while (k < dist_count) {
1083  diff = dists[k] - dists_after[j];
1084  if (NEAR_ZERO(diff, extr_tol.dist)) {
1085  size_t n;
1086  for (n=k; n<dist_count-1; n++)
1087  dists[n] = dists[n+1];
1088  dist_count--;
1089  } else {
1090  k++;
1091  }
1092  }
1093  }
1094 
1095  /* if we are just doing the Jordan curve theorem */
1096  if (check_inout) {
1097  for (j = 0; j < dist_count; j++) {
1098  if (dists[j] < 0.0)
1099  hit_count++;
1100  }
1101  continue;
1102  }
1103 
1104  /* process remaining distances into hits */
1105  for (j = 0; j < dist_count; j++) {
1106  if (dists[j] < dist_bottom) {
1107  if (hits_before_bottom >= MAX_HITS) {
1108  bu_log("ERROR: rt_extrude_shot: too many hits before bottom on extrusion (%s), limit is %d\n",
1109  stp->st_dp->d_namep, MAX_HITS);
1110  bu_bomb("ERROR: rt_extrude_shot: too many hits before bottom on extrusion\n");
1111  }
1112  dists_before[hits_before_bottom] = dists[j];
1113  hits_before_bottom++;
1114  continue;
1115  }
1116  if (dists[j] > dist_top) {
1117  if (hits_after_top >= MAX_HITS) {
1118  bu_log("ERROR: rt_extrude_shot: too many hits after top on extrusion (%s), limit is %d\n",
1119  stp->st_dp->d_namep, MAX_HITS);
1120  bu_bomb("ERROR: rt_extrude_shot: too many hits after top on extrusion\n");
1121  }
1122  dists_after[hits_after_top] = dists[j];
1123  hits_after_top++;
1124 
1125  continue;
1126  }
1127 
1128  /* got a hit at distance dists[j] */
1129  if (hit_count >= MAX_HITS) {
1130  bu_log("Too many hits on extrusion (%s), limit is %d\n",
1131  stp->st_dp->d_namep, MAX_HITS);
1132  bu_bomb("Too many hits on extrusion\n");
1133  }
1134  hits[hit_count].hit_magic = RT_HIT_MAGIC;
1135  hits[hit_count].hit_dist = dists[j];
1136  hits[hit_count].hit_surfno = surfno;
1137  switch (*lng) {
1138  case CURVE_CARC_MAGIC:
1139  hits[hit_count].hit_private = (void *)csg;
1140  VMOVE(hits[hit_count].hit_vpriv, tmp);
1141  break;
1142  case CURVE_LSEG_MAGIC:
1143  VMOVE(hits[hit_count].hit_vpriv, tmp);
1144  break;
1145  case CURVE_BEZIER_MAGIC:
1146  V2MOVE(hits[hit_count].hit_vpriv, normal[j]);
1147  hits[hit_count].hit_vpriv[Z] = 0.0;
1148  break;
1149  default:
1150  bu_log("ERROR: rt_extrude_shot: unrecognized segment type in solid %s\n",
1151  stp->st_dp->d_namep);
1152  bu_bomb("ERROR: rt_extrude_shot: unrecognized segment type in solid\n");
1153  break;
1154  }
1155  hit_count++;
1156  }
1157  if (free_dists)
1158  bu_free((char *)dists, "dists");
1159  }
1160 
1161  if (check_inout) {
1162  if (hit_count&1) {
1163  struct seg *segp;
1164 
1165  hit_count = 2;
1166  hits[0].hit_magic = RT_HIT_MAGIC;
1167  hits[0].hit_dist = dist_bottom;
1168  hits[0].hit_surfno = bot_face;
1169  VMOVE(hits[0].hit_normal, extr->pl1);
1170 
1171  hits[1].hit_magic = RT_HIT_MAGIC;
1172  hits[1].hit_dist = dist_top;
1173  hits[1].hit_surfno = -top_face;
1174  VMOVE(hits[1].hit_normal, extr->pl1);
1175 
1176  RT_GET_SEG(segp, ap->a_resource);
1177  segp->seg_stp = stp;
1178  segp->seg_in = hits[0]; /* struct copy */
1179  segp->seg_out = hits[1]; /* struct copy */
1180  BU_LIST_INSERT(&(seghead->l), &(segp->l));
1181  return 2;
1182  } else {
1183  return 0;
1184  }
1185  }
1186 
1187  if (hit_count) {
1188  /* Sort hits, Near to Far */
1189  rt_hitsort(hits, hit_count);
1190  }
1191 
1192  if (hits_before_bottom & 1) {
1193  if (hit_count >= MAX_HITS) {
1194  bu_log("Too many hits on extrusion (%s), limit is %d\n",
1195  stp->st_dp->d_namep, MAX_HITS);
1196  bu_bomb("Too many hits on extrusion\n");
1197  }
1198  for (counter=hit_count-1; counter >= 0; counter--)
1199  hits[counter+1] = hits[counter];
1200  hits[0].hit_magic = RT_HIT_MAGIC;
1201  hits[0].hit_dist = dist_bottom;
1202  hits[0].hit_surfno = bot_face;
1203  VMOVE(hits[0].hit_normal, extr->pl1);
1204  hit_count++;
1205  }
1206 
1207  if (hits_after_top & 1) {
1208  if (hit_count >= MAX_HITS) {
1209  bu_log("Too many hits on extrusion (%s), limit is %d\n",
1210  stp->st_dp->d_namep, MAX_HITS);
1211  bu_bomb("Too many hits on extrusion\n");
1212  }
1213  hits[hit_count].hit_magic = RT_HIT_MAGIC;
1214  hits[hit_count].hit_dist = dist_top;
1215  hits[hit_count].hit_surfno = top_face;
1216  VMOVE(hits[hit_count].hit_normal, extr->pl1);
1217  hit_count++;
1218  }
1219 
1220  if (hit_count%2) {
1221  point_t pt;
1222 
1223  if (hit_count != 1) {
1224  bu_log("ERROR: rt_extrude_shot(): odd number of hits (%zu) (ignoring last hit)\n", hit_count);
1225  bu_log("ray start = (%20.10f %20.10f %20.10f)\n", V3ARGS(rp->r_pt));
1226  bu_log("\tray dir = (%20.10f %20.10f %20.10f)", V3ARGS(rp->r_dir));
1227  VJOIN1(pt, rp->r_pt, hits[hit_count-1].hit_dist, rp->r_dir);
1228  bu_log("\tignored hit at (%g %g %g)\n", V3ARGS(pt));
1229  }
1230  hit_count--;
1231  }
1232 
1233  /* build segments */
1234  {
1235  size_t cnt;
1236  struct seg *segp;
1237 
1238  for (cnt = 0; cnt < hit_count; cnt += 2) {
1239  RT_GET_SEG(segp, ap->a_resource);
1240  segp->seg_stp = stp;
1241  segp->seg_in = hits[cnt]; /* struct copy */
1242  segp->seg_out = hits[cnt+1]; /* struct copy */
1243  segp->seg_out.hit_surfno = -segp->seg_out.hit_surfno; /* for exit hits */
1244  BU_LIST_INSERT(&(seghead->l), &(segp->l));
1245  }
1246  }
1247 
1248  return hit_count;
1249 }
1250 
1251 
1252 /**
1253  * Given ONE ray distance, return the normal and entry/exit point.
1254  */
1255 void
1256 rt_extrude_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
1257 {
1258  struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
1259  fastf_t alpha;
1260  point_t hit_in_plane;
1261  vect_t tmp, tmp2;
1262 
1263  VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
1264 
1265  switch (hitp->hit_surfno) {
1266  case LINE_SEG:
1267  MAT4X3VEC(tmp, extr->irot, hitp->hit_vpriv);
1268  VCROSS(hitp->hit_normal, extr->unit_h, tmp);
1269  VUNITIZE(hitp->hit_normal);
1270  break;
1271  case -LINE_SEG:
1272  MAT4X3VEC(tmp, extr->irot, hitp->hit_vpriv);
1273  VCROSS(hitp->hit_normal, extr->unit_h, tmp);
1274  VUNITIZE(hitp->hit_normal);
1275  break;
1276  case TOP_FACE:
1277  case BOTTOM_FACE:
1278  case -TOP_FACE:
1279  case -BOTTOM_FACE:
1280  break;
1281  case CARC_SEG:
1282  case -CARC_SEG:
1283  alpha = DIST_PT_PLANE(hitp->hit_point, extr->pl1) / VDOT(extr->unit_h, extr->pl1);
1284  VJOIN1(hit_in_plane, hitp->hit_point, -alpha, extr->unit_h);
1285  VSUB2(tmp, hit_in_plane, hitp->hit_vpriv);
1286  VCROSS(tmp2, extr->pl1, tmp);
1287  VCROSS(hitp->hit_normal, tmp2, extr->unit_h);
1288  VUNITIZE(hitp->hit_normal);
1289  break;
1290  case BEZIER_SEG:
1291  case -BEZIER_SEG:
1292  MAT4X3VEC(hitp->hit_normal, extr->irot, hitp->hit_vpriv);
1293  VUNITIZE(hitp->hit_normal);
1294  break;
1295  default:
1296  bu_bomb("ERROR: rt_extrude_norm(): unrecognized surf_no in hit structure!\n");
1297  break;
1298  }
1299  if (hitp->hit_surfno < 0) {
1300  if (VDOT(hitp->hit_normal, rp->r_dir) < 0.0)
1301  VREVERSE(hitp->hit_normal, hitp->hit_normal);
1302  } else {
1303  if (VDOT(hitp->hit_normal, rp->r_dir) > 0.0)
1304  VREVERSE(hitp->hit_normal, hitp->hit_normal);
1305  }
1306 
1307 }
1308 
1309 
1310 /**
1311  * Return the curvature of the extrude.
1312  */
1313 void
1314 rt_extrude_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
1315 {
1316  struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
1317  struct carc_seg *csg = NULL;
1318  fastf_t radius, a, b, a_sq, b_sq;
1319  fastf_t curvature, tmp, dota, dotb;
1320  fastf_t der = 0.0;
1321  vect_t diff = VINIT_ZERO;
1322  vect_t ra = VINIT_ZERO;
1323  vect_t rb = VINIT_ZERO;
1324 
1325  switch (hitp->hit_surfno) {
1326  case LINE_SEG:
1327  case -LINE_SEG:
1328  VMOVE(cvp->crv_pdir, hitp->hit_vpriv);
1329  VUNITIZE(cvp->crv_pdir);
1330  cvp->crv_c1 = cvp->crv_c2 = 0;
1331  break;
1332  case CARC_SEG:
1333  case -CARC_SEG:
1334  /* curvature for an ellipse (the rotated and projected
1335  * circular arc) in XY-plane based on curvature for
1336  * ellipse = |ra||rb|/(|derivative|**3)
1337  */
1338  csg = (struct carc_seg *)hitp->hit_private;
1339  VCROSS(cvp->crv_pdir, extr->unit_h, hitp->hit_normal);
1340  VSUB2(diff, hitp->hit_point, hitp->hit_vpriv);
1341  if (csg->radius < 0.0)
1342  radius = -csg->radius;
1343  else
1344  radius = csg->radius;
1345  VSCALE(ra, extr->rot_axis, radius);
1346  VSCALE(rb, extr->perp, radius);
1347 
1348  a_sq = MAG2SQ(ra);
1349  b_sq = MAG2SQ(rb);
1350  a = sqrt(a_sq);
1351  b = sqrt(b_sq);
1352  dota = VDOT(diff, ra);
1353  dotb = VDOT(diff, rb);
1354  tmp = (a_sq/(b_sq*b_sq))*dotb*dotb + (b_sq/(a_sq*a_sq))*dota*dota;
1355  der = sqrt(tmp);
1356  curvature = a*b/(der*der*der);
1357  if (VDOT(hitp->hit_normal, diff) > 0.0)
1358  cvp->crv_c1 = curvature;
1359  else
1360  cvp->crv_c1 = -curvature;
1361  cvp->crv_c2 = 0;
1362  break;
1363  }
1364 }
1365 
1366 void
1367 rt_extrude_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
1368 {
1369  if (ap) RT_CK_APPLICATION(ap);
1370  if (stp) RT_CK_SOLTAB(stp);
1371 
1372  uvp->uv_u = hitp->hit_vpriv[X];
1373  uvp->uv_v = hitp->hit_vpriv[Y];
1374  uvp->uv_du = 0;
1375  uvp->uv_dv = 0;
1376 }
1377 
1378 void
1380 {
1381  struct extrude_specific *extrude =
1382  (struct extrude_specific *)stp->st_specific;
1383 
1384  if (extrude->verts)
1385  bu_free((char *)extrude->verts, "extrude->verts");
1386  rt_curve_free(&(extrude->crv));
1387  BU_PUT(extrude, struct extrude_specific);
1388 }
1389 
1390 
1391 int
1392 rt_extrude_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info))
1393 {
1394  struct rt_extrude_internal *extrude_ip;
1395  struct rt_curve *crv = NULL;
1396  struct rt_sketch_internal *sketch_ip;
1397  point_t end_of_h;
1398  size_t i1, i2, nused1, nused2;
1399  struct bn_vlist *vp1, *vp2, *vp2_start;
1400 
1401  BU_CK_LIST_HEAD(vhead);
1402  RT_CK_DB_INTERNAL(ip);
1403  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
1404  RT_EXTRUDE_CK_MAGIC(extrude_ip);
1405 
1406  if (!extrude_ip->skt) {
1407  bu_log("ERROR: no sketch to extrude!\n");
1408  RT_ADD_VLIST(vhead, extrude_ip->V, BN_VLIST_LINE_MOVE);
1409  RT_ADD_VLIST(vhead, extrude_ip->V, BN_VLIST_LINE_DRAW);
1410  return 0;
1411  }
1412 
1413  sketch_ip = extrude_ip->skt;
1414  RT_SKETCH_CK_MAGIC(sketch_ip);
1415 
1416  crv = &sketch_ip->curve;
1417 
1418  /* empty sketch, nothing to do */
1419  if (crv->count == 0) {
1420  if (extrude_ip->sketch_name) {
1421  bu_log("Sketch [%s] is empty, nothing to draw\n", extrude_ip->sketch_name);
1422  } else {
1423  bu_log("Unnamed sketch is empty, nothing to draw\n");
1424  }
1425  RT_ADD_VLIST(vhead, extrude_ip->V, BN_VLIST_LINE_MOVE);
1426  RT_ADD_VLIST(vhead, extrude_ip->V, BN_VLIST_LINE_DRAW);
1427  return 0;
1428  }
1429 
1430  /* plot bottom curve */
1431  vp1 = BU_LIST_LAST(bn_vlist, vhead);
1432  nused1 = vp1->nused;
1433  if (curve_to_vlist(vhead, ttol, extrude_ip->V, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, crv)) {
1434  bu_log("ERROR: sketch (%s) references non-existent vertices!\n",
1435  extrude_ip->sketch_name);
1436  return -1;
1437  }
1438 
1439  /* plot top curve */
1440  VADD2(end_of_h, extrude_ip->V, extrude_ip->h);
1441  vp2 = BU_LIST_LAST(bn_vlist, vhead);
1442  nused2 = vp2->nused;
1443  curve_to_vlist(vhead, ttol, end_of_h, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, crv);
1444 
1445  /* plot connecting lines */
1446  vp2_start = vp2;
1447  i1 = nused1;
1448  if (i1 >= vp1->nused) {
1449  i1 = 0;
1450  vp1 = BU_LIST_NEXT(bn_vlist, &vp1->l);
1451  }
1452  i2 = nused2;
1453  if (i2 >= vp2->nused) {
1454  i2 = 0;
1455  vp2 = BU_LIST_NEXT(bn_vlist, &vp2->l);
1456  nused2--;
1457  }
1458 
1459  while (vp1 != vp2_start || (i1 < BN_VLIST_CHUNK && i2 < BN_VLIST_CHUNK && i1 != nused2)) {
1460  RT_ADD_VLIST(vhead, vp1->pt[i1], BN_VLIST_LINE_MOVE);
1461  RT_ADD_VLIST(vhead, vp2->pt[i2], BN_VLIST_LINE_DRAW);
1462  i1++;
1463  if (i1 >= vp1->nused) {
1464  i1 = 0;
1465  vp1 = BU_LIST_NEXT(bn_vlist, &vp1->l);
1466  }
1467  i2++;
1468  if (i2 >= vp2->nused) {
1469  i2 = 0;
1470  vp2 = BU_LIST_NEXT(bn_vlist, &vp2->l);
1471  }
1472  }
1473 
1474  return 0;
1475 }
1476 
1477 void
1478 rt_extrude_centroid(point_t *cent, const struct rt_db_internal *ip)
1479 {
1480  struct rt_extrude_internal *eip;
1481  struct rt_sketch_internal *skt;
1482  struct rt_db_internal db_skt;
1483  point_t skt_cent;
1484  point_t middle_h;
1485  eip = (struct rt_extrude_internal *)ip->idb_ptr;
1486  RT_EXTRUDE_CK_MAGIC(eip);
1487  skt = eip->skt;
1488  RT_SKETCH_CK_MAGIC(skt);
1489 
1490  RT_DB_INTERNAL_INIT(&db_skt);
1491  db_skt.idb_ptr = (void *)skt;
1492 
1493  rt_sketch_centroid(&skt_cent, &db_skt);
1494 
1495  VSCALE(middle_h, eip->h, 0.5);
1496  VADD2(*cent, skt_cent, middle_h);
1497 }
1498 
1499 
1500 void
1501 get_indices(void *seg, int *start, int *end)
1502 {
1503  struct carc_seg *csg;
1504  struct nurb_seg *nsg;
1505  struct bezier_seg *bsg;
1506  struct line_seg *lsg=(struct line_seg *)seg;
1507 
1508  switch (lsg->magic) {
1509  case CURVE_LSEG_MAGIC:
1510  *start = lsg->start;
1511  *end = lsg->end;
1512  break;
1513  case CURVE_CARC_MAGIC:
1514  csg = (struct carc_seg *)seg;
1515  if (csg->radius < 0.0) {
1516  *start = csg->start;
1517  *end = *start;
1518  break;
1519  }
1520  *start = csg->start;
1521  *end = csg->end;
1522  break;
1523  case CURVE_NURB_MAGIC:
1524  nsg = (struct nurb_seg *)seg;
1525  *start = nsg->ctl_points[0];
1526  *end = nsg->ctl_points[nsg->c_size-1];
1527  break;
1528  case CURVE_BEZIER_MAGIC:
1529  bsg = (struct bezier_seg *)seg;
1530  *start = bsg->ctl_points[0];
1531  *end = bsg->ctl_points[bsg->degree];
1532  break;
1533  }
1534 }
1535 
1536 
1537 static void
1538 get_seg_midpoint(void *seg, struct rt_sketch_internal *skt, point2d_t pt)
1539 {
1540  struct edge_g_cnurb eg;
1541  point_t tmp_pt;
1542  struct line_seg *lsg;
1543  struct carc_seg *csg;
1544  struct nurb_seg *nsg;
1545  struct bezier_seg *bsg;
1546  uint32_t *lng;
1547  point2d_t *V;
1548  point2d_t pta;
1549  int i;
1550  int coords;
1551 
1552  lng = (uint32_t *)seg;
1553 
1554  switch (*lng) {
1555  case CURVE_LSEG_MAGIC:
1556  lsg = (struct line_seg *)lng;
1557  V2ADD2(pta, skt->verts[lsg->start], skt->verts[lsg->end]);
1558  V2SCALE(pt, pta, 0.5);
1559  break;
1560  case CURVE_CARC_MAGIC:
1561  csg = (struct carc_seg *)lng;
1562  if (csg->radius < 0.0) {
1563  V2MOVE(pt, skt->verts[csg->start]);
1564  } else {
1565  point2d_t start2d = V2INIT_ZERO;
1566  point2d_t end2d = V2INIT_ZERO;
1567  point2d_t mid_pt = V2INIT_ZERO;
1568  point2d_t s2m = V2INIT_ZERO;
1569  point2d_t dir = V2INIT_ZERO;
1570  point2d_t center2d = V2INIT_ZERO;
1571  fastf_t tmp_len, len_sq, mid_ang, s2m_len_sq, cross_z;
1572  fastf_t start_ang, end_ang;
1573 
1574  /* this is an arc (not a full circle) */
1575  V2MOVE(start2d, skt->verts[csg->start]);
1576  V2MOVE(end2d, skt->verts[csg->end]);
1577  mid_pt[0] = (start2d[0] + end2d[0]) * 0.5;
1578  mid_pt[1] = (start2d[1] + end2d[1]) * 0.5;
1579  V2SUB2(s2m, mid_pt, start2d);
1580  dir[0] = -s2m[1];
1581  dir[1] = s2m[0];
1582  s2m_len_sq = s2m[0]*s2m[0] + s2m[1]*s2m[1];
1583  if (s2m_len_sq <= SMALL_FASTF) {
1584  bu_log("start and end points are too close together in circular arc of sketch\n");
1585  break;
1586  }
1587  len_sq = csg->radius*csg->radius - s2m_len_sq;
1588  if (len_sq < 0.0) {
1589  bu_log("Impossible radius for specified start and end points in circular arc\n");
1590  break;
1591  }
1592  tmp_len = sqrt(dir[0]*dir[0] + dir[1]*dir[1]);
1593  dir[0] = dir[0] / tmp_len;
1594  dir[1] = dir[1] / tmp_len;
1595  tmp_len = sqrt(len_sq);
1596  V2JOIN1(center2d, mid_pt, tmp_len, dir);
1597 
1598  /* check center location */
1599  cross_z = (end2d[X] - start2d[X])*(center2d[Y] - start2d[Y]) -
1600  (end2d[Y] - start2d[Y])*(center2d[X] - start2d[X]);
1601  if (!(cross_z > 0.0 && csg->center_is_left)) {
1602  V2JOIN1(center2d, mid_pt, -tmp_len, dir);
1603  }
1604  start_ang = atan2(start2d[Y]-center2d[Y], start2d[X]-center2d[X]);
1605  end_ang = atan2(end2d[Y]-center2d[Y], end2d[X]-center2d[X]);
1606  if (csg->orientation) {
1607  /* clock-wise */
1608  while (end_ang > start_ang)
1609  end_ang -= M_2PI;
1610  } else {
1611  /* counter-clock-wise */
1612  while (end_ang < start_ang)
1613  end_ang += M_2PI;
1614  }
1615 
1616  /* get mid angle */
1617  mid_ang = (start_ang + end_ang) * 0.5;
1618 
1619  /* calculate mid point */
1620  pt[X] = center2d[X] + csg->radius * cos(mid_ang);
1621  pt[Y] = center2d[Y] + csg->radius * sin(mid_ang);
1622  break;
1623  }
1624  break;
1625  case CURVE_NURB_MAGIC:
1626  nsg = (struct nurb_seg *)lng;
1627 
1628  eg.l.magic = NMG_EDGE_G_CNURB_MAGIC;
1629  eg.order = nsg->order;
1630  eg.k.k_size = nsg->k.k_size;
1631  eg.k.knots = nsg->k.knots;
1632  eg.c_size = nsg->c_size;
1633  coords = 2 + RT_NURB_IS_PT_RATIONAL(nsg->pt_type);
1634  eg.pt_type = RT_NURB_MAKE_PT_TYPE(coords, 2, RT_NURB_IS_PT_RATIONAL(nsg->pt_type));
1635  eg.ctl_points = (fastf_t *)bu_malloc(nsg->c_size * coords * sizeof(fastf_t), "eg.ctl_points");
1636  if (RT_NURB_IS_PT_RATIONAL(nsg->pt_type)) {
1637  for (i = 0; i < nsg->c_size; i++) {
1638  V2MOVE(&eg.ctl_points[i*coords], skt->verts[nsg->ctl_points[i]]);
1639  eg.ctl_points[(i+1)*coords - 1] = nsg->weights[i];
1640  }
1641  } else {
1642  for (i = 0; i < nsg->c_size; i++) {
1643  V2MOVE(&eg.ctl_points[i*coords], skt->verts[nsg->ctl_points[i]]);
1644  }
1645  }
1646  rt_nurb_c_eval(&eg, (nsg->k.knots[nsg->k.k_size-1] - nsg->k.knots[0]) * 0.5, tmp_pt);
1647  if (RT_NURB_IS_PT_RATIONAL(nsg->pt_type)) {
1648  int j;
1649 
1650  for (j = 0; j < coords-1; j++)
1651  pt[j] = tmp_pt[j] / tmp_pt[coords-1];
1652  } else {
1653  V2MOVE(pt, tmp_pt);
1654  }
1655  bu_free((char *)eg.ctl_points, "eg.ctl_points");
1656  break;
1657  case CURVE_BEZIER_MAGIC:
1658  bsg = (struct bezier_seg *)lng;
1659  V = (point2d_t *)bu_calloc(bsg->degree+1, sizeof(point2d_t), "Bezier control points");
1660  for (i = 0; i <= bsg->degree; i++) {
1661  V2MOVE(V[i], skt->verts[bsg->ctl_points[i]]);
1662  }
1663  bezier(V, bsg->degree, 0.51, NULL, NULL, pt, NULL);
1664  bu_free((char *)V, "Bezier control points");
1665  break;
1666  default:
1667  bu_bomb("Unrecognized segment type in sketch\n");
1668  break;
1669  }
1670 }
1671 
1672 
1673 struct loop_inter {
1675  int vert_index; /* index of vertex intersected, or -1 if no hit on a vertex */
1676  fastf_t dist; /* hit distance */
1677  struct loop_inter *next;
1678 };
1679 
1680 
1681 static void
1682 isect_2D_loop_ray(point2d_t pta, point2d_t dir, struct bu_ptbl *loop, struct loop_inter **root,
1683  int which_loop, struct rt_sketch_internal *ip, struct bn_tol *tol)
1684 {
1685  int i, j;
1686  int code;
1687  vect_t norm;
1688  fastf_t dist[2];
1689 
1690  vect_t s2m, tmp_dir;
1691  fastf_t s2m_len_sq, len_sq, tmp_len, cross_z;
1692 
1693  vect_t ra = VINIT_ZERO;
1694  vect_t rb = VINIT_ZERO;
1695  point2d_t start2d = V2INIT_ZERO;
1696  point2d_t end2d = V2INIT_ZERO;
1697  point2d_t mid_pt = V2INIT_ZERO;
1698  point2d_t center2d = V2INIT_ZERO;
1699 
1700  norm[X] = -dir[Y];
1701  norm[Y] = dir[X];
1702  norm[Z] = 0.0;
1703 
1704  for (i = 0; i < BU_PTBL_END(loop); i++) {
1705  uint32_t *lng;
1706  struct loop_inter *inter;
1707  struct line_seg *lsg=NULL;
1708  struct carc_seg *csg=NULL;
1709  struct bezier_seg *bsg=NULL;
1710  point2d_t d1;
1711  point2d_t diff;
1712  fastf_t radius;
1713  point2d_t *verts;
1714  point2d_t *intercept;
1715  point2d_t *normal = NULL;
1716 
1717  lng = (uint32_t *)BU_PTBL_GET(loop, i);
1718  switch (*lng) {
1719  case CURVE_LSEG_MAGIC:
1720  lsg = (struct line_seg *)lng;
1721  V2SUB2(d1, ip->verts[lsg->end], ip->verts[lsg->start]);
1722  code = bn_isect_line2_lseg2(dist, pta, dir, ip->verts[lsg->start], d1, tol);
1723  if (code < 0)
1724  break;
1725  if (code == 0) {
1726  /* edge is collinear with ray */
1727  /* add two intersections, one at each end vertex */
1728  BU_ALLOC(inter, struct loop_inter);
1729 
1730  inter->which_loop = which_loop;
1731  inter->vert_index = lsg->start;
1732  inter->dist = dist[0];
1733  inter->next = NULL;
1734  if (!(*root)) {
1735  (*root) = inter;
1736  } else {
1737  inter->next = (*root);
1738  (*root) = inter;
1739  }
1740  BU_ALLOC(inter, struct loop_inter);
1741 
1742  inter->which_loop = which_loop;
1743  inter->vert_index = lsg->end;
1744  inter->dist = dist[1];
1745  inter->next = NULL;
1746  inter->next = (*root);
1747  (*root) = inter;
1748  } else if (code == 1) {
1749  /* hit at start vertex */
1750  BU_ALLOC(inter, struct loop_inter);
1751 
1752  inter->which_loop = which_loop;
1753  inter->vert_index = lsg->start;
1754  inter->dist = dist[0];
1755  inter->next = NULL;
1756  if (!(*root)) {
1757  (*root) = inter;
1758  } else {
1759  inter->next = (*root);
1760  (*root) = inter;
1761  }
1762  } else if (code == 2) {
1763  /* hit at end vertex */
1764  BU_ALLOC(inter, struct loop_inter);
1765 
1766  inter->which_loop = which_loop;
1767  inter->vert_index = lsg->end;
1768  inter->dist = dist[0];
1769  inter->next = NULL;
1770  if (!(*root)) {
1771  (*root) = inter;
1772  } else {
1773  inter->next = (*root);
1774  (*root) = inter;
1775  }
1776  } else {
1777  /* hit on edge, not at a vertex */
1778  BU_ALLOC(inter, struct loop_inter);
1779 
1780  inter->which_loop = which_loop;
1781  inter->vert_index = -1;
1782  inter->dist = dist[0];
1783  inter->next = NULL;
1784  if (!(*root)) {
1785  (*root) = inter;
1786  } else {
1787  inter->next = (*root);
1788  (*root) = inter;
1789  }
1790  }
1791  break;
1792  case CURVE_CARC_MAGIC:
1793  csg = (struct carc_seg *)lng;
1794  radius = csg->radius;
1795  if (csg->radius <= 0.0) {
1796  V2SUB2(diff, ip->verts[csg->start], ip->verts[csg->end]);
1797  radius = sqrt(MAG2SQ(diff));
1798  ra[X] = radius;
1799  ra[Y] = 0.0;
1800  ra[Z] = 0.0;
1801  rb[X] = 0.0;
1802  rb[Y] = radius;
1803  rb[Z] = 0.0;
1804  code = isect_line2_ellipse(dist, pta, dir, ip->verts[csg->end],
1805  ra, rb);
1806 
1807  if (code <= 0)
1808  break;
1809  for (j = 0; j < code; j++) {
1810  BU_ALLOC(inter, struct loop_inter);
1811 
1812  inter->which_loop = which_loop;
1813  inter->vert_index = -1;
1814  inter->dist = dist[j];
1815  inter->next = NULL;
1816  if (!(*root)) {
1817  (*root) = inter;
1818  } else {
1819  inter->next = (*root);
1820  (*root) = inter;
1821  }
1822  }
1823 
1824  } else {
1825  point_t center = VINIT_ZERO;
1826 
1827  V2MOVE(start2d, ip->verts[csg->start]);
1828  V2MOVE(end2d, ip->verts[csg->end]);
1829  mid_pt[0] = (start2d[0] + end2d[0]) * 0.5;
1830  mid_pt[1] = (start2d[1] + end2d[1]) * 0.5;
1831  V2SUB2(s2m, mid_pt, start2d);
1832  tmp_dir[0] = -s2m[1];
1833  tmp_dir[1] = s2m[0];
1834  s2m_len_sq = s2m[0]*s2m[0] + s2m[1]*s2m[1];
1835  if (s2m_len_sq <= SMALL_FASTF) {
1836  bu_log("start and end points are too close together in circular arc of sketch\n");
1837  break;
1838  }
1839  len_sq = radius*radius - s2m_len_sq;
1840  if (len_sq < 0.0) {
1841  bu_log("Impossible radius for specified start and end points in circular arc\n");
1842  break;
1843  }
1844  tmp_len = sqrt(tmp_dir[0]*tmp_dir[0] + tmp_dir[1]*tmp_dir[1]);
1845  tmp_dir[0] = tmp_dir[0] / tmp_len;
1846  tmp_dir[1] = tmp_dir[1] / tmp_len;
1847  tmp_len = sqrt(len_sq);
1848  V2JOIN1(center2d, mid_pt, tmp_len, tmp_dir);
1849 
1850  /* check center location */
1851  cross_z = (end2d[X] - start2d[X])*(center2d[Y] - start2d[Y]) - (end2d[Y] - start2d[Y])*(center2d[X] - start2d[X]);
1852  if (!(cross_z > 0.0 && csg->center_is_left))
1853  V2JOIN1(center2d, mid_pt, -tmp_len, tmp_dir);
1854 
1855  VSET(ra, radius, 0.0, 0.0);
1856  VSET(rb, 0.0, radius, 0.0);
1857  VSET(center, center2d[X], center2d[Y], 0.0);
1858 
1859  code = isect_line_earc(dist, pta, dir, center, ra, rb,
1860  norm, ip->verts[csg->start], ip->verts[csg->end],
1861  csg->orientation);
1862  if (code <= 0)
1863  break;
1864  for (j = 0; j < code; j++) {
1865  BU_ALLOC(inter, struct loop_inter);
1866 
1867  inter->which_loop = which_loop;
1868  inter->vert_index = -1;
1869  inter->dist = dist[j];
1870  inter->next = NULL;
1871  if (!(*root)) {
1872  (*root) = inter;
1873  } else {
1874  inter->next = (*root);
1875  (*root) = inter;
1876  }
1877  }
1878  }
1879  break;
1880 
1881  case CURVE_BEZIER_MAGIC:
1882  bsg = (struct bezier_seg *)lng;
1883  intercept = NULL;
1884  verts = (point2d_t *)bu_calloc(bsg->degree + 1, sizeof(point2d_t), "Bezier verts");
1885  for (j = 0; j <= bsg->degree; j++) {
1886  V2MOVE(verts[j], ip->verts[bsg->ctl_points[j]]);
1887  }
1888 
1889  code = bezier_roots(verts, bsg->degree, &intercept, &normal, pta, dir, norm, 0, tol->dist);
1890  for (j = 0; j < code; j++) {
1891  V2SUB2(diff, intercept[j], pta);
1892  dist[0] = sqrt(MAG2SQ(diff));
1893  BU_ALLOC(inter, struct loop_inter);
1894 
1895  inter->which_loop = which_loop;
1896  inter->vert_index = -1;
1897  inter->dist = dist[0];
1898  inter->next = NULL;
1899  if (!(*root)) {
1900  (*root) = inter;
1901  } else {
1902  inter->next = (*root);
1903  (*root) = inter;
1904  }
1905  }
1906 
1907  if ((*intercept))
1908  bu_free((char *)intercept, "Bezier Intercepts");
1909  if ((*normal))
1910  bu_free((char *)normal, "Bezier normals");
1911  bu_free((char *)verts, "Bezier Ctl points");
1912  break;
1913 
1914  default:
1915  bu_log("isect_2D_loop_ray: Unrecognized curve segment type x%x\n", *lng);
1916  bu_bomb("isect_2D_loop_ray: Unrecognized curve segment type\n");
1917  break;
1918  }
1919  }
1920 }
1921 
1922 
1923 static void
1924 sort_intersections(struct loop_inter **root, struct bn_tol *tol)
1925 {
1926  struct loop_inter *ptr, *prev, *pprev;
1927  int done = 0;
1928  fastf_t diff;
1929 
1930  /* eliminate any duplicates */
1931  ptr = (*root);
1932  while (ptr->next) {
1933  prev = ptr;
1934  ptr = ptr->next;
1935  if (ptr->vert_index > -1 && ptr->vert_index == prev->vert_index) {
1936  prev->next = ptr->next;
1937  bu_free((char *)ptr, "struct loop_inter");
1938  ptr = prev;
1939  }
1940  }
1941 
1942  ptr = (*root);
1943  while (ptr->next) {
1944  prev = ptr;
1945  ptr = ptr->next;
1946  diff = fabs(ptr->dist - prev->dist);
1947  if (diff < tol->dist) {
1948  prev->next = ptr->next;
1949  bu_free((char *)ptr, "struct loop_inter");
1950  ptr = prev;
1951  }
1952  }
1953 
1954  while (!done) {
1955  done = 1;
1956  ptr = (*root);
1957  prev = NULL;
1958  pprev = NULL;
1959  while (ptr->next) {
1960  pprev = prev;
1961  prev = ptr;
1962  ptr = ptr->next;
1963  if (ptr->dist < prev->dist) {
1964  done = 0;
1965  if (pprev) {
1966  prev->next = ptr->next;
1967  pprev->next = ptr;
1968  ptr->next = prev;
1969  } else {
1970  prev->next = ptr->next;
1971  ptr->next = prev;
1972  (*root) = ptr;
1973  }
1974  }
1975  }
1976  }
1977 }
1978 
1979 
1980 static int
1981 classify_sketch_loops(struct bu_ptbl *loopa, struct bu_ptbl *loopb, struct rt_sketch_internal *ip)
1982 {
1983  struct loop_inter *inter_root=NULL, *ptr, *tmp;
1984  struct bn_tol tol;
1985  point2d_t pta, ptb;
1986  point2d_t dir;
1987  void *seg;
1988  fastf_t inv_len;
1989  int loopa_count = 0, loopb_count = 0;
1990  int ret=UNKNOWN;
1991 
1992  BU_CK_PTBL(loopa);
1993  BU_CK_PTBL(loopb);
1994  RT_SKETCH_CK_MAGIC(ip);
1995 
1996  tol.magic = BN_TOL_MAGIC;
1997  tol.dist = 0.0005;
1998  tol.dist_sq = tol.dist * tol.dist;
1999  tol.perp = 1.0e-6;
2000  tol.para = 1.0 - tol.perp;
2001 
2002  /* find points on a midpoint of a segment for each loop */
2003  seg = (void *)BU_PTBL_GET(loopa, 0);
2004  get_seg_midpoint(seg, ip, pta);
2005  seg = (void *)BU_PTBL_GET(loopb, 0);
2006  get_seg_midpoint(seg, ip, ptb);
2007 
2008  V2SUB2(dir, ptb, pta);
2009  inv_len = 1.0 / sqrt(MAG2SQ(dir));
2010  V2SCALE(dir, dir, inv_len);
2011 
2012  /* intersect pta<->ptb line with both loops */
2013  isect_2D_loop_ray(pta, dir, loopa, &inter_root, LOOPA, ip, &tol);
2014  isect_2D_loop_ray(pta, dir, loopb, &inter_root, LOOPB, ip, &tol);
2015 
2016  sort_intersections(&inter_root, &tol);
2017 
2018  /* examine intercepts to determine loop relationship */
2019  ptr = inter_root;
2020  while (ptr) {
2021  tmp = ptr;
2022  if (ret == UNKNOWN) {
2023  if (ptr->which_loop == LOOPA) {
2024  loopa_count++;
2025  if (loopa_count && loopb_count) {
2026  if (loopb_count % 2) {
2027  ret = A_IN_B;
2028  } else {
2029  ret = DISJOINT;
2030  }
2031  }
2032  } else {
2033  loopb_count++;
2034  if (loopa_count && loopb_count) {
2035  if (loopa_count % 2) {
2036  ret = B_IN_A;
2037  } else {
2038  ret = DISJOINT;
2039  }
2040  }
2041  }
2042  }
2043  ptr = ptr->next;
2044  bu_free((char *)tmp, "loop intercept");
2045  }
2046 
2047  return ret;
2048 }
2049 
2050 
2051 /*
2052  * Returns -
2053  * -1 failure
2054  * 0 OK. *r points to nmgregion that holds this tessellation.
2055  */
2056 int
2057 rt_extrude_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
2058 {
2059  struct bu_list vhead;
2060  struct shell *s;
2061  struct faceuse *fu;
2062  struct vertex ***verts;
2063  struct vertex **vertsa;
2064  struct rt_extrude_internal *extrude_ip;
2065  struct rt_sketch_internal *sketch_ip;
2066  struct rt_curve *crv = NULL;
2067  struct bu_ptbl *aloop=NULL, loops, **containing_loops, *outer_loop;
2068  plane_t pl;
2069  int *used_seg;
2070  size_t i, j, k;
2071  size_t vert_count = 0;
2072  struct bn_vlist *vlp;
2073 
2074  RT_CK_DB_INTERNAL(ip);
2075  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2076  RT_EXTRUDE_CK_MAGIC(extrude_ip);
2077 
2078  if (!extrude_ip->skt) {
2079  bu_log("rt_extrude_tess: ERROR: no sketch for extrusion!\n");
2080  return -1;
2081  }
2082 
2083  sketch_ip = extrude_ip->skt;
2084  RT_SKETCH_CK_MAGIC(sketch_ip);
2085 
2086  crv = &sketch_ip->curve;
2087 
2088  if (crv->count < 1)
2089  return 0;
2090 
2091  /* find all the loops */
2092  used_seg = (int *)bu_calloc(crv->count, sizeof(int), "used_seg");
2093  bu_ptbl_init(&loops, 5, "loops");
2094  for (i = 0; i < crv->count; i++) {
2095  void *cur_seg;
2096  int loop_start = 0, loop_end = 0;
2097  int seg_start = 0, seg_end = 0;
2098 
2099  if (used_seg[i])
2100  continue;
2101 
2102  BU_ALLOC(aloop, struct bu_ptbl);
2103  bu_ptbl_init(aloop, 5, "aloop");
2104 
2105  bu_ptbl_ins(aloop, (long *)crv->segment[i]);
2106  used_seg[i] = 1;
2107  cur_seg = crv->segment[i];
2108  get_indices(cur_seg, &loop_start, &loop_end);
2109 
2110  while (loop_end != loop_start) {
2111  int added_seg;
2112 
2113  added_seg = 0;
2114  for (j = 0; j < crv->count; j++) {
2115  if (used_seg[j])
2116  continue;
2117 
2118  get_indices(crv->segment[j], &seg_start, &seg_end);
2119  if (seg_start != seg_end && seg_start == loop_end) {
2120  added_seg++;
2121  bu_ptbl_ins(aloop, (long *)crv->segment[j]);
2122  used_seg[j] = 1;
2123  loop_end = seg_end;
2124  if (loop_start == loop_end)
2125  break;
2126  }
2127  }
2128  if (!added_seg) {
2129  bu_log("rt_extrude_tess: A loop is not closed in sketch %s\n",
2130  extrude_ip->sketch_name);
2131  bu_log("\ttessellation failed!!\n");
2132  for (j = 0; j < (size_t)BU_PTBL_END(&loops); j++) {
2133  aloop = (struct bu_ptbl *)BU_PTBL_GET(&loops, j);
2134  bu_ptbl_free(aloop);
2135  bu_free((char *)aloop, "aloop");
2136  }
2137  bu_ptbl_free(&loops);
2138  bu_free((char *)used_seg, "used_seg");
2139  return -2;
2140  }
2141  }
2142  bu_ptbl_ins(&loops, (long *)aloop);
2143  }
2144  bu_free((char *)used_seg, "used_seg");
2145 
2146  /* sort the loops to find inside/outside relationships */
2147  containing_loops = (struct bu_ptbl **)bu_calloc(BU_PTBL_END(&loops),
2148  sizeof(struct bu_ptbl *), "containing_loops");
2149  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2150  BU_ALLOC(containing_loops[i], struct bu_ptbl);
2151  bu_ptbl_init(containing_loops[i], BU_PTBL_END(&loops), "containing_loops[i]");
2152  }
2153 
2154  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2155  struct bu_ptbl *loopa;
2156 
2157  loopa = (struct bu_ptbl *)BU_PTBL_GET(&loops, i);
2158  for (j=i+1; j<(size_t)BU_PTBL_END(&loops); j++) {
2159  struct bu_ptbl *loopb;
2160 
2161  loopb = (struct bu_ptbl *)BU_PTBL_GET(&loops, j);
2162  switch (classify_sketch_loops(loopa, loopb, sketch_ip)) {
2163  case A_IN_B:
2164  bu_ptbl_ins(containing_loops[i], (long *)loopb);
2165  break;
2166  case B_IN_A:
2167  bu_ptbl_ins(containing_loops[j], (long *)loopa);
2168  break;
2169  case DISJOINT:
2170  break;
2171  default:
2172  bu_log("rt_extrude_tess: Failed to classify loops!!\n");
2173  goto failed;
2174  }
2175  }
2176  }
2177 
2178  /* make loops */
2179 
2180  /* find an outermost loop */
2181  outer_loop = (struct bu_ptbl *)NULL;
2182  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2183  if (BU_PTBL_END(containing_loops[i]) == 0) {
2184  outer_loop = (struct bu_ptbl *)BU_PTBL_GET(&loops, i);
2185  break;
2186  }
2187  }
2188 
2189  if (!outer_loop) {
2190  bu_log("No outer loop in sketch %s\n", extrude_ip->sketch_name);
2191  bu_log("\ttessellation failed\n");
2192  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2193  aloop = (struct bu_ptbl *)BU_PTBL_GET(&loops, i);
2194  bu_ptbl_free(aloop);
2195  bu_free((char *)aloop, "aloop");
2196  bu_ptbl_free(containing_loops[i]);
2197  bu_free((char *)containing_loops[i], "aloop");
2198  }
2199  bu_ptbl_free(&loops);
2200  bu_free((char *)containing_loops, "containing_loops");
2201  }
2202 
2203  BU_LIST_INIT(&vhead);
2206  }
2207  for (i = 0; outer_loop && i<(size_t)BU_PTBL_END(outer_loop); i++) {
2208  void *seg;
2209 
2210  seg = (void *)BU_PTBL_GET(outer_loop, i);
2211  if (seg_to_vlist(&vhead, ttol, extrude_ip->V, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, seg))
2212  goto failed;
2213  }
2214 
2215  /* count vertices */
2216  vert_count = 0;
2217  for (BU_LIST_FOR (vlp, bn_vlist, &vhead)) {
2218  for (i = 0; i < vlp->nused; i++) {
2219  if (vlp->cmd[i] == BN_VLIST_LINE_DRAW)
2220  vert_count++;
2221  }
2222  }
2223 
2224  *r = nmg_mrsv(m);
2225  s = BU_LIST_FIRST(shell, &((*r)->s_hd));
2226 
2227  /* make initial face from outer_loop */
2228  verts = (struct vertex ***)bu_calloc(vert_count, sizeof(struct vertex **), "verts");
2229  for (i = 0; i < vert_count; i++) {
2230  verts[i] = (struct vertex **)bu_calloc(1, sizeof(struct vertex *), "verts[i]");
2231  }
2232 
2233  fu = nmg_cmface(s, verts, vert_count);
2234  j = 0;
2235  for (BU_LIST_FOR (vlp, bn_vlist, &vhead)) {
2236  for (i = 0; i < vlp->nused; i++) {
2237  if (vlp->cmd[i] == BN_VLIST_LINE_DRAW) {
2238  nmg_vertex_gv(*verts[j], vlp->pt[i]);
2239  j++;
2240  }
2241  }
2242  }
2243  BN_FREE_VLIST(&RTG.rtg_vlfree, &vhead);
2244 
2245  /* make sure face normal is in correct direction */
2246  bu_free((char *)verts, "verts");
2247  if (nmg_calc_face_plane(fu, pl)) {
2248  bu_log("Failed to calculate face plane for extrusion\n");
2249  return -1;
2250  }
2251  nmg_face_g(fu, pl);
2252  if (VDOT(pl, extrude_ip->h) > 0.0) {
2253  nmg_reverse_face(fu);
2254  fu = fu->fumate_p;
2255  }
2256 
2257  /* add the rest of the loops */
2258  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2259  int fdir;
2260  vect_t cross;
2261  fastf_t pt_count = 0.0;
2262  fastf_t dot;
2263  int rev = 0;
2264 
2265  aloop = (struct bu_ptbl *)BU_PTBL_GET(&loops, i);
2266  if (aloop == outer_loop)
2267  continue;
2268 
2269  if (BU_PTBL_END(containing_loops[i]) % 2) {
2270  fdir = OT_OPPOSITE;
2271  } else {
2272  fdir = OT_SAME;
2273  }
2274 
2275  for (j = 0; j < (size_t)BU_PTBL_END(aloop); j++) {
2276  void *seg;
2277 
2278  seg = (void *)BU_PTBL_GET(aloop, j);
2279  if (seg_to_vlist(&vhead, ttol, extrude_ip->V,
2280  extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, seg))
2281  goto failed;
2282  }
2283 
2284  /* calculate plane of this loop */
2285  VSETALLN(pl, 0.0, 4);
2286  for (BU_LIST_FOR (vlp, bn_vlist, &vhead)) {
2287  for (j = 0; j < vlp->nused; j++) {
2288  if (vlp->cmd[j] == BN_VLIST_LINE_DRAW) {
2289  VCROSS(cross, vlp->pt[j-1], vlp->pt[j]);
2290  VADD2(pl, pl, cross);
2291  }
2292  }
2293  }
2294 
2295  VUNITIZE(pl);
2296 
2297  for (BU_LIST_FOR (vlp, bn_vlist, &vhead)) {
2298  for (j = 0; j < vlp->nused; j++) {
2299  if (vlp->cmd[j] == BN_VLIST_LINE_DRAW) {
2300  pl[W] += VDOT(pl, vlp->pt[j]);
2301  pt_count++;
2302  }
2303  }
2304  }
2305  pl[W] /= pt_count;
2306 
2307  dot = -VDOT(pl, extrude_ip->h);
2308  rev = 0;
2309  if (fdir == OT_SAME && dot < 0.0)
2310  rev = 1;
2311  else if (fdir == OT_OPPOSITE && dot > 0.0)
2312  rev = 1;
2313 
2314  vertsa = (struct vertex **)bu_calloc((int)pt_count, sizeof(struct vertex *), "verts");
2315 
2316  fu = nmg_add_loop_to_face(s, fu, vertsa, (int)pt_count, fdir);
2317 
2318  k = 0;
2319  for (BU_LIST_FOR (vlp, bn_vlist, &vhead)) {
2320  for (j = 0; j < vlp->nused; j++) {
2321  if (vlp->cmd[j] == BN_VLIST_LINE_DRAW) {
2322  if (rev) {
2323  nmg_vertex_gv(vertsa[(int)(pt_count) - k - 1], vlp->pt[j]);
2324  } else {
2325  nmg_vertex_gv(vertsa[k], vlp->pt[j]);
2326  }
2327  k++;
2328  }
2329  }
2330  }
2331  RT_FREE_VLIST(&vhead);
2332  }
2333 
2334  /* extrude this face */
2335  if (nmg_extrude_face(fu, extrude_ip->h, tol)) {
2336  bu_log("Failed to extrude face sketch\n");
2337  return -1;
2338  }
2339 
2340  nmg_region_a(*r, tol);
2341 
2342  return 0;
2343 
2344  failed:
2345  for (i = 0; i < (size_t)BU_PTBL_END(&loops); i++) {
2346  bu_ptbl_free(containing_loops[i]);
2347  bu_free((char *)containing_loops[i], "containing_loops[i]");
2348  }
2349  bu_free((char *)containing_loops, "containing_loops");
2350  bu_ptbl_free(aloop);
2351  bu_free((char *)aloop, "aloop");
2352  return -1;
2353 }
2354 
2355 
2356 /**
2357  * Import an EXTRUDE from the database format to the internal format.
2358  * Apply modeling transformations as well.
2359  */
2360 int
2361 rt_extrude_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip, struct resource *resp)
2362 {
2363  struct rt_extrude_internal *extrude_ip;
2364  struct rt_db_internal tmp_ip;
2365  struct directory *dp;
2366  char *sketch_name;
2367  union record *rp;
2368  char *ptr;
2369 
2370  /* must be double for import and export */
2371  double tmp_vec[ELEMENTS_PER_VECT];
2372 
2373  BU_CK_EXTERNAL(ep);
2374  rp = (union record *)ep->ext_buf;
2375  /* Check record type */
2376  if (rp->u_id != DBID_EXTR) {
2377  bu_log("rt_extrude_import4: defective record\n");
2378  return -1;
2379  }
2380 
2381  RT_CK_DB_INTERNAL(ip);
2382  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
2383  ip->idb_type = ID_EXTRUDE;
2384  ip->idb_meth = &OBJ[ID_EXTRUDE];
2385  BU_ALLOC(ip->idb_ptr, struct rt_extrude_internal);
2386 
2387  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2388  extrude_ip->magic = RT_EXTRUDE_INTERNAL_MAGIC;
2389 
2390  sketch_name = (char *)rp + sizeof(struct extr_rec);
2391  if (!dbip) {
2392  extrude_ip->skt = (struct rt_sketch_internal *)NULL;
2393  } else if ((dp=db_lookup(dbip, sketch_name, LOOKUP_NOISY)) == RT_DIR_NULL) {
2394  bu_log("rt_extrude_import4: ERROR: Cannot find sketch (%.16s) for extrusion (%.16s)\n",
2395  sketch_name, rp->extr.ex_name);
2396  extrude_ip->skt = (struct rt_sketch_internal *)NULL;
2397  } else {
2398  if (rt_db_get_internal(&tmp_ip, dp, dbip, bn_mat_identity, resp) != ID_SKETCH) {
2399  bu_log("rt_extrude_import4: ERROR: Cannot import sketch (%.16s) for extrusion (%.16s)\n",
2400  sketch_name, rp->extr.ex_name);
2401  bu_free(ip->idb_ptr, "extrusion");
2402  return -1;
2403  } else {
2404  extrude_ip->skt = (struct rt_sketch_internal *)tmp_ip.idb_ptr;
2405  }
2406  }
2407 
2408  if (mat == NULL) mat = bn_mat_identity;
2409  bu_cv_ntohd((unsigned char *)tmp_vec, rp->extr.ex_V, ELEMENTS_PER_VECT);
2410  MAT4X3PNT(extrude_ip->V, mat, tmp_vec);
2411  bu_cv_ntohd((unsigned char *)tmp_vec, rp->extr.ex_h, ELEMENTS_PER_VECT);
2412  MAT4X3VEC(extrude_ip->h, mat, tmp_vec);
2413  bu_cv_ntohd((unsigned char *)tmp_vec, rp->extr.ex_uvec, ELEMENTS_PER_VECT);
2414  MAT4X3VEC(extrude_ip->u_vec, mat, tmp_vec);
2415  bu_cv_ntohd((unsigned char *)tmp_vec, rp->extr.ex_vvec, ELEMENTS_PER_VECT);
2416  MAT4X3VEC(extrude_ip->v_vec, mat, tmp_vec);
2417  extrude_ip->keypoint = ntohl(*(uint32_t *)&rp->extr.ex_key[0]);
2418 
2419  ptr = (char *)rp;
2420  ptr += sizeof(struct extr_rec);
2421  extrude_ip->sketch_name = (char *)bu_calloc(NAMESIZE+1, sizeof(char), "Extrude sketch name");
2422  bu_strlcpy(extrude_ip->sketch_name, ptr, NAMESIZE+1);
2423 
2424  return 0; /* OK */
2425 }
2426 
2427 
2428 /**
2429  * The name is added by the caller, in the usual place.
2430  */
2431 int
2432 rt_extrude_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
2433 {
2434  struct rt_extrude_internal *extrude_ip;
2435 
2436  /* must be double for import and export */
2437  double tmp_vec[ELEMENTS_PER_VECT];
2438 
2439  union record *rec;
2440  unsigned char *ptr;
2441 
2442  if (dbip) RT_CK_DBI(dbip);
2443 
2444  RT_CK_DB_INTERNAL(ip);
2445  if (ip->idb_type != ID_EXTRUDE) return -1;
2446  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2447  RT_EXTRUDE_CK_MAGIC(extrude_ip);
2448 
2449  BU_CK_EXTERNAL(ep);
2450  ep->ext_nbytes = 2*sizeof(union record);
2451  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "extrusion external");
2452  rec = (union record *)ep->ext_buf;
2453 
2454  rec->extr.ex_id = DBID_EXTR;
2455 
2456  VSCALE(tmp_vec, extrude_ip->V, local2mm);
2457  bu_cv_htond(rec->extr.ex_V, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT);
2458  VSCALE(tmp_vec, extrude_ip->h, local2mm);
2459  bu_cv_htond(rec->extr.ex_h, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT);
2460  VSCALE(tmp_vec, extrude_ip->u_vec, local2mm);
2461  bu_cv_htond(rec->extr.ex_uvec, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT);
2462  VSCALE(tmp_vec, extrude_ip->v_vec, local2mm);
2463  bu_cv_htond(rec->extr.ex_vvec, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT);
2464  *(uint32_t *)rec->extr.ex_key = htonl(extrude_ip->keypoint);
2465  *(uint32_t *)rec->extr.ex_count = htonl(1);
2466 
2467  ptr = (unsigned char *)rec;
2468  ptr += sizeof(struct extr_rec);
2469 
2470  bu_strlcpy((char *)ptr, extrude_ip->sketch_name, ep->ext_nbytes-sizeof(struct extr_rec));
2471 
2472  return 0;
2473 }
2474 
2475 
2476 /**
2477  * The name is added by the caller, in the usual place.
2478  */
2479 int
2480 rt_extrude_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
2481 {
2482  struct rt_extrude_internal *extrude_ip;
2483  unsigned char *ptr;
2484  size_t rem;
2485 
2486  /* must be double for import and export */
2487  double tmp_vec[4][ELEMENTS_PER_VECT];
2488 
2489  if (dbip) RT_CK_DBI(dbip);
2490 
2491  RT_CK_DB_INTERNAL(ip);
2492  if (ip->idb_type != ID_EXTRUDE) return -1;
2493 
2494  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2495  RT_EXTRUDE_CK_MAGIC(extrude_ip);
2496 
2497  BU_CK_EXTERNAL(ep);
2498  ep->ext_nbytes = (long)(4 * ELEMENTS_PER_VECT * SIZEOF_NETWORK_DOUBLE + SIZEOF_NETWORK_LONG + strlen(extrude_ip->sketch_name) + 1);
2499  ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "extrusion external");
2500 
2501  ptr = (unsigned char *)ep->ext_buf;
2502  rem = ep->ext_nbytes;
2503 
2504  VSCALE(tmp_vec[0], extrude_ip->V, local2mm);
2505  VSCALE(tmp_vec[1], extrude_ip->h, local2mm);
2506  VSCALE(tmp_vec[2], extrude_ip->u_vec, local2mm);
2507  VSCALE(tmp_vec[3], extrude_ip->v_vec, local2mm);
2508  bu_cv_htond(ptr, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT*4);
2509 
2510  ptr += ELEMENTS_PER_VECT * 4 * SIZEOF_NETWORK_DOUBLE;
2511  rem -= ELEMENTS_PER_VECT * 4 * SIZEOF_NETWORK_DOUBLE;
2512 
2513  *(uint32_t *)ptr = htonl(extrude_ip->keypoint);
2514 
2515  ptr += SIZEOF_NETWORK_LONG;
2516  rem -= SIZEOF_NETWORK_LONG;
2517 
2518  bu_strlcpy((char *)ptr, extrude_ip->sketch_name, rem);
2519 
2520  return 0;
2521 }
2522 
2523 
2524 /**
2525  * Import an EXTRUDE from the database format to the internal format.
2526  * Apply modeling transformations as well.
2527  */
2528 int
2529 rt_extrude_import5(struct rt_db_internal *ip, const struct bu_external *ep, const mat_t mat, const struct db_i *dbip, struct resource *resp)
2530 {
2531  struct rt_extrude_internal *extrude_ip;
2532  struct rt_db_internal tmp_ip;
2533  struct directory *dp;
2534  char *sketch_name;
2535  unsigned char *ptr;
2536 
2537  /* must be double for import and export */
2538  double tmp_vec[4][ELEMENTS_PER_VECT];
2539 
2540  BU_CK_EXTERNAL(ep);
2541 
2542  RT_CK_DB_INTERNAL(ip);
2543  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
2544  ip->idb_type = ID_EXTRUDE;
2545  ip->idb_meth = &OBJ[ID_EXTRUDE];
2546  BU_ALLOC(ip->idb_ptr, struct rt_extrude_internal);
2547 
2548  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2549  extrude_ip->magic = RT_EXTRUDE_INTERNAL_MAGIC;
2550 
2551  ptr = (unsigned char *)ep->ext_buf;
2552  sketch_name = (char *)ptr + ELEMENTS_PER_VECT*4*SIZEOF_NETWORK_DOUBLE + SIZEOF_NETWORK_LONG;
2553  if (!dbip) {
2554  extrude_ip->skt = (struct rt_sketch_internal *)NULL;
2555  } else if ((dp=db_lookup(dbip, sketch_name, LOOKUP_NOISY)) == RT_DIR_NULL) {
2556  bu_log("rt_extrude_import4: ERROR: Cannot find sketch (%s) for extrusion\n",
2557  sketch_name);
2558  extrude_ip->skt = (struct rt_sketch_internal *)NULL;
2559  } else {
2560  if (rt_db_get_internal(&tmp_ip, dp, dbip, bn_mat_identity, resp) != ID_SKETCH) {
2561  bu_log("rt_extrude_import4: ERROR: Cannot import sketch (%s) for extrusion\n",
2562  sketch_name);
2563  bu_free(ip->idb_ptr, "extrusion");
2564  return -1;
2565  } else {
2566  extrude_ip->skt = (struct rt_sketch_internal *)tmp_ip.idb_ptr;
2567  }
2568  }
2569 
2570  bu_cv_ntohd((unsigned char *)tmp_vec, ptr, ELEMENTS_PER_VECT*4);
2571  if (mat == NULL) mat = bn_mat_identity;
2572  MAT4X3PNT(extrude_ip->V, mat, tmp_vec[0]);
2573  MAT4X3VEC(extrude_ip->h, mat, tmp_vec[1]);
2574  MAT4X3VEC(extrude_ip->u_vec, mat, tmp_vec[2]);
2575  MAT4X3VEC(extrude_ip->v_vec, mat, tmp_vec[3]);
2576  ptr += ELEMENTS_PER_VECT * 4 * SIZEOF_NETWORK_DOUBLE;
2577  extrude_ip->keypoint = ntohl(*(uint32_t *)ptr);
2578  ptr += SIZEOF_NETWORK_LONG;
2579  extrude_ip->sketch_name = bu_strdup((const char *)ptr);
2580 
2581  return 0; /* OK */
2582 }
2583 
2584 
2585 /**
2586  * Make human-readable formatted presentation of this solid. First
2587  * line describes type of solid. Additional lines are indented one
2588  * tab, and give parameter values.
2589  */
2590 int
2591 rt_extrude_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
2592 {
2593  struct rt_extrude_internal *extrude_ip;
2594  char buf[256];
2595  point_t V;
2596  vect_t h, u, v;
2597 
2598  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2599  RT_EXTRUDE_CK_MAGIC(extrude_ip);
2600 
2601  bu_vls_strcat(str, "2D extrude (EXTRUDE)\n");
2602  VSCALE(V, extrude_ip->V, mm2local);
2603  VSCALE(h, extrude_ip->h, mm2local);
2604  VSCALE(u, extrude_ip->u_vec, mm2local);
2605  VSCALE(v, extrude_ip->v_vec, mm2local);
2606  sprintf(buf, "\tV = (%g %g %g)\n\tH = (%g %g %g)\n\tu_dir = (%g %g %g)\n\tv_dir = (%g %g %g)\n",
2607  V3INTCLAMPARGS(V),
2608  V3INTCLAMPARGS(h),
2609  V3INTCLAMPARGS(u),
2610  V3INTCLAMPARGS(v));
2611  bu_vls_strcat(str, buf);
2612 
2613  if (!verbose)
2614  return 0;
2615 
2616  snprintf(buf, 256, "\tsketch name: %s\n", extrude_ip->sketch_name);
2617  bu_vls_strcat(str, buf);
2618 
2619  return 0;
2620 }
2621 
2622 
2623 /**
2624  * Free the storage associated with the rt_db_internal version of this
2625  * solid.
2626  */
2627 void
2629 {
2630  struct rt_extrude_internal *extrude_ip;
2631  struct rt_db_internal tmp_ip;
2632 
2633  RT_CK_DB_INTERNAL(ip);
2634 
2635  extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
2636  RT_EXTRUDE_CK_MAGIC(extrude_ip);
2637  if (extrude_ip->skt) {
2638  RT_DB_INTERNAL_INIT(&tmp_ip);
2639  tmp_ip.idb_major_type = DB5_MAJORTYPE_BRLCAD;
2640  tmp_ip.idb_type = ID_SKETCH;
2641  tmp_ip.idb_ptr = (void *)extrude_ip->skt;
2642  tmp_ip.idb_meth = &OBJ[ID_SKETCH];
2643  tmp_ip.idb_meth->ft_ifree(&tmp_ip);
2644  }
2645  extrude_ip->magic = 0; /* sanity */
2646 
2647  bu_free(extrude_ip->sketch_name, "Extrude sketch_name");
2648  bu_free((char *)extrude_ip, "extrude ifree");
2649  ip->idb_ptr = ((void *)0); /* sanity */
2650 }
2651 
2652 
2653 int
2655  struct rt_db_internal *op,
2656  const mat_t mat,
2657  struct rt_db_internal *ip,
2658  int release,
2659  struct db_i *dbip,
2660  struct resource *resp)
2661 {
2662  struct rt_extrude_internal *eip, *eop;
2663  point_t tmp_vec;
2664 
2665  if (dbip) RT_CK_DBI(dbip);
2666  RT_CK_DB_INTERNAL(ip);
2667  RT_CK_RESOURCE(resp);
2668  eip = (struct rt_extrude_internal *)ip->idb_ptr;
2669  RT_EXTRUDE_CK_MAGIC(eip);
2670 
2672  bu_log("Barrier check at start of extrude_xform():\n");
2674  }
2675 
2676  if (op != ip) {
2677  RT_DB_INTERNAL_INIT(op);
2678  BU_ALLOC(eop, struct rt_extrude_internal);
2679  eop->magic = RT_EXTRUDE_INTERNAL_MAGIC;
2680  eop->sketch_name = bu_strdup(eip->sketch_name);
2681  op->idb_ptr = (void *)eop;
2682  op->idb_meth = &OBJ[ID_EXTRUDE];
2683  op->idb_major_type = DB5_MAJORTYPE_BRLCAD;
2684  op->idb_type = ID_EXTRUDE;
2685  if (ip->idb_avs.magic == BU_AVS_MAGIC) {
2686  bu_avs_init(&op->idb_avs, ip->idb_avs.count, "avs");
2687  bu_avs_merge(&op->idb_avs, &ip->idb_avs);
2688  }
2689  } else {
2690  eop = (struct rt_extrude_internal *)ip->idb_ptr;
2691  }
2692 
2693  MAT4X3PNT(tmp_vec, mat, eip->V);
2694  VMOVE(eop->V, tmp_vec);
2695  MAT4X3VEC(tmp_vec, mat, eip->h);
2696  VMOVE(eop->h, tmp_vec);
2697  MAT4X3VEC(tmp_vec, mat, eip->u_vec);
2698  VMOVE(eop->u_vec, tmp_vec);
2699  MAT4X3VEC(tmp_vec, mat, eip->v_vec);
2700  VMOVE(eop->v_vec, tmp_vec);
2701  eop->keypoint = eip->keypoint;
2702 
2703  if (release && ip != op) {
2704  eop->skt = eip->skt;
2705  eip->skt = (struct rt_sketch_internal *)NULL;
2706  rt_db_free_internal(ip);
2707  } else if (eip->skt) {
2708  eop->skt = rt_copy_sketch(eip->skt);
2709  } else {
2710  eop->skt = (struct rt_sketch_internal *)NULL;
2711  }
2712 
2713  if (bu_debug&BU_DEBUG_MEM_CHECK) {
2714  bu_log("Barrier check at end of extrude_xform():\n");
2716  }
2717 
2718  return 0;
2719 }
2720 
2721 
2722 int
2723 rt_extrude_form(struct bu_vls *logstr, const struct rt_functab *ftp)
2724 {
2725  RT_CK_FUNCTAB(ftp);
2726 
2727  bu_vls_printf(logstr, "V {%%f %%f %%f} H {%%f %%f %%f} A {%%f %%f %%f} B {%%f %%f %%f} S %%s K %%d");
2728 
2729  return BRLCAD_OK;
2730 }
2731 
2732 
2733 int
2734 rt_extrude_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
2735 {
2736  struct rt_extrude_internal *extr=(struct rt_extrude_internal *) intern->idb_ptr;
2737 
2738  RT_EXTRUDE_CK_MAGIC(extr);
2739 
2740  if (attr == (char *)NULL) {
2741  bu_vls_strcpy(logstr, "extrude");
2742  bu_vls_printf(logstr, " V {%.25g %.25g %.25g}", V3ARGS(extr->V));
2743  bu_vls_printf(logstr, " H {%.25g %.25g %.25g}", V3ARGS(extr->h));
2744  bu_vls_printf(logstr, " A {%.25g %.25g %.25g}", V3ARGS(extr->u_vec));
2745  bu_vls_printf(logstr, " B {%.25g %.25g %.25g}", V3ARGS(extr->v_vec));
2746  bu_vls_printf(logstr, " S %s", extr->sketch_name);
2747  } else if (*attr == 'V')
2748  bu_vls_printf(logstr, "%.25g %.25g %.25g", V3ARGS(extr->V));
2749  else if (*attr == 'H')
2750  bu_vls_printf(logstr, "%.25g %.25g %.25g", V3ARGS(extr->h));
2751  else if (*attr == 'A')
2752  bu_vls_printf(logstr, "%.25g %.25g %.25g", V3ARGS(extr->u_vec));
2753  else if (*attr == 'B')
2754  bu_vls_printf(logstr, "%.25g %.25g %.25g", V3ARGS(extr->v_vec));
2755  else if (*attr == 'S' || BU_STR_EQUAL(attr, "sk_name"))
2756  bu_vls_printf(logstr, "%s", extr->sketch_name);
2757  else {
2758  bu_vls_strcat(logstr, "ERROR: unrecognized attribute, must be V, H, A, B, or S!");
2759  return BRLCAD_ERROR;
2760  }
2761 
2762  return BRLCAD_OK;
2763 }
2764 
2765 
2766 int
2767 rt_extrude_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv)
2768 {
2769  struct rt_extrude_internal *extr;
2770  fastf_t *newval;
2771  fastf_t len;
2772 
2773  RT_CK_DB_INTERNAL(intern);
2774  extr = (struct rt_extrude_internal *)intern->idb_ptr;
2775  RT_EXTRUDE_CK_MAGIC(extr);
2776 
2777  while (argc >= 2) {
2778  int array_len=3;
2779 
2780  if (*argv[0] == 'V') {
2781  newval = extr->V;
2782  if (tcl_list_to_fastf_array(brlcad_interp, argv[1], &newval, &array_len) != array_len) {
2783  bu_vls_printf(logstr, "ERROR: incorrect number of coordinates for vertex\n");
2784  return BRLCAD_ERROR;
2785  }
2786  } else if (*argv[0] == 'H') {
2787  newval = extr->h;
2788  if (tcl_list_to_fastf_array(brlcad_interp, argv[1], &newval, &array_len) !=
2789  array_len) {
2790  bu_vls_printf(logstr, "ERROR: incorrect number of coordinates for vector\n");
2791  return BRLCAD_ERROR;
2792  }
2793  } else if (*argv[0] == 'A') {
2794  newval = extr->u_vec;
2795  if (tcl_list_to_fastf_array(brlcad_interp, argv[1], &newval, &array_len) !=
2796  array_len) {
2797  bu_vls_printf(logstr, "ERROR: incorrect number of coordinates for vector\n");
2798  return BRLCAD_ERROR;
2799  }
2800 
2801  /* insure that u_vec and v_vec are the same length */
2802  len = MAGNITUDE(extr->u_vec);
2803  VUNITIZE(extr->v_vec);
2804  VSCALE(extr->v_vec, extr->v_vec, len);
2805  } else if (*argv[0] == 'B') {
2806  newval = extr->v_vec;
2807  if (tcl_list_to_fastf_array(brlcad_interp, argv[1], &newval, &array_len) != array_len) {
2808  bu_vls_printf(logstr, "ERROR: incorrect number of coordinates for vector\n");
2809  return BRLCAD_ERROR;
2810  }
2811  /* insure that u_vec and v_vec are the same length */
2812  len = MAGNITUDE(extr->v_vec);
2813  VUNITIZE(extr->u_vec);
2814  VSCALE(extr->u_vec, extr->u_vec, len);
2815  } else if (*argv[0] =='K') {
2816  extr->keypoint = atoi(argv[1]);
2817  } else if (*argv[0] == 'S' || BU_STR_EQUAL(argv[0], "sk_name")) {
2818  if (extr->sketch_name)
2819  bu_free((char *)extr->sketch_name, "rt_extrude_tcladjust: sketch_name");
2820  extr->sketch_name = bu_strdup(argv[1]);
2821  }
2822 
2823  argc -= 2;
2824  argv += 2;
2825  }
2826 
2827  if (extr->sketch_name == NULL)
2828  return BRLCAD_ERROR;
2829 
2830  return BRLCAD_OK;
2831 }
2832 
2833 
2834 int
2835 rt_extrude_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
2836 {
2837  if (!ps) return 0;
2838  if (ip) RT_CK_DB_INTERNAL(ip);
2839 
2840  return 0; /* OK */
2841 }
2842 
2843 
2844 /** @} */
2845 
2846 /*
2847  * Local Variables:
2848  * mode: C
2849  * tab-width: 8
2850  * indent-tabs-mode: t
2851  * c-file-style: "stroustrup"
2852  * End:
2853  * ex: shiftwidth=4 tabstop=8
2854  */
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
#define RT_CK_FUNCTAB(_p)
Definition: raytrace.h:2242
int rt_extrude_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: extrude.c:2480
int rt_extrude_adjust(struct bu_vls *logstr, struct rt_db_internal *intern, int argc, const char **argv)
Definition: extrude.c:2767
size_t nused
elements 0..nused active
Definition: vlist.h:73
vect_t unit_h
Definition: extrude.c:57
#define RT_LEN_TOL
Definition: raytrace.h:169
int nmg_calc_face_plane(struct faceuse *fu_in, fastf_t *pl)
Definition: nmg_misc.c:1557
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
struct bu_list l
magic, forw, back
Definition: vlist.h:72
#define SIZEOF_NETWORK_DOUBLE
Definition: cv.h:48
#define BU_AVS_MAGIC
Definition: magic.h:46
struct hit seg_in
IN information.
Definition: raytrace.h:370
int bezier_roots(point2d_t *w, int degree, point2d_t **intercept, point2d_t **normal, point2d_t ray_start, point2d_t ray_dir, point2d_t ray_perp, int depth, fastf_t epsilon)
Definition: bezier.c:308
int rt_extrude_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: extrude.c:2432
int seg_to_vlist(struct bu_list *vhead, const struct rt_tess_tol *ttol, point_t V, vect_t u_vec, vect_t v_vec, struct rt_sketch_internal *sketch_ip, void *seg)
Definition: list.h:118
const struct directory * st_dp
Directory entry of solid.
Definition: raytrace.h:436
#define BU_DEBUG_MEM_CHECK
Definition: debug.h:54
#define BU_LIST_LAST(structure, hp)
Definition: list.h:306
#define DISJOINT
Definition: extrude.c:94
void * hit_private
PRIVATE handle for xxx_shot()
Definition: raytrace.h:254
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
void nmg_reverse_face(register struct faceuse *fu)
Definition: nmg_mod.c:1511
#define RT_CK_RTI(_p)
Definition: raytrace.h:1833
int cmd[BN_VLIST_CHUNK]
VL_CMD_*.
Definition: vlist.h:74
double dist
>= 0
Definition: tol.h:73
int rt_extrude_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: extrude.c:1392
void(* ft_ifree)(struct rt_db_internal *)
Definition: raytrace.h:2159
vect_t crv_pdir
Principle direction.
Definition: raytrace.h:307
const mat_t bn_mat_identity
Matrix and vector functionality.
Definition: mat.c:46
fastf_t uv_u
Range 0..1.
Definition: raytrace.h:341
void rt_sketch_surf_area(fastf_t *area, const struct rt_db_internal *ip)
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
if lu s
Definition: nmg_mod.c:3860
struct bu_list rtg_vlfree
head of bn_vlist freelist
Definition: raytrace.h:1698
void bu_ptbl_init(struct bu_ptbl *b, size_t len, const char *str)
Definition: ptbl.c:32
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
void bu_avs_merge(struct bu_attribute_value_set *dest, const struct bu_attribute_value_set *src)
Definition: avs.c:154
#define SIZEOF_NETWORK_LONG
Definition: cv.h:46
Definition: pc.h:108
double dist_sq
dist * dist
Definition: tol.h:74
void rt_hitsort(struct hit h[], int nh)
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
Definition: raytrace.h:368
#define BU_LIST_IS_INITIALIZED(_hp)
Definition: list.h:175
#define CURVE_CARC_MAGIC
Definition: magic.h:198
Definition: raytrace.h:248
void nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
Definition: nmg_mk.c:1668
#define BN_TOL_MAGIC
Definition: magic.h:74
#define SMALL_FASTF
Definition: defines.h:342
void nmg_face_g(struct faceuse *fu, const fastf_t *p)
Definition: nmg_mk.c:2235
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
int rt_extrude_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
Definition: extrude.c:2734
void rt_extrude_ifree(struct rt_db_internal *ip)
Definition: extrude.c:2628
Header file for the BRL-CAD common definitions.
#define BU_CK_PTBL(_p)
Definition: ptbl.h:74
#define RT_FREE_VLIST(hd)
Definition: raytrace.h:1863
int bu_ptbl_ins(struct bu_ptbl *b, long *p)
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
struct loop_inter * next
Definition: extrude.c:1677
#define CURVE_NURB_MAGIC
Definition: magic.h:200
int vert_index
Definition: extrude.c:1675
void bu_cv_htond(unsigned char *out, const unsigned char *in, size_t count)
#define MAX_FASTF
Definition: defines.h:340
void rt_curve_free(struct rt_curve *crv)
Definition: sketch.c:2092
#define CURVE_BEZIER_MAGIC
Definition: magic.h:197
#define BN_FREE_VLIST(_free_hd, hd)
Definition: vlist.h:118
void rt_extrude_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
Definition: extrude.c:1314
struct bu_list l
Definition: raytrace.h:369
#define MAX_HITS
Definition: extrude.c:80
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
Definition: ptbl.h:62
int rt_check_curve(const struct rt_curve *crv, const struct rt_sketch_internal *skt, int noisy)
Definition: sketch.c:56
if(share_geom)
Definition: nmg_mod.c:3829
int idb_major_type
Definition: raytrace.h:192
Definition: color.c:49
int rt_extrude_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip, struct resource *resp)
Definition: extrude.c:2361
void * memset(void *s, int c, size_t n)
#define TOP_FACE
Definition: extrude.c:83
vect_t hit_vpriv
PRIVATE vector for xxx_*()
Definition: raytrace.h:253
#define RT_ADD_VLIST(hd, pnt, draw)
Definition: raytrace.h:1865
void bn_mat_print(const char *title, const mat_t m)
Definition: mat.c:81
int nmg_extrude_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
Definition: nmg_extrude.c:179
int bn_isect_line2_lseg2(fastf_t *dist, const point_t p, const vect_t d, const point_t a, const vect_t c, const struct bn_tol *tol)
Intersect a line in parametric form:
#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
#define RT_EXTRUDE_INTERNAL_MAGIC
Definition: magic.h:94
fastf_t crv_c2
curvature in other direction
Definition: raytrace.h:309
#define BU_PTBL_GET(ptbl, i)
Definition: ptbl.h:108
#define RT_DB_INTERNAL_INIT(_p)
Definition: raytrace.h:199
vect_t perp
Definition: extrude.c:62
#define BN_VLIST_LINE_MOVE
Definition: vlist.h:82
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
fastf_t uv_dv
delta in v
Definition: raytrace.h:344
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
void bn_mat_inv(mat_t output, const mat_t input)
#define V3ARGS(a)
Definition: color.c:56
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
#define BRLCAD_OK
Definition: defines.h:71
uint8_t * ext_buf
Definition: parse.h:216
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
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
struct hit seg_out
OUT information.
Definition: raytrace.h:371
void bn_mat_fromto(mat_t m, const fastf_t *from, const fastf_t *to, const struct bn_tol *tol)
Definition: mat.c:639
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
void get_indices(void *seg, int *start, int *end)
Definition: extrude.c:1501
fastf_t uv_scale
Definition: extrude.c:60
struct bu_attribute_value_set idb_avs
Definition: raytrace.h:196
vect_t u_vec
Definition: extrude.c:58
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
uint32_t magic
Definition: avs.h:84
#define B_IN_A
Definition: extrude.c:93
Support for uniform tolerances.
Definition: tol.h:71
void bu_avs_init(struct bu_attribute_value_set *avp, size_t len, const char *str)
Definition: avs.c:47
void rt_extrude_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: extrude.c:1478
#define LOOPA
Definition: extrude.c:96
struct nmgregion * nmg_mrsv(struct model *m)
Definition: nmg_mk.c:306
ustring alpha
int bu_mem_barriercheck(void)
Definition: malloc.c:660
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
#define LINE_SEG
Definition: extrude.c:85
void bu_ptbl_free(struct bu_ptbl *b)
Definition: ptbl.c:226
int rt_extrude_import5(struct rt_db_internal *ip, const struct bu_external *ep, const mat_t mat, const struct db_i *dbip, struct resource *resp)
Definition: extrude.c:2529
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
struct rt_curve crv
Definition: extrude.c:66
double perp
nearly 0
Definition: tol.h:75
#define ZERO(val)
Definition: units.c:38
void rt_extrude_volume(fastf_t *vol, const struct rt_db_internal *ip)
Definition: extrude.c:335
int bu_debug
Definition: globals.c:87
#define BU_LIST_INIT(_hp)
Definition: list.h:148
struct rt_sketch_internal * rt_copy_sketch(const struct rt_sketch_internal *sketch_ip)
Definition: sketch.c:2246
void * idb_ptr
Definition: raytrace.h:195
HIDDEN int code(fastf_t x, fastf_t y)
Definition: clip.c:43
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_extrude_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *tol)
Definition: extrude.c:103
plane_t pl1_rot
Definition: extrude.c:64
void bu_cv_ntohd(unsigned char *out, const unsigned char *in, size_t count)
uint32_t magic
Definition: tol.h:72
const struct rt_functab OBJ[]
Definition: table.c:159
#define RT_CK_RESOURCE(_p)
Definition: raytrace.h:1490
Definition: vlist.h:71
#define BU_PTBL_END(ptbl)
Definition: ptbl.h:106
#define NMG_EDGE_G_CNURB_MAGIC
Definition: magic.h:121
int rt_extrude_params(struct pc_pc_set *ps, const struct rt_db_internal *ip)
Definition: extrude.c:2835
vect_t rot_axis
Definition: extrude.c:61
int curve_to_vlist(struct bu_list *vhead, const struct rt_tess_tol *ttol, point_t V, vect_t u_vec, vect_t v_vec, struct rt_sketch_internal *sketch_ip, struct rt_curve *crv)
int rt_extrude_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: extrude.c:376
void rt_copy_curve(struct rt_curve *crv_out, const struct rt_curve *crv_in)
Definition: sketch.c:2176
int rt_extrude_form(struct bu_vls *logstr, const struct rt_functab *ftp)
Definition: extrude.c:2723
void rt_extrude_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
Definition: extrude.c:1256
void rt_sketch_centroid(point_t *cent, const struct rt_db_internal *ip)
Definition: sketch.c:1036
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
void * ptr
ptr to in-memory-only obj
Definition: raytrace.h:862
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
fastf_t dist
Definition: extrude.c:1676
#define CARC_SEG
Definition: extrude.c:86
fastf_t uv_du
delta in u
Definition: raytrace.h:343
int tcl_list_to_fastf_array(Tcl_Interp *interp, const char *char_list, fastf_t **array, int *array_len)
Definition: tcl.c:829
void bezier(point2d_t *V, int degree, double t, point2d_t *Left, point2d_t *Right, point2d_t eval_pt, point2d_t normal)
Definition: bezier.c:192
#define BOTTOM_FACE
Definition: extrude.c:84
fastf_t crv_c1
curvature in principle dir
Definition: raytrace.h:308
Definition: color.c:51
plane_t pl1
Definition: extrude.c:63
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
#define BEZIER_SEG
Definition: extrude.c:88
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
plane_t pl2
Definition: extrude.c:63
void rt_extrude_free(struct soltab *stp)
Definition: extrude.c:1379
int bn_isect_line2_line2(fastf_t *dist, const point_t p, const vect_t d, const point_t a, const vect_t c, const struct bn_tol *tol)
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
#define BU_CK_LIST_HEAD(_p)
Definition: list.h:142
int which_loop
Definition: extrude.c:1674
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
void rt_nurb_c_eval(const struct edge_g_cnurb *crv, fastf_t param, fastf_t *final_value)
Definition: nurb_eval.c:125
int rt_extrude_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
Definition: extrude.c:841
#define UNKNOWN
Definition: extrude.c:91
#define ID_EXTRUDE
Solid of extrusion.
Definition: raytrace.h:485
int rt_extrude_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: extrude.c:2591
struct faceuse * nmg_cmface(struct shell *s, struct vertex ***verts, int n)
Definition: nmg_mod.c:979
size_t ext_nbytes
Definition: parse.h:210
#define CURVE_LSEG_MAGIC
Definition: magic.h:199
#define BN_VLIST_CHUNK
Definitions for handling lists of vectors (really vertices, or points) and polygons in 3-space...
Definition: vlist.h:45
bn_poly_t rem[1]
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
#define A_IN_B
Definition: extrude.c:92
point_t pt[BN_VLIST_CHUNK]
associated 3-point/vect
Definition: vlist.h:75
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
void rt_extrude_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
Definition: extrude.c:1367
Definition: vls.h:56
#define BRLCAD_ERROR
Definition: defines.h:72
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
double fastf_t
Definition: defines.h:300
point_t * verts
Definition: extrude.c:65
#define VPRINT(a, b)
Definition: raytrace.h:1881
#define BU_LIST_NEXT(structure, hp)
Definition: list.h:316
#define ID_SKETCH
2D sketch
Definition: raytrace.h:484
Tcl_Interp * brlcad_interp
Definition: tcl.c:41
double para
nearly 1
Definition: tol.h:76
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
int rt_extrude_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: extrude.c:2057
Definition: color.c:50
int rt_extrude_xform(struct rt_db_internal *op, const mat_t mat, struct rt_db_internal *ip, int release, struct db_i *dbip, struct resource *resp)
Definition: extrude.c:2654
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
fastf_t uv_v
Range 0..1.
Definition: raytrace.h:342
eu1 orientation
Definition: nmg_mod.c:3916
#define LOOPB
Definition: extrude.c:97
#define bu_strdup(s)
Definition: str.h:71
void rt_extrude_print(const struct soltab *stp)
Definition: extrude.c:609
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
vect_t v_vec
Definition: extrude.c:59
#define RT_HIT_MAGIC
Definition: magic.h:161
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
struct rt_g RTG
Definition: globals.c:39
void nmg_region_a(struct nmgregion *r, const struct bn_tol *tol)
Definition: nmg_mk.c:2557