inline void rt_metaball_norm_internal(vect_t *n, point_t *p, struct rt_metaball_internal *mb) { struct wdb_metaballpt *mbpt; vect_t v; fastf_t a; VSETALL(*n, 0.0); switch (mb->method) { case METABALL_METABALL: bu_log("Sorry, strict metaballs are not yet implemented\n"); break; case METABALL_ISOPOTENTIAL: for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) { VSUB2(v, *p, mbpt->coord); a = MAGSQ(v); VJOIN1(*n, *n, fabs(mbpt->fldstr)*mbpt->fldstr / (SQ(a)), v); /* f/r^4 */ } break; case METABALL_BLOB: for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) { VSUB2(v, *p, mbpt->coord); a = MAGSQ(v); VJOIN1(*n, *n, 2.0*mbpt->sweat/SQ(mbpt->fldstr)*exp(mbpt->sweat*(1-(a/SQ(mbpt->fldstr)))) , v); } break; default: bu_log("unknown metaball method\n"); break; } VUNITIZE(*n); }
struct hyp_specific * hyp_internal_to_specific(struct rt_hyp_internal *hyp_in) { struct hyp_specific *hyp; BU_GET(hyp, struct hyp_specific); hyp->hyp_r1 = hyp_in->hyp_bnr * MAGNITUDE(hyp_in->hyp_A); hyp->hyp_r2 = hyp_in->hyp_bnr * hyp_in->hyp_b; hyp->hyp_c = sqrt(4 * MAGSQ(hyp_in->hyp_A) / MAGSQ(hyp_in->hyp_Hi) * (1 - hyp_in->hyp_bnr * hyp_in->hyp_bnr)); VSCALE(hyp->hyp_H, hyp_in->hyp_Hi, 0.5); VADD2(hyp->hyp_V, hyp_in->hyp_Vi, hyp->hyp_H); VMOVE(hyp->hyp_Au, hyp_in->hyp_A); VUNITIZE(hyp->hyp_Au); hyp->hyp_rx = 1.0 / (hyp->hyp_r1 * hyp->hyp_r1); hyp->hyp_ry = 1.0 / (hyp->hyp_r2 * hyp->hyp_r2); hyp->hyp_rz = (hyp->hyp_c * hyp->hyp_c) / (hyp->hyp_r1 * hyp->hyp_r1); /* calculate height to use for top/bottom intersection planes */ hyp->hyp_Hmag = MAGNITUDE(hyp->hyp_H); hyp->hyp_bounds = hyp->hyp_rz*hyp->hyp_Hmag*hyp->hyp_Hmag + 1.0; /* setup unit vectors for hyp_specific */ VMOVE(hyp->hyp_Hunit, hyp->hyp_H); VMOVE(hyp->hyp_Aunit, hyp->hyp_Au); VCROSS(hyp->hyp_Bunit, hyp->hyp_Hunit, hyp->hyp_Aunit); VUNITIZE(hyp->hyp_Aunit); VUNITIZE(hyp->hyp_Bunit); VUNITIZE(hyp->hyp_Hunit); return hyp; }
static int find_closest_color(float color[3]) { int icolor[3]; int i; int dist_sq; int color_num; VSCALE(icolor, color, 255); color_num = 0; dist_sq = MAGSQ(icolor); for (i = 1; i < 256; i++) { int tmp_dist; int diff[3]; VSUB2(diff, icolor, &rgb[i*3]); tmp_dist = MAGSQ(diff); if (tmp_dist < dist_sq) { dist_sq = tmp_dist; color_num = i; } } return color_num; }
/** * Given a pointer to a GED database record, and a transformation * matrix, determine if this is a valid HYP, and if so, precompute * various terms of the formula. * * Returns - * 0 HYP is OK * !0 Error in description * * Implicit return - * A struct hyp_specific is created, and its address is stored in * stp->st_specific for use by hyp_shot(). */ int rt_hyp_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip) { struct rt_hyp_internal *hyp_ip; struct hyp_specific *hyp; RT_CK_DB_INTERNAL(ip); hyp_ip = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(hyp_ip); /* TODO: check that this is a valid hyperboloid (assume it is, for now) */ /* set soltab ID */ stp->st_id = ID_HYP; stp->st_meth = &OBJ[ID_HYP]; hyp = hyp_internal_to_specific(hyp_ip); stp->st_specific = (void *)hyp; /* calculate bounding sphere */ VMOVE(stp->st_center, hyp->hyp_V); stp->st_aradius = sqrt((hyp->hyp_c*hyp->hyp_c + 1)*MAGSQ(hyp->hyp_H) + (hyp->hyp_r1*hyp->hyp_r1)); stp->st_bradius = stp->st_aradius; /* calculate bounding RPP */ if (rt_hyp_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1; return 0; /* OK */ }
int bn_mat_is_non_unif(const mat_t m) { double mag[3]; mag[0] = MAGSQ(m); mag[1] = MAGSQ(&m[4]); mag[2] = MAGSQ(&m[8]); if (fabs(1.0 - (mag[1] / mag[0])) > .0005 || fabs(1.0 - (mag[2] / mag[0])) > .0005) { return 1; } if (!ZERO(m[12]) || !ZERO(m[13]) || !ZERO(m[14])) { return 2; } return 0; }
fastf_t rt_metaball_point_value_iso(const point_t *p, const struct bu_list *points) { struct wdb_metaballpt *mbpt; fastf_t ret = 0.0; point_t v; for (BU_LIST_FOR(mbpt, wdb_metaballpt, points)) { VSUB2(v, mbpt->coord, *p); ret += fabs(mbpt->fldstr) * mbpt->fldstr / MAGSQ(v); /* f/r^2 */ } return ret; }
int TriIntersections::InsertPoint( ON_3dPoint P, uint8_t direction, EdgeIndex ei ) { /* first check to see if the point is on the other side of the * starting/ending point and return an error if it is */ if ((VDOT((P - edges[ei][0]), (edges[ei][1] - edges[ei][0])) < 0) || (VDOT((P - *edges[ei].Last()), (edges[ei][0] - *edges[ei].Last())) < 0)) { return -1; } double valtobeat = MAGSQ(P - edges[ei][0]); for (int i = 1; i < edges[ei].Count(); i++) { if (MAGSQ(edges[ei][i] - edges[ei][0]) > valtobeat) { edges[ei].Insert(i, P); dir[ei].Insert(i, direction); return i; } } return 0; }
fastf_t rt_metaball_point_value_blob(const point_t *p, const struct bu_list *points) { struct wdb_metaballpt *mbpt; fastf_t ret = 0.0; point_t v; for (BU_LIST_FOR(mbpt, wdb_metaballpt, points)) { /* TODO: test if sweat is sufficient enough that r=0 returns a positive value? */ /* TODO: test to see if negative contribution needs to be wiped out? */ VSUB2(v, mbpt->coord, *p); ret += 1.0 / exp((mbpt->sweat/(mbpt->fldstr*mbpt->fldstr)) * MAGSQ(v) - mbpt->sweat); } return ret; }
/* * True if the intersection distance is >= distance back to the * origin of the first ray in a chain. * Called via isvisible on a hit. */ static int hiteye(struct application *ap, struct partition *PartHeadp, struct seg *segHeadp) { register struct partition *pp; register struct hit *hitp; vect_t work; for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) if ( pp->pt_outhit->hit_dist > 0 ) break; if ( pp == PartHeadp ) { bu_log("hiteye: no hit out front?\n"); return(1); } hitp = pp->pt_inhit; if ( hitp->hit_dist >= INFINITY ) { bu_log("hiteye: entry beyond infinity\n"); return(1); } /* The current ray segment exits "in front" of me, * find out where it went in. * Check to see if eye is "inside" of the solid. */ if ( hitp->hit_dist < -1.0e-10 ) { /* * If we are under 1.0 units inside of a solid, we pushed * into it ourselves in trying to get away from the surface. * Otherwise, its hard to tell how we got in here! */ if ( hitp->hit_dist < -1.001 ) { bu_log("hiteye: *** GAK2, eye inside solid (%g) ***\n", hitp->hit_dist ); for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) rt_pr_pt( ap->a_rt_i, pp ); } return(0); } VSUB2( work, firstray.r_pt, ap->a_ray.r_pt ); if ( hitp->hit_dist * hitp->hit_dist > MAGSQ(work) ) return(1); else return(0); }
void bn_vec_ortho(register vect_t out, register const vect_t in) { register int j, k; register fastf_t f; register int i; if (UNLIKELY(NEAR_ZERO(MAGSQ(in), SQRT_SMALL_FASTF))) { bu_log("bn_vec_ortho(): zero magnitude input vector %g %g %g\n", V3ARGS(in)); VSETALL(out, 0); return; } /* Find component closest to zero */ f = fabs(in[X]); i = X; j = Y; k = Z; if (fabs(in[Y]) < f) { f = fabs(in[Y]); i = Y; j = Z; k = X; } if (fabs(in[Z]) < f) { i = Z; j = X; k = Y; } f = hypot(in[j], in[k]); if (UNLIKELY(ZERO(f))) { bu_log("bn_vec_ortho(): zero hypot on %g %g %g\n", V3ARGS(in)); VSETALL(out, 0); return; } f = 1.0 / f; out[i] = 0.0; out[j] = -in[k] * f; out[k] = in[j] * f; return; }
/* * True if the intersection distance is >= distance back to the * origin of the first ray in a chain. * Called via isvisible on a hit. */ static int hiteye( struct application *ap, struct partition *PartHeadp ) { register struct partition *pp; register struct hit *hitp; vect_t work; int cpu_num; for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) if ( pp->pt_outhit->hit_dist > 0 ) break; if ( pp == PartHeadp ) { bu_log("hiteye: no hit out front?\n"); return 1; } hitp = pp->pt_inhit; if ( hitp->hit_dist >= INFINITY ) { bu_log("hiteye: entry beyond infinity\n"); return 1; } /* The current ray segment exits "in front" of me, * find out where it went in. * Check to see if eye is "inside" of the solid. */ if ( hitp->hit_dist < -1.0e-10 ) { return 0; } if ( ap->a_resource == RESOURCE_NULL) cpu_num = 0; else cpu_num = ap->a_resource->re_cpu; VSUB2( work, firstray[cpu_num].r_pt, ap->a_ray.r_pt ); if ( hitp->hit_dist * hitp->hit_dist > MAGSQ(work) ) return 1; else return 0; }
/** * Given a pointer to a GED database record, and a transformation * matrix, determine if this is a valid superellipsoid, and if so, * precompute various terms of the formula. * * Returns - * 0 SUPERELL is OK * !0 Error in description * * Implicit return - A struct superell_specific is created, and its * address is stored in stp->st_specific for use by rt_superell_shot() */ int rt_superell_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip) { struct superell_specific *superell; struct rt_superell_internal *eip; fastf_t magsq_a, magsq_b, magsq_c; mat_t R, TEMP; vect_t Au, Bu, Cu; /* A, B, C with unit length */ fastf_t f; eip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(eip); /* Validate that |A| > 0, |B| > 0, |C| > 0 */ magsq_a = MAGSQ(eip->a); magsq_b = MAGSQ(eip->b); magsq_c = MAGSQ(eip->c); if (magsq_a < rtip->rti_tol.dist_sq || magsq_b < rtip->rti_tol.dist_sq || magsq_c < rtip->rti_tol.dist_sq) { bu_log("rt_superell_prep(): superell(%s) near-zero length A(%g), B(%g), or C(%g) vector\n", stp->st_name, magsq_a, magsq_b, magsq_c); return 1; /* BAD */ } if (eip->n < rtip->rti_tol.dist || eip->e < rtip->rti_tol.dist) { bu_log("rt_superell_prep(): superell(%s) near-zero length <n, e> curvature (%g, %g) causes problems\n", stp->st_name, eip->n, eip->e); /* BAD */ } if (eip->n > 10000.0 || eip->e > 10000.0) { bu_log("rt_superell_prep(): superell(%s) very large <n, e> curvature (%g, %g) causes problems\n", stp->st_name, eip->n, eip->e); /* BAD */ } /* Create unit length versions of A, B, C */ f = 1.0/sqrt(magsq_a); VSCALE(Au, eip->a, f); f = 1.0/sqrt(magsq_b); VSCALE(Bu, eip->b, f); f = 1.0/sqrt(magsq_c); VSCALE(Cu, eip->c, f); /* Validate that A.B == 0, B.C == 0, A.C == 0 (check dir only) */ f = VDOT(Au, Bu); if (! NEAR_ZERO(f, rtip->rti_tol.dist)) { bu_log("rt_superell_prep(): superell(%s) A not perpendicular to B, f=%f\n", stp->st_name, f); return 1; /* BAD */ } f = VDOT(Bu, Cu); if (! NEAR_ZERO(f, rtip->rti_tol.dist)) { bu_log("rt_superell_prep(): superell(%s) B not perpendicular to C, f=%f\n", stp->st_name, f); return 1; /* BAD */ } f = VDOT(Au, Cu); if (! NEAR_ZERO(f, rtip->rti_tol.dist)) { bu_log("rt_superell_prep(): superell(%s) A not perpendicular to C, f=%f\n", stp->st_name, f); return 1; /* BAD */ } /* Solid is OK, compute constant terms now */ BU_GET(superell, struct superell_specific); stp->st_specific = (void *)superell; superell->superell_n = eip->n; superell->superell_e = eip->e; VMOVE(superell->superell_V, eip->v); VSET(superell->superell_invsq, 1.0/magsq_a, 1.0/magsq_b, 1.0/magsq_c); VMOVE(superell->superell_Au, Au); VMOVE(superell->superell_Bu, Bu); VMOVE(superell->superell_Cu, Cu); /* compute the inverse magnitude square for equations during shot */ superell->superell_invmsAu = 1.0 / magsq_a; superell->superell_invmsBu = 1.0 / magsq_b; superell->superell_invmsCu = 1.0 / magsq_c; /* compute the rotation matrix */ MAT_IDN(R); VMOVE(&R[0], Au); VMOVE(&R[4], Bu); VMOVE(&R[8], Cu); bn_mat_trn(superell->superell_invR, R); /* computer invRSSR */ MAT_IDN(superell->superell_invRSSR); MAT_IDN(TEMP); TEMP[0] = superell->superell_invsq[0]; TEMP[5] = superell->superell_invsq[1]; TEMP[10] = superell->superell_invsq[2]; bn_mat_mul(TEMP, TEMP, R); bn_mat_mul(superell->superell_invRSSR, superell->superell_invR, TEMP); /* compute Scale(Rotate(vect)) */ MAT_IDN(superell->superell_SoR); VSCALE(&superell->superell_SoR[0], eip->a, superell->superell_invsq[0]); VSCALE(&superell->superell_SoR[4], eip->b, superell->superell_invsq[1]); VSCALE(&superell->superell_SoR[8], eip->c, superell->superell_invsq[2]); /* Compute bounding sphere */ VMOVE(stp->st_center, eip->v); f = magsq_a; if (magsq_b > f) f = magsq_b; if (magsq_c > f) f = magsq_c; stp->st_aradius = stp->st_bradius = sqrt(f); /* Compute bounding RPP */ if (rt_superell_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1; return 0; /* OK */ }
/** * Calculate a bounding RPP for a superell */ int rt_superell_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) { struct rt_superell_internal *eip; fastf_t magsq_a, magsq_b, magsq_c; vect_t Au, Bu, Cu; mat_t R; vect_t w1, w2, P; /* used for bounding RPP */ fastf_t f; eip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(eip); magsq_a = MAGSQ(eip->a); magsq_b = MAGSQ(eip->b); magsq_c = MAGSQ(eip->c); /* Create unit length versions of A, B, C */ f = 1.0/sqrt(magsq_a); VSCALE(Au, eip->a, f); f = 1.0/sqrt(magsq_b); VSCALE(Bu, eip->b, f); f = 1.0/sqrt(magsq_c); VSCALE(Cu, eip->c, f); MAT_IDN(R); VMOVE(&R[0], Au); VMOVE(&R[4], Bu); VMOVE(&R[8], Cu); /* Compute bounding RPP */ VSET(w1, magsq_a, magsq_b, magsq_c); /* X */ VSET(P, 1.0, 0, 0); /* bounding plane normal */ MAT3X3VEC(w2, R, P); /* map plane to local coord syst */ VELMUL(w2, w2, w2); /* square each term */ f = VDOT(w1, w2); f = sqrt(f); (*min)[X] = eip->v[X] - f; /* V.P +/- f */ (*max)[X] = eip->v[X] + f; /* Y */ VSET(P, 0, 1.0, 0); /* bounding plane normal */ MAT3X3VEC(w2, R, P); /* map plane to local coord syst */ VELMUL(w2, w2, w2); /* square each term */ f = VDOT(w1, w2); f = sqrt(f); (*min)[Y] = eip->v[Y] - f; /* V.P +/- f */ (*max)[Y] = eip->v[Y] + f; /* Z */ VSET(P, 0, 0, 1.0); /* bounding plane normal */ MAT3X3VEC(w2, R, P); /* map plane to local coord syst */ VELMUL(w2, w2, w2); /* square each term */ f = VDOT(w1, w2); f = sqrt(f); (*min)[Z] = eip->v[Z] - f; /* V.P +/- f */ (*max)[Z] = eip->v[Z] + f; return 0; }
/** * Returns - * -1 failure * 0 OK. *r points to nmgregion that holds this tessellation. */ int rt_hyp_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol) { fastf_t c, dtol, f, mag_a, mag_h, ntol, r1, r2, r3, cprime; fastf_t **ellipses = NULL; fastf_t theta_new; int *pts_dbl, face, i, j, nseg; int jj, nell; mat_t invRoS; mat_t SoR; struct rt_hyp_internal *iip; struct hyp_specific *xip; struct rt_pt_node *pos_a, *pos_b, *pts_a, *pts_b; struct shell *s; struct faceuse **outfaceuses = NULL; struct faceuse *fu_top; struct loopuse *lu; struct edgeuse *eu; struct vertex *vertp[3]; struct vertex ***vells = (struct vertex ***)NULL; vect_t A, Au, B, Bu, Hu, V; struct bu_ptbl vert_tab; MAT_ZERO(invRoS); MAT_ZERO(SoR); RT_CK_DB_INTERNAL(ip); iip = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(iip); xip = hyp_internal_to_specific(iip); /* * make sure hyp description is valid */ /* compute |A| |H| */ mag_a = MAGSQ(xip->hyp_Au); /* should already be unit vector */ mag_h = MAGNITUDE(xip->hyp_H); c = xip->hyp_c; cprime = c / mag_h; r1 = xip->hyp_r1; r2 = xip->hyp_r2; r3 = r1 / c; /* Check for |H| > 0, |A| == 1, r1 > 0, r2 > 0, c > 0 */ if (NEAR_ZERO(mag_h, RT_LEN_TOL) || !NEAR_EQUAL(mag_a, 1.0, RT_LEN_TOL) || r1 <= 0.0 || r2 <= 0.0 || c <= 0.) { return 1; /* BAD */ } /* Check for A.H == 0 */ f = VDOT(xip->hyp_Au, xip->hyp_H) / mag_h; if (! NEAR_ZERO(f, RT_DOT_TOL)) { return 1; /* BAD */ } /* make unit vectors in A, H, and HxA directions */ VMOVE(Hu, xip->hyp_H); VUNITIZE(Hu); VMOVE(Au, xip->hyp_Au); VCROSS(Bu, Hu, Au); dtol = primitive_get_absolute_tolerance(ttol, 2.0 * r2); /* To ensure normal tolerance, remain below this angle */ if (ttol->norm > 0.0) ntol = ttol->norm; else /* tolerate everything */ ntol = M_PI; /* * build hyp from 2 hyperbolas */ /* calculate major axis hyperbola */ BU_ALLOC(pts_a, struct rt_pt_node); /* set base, center, and top points */ pos_a = pts_a; VSET(pos_a->p, sqrt((mag_h*mag_h) * (c*c) + (r1*r1)), 0, -mag_h); BU_ALLOC(pos_a->next, struct rt_pt_node); pos_a = pos_a->next; VSET(pos_a->p, r1, 0, 0); BU_ALLOC(pos_a->next, struct rt_pt_node); pos_a = pos_a->next; VSET(pos_a->p, sqrt((mag_h*mag_h) * (c*c) + (r1*r1)), 0, mag_h); pos_a->next = NULL; /* refine hyp according to tolerances */ i = 1; { point_t p0, p1, p2; fastf_t mm, len, dist, ang0, ang2; vect_t v01, v02; /* vectors from p0->p1 and p0->p2 */ vect_t nLine, nHyp; struct rt_pt_node *add; while (i) { pos_a = pts_a; i = 0; while (pos_a->next) { VMOVE(p0, pos_a->p); VMOVE(p2, pos_a->next->p); /* either X or Y will be zero; so adding handles either case */ mm = (p2[Z] - p0[Z]) / ((p2[X]+p2[Y]) - (p0[X]+p0[Y])); if (!ZERO(p0[X])) { p1[X] = fabs(mm*c*r1) / sqrt(mm*mm*c*c - 1.0); p1[Y] = 0.0; p1[Z] = sqrt(p1[X]*p1[X] - r1*r1) / c; } else { p1[X] = 0.0; p1[Y] = fabs(mm*r2*r2*c) / sqrt(mm*mm*r2*r2*c*c - r1*r1); p1[Z] = (r3/r2) * sqrt(p1[Y]*p1[Y] - r2*r2); } if (p0[Z] + p2[Z] < 0) p1[Z] = -p1[Z]; VSUB2(v01, p1, p0); VSUB2(v02, p2, p0); VUNITIZE(v02); len = VDOT(v01, v02); VSCALE(v02, v02, len); VSUB2(nLine, v01, v02); dist = MAGNITUDE(nLine); VUNITIZE(nLine); VSET(nHyp, p0[X] / (r1*r1), p0[Y] / (r2*r2), p0[Z] / (r3*r3)); VUNITIZE(nHyp); ang0 = fabs(acos(VDOT(nLine, nHyp))); VSET(nHyp, p2[X] / (r1*r1), p2[Y] / (r2*r2), p2[Z] / (r3*r3)); VUNITIZE(nHyp); ang2 = fabs(acos(VDOT(nLine, nHyp))); if (dist > dtol || ang0 > ntol || ang2 > ntol) { /* split segment */ BU_ALLOC(add, struct rt_pt_node); VMOVE(add->p, p1); add->next = pos_a->next; pos_a->next = add; pos_a = pos_a->next; i = 1; } pos_a = pos_a->next; } } } /* calculate minor axis hyperbola */ BU_ALLOC(pts_b, struct rt_pt_node); pos_a = pts_a; pos_b = pts_b; i = 0; while (pos_a) { pos_b->p[Z] = pos_a->p[Z]; pos_b->p[X] = 0; pos_b->p[Y] = r2 * sqrt(pos_b->p[Z] * pos_b->p[Z]/(r3*r3) + 1.0); pos_a = pos_a->next; if (pos_a) { BU_ALLOC(pos_b->next, struct rt_pt_node); pos_b = pos_b->next; } else { pos_b->next = NULL; } i++; }
int rt_hyp_plot(struct bu_list *vhead, struct rt_db_internal *incoming, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info)) { int i, j; /* loop indices */ struct rt_hyp_internal *hyp_in; struct hyp_specific *hyp; vect_t majorAxis[8], /* vector offsets along major axis */ minorAxis[8], /* vector offsets along minor axis */ heightAxis[7], /* vector offsets for layers */ Bunit; /* unit vector along semi-minor axis */ vect_t ell[16]; /* stores 16 points to draw ellipses */ vect_t ribs[16][7]; /* assume 7 layers for now */ fastf_t scale; /* used to calculate semi-major/minor axes for top/bottom */ fastf_t cos22_5 = 0.9238795325112867385; fastf_t cos67_5 = 0.3826834323650898373; BU_CK_LIST_HEAD(vhead); RT_CK_DB_INTERNAL(incoming); hyp_in = (struct rt_hyp_internal *)incoming->idb_ptr; RT_HYP_CK_MAGIC(hyp_in); hyp = hyp_internal_to_specific(hyp_in); VCROSS(Bunit, hyp->hyp_H, hyp->hyp_Au); VUNITIZE(Bunit); VMOVE(heightAxis[0], hyp->hyp_H); VSCALE(heightAxis[1], heightAxis[0], 0.5); VSCALE(heightAxis[2], heightAxis[0], 0.25); VSETALL(heightAxis[3], 0); VREVERSE(heightAxis[4], heightAxis[2]); VREVERSE(heightAxis[5], heightAxis[1]); VREVERSE(heightAxis[6], heightAxis[0]); for (i = 0; i < 7; i++) { /* determine Z height depending on i */ scale = sqrt(MAGSQ(heightAxis[i])*(hyp->hyp_c * hyp->hyp_c)/(hyp->hyp_r1 * hyp->hyp_r1) + 1); /* calculate vectors for offset */ VSCALE(majorAxis[0], hyp->hyp_Au, hyp->hyp_r1 * scale); VSCALE(majorAxis[1], majorAxis[0], cos22_5); VSCALE(majorAxis[2], majorAxis[0], M_SQRT1_2); VSCALE(majorAxis[3], majorAxis[0], cos67_5); VREVERSE(majorAxis[4], majorAxis[3]); VREVERSE(majorAxis[5], majorAxis[2]); VREVERSE(majorAxis[6], majorAxis[1]); VREVERSE(majorAxis[7], majorAxis[0]); VSCALE(minorAxis[0], Bunit, hyp->hyp_r2 * scale); VSCALE(minorAxis[1], minorAxis[0], cos22_5); VSCALE(minorAxis[2], minorAxis[0], M_SQRT1_2); VSCALE(minorAxis[3], minorAxis[0], cos67_5); VREVERSE(minorAxis[4], minorAxis[3]); VREVERSE(minorAxis[5], minorAxis[2]); VREVERSE(minorAxis[6], minorAxis[1]); VREVERSE(minorAxis[7], minorAxis[0]); /* calculate ellipse */ VADD3(ell[ 0], hyp->hyp_V, heightAxis[i], majorAxis[0]); VADD4(ell[ 1], hyp->hyp_V, heightAxis[i], majorAxis[1], minorAxis[3]); VADD4(ell[ 2], hyp->hyp_V, heightAxis[i], majorAxis[2], minorAxis[2]); VADD4(ell[ 3], hyp->hyp_V, heightAxis[i], majorAxis[3], minorAxis[1]); VADD3(ell[ 4], hyp->hyp_V, heightAxis[i], minorAxis[0]); VADD4(ell[ 5], hyp->hyp_V, heightAxis[i], majorAxis[4], minorAxis[1]); VADD4(ell[ 6], hyp->hyp_V, heightAxis[i], majorAxis[5], minorAxis[2]); VADD4(ell[ 7], hyp->hyp_V, heightAxis[i], majorAxis[6], minorAxis[3]); VADD3(ell[ 8], hyp->hyp_V, heightAxis[i], majorAxis[7]); VADD4(ell[ 9], hyp->hyp_V, heightAxis[i], majorAxis[6], minorAxis[4]); VADD4(ell[10], hyp->hyp_V, heightAxis[i], majorAxis[5], minorAxis[5]); VADD4(ell[11], hyp->hyp_V, heightAxis[i], majorAxis[4], minorAxis[6]); VADD3(ell[12], hyp->hyp_V, heightAxis[i], minorAxis[7]); VADD4(ell[13], hyp->hyp_V, heightAxis[i], majorAxis[3], minorAxis[6]); VADD4(ell[14], hyp->hyp_V, heightAxis[i], majorAxis[2], minorAxis[5]); VADD4(ell[15], hyp->hyp_V, heightAxis[i], majorAxis[1], minorAxis[4]); /* draw ellipse */ RT_ADD_VLIST(vhead, ell[15], BN_VLIST_LINE_MOVE); for (j = 0; j < 16; j++) { RT_ADD_VLIST(vhead, ell[j], BN_VLIST_LINE_DRAW); } /* add ellipse's points to ribs */ for (j = 0; j < 16; j++) { VMOVE(ribs[j][i], ell[j]); } } /* draw ribs */ for (i = 0; i < 16; i++) { RT_ADD_VLIST(vhead, ribs[i][0], BN_VLIST_LINE_MOVE); for (j = 1; j < 7; j++) { RT_ADD_VLIST(vhead, ribs[i][j], BN_VLIST_LINE_DRAW); } } BU_PUT(hyp, struct hyp_specific); return 0; }
/** * R E C _ B B O X * * Calculate the RPP for an REC */ int rt_rec_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) { mat_t R; vect_t P, w1; fastf_t f, tmp, z; double magsq_h, magsq_a, magsq_b, magsq_c, magsq_d; double mag_h, mag_a, mag_b; struct rt_tgc_internal *tip; RT_CK_DB_INTERNAL(ip); tip = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tip); mag_h = sqrt(magsq_h = MAGSQ(tip->h)); mag_a = sqrt(magsq_a = MAGSQ(tip->a)); mag_b = sqrt(magsq_b = MAGSQ(tip->b)); magsq_c = MAGSQ(tip->c); magsq_d = MAGSQ(tip->d); MAT_IDN(R); f = 1.0/mag_a; VSCALE(&R[0], tip->a, f); f = 1.0/mag_b; VSCALE(&R[4], tip->b, f); f = 1.0/mag_h; VSCALE(&R[8], tip->h, f); /* X */ VSET(P, 1.0, 0, 0); /* bounding plane normal */ MAT3X3VEC(w1, R, P); /* map plane into local coord syst */ /* 1st end ellipse (no Z part) */ tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; (*min)[X] = tip->v[X] - f; /* V.P +/- f */ (*max)[X] = tip->v[X] + f; /* 2nd end ellipse */ z = w1[Z] * mag_h; /* Z part */ tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; if (tip->v[X] - f + z < (*min)[X]) (*min)[X] = tip->v[X] - f + z; if (tip->v[X] + f + z > (*max)[X]) (*max)[X] = tip->v[X] + f + z; /* Y */ VSET(P, 0, 1.0, 0); /* bounding plane normal */ MAT3X3VEC(w1, R, P); /* map plane into local coord syst */ /* 1st end ellipse (no Z part) */ tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; (*min)[Y] = tip->v[Y] - f; /* V.P +/- f */ (*max)[Y] = tip->v[Y] + f; /* 2nd end ellipse */ z = w1[Z] * mag_h; /* Z part */ tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; if (tip->v[Y] - f + z < (*min)[Y]) (*min)[Y] = tip->v[Y] - f + z; if (tip->v[Y] + f + z > (*max)[Y]) (*max)[Y] = tip->v[Y] + f + z; /* Z */ VSET(P, 0, 0, 1.0); /* bounding plane normal */ MAT3X3VEC(w1, R, P); /* map plane into local coord syst */ /* 1st end ellipse (no Z part) */ tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; (*min)[Z] = tip->v[Z] - f; /* V.P +/- f */ (*max)[Z] = tip->v[Z] + f; /* 2nd end ellipse */ z = w1[Z] * mag_h; /* Z part */ tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y]; if (tmp > SMALL) f = sqrt(tmp); /* XY part */ else f = 0; if (tip->v[Z] - f + z < (*min)[Z]) (*min)[Z] = tip->v[Z] - f + z; if (tip->v[Z] + f + z > (*max)[Z]) (*max)[Z] = tip->v[Z] + f + z; return 0; }
/** * finds the intersection point between segments x1, x2 and x3, x4 and * stores the result in x we assume that the segments are coplanar. * * return values: * * 0: no intersection * 1: intersection in a point * 2: intersection in a line * * * x1* *x3 * \ / * \ / * \ / * \ / * \ / * \ / * \ / * \ / * * <----x * / \ * / \ * / \ * / \ * / \ * / \ * x4* *x2 * * * * the equations for the lines are: * * P(s) = x1 + s (x2 - x1) s in [0, 1] * Q(t) = x3 + t (x4 - x3) t in [0, 1] * * so we need to find s and t s.t. P(s) = Q(t) * So some vector calculus tells us that: * * (CXB) dot (AXB) * s = --------------- * |AXB|^2 * * (-CXA) dot (BXA) * t = ---------------- * |BXA|^2 * * * Where we define: * * A = (x2-x1) * B = (x4-x3) * C = (x3-x1) * * This equation blows up if |AXB|^2 is 0 (in which case |BXA|^2 is * also 0), which indicates that the lines are parallel which is kind * of a pain. */ int SegmentSegmentIntersect( const ON_3dPoint& x1, const ON_3dPoint& x2, const ON_3dPoint& x3, const ON_3dPoint& x4, ON_3dPoint x[2], /* segments could in degenerate cases intersect in another segment*/ double tol ) { ON_3dPoint A = (x2 - x1); ON_3dPoint B = (x4 - x3); ON_3dPoint C = (x3 - x1); double AXB[3]; VCROSS(AXB, A, B); double BXA[3]; VCROSS(BXA, B, A); double CXB[3]; VCROSS(CXB, C, B); double negC[3]; VSCALE(negC, C, -1.0); double negCXA[3]; VCROSS(negCXA, negC, A); if (VNEAR_ZERO(AXB, tol)) {/* the lines are parallel **commence sad music*/ /* this is a potential bug if someone gets cheeky and passes us x2==x1*/ double coincident_test[3]; VCROSS(coincident_test, x4 - x2, x4 - x1); if (VNEAR_ZERO(coincident_test, tol)) { /* the lines are coincident, meaning the segments lie on the same * line but they could: * --not intersect at all * --intersect in a point * --intersect in a segment * So here's the plan we. We're going to use dot products, * The aspect of dot products that's important: * A dot B is positive if A and B point the same way * and negative when they point in opposite directions * so --> dot --> is positive, but <-- dot --> is negative * so if (x3-x1) dot (x4-x1) is negative, then x1 lies on the segment (x3, x4) * which means that x1 should be one of the points we return so we just go * through and find which points are contained in the other segment * and those are our return values */ int points = 0; if (x1 == x3 || x1 == x4) { x[points] = x1; points++; } if (x2 == x3 || x2 == x4) { x[points] = x2; points++; } if (VDOT((x3 - x1), (x4 - x1)) < 0) { x[points] = x1; points++; } if (VDOT((x3 - x2), (x4 - x2)) < 0) { x[points] = x2; points++; } if (VDOT((x1 - x3), (x2 - x3)) < 0) { x[points] = x3; points++; } if (VDOT((x1 - x4), (x2 - x4)) < 0) { x[points] = x4; points++; } assert(points <= 2); return points; } } else { double s = VDOT(CXB, AXB)/MAGSQ(AXB); double t = VDOT(negCXA, BXA)/MAGSQ(BXA); /* now we need to perform some tests to make sure we're not * outside these bounds by tiny little amounts */ if (-tol <= s && s <= 1.0 + tol && -tol <= t && t <= 1.0 + tol) { ON_3dPoint Ps = x1 + s * (x2 - x1); /* The answer according to equation P*/ ON_3dPoint Qt = x3 + t * (x4 - x3); /* The answer according to equation Q*/ assert(VNEAR_EQUAL(Ps, Qt, tol)); /* check to see if they agree, just a sanity check*/ x[0] = Ps; return 1; } else { /* this happens when the lines through x1, x2 and x3, x4 intersect but not the segments*/ return 0; } } return 0; }
int read_arbn(char *name) { int npt; /* # vertex pts to be read in */ int npe; /* # planes from 3 vertex points */ int neq; /* # planes from equation */ int nae; /* # planes from az, el & vertex index */ int nface; /* total number of faces */ double *input_points = (double *)0; double *vertex = (double *)0; /* vertex list of final solid */ int last_vertex; /* index of first unused vertex */ int max_vertex; /* size of vertex array */ int *used = (int *)0; /* plane eqn use count */ plane_t *eqn = (plane_t *)0; /* plane equations */ int cur_eq = 0; /* current (free) equation number */ int symm = 0; /* symmetry about Y used */ register int i; int j; int k; register int m; point_t cent; /* centroid of arbn */ struct bn_tol tol; /* XXX The tolerance here is sheer guesswork */ tol.magic = BN_TOL_MAGIC; tol.dist = 0.005; tol.dist_sq = tol.dist * tol.dist; tol.perp = 1e-6; tol.para = 1 - tol.perp; npt = getint( scard, 10+0*10, 10 ); npe = getint( scard, 10+1*10, 10 ); neq = getint( scard, 10+2*10, 10 ); nae = getint( scard, 10+3*10, 10 ); nface = npe + neq + nae; if ( npt < 1 ) { /* Having one point is necessary to compute centroid */ printf("arbn defined without at least one point\n"); bad: if (npt>0) eat( (npt+1)/2 ); /* vertex input_points */ if (npe>0) eat( (npe+5)/6 ); /* vertex pt index numbers */ if (neq>0) eat( neq ); /* plane eqns? */ if (nae>0) eat( (nae+1)/2 ); /* az el & vertex index? */ return(-1); } /* Allocate storage for plane equations */ eqn = (plane_t *)bu_malloc(nface*sizeof(plane_t), "eqn"); /* Allocate storage for per-plane use count */ used = (int *)bu_malloc(nface*sizeof(int), "used"); if ( npt >= 1 ) { /* Obtain vertex input_points */ input_points = (double *)bu_malloc(npt*3*sizeof(double), "input_points"); if ( getxsoldata( input_points, npt*3, sol_work ) < 0 ) goto bad; } /* Get planes defined by three points, 6 per card */ for ( i=0; i<npe; i += 6 ) { if ( get_line( scard, sizeof(scard), "arbn vertex point indices" ) == EOF ) { printf("too few cards for arbn %d\n", sol_work); return(-1); } for ( j=0; j<6; j++ ) { int q, r, s; point_t a, b, c; q = getint( scard, 10+j*10+0, 4 ); r = getint( scard, 10+j*10+4, 3 ); s = getint( scard, 10+j*10+7, 3 ); if ( q == 0 || r == 0 || s == 0 ) continue; if ( q < 0 ) { VMOVE( a, &input_points[((-q)-1)*3] ); a[Y] = -a[Y]; symm = 1; } else { VMOVE( a, &input_points[((q)-1)*3] ); } if ( r < 0 ) { VMOVE( b, &input_points[((-r)-1)*3] ); b[Y] = -b[Y]; symm = 1; } else { VMOVE( b, &input_points[((r)-1)*3] ); } if ( s < 0 ) { VMOVE( c, &input_points[((-s)-1)*3] ); c[Y] = -c[Y]; symm = 1; } else { VMOVE( c, &input_points[((s)-1)*3] ); } if ( bn_mk_plane_3pts( eqn[cur_eq], a, b, c, &tol ) < 0 ) { printf("arbn degenerate plane\n"); VPRINT("a", a); VPRINT("b", b); VPRINT("c", c); continue; } cur_eq++; } } /* Get planes defined by their equation */ for ( i=0; i < neq; i++ ) { register double scale; if ( get_line( scard, sizeof(scard), "arbn plane equation card" ) == EOF ) { printf("too few cards for arbn %d\n", sol_work); return(-1); } eqn[cur_eq][0] = getdouble( scard, 10+0*10, 10 ); eqn[cur_eq][1] = getdouble( scard, 10+1*10, 10 ); eqn[cur_eq][2] = getdouble( scard, 10+2*10, 10 ); eqn[cur_eq][3] = getdouble( scard, 10+3*10, 10 ); scale = MAGNITUDE(eqn[cur_eq]); if ( scale < SMALL ) { printf("arbn plane normal too small\n"); continue; } scale = 1/scale; VSCALE( eqn[cur_eq], eqn[cur_eq], scale ); eqn[cur_eq][3] *= scale; cur_eq++; } /* Get planes defined by azimuth, elevation, and pt, 2 per card */ for ( i=0; i < nae; i += 2 ) { if ( get_line( scard, sizeof(scard), "arbn az/el card" ) == EOF ) { printf("too few cards for arbn %d\n", sol_work); return(-1); } for ( j=0; j<2; j++ ) { double az, el; int vert_no; double cos_el; point_t pt; az = getdouble( scard, 10+j*30+0*10, 10 ) * bn_degtorad; el = getdouble( scard, 10+j*30+1*10, 10 ) * bn_degtorad; vert_no = getint( scard, 10+j*30+2*10, 10 ); if ( vert_no == 0 ) break; cos_el = cos(el); eqn[cur_eq][X] = cos(az)*cos_el; eqn[cur_eq][Y] = sin(az)*cos_el; eqn[cur_eq][Z] = sin(el); if ( vert_no < 0 ) { VMOVE( pt, &input_points[((-vert_no)-1)*3] ); pt[Y] = -pt[Y]; } else { VMOVE( pt, &input_points[((vert_no)-1)*3] ); } eqn[cur_eq][3] = VDOT(pt, eqn[cur_eq]); cur_eq++; } } if ( nface != cur_eq ) { printf("arbn expected %d faces, got %d\n", nface, cur_eq); return(-1); } /* Average all given points together to find centroid */ /* This is why there must be at least one (two?) point given */ VSETALL(cent, 0); for ( i=0; i<npt; i++ ) { VADD2( cent, cent, &input_points[i*3] ); } VSCALE( cent, cent, 1.0/npt ); if ( symm ) cent[Y] = 0; /* Point normals away from centroid */ for ( i=0; i<nface; i++ ) { double dist; dist = VDOT( eqn[i], cent ) - eqn[i][3]; /* If dist is negative, 'cent' is inside halfspace */ #define DIST_TOL (1.0e-8) #define DIST_TOL_SQ (1.0e-10) if ( dist < -DIST_TOL ) continue; if ( dist > DIST_TOL ) { /* Flip halfspace over */ VREVERSE( eqn[i], eqn[i] ); eqn[i][3] = -eqn[i][3]; } else { /* Centroid lies on this face */ printf("arbn centroid lies on face\n"); return(-1); } } /* Release storage for input points */ bu_free( (char *)input_points, "input_points" ); input_points = (double *)0; /* * ARBN must be convex. Test for concavity. * Byproduct is an enumeration of all the verticies. */ last_vertex = max_vertex = 0; /* Zero face use counts */ for ( i=0; i<nface; i++ ) { used[i] = 0; } for ( i=0; i<nface-2; i++ ) { for ( j=i+1; j<nface-1; j++ ) { double dot; int point_count; /* # points on this line */ /* If normals are parallel, no intersection */ dot = VDOT( eqn[i], eqn[j] ); if ( !NEAR_ZERO( dot, 0.999999 ) ) continue; point_count = 0; for ( k=j+1; k<nface; k++ ) { point_t pt; if ( bn_mkpoint_3planes( pt, eqn[i], eqn[j], eqn[k] ) < 0 ) continue; /* See if point is outside arb */ for ( m=0; m<nface; m++ ) { if ( i==m || j==m || k==m ) continue; if ( VDOT(pt, eqn[m])-eqn[m][3] > DIST_TOL ) goto next_k; } /* See if vertex already was found */ for ( m=0; m<last_vertex; m++ ) { vect_t dist; VSUB2( dist, pt, &vertex[m*3] ); if ( MAGSQ(dist) < DIST_TOL_SQ ) goto next_k; } /* * Add point to vertex array. * If more room needed, realloc. */ if ( last_vertex >= max_vertex ) { if ( max_vertex == 0 ) { max_vertex = 3; vertex = (double *)bu_malloc( max_vertex*3*sizeof(double), "vertex" ); } else { max_vertex *= 10; vertex = (double *)bu_realloc( (char *)vertex, max_vertex*3*sizeof(double), "vertex" ); } } VMOVE( &vertex[last_vertex*3], pt ); last_vertex++; point_count++; /* Increment "face used" counts */ used[i]++; used[j]++; used[k]++; next_k: ; } if ( point_count > 2 ) { printf("arbn: warning, point_count on line=%d\n", point_count); } } } /* If any planes were not used, then arbn is not convex */ for ( i=0; i<nface; i++ ) { if ( used[i] != 0 ) continue; /* face was used */ printf("arbn face %d unused, solid is not convex\n", i); return(-1); } /* Write out the solid ! */ i = mk_arbn( outfp, name, nface, eqn ); if ( input_points ) bu_free( (char *)input_points, "input_points" ); if ( vertex ) bu_free( (char *)vertex, "vertex" ); if ( eqn ) bu_free( (char *)eqn, "eqn" ); if ( used ) bu_free( (char *)used, "used" ); return(i); }
/* * G E T S O L I D * * Returns - * -1 error * 0 conversion OK * 1 EOF */ int getsolid(void) { char given_solid_num[16]; char solid_type[16]; int i; double r1, r2; vect_t work; double m1, m2; /* Magnitude temporaries */ char *name=NULL; double dd[4*6]; /* 4 cards of 6 nums each */ point_t tmp[8]; /* 8 vectors of 3 nums each */ int ret; #define D(_i) (&(dd[_i*3])) #define T(_i) (&(tmp[_i][0])) if ( (i = get_line( scard, sizeof(scard), "solid card" )) == EOF ) { printf("getsolid: unexpected EOF\n"); return( 1 ); } switch ( version ) { case 5: bu_strlcpy( given_solid_num, scard+0, sizeof(given_solid_num) ); given_solid_num[5] = '\0'; bu_strlcpy( solid_type, scard+5, sizeof(solid_type) ); solid_type[5] = '\0'; break; case 4: bu_strlcpy( given_solid_num, scard+0, sizeof(given_solid_num) ); given_solid_num[3] = '\0'; bu_strlcpy( solid_type, scard+3, sizeof(solid_type) ); solid_type[7] = '\0'; break; case 1: /* DoE/MORSE version, believed to be original MAGIC format */ bu_strlcpy( given_solid_num, scard+5, sizeof(given_solid_num) ); given_solid_num[4] = '\0'; bu_strlcpy( solid_type, scard+2, sizeof(solid_type) ); break; default: fprintf(stderr, "getsolid() version %d unimplemented\n", version); bu_exit(1, NULL); break; } /* Trim trailing spaces */ trim_trail_spaces( given_solid_num ); trim_trail_spaces( solid_type ); /* another solid - increment solid counter * rather than using number from the card, which may go into * pseudo-hex format in version 4 models (due to 3 column limit). */ sol_work++; if ( version == 5 ) { if ( (i = getint( scard, 0, 5 )) != sol_work ) { printf("expected solid card %d, got %d, abort\n", sol_work, i ); return(1); } } /* Reduce solid type to lower case */ { register char *cp; register char c; cp = solid_type; while ( (c = *cp) != '\0' ) { if ( !isascii(c) ) { *cp++ = '?'; } else if ( isupper(c) ) { *cp++ = tolower(c); } else { cp++; } } } namecvt( sol_work, &name, 's' ); if (verbose) col_pr( name ); if ( strcmp( solid_type, "end" ) == 0 ) { /* DoE/MORSE version 1 format */ bu_free( name, "name" ); return(1); /* END */ } if ( strcmp( solid_type, "ars" ) == 0 ) { int ncurves; int pts_per_curve; double **curve; ncurves = getint( scard, 10, 10 ); pts_per_curve = getint( scard, 20, 10 ); /* Allocate curves pointer array */ curve = (double **)bu_malloc((ncurves+1)*sizeof(double *), "curve"); /* Allocate space for a curve, and read it in */ for ( i=0; i<ncurves; i++ ) { curve[i] = (double *)bu_malloc((pts_per_curve+1)*3*sizeof(double), "curve[i]" ); /* Get data for this curve */ if ( getxsoldata( curve[i], pts_per_curve*3, sol_work ) < 0 ) { printf("ARS %d: getxsoldata failed, curve %d\n", sol_work, i); return(-1); } } if ( (ret = mk_ars( outfp, name, ncurves, pts_per_curve, curve )) < 0 ) { printf("mk_ars(%s) failed\n", name ); /* Need to free memory; 'ret' is returned below */ } for ( i=0; i<ncurves; i++ ) { bu_free( (char *)curve[i], "curve[i]" ); } bu_free( (char *)curve, "curve" ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "rpp" ) == 0 ) { double min[3], max[3]; if ( getsoldata( dd, 2*3, sol_work ) < 0 ) return(-1); VSET( min, dd[0], dd[2], dd[4] ); VSET( max, dd[1], dd[3], dd[5] ); ret = mk_rpp( outfp, name, min, max ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "box" ) == 0 ) { if ( getsoldata( dd, 4*3, sol_work ) < 0 ) return(-1); VMOVE( T(0), D(0) ); VADD2( T(1), D(0), D(2) ); VADD3( T(2), D(0), D(2), D(1) ); VADD2( T(3), D(0), D(1) ); VADD2( T(4), D(0), D(3) ); VADD3( T(5), D(0), D(3), D(2) ); VADD4( T(6), D(0), D(3), D(2), D(1) ); VADD3( T(7), D(0), D(3), D(1) ); ret = mk_arb8( outfp, name, &tmp[0][X] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "raw" ) == 0 || strcmp( solid_type, "wed" ) == 0 /* DoE name */ ) { if ( getsoldata( dd, 4*3, sol_work ) < 0 ) return(-1); VMOVE( T(0), D(0) ); VADD2( T(1), D(0), D(2) ); VMOVE( T(2), T(1) ); VADD2( T(3), D(0), D(1) ); VADD2( T(4), D(0), D(3) ); VADD3( T(5), D(0), D(3), D(2) ); VMOVE( T(6), T(5) ); VADD3( T(7), D(0), D(3), D(1) ); ret = mk_arb8( outfp, name, &tmp[0][X] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "rvw" ) == 0 ) { /* Right Vertical Wedge (Origin: DoE/MORSE) */ double a2, theta, phi, h2; double a2theta; double angle1, angle2; vect_t a, b, c; if ( getsoldata( dd, 1*3+4, sol_work ) < 0 ) return(-1); a2 = dd[3]; /* XY side length */ theta = dd[4]; phi = dd[5]; h2 = dd[6]; /* height in +Z */ angle1 = (phi+theta-90) * bn_degtorad; angle2 = (phi+theta) * bn_degtorad; a2theta = a2 * tan(theta * bn_degtorad); VSET( a, a2theta*cos(angle1), a2theta*sin(angle1), 0 ); VSET( b, -a2*cos(angle2), -a2*sin(angle2), 0 ); VSET( c, 0, 0, h2 ); VSUB2( T(0), D(0), b ); VMOVE( T(1), D(0) ); VMOVE( T(2), D(0) ); VADD2( T(3), T(0), a ); VADD2( T(4), T(0), c ); VADD2( T(5), T(1), c ); VMOVE( T(6), T(5) ); VADD2( T(7), T(3), c ); ret = mk_arb8( outfp, name, &tmp[0][X] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arw" ) == 0) { /* ARbitrary Wedge --- ERIM */ if ( getsoldata( dd, 4*3, sol_work ) < 0) return(-1); VMOVE( T(0), D(0) ); VADD2( T(1), D(0), D(2) ); VADD3( T(2), D(0), D(2), D(3) ); VADD2( T(3), D(0), D(3) ); VADD2( T(4), D(0), D(1) ); VMOVE( T(5), T(4) ); VADD3( T(6), D(0), D(1), D(3) ); VMOVE( T(7), T(6) ); ret = mk_arb8( outfp, name, &tmp[0][X]); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arb8" ) == 0 ) { if ( getsoldata( dd, 8*3, sol_work ) < 0 ) return(-1); ret = mk_arb8( outfp, name, dd ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arb7" ) == 0 ) { if ( getsoldata( dd, 7*3, sol_work ) < 0 ) return(-1); VMOVE( D(7), D(4) ); ret = mk_arb8( outfp, name, dd ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arb6" ) == 0 ) { if ( getsoldata( dd, 6*3, sol_work ) < 0 ) return(-1); /* Note that the ordering is important, as data is in D(4), D(5) */ VMOVE( D(7), D(5) ); VMOVE( D(6), D(5) ); VMOVE( D(5), D(4) ); ret = mk_arb8( outfp, name, dd ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arb5" ) == 0 ) { if ( getsoldata( dd, 5*3, sol_work ) < 0 ) return(-1); VMOVE( D(5), D(4) ); VMOVE( D(6), D(4) ); VMOVE( D(7), D(4) ); ret = mk_arb8( outfp, name, dd ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arb4" ) == 0 ) { if ( getsoldata( dd, 4*3, sol_work ) < 0 ) return(-1); ret = mk_arb4( outfp, name, dd ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "rcc" ) == 0 ) { /* V, H, r */ if ( getsoldata( dd, 2*3+1, sol_work ) < 0 ) return(-1); ret = mk_rcc( outfp, name, D(0), D(1), dd[6] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "rec" ) == 0 ) { /* V, H, A, B */ if ( getsoldata( dd, 4*3, sol_work ) < 0 ) return(-1); ret = mk_tgc( outfp, name, D(0), D(1), D(2), D(3), D(2), D(3) ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "trc" ) == 0 ) { /* V, H, r1, r2 */ if ( getsoldata( dd, 2*3+2, sol_work ) < 0 ) return(-1); ret = mk_trc_h( outfp, name, D(0), D(1), dd[6], dd[7] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "tec" ) == 0 ) { /* V, H, A, B, p */ if ( getsoldata( dd, 4*3+1, sol_work ) < 0 ) return(-1); r1 = 1.0/dd[12]; /* P */ VSCALE( D(4), D(2), r1 ); VSCALE( D(5), D(3), r1 ); ret = mk_tgc( outfp, name, D(0), D(1), D(2), D(3), D(4), D(5) ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "tgc" ) == 0 ) { /* V, H, A, B, r1, r2 */ if ( getsoldata( dd, 4*3+2, sol_work ) < 0 ) return(-1); r1 = dd[12] / MAGNITUDE( D(2) ); /* A/|A| * C */ r2 = dd[13] / MAGNITUDE( D(3) ); /* B/|B| * D */ VSCALE( D(4), D(2), r1 ); VSCALE( D(5), D(3), r2 ); ret = mk_tgc( outfp, name, D(0), D(1), D(2), D(3), D(4), D(5) ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "sph" ) == 0 ) { /* V, radius */ if ( getsoldata( dd, 1*3+1, sol_work ) < 0 ) return(-1); ret = mk_sph( outfp, name, D(0), dd[3] ); bu_free( name, "name" ); return(ret); } if ( strncmp( solid_type, "wir", 3 ) == 0 ) { int numpts; /* points per wire */ int num; int i; double dia; double *pts; /* 3 entries per pt */ struct wdb_pipept *ps; struct bu_list head; /* allow a whole struct for head */ /* This might be getint( solid_type, 3, 2 ); for non-V5 */ numpts = getint( scard, 8, 2 ); num = numpts * 3 + 1; /* 3 entries per pt */ /* allocate space for the points array */ pts = ( double *)bu_malloc(num * sizeof( double), "pts" ); if ( getsoldata( pts, num, sol_work ) < 0 ) { return(-1); } dia = pts[num-1] * 2.0; /* radius X 2.0 == diameter */ /* allocate nodes on a list and store all information in * the appropriate location. */ BU_LIST_INIT( &head ); for ( i = 0; i < numpts; i++ ) { /* malloc a new structure */ ps = (struct wdb_pipept *)bu_malloc(sizeof( struct wdb_pipept), "ps"); ps->l.magic = WDB_PIPESEG_MAGIC; VMOVE( ps->pp_coord, &pts[i*3]); /* 3 pts at a time */ ps->pp_id = 0; /* solid */ ps->pp_od = dia; ps->pp_bendradius = dia; BU_LIST_INSERT( &head, &ps->l ); } if ( mk_pipe( outfp, name, &head ) < 0 ) return(-1); mk_pipe_free( &head ); bu_free( name, "name" ); return(0); /* OK */ } if ( strcmp( solid_type, "rpc" ) == 0 ) { /* V, H, B, r */ if ( getsoldata( dd, 3*3+1, sol_work ) < 0 ) return(-1); ret = mk_rpc( outfp, name, D(0), D(1), D(2), dd[9] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "rhc" ) == 0 ) { /* V, H, B, r, c */ if ( getsoldata( dd, 3*3+2, sol_work ) < 0 ) return(-1); ret = mk_rhc( outfp, name, D(0), D(1), D(2), dd[9], dd[10] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "epa" ) == 0 ) { /* V, H, Au, r1, r2 */ if ( getsoldata( dd, 3*3+2, sol_work ) < 0 ) return(-1); ret = mk_epa( outfp, name, D(0), D(1), D(2), dd[9], dd[10] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "ehy" ) == 0 ) { /* V, H, Au, r1, r2, c */ if ( getsoldata( dd, 3*3+3, sol_work ) < 0 ) return(-1); ret = mk_ehy( outfp, name, D(0), D(1), D(2), dd[9], dd[10], dd[11] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "eto" ) == 0 ) { /* V, N, C, r, rd */ if ( getsoldata( dd, 3*3+2, sol_work ) < 0 ) return(-1); ret = mk_eto( outfp, name, D(0), D(1), D(2), dd[9], dd[10] ); bu_free( name, "name" ); return(ret); } if ( version <= 4 && strcmp( solid_type, "ell" ) == 0 ) { /* Foci F1, F2, major axis length L */ vect_t v; /* * For simplicity, we convert ELL to ELL1, then * fall through to ELL1 code. * Format of ELL is F1, F2, len * ELL1 format is V, A, r */ if ( getsoldata( dd, 2*3+1, sol_work ) < 0 ) return(-1); VADD2SCALE( v, D(0), D(1), 0.5 ); /* V is midpoint */ VSUB2( work, D(1), D(0) ); /* work holds F2 - F1 */ m1 = MAGNITUDE( work ); r2 = 0.5 * dd[6] / m1; VSCALE( D(1), work, r2 ); /* A */ dd[6] = sqrt( MAGSQ( D(1) ) - (m1 * 0.5)*(m1 * 0.5) ); /* r */ VMOVE( D(0), v ); goto ell1; } if ( (version == 5 && strcmp( solid_type, "ell" ) == 0) || strcmp( solid_type, "ell1" ) == 0 ) { /* V, A, r */ /* GIFT4 name is "ell1", GIFT5 name is "ell" */ if ( getsoldata( dd, 2*3+1, sol_work ) < 0 ) return(-1); ell1: r1 = dd[6]; /* R */ VMOVE( work, D(0) ); work[0] += bn_pi; work[1] += bn_pi; work[2] += bn_pi; VCROSS( D(2), work, D(1) ); m1 = r1/MAGNITUDE( D(2) ); VSCALE( D(2), D(2), m1 ); VCROSS( D(3), D(1), D(2) ); m2 = r1/MAGNITUDE( D(3) ); VSCALE( D(3), D(3), m2 ); /* Now we have V, A, B, C */ ret = mk_ell( outfp, name, D(0), D(1), D(2), D(3) ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "ellg" ) == 0 ) { /* V, A, B, C */ if ( getsoldata( dd, 4*3, sol_work ) < 0 ) return(-1); ret = mk_ell( outfp, name, D(0), D(1), D(2), D(3) ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "tor" ) == 0 ) { /* V, N, r1, r2 */ if ( getsoldata( dd, 2*3+2, sol_work ) < 0 ) return(-1); ret = mk_tor( outfp, name, D(0), D(1), dd[6], dd[7] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "haf" ) == 0 ) { /* N, d */ if ( getsoldata( dd, 1*3+1, sol_work ) < 0 ) return(-1); ret = mk_half( outfp, name, D(0), -dd[3] ); bu_free( name, "name" ); return(ret); } if ( strcmp( solid_type, "arbn" ) == 0 ) { ret = read_arbn( name ); bu_free( name, "name" ); } /* * The solid type string is defective, * or that solid is not currently supported. */ printf("getsolid: no support for solid type '%s'\n", solid_type ); return(-1); }
/** * Mirror an object about some axis at a specified point on the axis. * It is the caller's responsibility to retain and free the internal. * * Returns the modified internal object or NULL on error. **/ struct rt_db_internal * rt_mirror(struct db_i *dbip, struct rt_db_internal *ip, point_t mirror_pt, vect_t mirror_dir, struct resource *resp) { int id; int err; static fastf_t tol_dist_sq = 0.0005 * 0.0005; plane_t plane; RT_CK_DBI(dbip); RT_CK_DB_INTERNAL(ip); if (!NEAR_EQUAL(MAGSQ(mirror_dir), 1.0, tol_dist_sq)) { bu_log("ERROR: mirror direction is invalid\n"); return NULL; } if (!resp) { resp=&rt_uniresource; } /* not the best, but consistent until v6 */ id = ip->idb_type; /* set up the plane direction */ VUNITIZE(mirror_dir); VMOVE(plane, mirror_dir); /* determine the plane offset */ plane[W] = VDOT(mirror_pt, mirror_dir); switch (id) { case ID_TOR: { err = rt_tor_mirror(ip, plane); return err ? NULL : ip; } case ID_TGC: case ID_REC: { err = rt_tgc_mirror(ip, plane); return err ? NULL : ip; } case ID_ELL: case ID_SPH: { err = rt_ell_mirror(ip, plane); return err ? NULL : ip; } case ID_ARB8: { err = rt_arb_mirror(ip, plane); return err ? NULL : ip; } case ID_HALF: { err = rt_half_mirror(ip, plane); return err ? NULL : ip; } case ID_GRIP: { err = rt_grip_mirror(ip, plane); return err ? NULL : ip; } case ID_POLY: { err = rt_poly_mirror(ip, plane); return err ? NULL : ip; } case ID_BSPLINE: { err = rt_nurb_mirror(ip, plane); return err ? NULL : ip; } case ID_ARBN: { err = rt_arbn_mirror(ip, plane); return err ? NULL : ip; } case ID_PIPE: { err = rt_pipe_mirror(ip, plane); return err ? NULL : ip; } case ID_PARTICLE: { err = rt_particle_mirror(ip, plane); return err ? NULL : ip; } case ID_RPC: { err = rt_rpc_mirror(ip, plane); return err ? NULL : ip; } case ID_RHC: { err = rt_rhc_mirror(ip, plane); return err ? NULL : ip; } case ID_EPA: { err = rt_epa_mirror(ip, plane); return err ? NULL : ip; } case ID_ETO: { err = rt_eto_mirror(ip, plane); return err ? NULL : ip; } case ID_HYP: { err = rt_hyp_mirror(ip, plane); return err ? NULL : ip; } case ID_NMG: { err = rt_nmg_mirror(ip, plane); return err ? NULL : ip; } case ID_ARS: { err = rt_ars_mirror(ip, plane); return err ? NULL : ip; } case ID_EBM: { err = rt_ebm_mirror(ip, plane); return err ? NULL : ip; } case ID_DSP: { err = rt_dsp_mirror(ip, plane); return err ? NULL : ip; } case ID_VOL: { err = rt_vol_mirror(ip, plane); return err ? NULL : ip; } case ID_SUPERELL: { err = rt_superell_mirror(ip, plane); return err ? NULL : ip; } case ID_COMBINATION: { err = rt_comb_mirror(ip, plane); return err ? NULL : ip; } case ID_BOT: { err = rt_bot_mirror(ip, plane); return err ? NULL : ip; } default: { bu_log("Unknown or unsupported object type (id==%d)\n", id); } } /* sanity in case object is unknown */ return NULL; }
/** * R E C _ P R E P * * Given a pointer to a GED database record, and a transformation matrix, * determine if this is a valid REC, * and if so, precompute various terms of the formulas. * * Returns - * 0 REC is OK * !0 Error in description * * Implicit return - A struct rec_specific is created, and its * address is stored in stp->st_specific for use by rt_rec_shot(). If * the TGC is really an REC, stp->st_id is modified to ID_REC. */ int rt_rec_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip) { struct rt_tgc_internal *tip; struct rec_specific *rec; double magsq_h, magsq_a, magsq_b; double mag_h, mag_a, mag_b; mat_t R; mat_t Rinv; mat_t S; vect_t invsq; /* [ 1/(|A|**2), 1/(|B|**2), 1/(|Hv|**2) ] */ vect_t work; fastf_t f; if (!stp || !ip) return -1; RT_CK_SOLTAB(stp); RT_CK_DB_INTERNAL(ip); if (rtip) RT_CK_RTI(rtip); tip = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tip); /* Validate that |H| > 0, compute |A| |B| |C| |D| */ mag_h = sqrt(magsq_h = MAGSQ(tip->h)); mag_a = sqrt(magsq_a = MAGSQ(tip->a)); mag_b = sqrt(magsq_b = MAGSQ(tip->b)); /* Check for |H| > 0, |A| > 0, |B| > 0 */ if (NEAR_ZERO(mag_h, RT_LEN_TOL) || NEAR_ZERO(mag_a, RT_LEN_TOL) || NEAR_ZERO(mag_b, RT_LEN_TOL)) { return 1; /* BAD, too small */ } /* Make sure that A == C, B == D */ VSUB2(work, tip->a, tip->c); f = MAGNITUDE(work); if (! NEAR_ZERO(f, RT_LEN_TOL)) { return 1; /* BAD, !cylinder */ } VSUB2(work, tip->b, tip->d); f = MAGNITUDE(work); if (! NEAR_ZERO(f, RT_LEN_TOL)) { return 1; /* BAD, !cylinder */ } /* Check for A.B == 0, H.A == 0 and H.B == 0 */ f = VDOT(tip->a, tip->b) / (mag_a * mag_b); if (! NEAR_ZERO(f, RT_DOT_TOL)) { return 1; /* BAD */ } f = VDOT(tip->h, tip->a) / (mag_h * mag_a); if (! NEAR_ZERO(f, RT_DOT_TOL)) { return 1; /* BAD */ } f = VDOT(tip->h, tip->b) / (mag_h * mag_b); if (! NEAR_ZERO(f, RT_DOT_TOL)) { return 1; /* BAD */ } /* * This TGC is really an REC */ stp->st_id = ID_REC; /* "fix" soltab ID */ stp->st_meth = &rt_functab[ID_REC]; BU_GET(rec, struct rec_specific); stp->st_specific = (genptr_t)rec; VMOVE(rec->rec_Hunit, tip->h); VUNITIZE(rec->rec_Hunit); VMOVE(rec->rec_V, tip->v); VMOVE(rec->rec_A, tip->a); VMOVE(rec->rec_B, tip->b); rec->rec_iAsq = 1.0/magsq_a; rec->rec_iBsq = 1.0/magsq_b; VSET(invsq, 1.0/magsq_a, 1.0/magsq_b, 1.0/magsq_h); /* Compute R and Rinv matrices */ MAT_IDN(R); f = 1.0/mag_a; VSCALE(&R[0], tip->a, f); f = 1.0/mag_b; VSCALE(&R[4], tip->b, f); f = 1.0/mag_h; VSCALE(&R[8], tip->h, f); bn_mat_trn(Rinv, R); /* inv of rot mat is trn */ /* Compute S */ MAT_IDN(S); S[ 0] = sqrt(invsq[0]); S[ 5] = sqrt(invsq[1]); S[10] = sqrt(invsq[2]); /* Compute SoR and invRoS */ bn_mat_mul(rec->rec_SoR, S, R); bn_mat_mul(rec->rec_invRoS, Rinv, S); /* Compute bounding sphere and RPP */ { fastf_t dx, dy, dz; /* For bounding sphere */ if (stp->st_meth->ft_bbox(ip, &(stp->st_min), &(stp->st_max), &(rtip->rti_tol))) return 1; VSET(stp->st_center, (stp->st_max[X] + stp->st_min[X])/2, (stp->st_max[Y] + stp->st_min[Y])/2, (stp->st_max[Z] + stp->st_min[Z])/2); dx = (stp->st_max[X] - stp->st_min[X])/2; f = dx; dy = (stp->st_max[Y] - stp->st_min[Y])/2; if (dy > f) f = dy; dz = (stp->st_max[Z] - stp->st_min[Z])/2; if (dz > f) f = dz; stp->st_aradius = f; stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz); } return 0; /* OK */ }
void Do_subfigs() { int i, j; int entity_type; struct wmember head1; struct wmember *wmem; if (RT_G_DEBUG & DEBUG_MEM_FULL) bu_mem_barriercheck(); BU_LIST_INIT(&head1.l); for (i = 0; i < totentities; i++) { int subfigdef_de; int subfigdef_index; int no_of_members; int *members; char *name = NULL; struct wmember head2; double mat_scale[3]; int non_unit; if (dir[i]->type != 408) continue; if (RT_G_DEBUG & DEBUG_MEM_FULL) bu_mem_barriercheck(); if (dir[i]->param <= pstart) { bu_log("Illegal parameter pointer for entity D%07d (%s)\n" , dir[i]->direct, dir[i]->name); continue; } Readrec(dir[i]->param); Readint(&entity_type, ""); if (entity_type != 408) { bu_log("Expected Singular Subfigure Instance Entity, found %s\n", iges_type(entity_type)); continue; } Readint(&subfigdef_de, ""); subfigdef_index = (subfigdef_de - 1)/2; if (subfigdef_index >= totentities) { bu_log("Singular Subfigure Instance Entity gives Subfigure Definition"); bu_log("\tEntity DE of %d, largest DE in file is %d\n", subfigdef_de, (totentities * 2) - 1); continue; } if (dir[subfigdef_index]->type != 308) { bu_log("Expected Subfigure Definition Entity, found %s\n", iges_type(dir[subfigdef_index]->type)); continue; } if (dir[subfigdef_index]->param <= pstart) { bu_log("Illegal parameter pointer for entity D%07d (%s)\n" , dir[subfigdef_index]->direct, dir[subfigdef_index]->name); continue; } Readrec(dir[subfigdef_index]->param); Readint(&entity_type, ""); if (entity_type != 308) { bu_log("Expected Subfigure Definition Entity, found %s\n", iges_type(entity_type)); continue; } Readint(&j, ""); /* ignore depth */ Readstrg(""); /* ignore subfigure name */ wmem = mk_addmember(dir[subfigdef_index]->name, &head1.l, NULL, WMOP_UNION); non_unit = 0; for (j = 0; j < 3; j++) { double mag_sq; mat_scale[j] = 1.0; mag_sq = MAGSQ(&(*dir[i]->rot)[j*4]); /* FIXME: arbitrary undefined tolerance */ if (!NEAR_EQUAL(mag_sq, 1.0, 100.0*SQRT_SMALL_FASTF)) { mat_scale[j] = 1.0/sqrt(mag_sq); non_unit = 1; } } if (non_unit) { bu_log("Illegal transformation matrix in %s for member %s\n", curr_file->obj_name, wmem->wm_name); bu_log(" row vector magnitudes are %g, %g, and %g\n", 1.0/mat_scale[0], 1.0/mat_scale[1], 1.0/mat_scale[2]); bn_mat_print("", *dir[i]->rot); for (j = 0; j < 11; j++) { if ((j+1)%4 == 0) continue; (*dir[i]->rot)[j] *= mat_scale[0]; } bn_mat_print("After scaling:", *dir[i]->rot); } memcpy(wmem->wm_mat, *dir[i]->rot, sizeof(mat_t)); Readint(&no_of_members, ""); /* get number of members */ members = (int *)bu_calloc(no_of_members, sizeof(int), "Do_subfigs: members"); for (j = 0; j < no_of_members; j++) Readint(&members[j], ""); BU_LIST_INIT(&head2.l); for (j = 0; j < no_of_members; j++) { int idx; idx = (members[j] - 1)/2; if (idx >= totentities) { bu_log("Subfigure Definition Entity gives Member Entity"); bu_log("\tDE of %d, largest DE in file is %d\n", members[j], (totentities * 2) - 1); continue; } if (dir[idx]->param <= pstart) { bu_log("Illegal parameter pointer for entity D%07d (%s)\n" , dir[idx]->direct, dir[idx]->name); continue; } if (dir[idx]->type == 416) { struct file_list *list_ptr; char *file_name; int found = 0; /* external reference */ Readrec(dir[idx]->param); Readint(&entity_type, ""); if (entity_type != 416) { bu_log("Expected External reference Entity, found %s\n", iges_type(entity_type)); continue; } if (dir[idx]->form != 1) { bu_log("External Reference Entity of form #%d found\n", dir[idx]->form); bu_log("\tOnly form #1 is currently handled\n"); continue; } Readname(&file_name, ""); /* Check if this external reference is already on the list */ for (BU_LIST_FOR(list_ptr, file_list, &iges_list.l)) { if (BU_STR_EQUAL(file_name, list_ptr->file_name)) { found = 1; name = list_ptr->obj_name; break; } } if (!found) { /* Need to add this one to the list */ BU_ALLOC(list_ptr, struct file_list); list_ptr->file_name = file_name; if (no_of_members == 1) bu_strlcpy(list_ptr->obj_name, dir[subfigdef_index]->name, NAMESIZE+1); else { bu_strlcpy(list_ptr->obj_name, "subfig", NAMESIZE+1); (void) Make_unique_brl_name(list_ptr->obj_name); } BU_LIST_APPEND(&curr_file->l, &list_ptr->l); name = list_ptr->obj_name; } else bu_free((char *)file_name, "Do_subfigs: file_name"); } else name = dir[idx]->name; if (no_of_members > 1) { wmem = mk_addmember(name, &head2.l, NULL, WMOP_UNION); memcpy(wmem->wm_mat, dir[idx]->rot, sizeof(mat_t)); } } if (no_of_members > 1) (void)mk_lcomb(fdout, dir[subfigdef_index]->name, &head2, 0, (char *)NULL, (char *)NULL, (unsigned char *)NULL, 0); }
/** * Intersect a ray with a revolve. If an intersection occurs, a struct * seg will be acquired and filled in. * * Returns - * 0 MISS * >0 HIT */ int rt_revolve_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead) { struct revolve_specific *rev = (struct revolve_specific *)stp->st_specific; struct seg *segp; struct hit *hitp; struct hit *hits[MAX_HITS], hit[MAX_HITS]; size_t i, j, nseg, nhits; int in, out; fastf_t k, m, h, aa, bb; point_t dp, pr, xlated; vect_t vr, ur, norm, normS, normE; fastf_t start, end, angle; vect_t dir; point_t hit1, hit2; point2d_t hit2d, pt1, pt2; fastf_t a, b, c, disc, k1, k2, t1, t2; uint32_t *lng; struct line_seg *lsg; struct carc_seg *csg; nhits = 0; for (i=0; i<MAX_HITS; i++) hits[i] = &hit[i]; vr[X] = VDOT(rev->xUnit, rp->r_dir); vr[Y] = VDOT(rev->yUnit, rp->r_dir); vr[Z] = VDOT(rev->zUnit, rp->r_dir); VSUB2(xlated, rp->r_pt, rev->v3d); pr[X] = VDOT(rev->xUnit, xlated); pr[Y] = VDOT(rev->yUnit, xlated); pr[Z] = VDOT(rev->zUnit, xlated); VMOVE(ur, vr); VUNITIZE(ur); if (rev->ang < M_2PI) { VREVERSE(normS, rev->yUnit); /* start normal */ start = (VDOT(normS, rev->v3d) - VDOT(normS, rp->r_pt)) / VDOT(normS, rp->r_dir); VCROSS(normE, rev->zUnit, rev->rEnd); /* end normal */ end = (VDOT(normE, rev->v3d) - VDOT(normE, rp->r_pt)) / VDOT(normE, rp->r_dir); VJOIN1(hit1, pr, start, vr); hit2d[Y] = hit1[Z]; hit2d[X] = sqrt(hit1[X]*hit1[X] + hit1[Y]*hit1[Y]); VJOIN1(hit2, xlated, start, rp->r_dir); if (VDOT(rev->xUnit, hit2) < 0) { /* set the sign of the 2D point's x coord */ hit2d[X] = -hit2d[X]; } if (rt_sketch_contains(rev->skt, hit2d)) { hit2d[X] = -hit2d[X]; if (rev->ang > M_PI && rt_sketch_contains(rev->skt, hit2d)) { /* skip it */ } else { hitp = hits[nhits++]; hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = start; hitp->hit_surfno = (hit2d[X]>0) ? START_FACE_NEG : START_FACE_POS; VSET(hitp->hit_vpriv, -hit2d[X], hit2d[Y], 0); } } VJOIN1(hit1, pr, end, vr); hit2d[Y] = hit1[Z]; hit2d[X] = sqrt(hit1[X]*hit1[X] + hit1[Y]*hit1[Y]); VJOIN1(hit2, xlated, end, rp->r_dir); if (VDOT(rev->rEnd, hit2) < 0) { /* set the sign of the 2D point's x coord */ hit2d[X] = -hit2d[X]; } if (rt_sketch_contains(rev->skt, hit2d)) { hit2d[X] = -hit2d[X]; if (rev->ang > M_PI && rt_sketch_contains(rev->skt, hit2d)) { /* skip it */ } else { if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = end; hitp->hit_surfno = (hit2d[X]>0) ? END_FACE_NEG : END_FACE_POS; VSET(hitp->hit_vpriv, -hit2d[X], hit2d[Y], 0); } } } /** * calculate hyperbola parameters * * [ (x*x) / aa^2 ] - [ (y-h)^2 / bb^2 ] = 1 * * x = aa cosh(t - k); * y = h + bb sinh(t - k); */ VREVERSE(dp, pr); VSET(norm, ur[X], ur[Y], 0); k = VDOT(dp, norm) / VDOT(ur, norm); h = pr[Z] + k*vr[Z]; if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) { aa = sqrt(pr[X]*pr[X] + pr[Y]*pr[Y]); bb = MAX_FASTF; } else { aa = sqrt((pr[X] + k*vr[X])*(pr[X] + k*vr[X]) + (pr[Y] + k*vr[Y])*(pr[Y] + k*vr[Y])); bb = sqrt(aa*aa * (1.0/(1 - ur[Z]*ur[Z]) - 1.0)); } /** * if (ur[Z] == 1) { * bb = inf; * // ray becomes a line parallel to sketch's y-axis instead of a hyberbola * } * if (ur[Z] == 0) { * bb = 0; * // ray becomes a line parallel to sketch's x-axis instead of a hyperbola * // all hits must have x > aa * } */ /* handle open sketches */ if (!NEAR_ZERO(ur[Z], RT_DOT_TOL)) { for (i=0; i<rev->skt->vert_count && rev->ends[i] != -1; i++) { V2MOVE(pt1, rev->skt->verts[rev->ends[i]]); hit2d[Y] = pt1[Y]; if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) { /* ur[Z] == 1 */ hit2d[X] = aa; } else { hit2d[X] = aa*sqrt((hit2d[Y]-h)*(hit2d[Y]-h)/(bb*bb) + 1); } if (pt1[X] < 0) hit2d[X] = -fabs(hit2d[X]); if (fabs(hit2d[X]) < fabs(pt1[X])) { /* valid hit */ if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = (hit2d[Y] - pr[Z]) / vr[Z]; hitp->hit_surfno = HORIZ_SURF; VJOIN1(hitp->hit_vpriv, pr, hitp->hit_dist, vr); hitp->hit_point[X] = hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; angle = atan2(hitp->hit_vpriv[Y], hitp->hit_vpriv[X]); if (pt1[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } hit2d[X] = -hit2d[X]; if (angle > rev->ang) { nhits--; continue; } else if ((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d) && hit2d[X] > 0) { nhits--; continue; } /* X and Y are used for uv(), Z is used for norm() */ hitp->hit_vpriv[X] = pt1[X]; hitp->hit_vpriv[Y] = angle; if (i+1 < rev->skt->vert_count && rev->ends[i+1] != -1 && NEAR_EQUAL(rev->skt->verts[rev->ends[i]][Y], rev->skt->verts[rev->ends[i+1]][Y], SMALL)) { hitp->hit_vpriv[Z] = rev->skt->verts[rev->ends[i+1]][X]; i++; if (fabs(hit2d[X]) < fabs(hitp->hit_vpriv[Z])) { nhits--; } } else { hitp->hit_vpriv[Z] = 0; } } } } /* find hyperbola intersection with each sketch segment */ nseg = rev->skt->curve.count; for (i=0; i<nseg; i++) { lng = (uint32_t *)rev->skt->curve.segment[i]; switch (*lng) { case CURVE_LSEG_MAGIC: lsg = (struct line_seg *)lng; V2MOVE(pt1, rev->skt->verts[lsg->start]); V2MOVE(pt2, rev->skt->verts[lsg->end]); V2SUB2(dir, pt2, pt1); if (ZERO(dir[X])) { m = 1.0; } else { m = dir[Y] / dir[X]; } if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) { /* ray is vertical line at x=aa */ if (FMIN(pt1[X], pt2[X]) < aa && aa < FMAX(pt1[X], pt2[X])) { /* check the positive side of the sketch (x > 0) */ k1 = (m * (aa - pt1[X]) + pt1[Y] - pr[Z]) / vr[Z]; VJOIN1(hit1, pr, k1, vr); angle = atan2(hit1[Y], hit1[X]); hit2d[X] = -aa; /* use neg to check for overlap in contains() */ hit2d[Y] = hit1[Z]; if (angle < 0) { angle += M_2PI; } if (angle < rev->ang && !((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d))) { if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit1); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = i; } } if (FMIN(pt1[X], pt2[X]) < -aa && -aa < FMAX(pt1[X], pt2[X])) { /* check negative side of the sketch (x < 0) */ k1 = (m * (-aa - pt1[X]) + pt1[Y] - pr[Z]) / vr[Z]; VJOIN1(hit1, pr, k1, vr); angle = atan2(hit1[Y], hit1[X]); hit2d[X] = aa; /* use neg to check for overlap in contains() */ hit2d[Y] = hit1[Z]; if (angle < 0) { angle += M_PI; } if (angle < rev->ang && !((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d))) { if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit1); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = 1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = i; } } } else if (NEAR_ZERO(ur[Z], RT_DOT_TOL)) { /* ray is horizontal line at y = h; hit2d[X] > aa */ if (FMIN(pt1[Y], pt2[Y]) < h && h < FMAX(pt1[Y], pt2[Y])) { if (ZERO(m)) { hit2d[X] = pt1[X]; } else { hit2d[X] = pt1[X] + (h-pt1[Y])/m; } hit2d[Y] = h; if (fabs(hit2d[X]) > aa) { k1 = k + sqrt(hit2d[X]*hit2d[X] - aa*aa); k2 = k - sqrt(hit2d[X]*hit2d[X] - aa*aa); VJOIN1(hit1, pr, k1, vr); angle = atan2(hit1[Y], hit1[X]); if (hit2d[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } hit2d[X] = -hit2d[X]; if (angle < rev->ang && !((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d))) { if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit1); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = i; } VJOIN1(hit2, pr, k2, vr); angle = atan2(hit2[Y], hit2[X]); if (-hit2d[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } if (angle < rev->ang && !((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d))) { if (nhits >= MAX_HITS) return -1; /* too many hits */ hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit2); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k2; hitp->hit_surfno = i; } } } } else { a = dir[X]*dir[X]/(aa*aa) - dir[Y]*dir[Y]/(bb*bb); b = 2*(dir[X]*pt1[X]/(aa*aa) - dir[Y]*(pt1[Y]-h)/(bb*bb)); c = pt1[X]*pt1[X]/(aa*aa) - (pt1[Y]-h)*(pt1[Y]-h)/(bb*bb) - 1; disc = b*b - (4.0 * a * c); if (!NEAR_ZERO(a, RT_PCOEF_TOL)) { if (disc > 0) { disc = sqrt(disc); t1 = (-b + disc) / (2.0 * a); t2 = (-b - disc) / (2.0 * a); k1 = (pt1[Y]-pr[Z] + t1*dir[Y])/vr[Z]; k2 = (pt1[Y]-pr[Z] + t2*dir[Y])/vr[Z]; if (t1 > 0 && t1 < 1) { if (nhits >= MAX_HITS) return -1; /* too many hits */ VJOIN1(hit1, pr, k1, vr); angle = atan2(hit1[Y], hit1[X]); V2JOIN1(hit2d, pt1, t1, dir); if (hit2d[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } hit2d[X] = -hit2d[X]; if (angle < rev->ang) { if ((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d)) { /* overlap, so ignore it */ } else { hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit1); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = i; } } } if (t2 > 0 && t2 < 1) { if (nhits >= MAX_HITS) return -1; /* too many hits */ VJOIN1(hit2, pr, k2, vr); angle = atan2(hit2[Y], hit2[X]); V2JOIN1(hit2d, pt1, t2, dir); if (hit2d[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } hit2d[X] = -hit2d[X]; if (angle < rev->ang) { if ((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d)) { /* overlap, so ignore it */ } else { hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit2); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k2; hitp->hit_surfno = i; } } } } } else if (!NEAR_ZERO(b, RT_PCOEF_TOL)) { t1 = -c / b; k1 = (pt1[Y]-pr[Z] + t1*dir[Y])/vr[Z]; if (t1 > 0 && t1 < 1) { if (nhits >= MAX_HITS) return -1; /* too many hits */ VJOIN1(hit1, pr, k1, vr); angle = atan2(hit1[Y], hit1[X]); V2JOIN1(hit2d, pt1, t1, dir); if (hit2d[X] < 0) { angle += M_PI; } else if (angle < 0) { angle += M_2PI; } hit2d[X] = -hit2d[X]; if (angle < rev->ang) { if ((angle + M_PI < rev->ang || angle - M_PI > 0) && rt_sketch_contains(rev->skt, hit2d)) { /* overlap, so ignore it */ } else { hitp = hits[nhits++]; hitp->hit_point[X] = -hit2d[X]; hitp->hit_point[Y] = hit2d[Y]; hitp->hit_point[Z] = 0; VMOVE(hitp->hit_vpriv, hit1); if (ZERO(m)) { hitp->hit_vpriv[Z] = 0.0; } else { hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m; } hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = i; } } } } } break; case CURVE_CARC_MAGIC: /* circle: (x-cx)^2 + (y-cy)^2 = cr^2 x = (1/2cx)y^2 + (-cy/cx)y + (1/2cx)(cy^2 + cx^2 - cr^2) + (1/2cx)(x^2) x = f(y) + (1/2cx)x^2 hyperbola: [(x-hx)/a]^2 - [(y-hy)/b]^2 = 1 x^2 = (a^2/b^2)y^2 + (-2*hy*a^2/b^2)y + (hy^2 * a^2/b^2) + a^2 x^2 = g(y) plug the second equation into the first to get: x = f(y) + (1/2cx)g(y) then square that to get: x^2 = {f(y) + (1/2cx)g(y)}^2 = g(y) move all to one side to get: 0 = {f(y) + (1/2cx)g(y)}^2 - g(y) this is a fourth order polynomial in y. */ { bn_poly_t circleX; /* f(y) */ bn_poly_t hypXsq; /* g(y) */ bn_poly_t hypXsq_scaled; /* g(y) / (2*cx) */ bn_poly_t sum; /* f(y) + g(y)/(2cx) */ bn_poly_t sum_sq; /* {f(y) + g(y)/(2cx)}^2 */ bn_poly_t answer; /* {f(y) + g(y)/(2cx)}^2 - g(y) */ bn_complex_t roots[4]; int rootcnt; fastf_t cx, cy, crsq = 0; /* carc's (x, y) coords and radius^2 */ point2d_t center, radius; /* calculate circle parameters */ csg = (struct carc_seg *)lng; if (csg->radius <= 0.0) { /* full circle, "end" is center and "start" is on the circle */ V2MOVE(center, rev->skt->verts[csg->end]); V2SUB2(radius, rev->skt->verts[csg->start], center); crsq = MAG2SQ(radius); } else { point_t startpt, endpt, midpt; vect_t s_to_m; vect_t bisector; vect_t vertical; fastf_t distance; fastf_t magsq_s2m; VSET(vertical, 0, 0, 1); V2MOVE(startpt, rev->skt->verts[csg->start]); startpt[Z] = 0.0; V2MOVE(endpt, rev->skt->verts[csg->end]); endpt[Z] = 0.0; VBLEND2(midpt, 0.5, startpt, 0.5, endpt); VSUB2(s_to_m, midpt, startpt); VCROSS(bisector, vertical, s_to_m); VUNITIZE(bisector); magsq_s2m = MAGSQ(s_to_m); if (magsq_s2m > csg->radius*csg->radius) { fastf_t max_radius; max_radius = sqrt(magsq_s2m); if (NEAR_EQUAL(max_radius, csg->radius, RT_LEN_TOL)) { csg->radius = max_radius; } else { bu_log("Impossible radius for circular arc in extrusion (%s), is %g, cannot be more than %g!\n", stp->st_dp->d_namep, csg->radius, sqrt(magsq_s2m)); bu_log("Difference is %g\n", max_radius - csg->radius); return -1; } } distance = sqrt(csg->radius*csg->radius - magsq_s2m); /* save arc center */ if (csg->center_is_left) { V2JOIN1(center, midpt, distance, bisector); } else { V2JOIN1(center, midpt, -distance, bisector); } } cx = center[X]; cy = center[Y]; circleX.dgr = 2; hypXsq.dgr = 2; hypXsq_scaled.dgr = 2; sum.dgr = 2; sum_sq.dgr = 4; answer.dgr = 4; circleX.cf[0] = (cy*cy + cx*cx - crsq)/(2.0*cx); circleX.cf[1] = -cy/cx; circleX.cf[2] = 1/(2.0*cx); hypXsq_scaled.cf[0] = hypXsq.cf[0] = aa*aa + h*h*aa*aa/(bb*bb); hypXsq_scaled.cf[1] = hypXsq.cf[1] = -2.0*h*aa*aa/(bb*bb); hypXsq_scaled.cf[2] = hypXsq.cf[2] = (aa*aa)/(bb*bb); bn_poly_scale(&hypXsq_scaled, 1.0 / (2.0 * cx)); bn_poly_add(&sum, &hypXsq_scaled, &circleX); bn_poly_mul(&sum_sq, &sum, &sum); bn_poly_sub(&answer, &sum_sq, &hypXsq); /* It is known that the equation is 4th order. Therefore, if the * root finder returns other than 4 roots, error. */ rootcnt = rt_poly_roots(&answer, roots, stp->st_dp->d_namep); if (rootcnt != 4) { if (rootcnt > 0) { bu_log("tor: rt_poly_roots() 4!=%d\n", rootcnt); bn_pr_roots(stp->st_name, roots, rootcnt); } else if (rootcnt < 0) { static int reported=0; bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep); if (!reported) { VPRINT("while shooting from:\t", rp->r_pt); VPRINT("while shooting at:\t", rp->r_dir); bu_log("Additional torus convergence failure details will be suppressed.\n"); reported=1; } } } break; } case CURVE_BEZIER_MAGIC: break; case CURVE_NURB_MAGIC: break; default: bu_log("rt_revolve_prep: ERROR: unrecognized segment type!\n"); break; } } if (nhits%2 != 0) { bu_log("odd number of hits: %zu\n", nhits); for (i=0; i<nhits; i++) { bu_log("\t(%6.2f, %6.2f)\t%6.2f\t%2d\n", hits[i]->hit_point[X], hits[i]->hit_point[Y], hits[i]->hit_dist, hits[i]->hit_surfno); } return -1; } /* sort hitpoints (an arbitrary number of hits depending on sketch) */ for (i=0; i<nhits; i+=2) { in = out = -1; for (j=0; j<nhits; j++) { if (hits[j] == NULL) continue; if (in == -1) { in = j; continue; } /* store shortest dist as 'in', second shortest as 'out' */ if (hits[j]->hit_dist <= hits[in]->hit_dist) { out = in; in = j; } else if (out == -1 || hits[j]->hit_dist <= hits[out]->hit_dist) { out = j; } } if (in == -1 || out == -1) { bu_log("failed to find valid segment. nhits: %zu\n", nhits); break; } if (ZERO(hits[in]->hit_dist - hits[out]->hit_dist)) { hits[in] = NULL; hits[out] = NULL; continue; } RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; segp->seg_in = *hits[in]; hits[in] = NULL; segp->seg_out = *hits[out]; hits[out] = NULL; BU_LIST_INSERT(&(seghead->l), &(segp->l)); } return nhits; }
/* * T R E E T H E R M _ R E N D E R * * This is called (from viewshade() in shade.c) once for each hit point * to be shaded. The purpose here is to fill in values in the shadework * structure. */ int tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, genptr_t dp) /* defined in material.h */ /* ptr to the shader-specific struct */ { register struct tthrm_specific *tthrm_sp = (struct tthrm_specific *)dp; struct rt_part_internal *part_p; point_t pt; vect_t pt_v; vect_t v; int solid_number; struct thrm_seg *thrm_seg; int best_idx; double best_val; double Vdot; int node; /* check the validity of the arguments we got */ RT_AP_CHECK(ap); RT_CHECK_PT(pp); CK_tthrm_SP(tthrm_sp); /* We are performing the shading in "region" space. We must * transform the hit point from "model" space to "region" space. * See the call to db_region_mat in tthrm_setup(). */ MAT4X3PNT(pt, tthrm_sp->tthrm_m_to_sh, swp->sw_hit.hit_point); if (rdebug&RDEBUG_SHADE) bu_log("tthrm_render(%s, %g %g %g)\n", tthrm_sp->tt_name, V3ARGS(pt)); solid_number = get_solid_number(pp); if (solid_number > tthrm_sp->tt_max_seg) { bu_log("%s:%d solid name %s has solid number higher than %ld\n", __FILE__, __LINE__, tthrm_sp->tt_max_seg); bu_bomb("Choke! ack! gasp! wheeeeeeze.\n"); } thrm_seg = &tthrm_sp->tt_segs[solid_number]; CK_THRM_SEG(thrm_seg); /* Extract the solid parameters for the particle we hit, * Compare them to the values for the node extracted. If they * don't match, then we probably have a mis-match between the * geometry and the treetherm output files. */ if (pp->pt_inseg->seg_stp->st_id != ID_PARTICLE) { bu_log("%d != ID_PART\n", pp->pt_inseg->seg_stp->st_id); bu_bomb(""); } part_p = (struct rt_part_internal *)pp->pt_inseg->seg_stp->st_specific; RT_PART_CK_MAGIC(part_p); VSUB2(v, part_p->part_V, thrm_seg->pt); if (MAGSQ(v) > 100.0) { double dist; dist = MAGNITUDE(v); /* Distance between particle origin and centroid of thermal * segment nodes is > 10.0mm (1cm). This suggests that * they aren't related. */ bu_log( "----------------------------- W A R N I N G -----------------------------\n\ %s:%d distance %g between origin of particle and thermal node centroid is\n\ too large. Probable mis-match between geometry and thermal data\n", __FILE__, __LINE__, dist); bu_bomb(""); }
/** * Find the square of the distance from a point P to a line segment described * by the two endpoints A and B. * * P * * * /. * / . * / . * / . (dist) * / . * / . * *------*--------* * A PCA B * * There are six distinct cases, with these return codes - * 0 P is within tolerance of lseg AB. *dist = 0. * 1 P is within tolerance of point A. *dist = 0. * 2 P is within tolerance of point B. *dist = 0. * 3 PCA is within tolerance of A. *dist = |P-A|**2. * 4 PCA is within tolerance of B. *dist = |P-B|**2. * 5 P is "above/below" lseg AB. *dist=|PCA-P|**2. * * This routine was formerly called bn_dist_pt_lseg(). * This is a special version that returns the square of the distance * and does not actually calculate PCA. * */ int bn_distsq_pt3_lseg3(fastf_t *dist, const fastf_t *a, const fastf_t *b, const fastf_t *p, const struct bn_tol *tol) { vect_t PtoA; /* P-A */ vect_t PtoB; /* P-B */ vect_t AtoB; /* B-A */ fastf_t P_A_sq; /* |P-A|**2 */ fastf_t P_B_sq; /* |P-B|**2 */ fastf_t B_A_sq; /* |B-A|**2 */ fastf_t t; /* distance squared along ray of projection of P */ fastf_t dot; BN_CK_TOL(tol); /* Check proximity to endpoint A */ VSUB2(PtoA, p, a); P_A_sq = MAGSQ(PtoA); if (P_A_sq < tol->dist_sq) { /* P is within the tol->dist radius circle around A */ *dist = 0.0; return 1; } /* Check proximity to endpoint B */ VSUB2(PtoB, p, b); P_B_sq = MAGSQ(PtoB); if (P_B_sq < tol->dist_sq) { /* P is within the tol->dist radius circle around B */ *dist = 0.0; return 2; } VSUB2(AtoB, b, a); B_A_sq = MAGSQ(AtoB); /* compute distance squared (in actual units) along line to PROJECTION of * point p onto the line: point pca */ dot = VDOT(PtoA, AtoB); t = dot * dot / B_A_sq; if (t < tol->dist_sq) { /* PCA is at A */ *dist = P_A_sq; return 3; } if (dot < -SMALL_FASTF && t > tol->dist_sq) { /* P is "left" of A */ *dist = P_A_sq; return 3; } if (t < (B_A_sq - tol->dist_sq)) { /* PCA falls between A and B */ register fastf_t dsq; /* Find distance from PCA to line segment (Pythagorus) */ dsq = P_A_sq - t; if (dsq < tol->dist_sq) { /* PCA is on lseg */ *dist = 0.0; return 0; } /* P is above or below lseg */ *dist = dsq; return 5; } /* P is "right" of B */ *dist = P_B_sq; return 4; }
/** * Brute force through all possible plane intersections. * Generate all edge lines, then intersect the line with all * the other faces to find the vertices on that line. * If the geometry is correct, there will be no more than two. * While not the fastest strategy, this will produce an accurate * plot without requiring extra bookkeeping. * Note that the vectors will be drawn in no special order. */ int rt_arbn_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol, const struct rt_view_info *UNUSED(info)) { struct rt_arbn_internal *aip; size_t i; size_t j; size_t k; BU_CK_LIST_HEAD(vhead); RT_CK_DB_INTERNAL(ip); aip = (struct rt_arbn_internal *)ip->idb_ptr; RT_ARBN_CK_MAGIC(aip); for (i = 0; i < aip->neqn - 1; i++) { for (j = i + 1; j < aip->neqn; j++) { double dot; int point_count; /* # points on this line */ point_t a, b; /* start and end points */ vect_t dist; VSETALL(a, 0); VSETALL(b, 0); /* If normals are parallel, no intersection */ dot = VDOT(aip->eqn[i], aip->eqn[j]); if (BN_VECT_ARE_PARALLEL(dot, tol)) continue; /* Have an edge line, isect with all other planes */ point_count = 0; for (k = 0; k < aip->neqn; k++) { size_t m; point_t pt; size_t next_k; next_k = 0; if (k == i || k == j) continue; if (bn_mkpoint_3planes(pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]) < 0) continue; /* See if point is outside arb */ for (m = 0; m < aip->neqn; m++) { if (i == m || j == m || k == m) continue; if (VDOT(pt, aip->eqn[m])-aip->eqn[m][3] > tol->dist) { next_k = 1; break; } } if (next_k != 0) continue; if (point_count <= 0) { RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE); VMOVE(a, pt); } else if (point_count == 1) { VSUB2(dist, pt, a); if (MAGSQ(dist) < tol->dist_sq) continue; RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW); VMOVE(b, pt); } else { VSUB2(dist, pt, a); if (MAGSQ(dist) < tol->dist_sq) continue; VSUB2(dist, pt, b); if (MAGSQ(dist) < tol->dist_sq) continue; bu_log("rt_arbn_plot() error, point_count=%d (>2) on edge %zu/%zu, non-convex\n", point_count+1, i, j); VPRINT(" a", a); VPRINT(" b", b); VPRINT("pt", pt); RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW); /* draw it */ } point_count++; } /* Point counts of 1 are (generally) not harmful, * occurring on pyramid peaks and the like. */ } } return 0; }