/** * The external format is: * V point * A vector * B vector * C vector */ int rt_superell_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip) { struct rt_superell_internal *eip; /* must be double for import and export */ double vec[ELEMENTS_PER_VECT*4 + 2]; if (dbip) RT_CK_DBI(dbip); RT_CK_DB_INTERNAL(ip); if (ip->idb_type != ID_SUPERELL) return -1; eip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(eip); BU_CK_EXTERNAL(ep); ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * (ELEMENTS_PER_VECT*4 + 2); ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "superell external"); /* scale 'em into local buffer */ VSCALE(&vec[0*ELEMENTS_PER_VECT], eip->v, local2mm); VSCALE(&vec[1*ELEMENTS_PER_VECT], eip->a, local2mm); VSCALE(&vec[2*ELEMENTS_PER_VECT], eip->b, local2mm); VSCALE(&vec[3*ELEMENTS_PER_VECT], eip->c, local2mm); vec[4*ELEMENTS_PER_VECT] = eip->n; vec[4*ELEMENTS_PER_VECT + 1] = eip->e; /* Convert from internal (host) to database (network) format */ bu_cv_htond(ep->ext_buf, (unsigned char *)vec, ELEMENTS_PER_VECT*4 + 2); return 0; }
int rt_superell_export4(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip) { struct rt_superell_internal *tip; union record *rec; if (dbip) RT_CK_DBI(dbip); RT_CK_DB_INTERNAL(ip); if (ip->idb_type != ID_SUPERELL) return -1; tip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(tip); BU_CK_EXTERNAL(ep); ep->ext_nbytes = sizeof(union record); ep->ext_buf = (uint8_t *)bu_calloc(1, ep->ext_nbytes, "superell external"); rec = (union record *)ep->ext_buf; rec->s.s_id = ID_SOLID; rec->s.s_type = SUPERELL; /* NOTE: This also converts to dbfloat_t */ VSCALE(&rec->s.s_values[0], tip->v, local2mm); VSCALE(&rec->s.s_values[3], tip->a, local2mm); VSCALE(&rec->s.s_values[6], tip->b, local2mm); VSCALE(&rec->s.s_values[9], tip->c, local2mm); printf("SUPERELL: %g %g\n", tip->n, tip->e); rec->s.s_values[12] = tip->n; rec->s.s_values[13] = tip->e; return 0; }
int rt_superell_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info)) { int i; struct rt_superell_internal *eip; fastf_t top[16*3]; fastf_t middle[16*3]; fastf_t bottom[16*3]; BU_CK_LIST_HEAD(vhead); RT_CK_DB_INTERNAL(ip); eip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(eip); rt_superell_16pts(top, eip->v, eip->a, eip->b); rt_superell_16pts(bottom, eip->v, eip->b, eip->c); rt_superell_16pts(middle, eip->v, eip->a, eip->c); RT_ADD_VLIST(vhead, &top[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE); for (i=0; i<16; i++) { RT_ADD_VLIST(vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW); } RT_ADD_VLIST(vhead, &bottom[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE); for (i=0; i<16; i++) { RT_ADD_VLIST(vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW); } RT_ADD_VLIST(vhead, &middle[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE); for (i=0; i<16; i++) { RT_ADD_VLIST(vhead, &middle[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW); } return 0; }
/** * Computes the volume of a superellipsoid * * Volume equation from http://lrv.fri.uni-lj.si/~franc/SRSbook/geometry.pdf * which also includes a derivation on page 32. */ void rt_superell_volume(fastf_t *volume, const struct rt_db_internal *ip) { #ifdef HAVE_TGAMMA struct rt_superell_internal *sip; double mag_a, mag_b, mag_c; #endif if (volume == NULL || ip == NULL) { return; } #ifdef HAVE_TGAMMA RT_CK_DB_INTERNAL(ip); sip = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(sip); mag_a = MAGNITUDE(sip->a); mag_b = MAGNITUDE(sip->b); mag_c = MAGNITUDE(sip->c); *volume = 2.0 * mag_a * mag_b * mag_c * sip->e * sip->n * (tgamma(sip->n/2.0 + 1.0) * tgamma(sip->n) / tgamma(3.0 * sip->n/2.0 + 1.0)) * (tgamma(sip->e / 2.0) * tgamma(sip->e / 2.0) / tgamma(sip->e)); #endif }
/* * Default keypoint in model space is established in "pt". Returns * GED_ERROR if unable to determine a keypoint, otherwise returns * GED_OK. */ int _ged_get_solid_keypoint(struct ged *const gedp, fastf_t *const pt, const struct rt_db_internal *const ip, const fastf_t *const mat) { point_t mpt; RT_CK_DB_INTERNAL(ip); switch (ip->idb_type) { case ID_CLINE: { struct rt_cline_internal *cli = (struct rt_cline_internal *)ip->idb_ptr; RT_CLINE_CK_MAGIC(cli); VMOVE(mpt, cli->v); break; } case ID_PARTICLE: { struct rt_part_internal *part = (struct rt_part_internal *)ip->idb_ptr; RT_PART_CK_MAGIC(part); VMOVE(mpt, part->part_V); break; } case ID_PIPE: { struct rt_pipe_internal *pipeip; struct wdb_pipept *pipe_seg; pipeip = (struct rt_pipe_internal *)ip->idb_ptr; RT_PIPE_CK_MAGIC(pipeip); pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head); VMOVE(mpt, pipe_seg->pp_coord); break; } case ID_METABALL: { struct rt_metaball_internal *metaball = (struct rt_metaball_internal *)ip->idb_ptr; struct wdb_metaballpt *metaballpt; RT_METABALL_CK_MAGIC(metaball); VSETALL(mpt, 0.0); metaballpt = BU_LIST_FIRST(wdb_metaballpt, &metaball->metaball_ctrl_head); VMOVE(mpt, metaballpt->coord); break; } case ID_ARBN: { struct rt_arbn_internal *arbn = (struct rt_arbn_internal *)ip->idb_ptr; size_t i, j, k; int good_vert = 0; RT_ARBN_CK_MAGIC(arbn); for (i = 0; i < arbn->neqn; i++) { for (j = i + 1; j < arbn->neqn; j++) { for (k = j + 1; k < arbn->neqn; k++) { if (!bn_mkpoint_3planes(mpt, arbn->eqn[i], arbn->eqn[j], arbn->eqn[k])) { size_t l; good_vert = 1; for (l = 0; l < arbn->neqn; l++) { if (l == i || l == j || l == k) continue; if (DIST_PT_PLANE(mpt, arbn->eqn[l]) > gedp->ged_wdbp->wdb_tol.dist) { good_vert = 0; break; } } if (good_vert) break; } } if (good_vert) break; } if (good_vert) break; } break; } case ID_EBM: { struct rt_ebm_internal *ebm = (struct rt_ebm_internal *)ip->idb_ptr; point_t pnt; RT_EBM_CK_MAGIC(ebm); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, ebm->mat, pnt); break; } case ID_BOT: { struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr; VMOVE(mpt, bot->vertices); break; } case ID_DSP: { struct rt_dsp_internal *dsp = (struct rt_dsp_internal *)ip->idb_ptr; point_t pnt; RT_DSP_CK_MAGIC(dsp); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, dsp->dsp_stom, pnt); break; } case ID_HF: { struct rt_hf_internal *hf = (struct rt_hf_internal *)ip->idb_ptr; RT_HF_CK_MAGIC(hf); VMOVE(mpt, hf->v); break; } case ID_VOL: { struct rt_vol_internal *vol = (struct rt_vol_internal *)ip->idb_ptr; point_t pnt; RT_VOL_CK_MAGIC(vol); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, vol->mat, pnt); break; } case ID_HALF: { struct rt_half_internal *haf = (struct rt_half_internal *)ip->idb_ptr; RT_HALF_CK_MAGIC(haf); VSCALE(mpt, haf->eqn, haf->eqn[H]); break; } case ID_ARB8: { struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr; RT_ARB_CK_MAGIC(arb); VMOVE(mpt, arb->pt[0]); break; } case ID_ELL: case ID_SPH: { struct rt_ell_internal *ell = (struct rt_ell_internal *)ip->idb_ptr; RT_ELL_CK_MAGIC(ell); VMOVE(mpt, ell->v); break; } case ID_SUPERELL: { struct rt_superell_internal *superell = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(superell); VMOVE(mpt, superell->v); break; } case ID_TOR: { struct rt_tor_internal *tor = (struct rt_tor_internal *)ip->idb_ptr; RT_TOR_CK_MAGIC(tor); VMOVE(mpt, tor->v); break; } case ID_TGC: case ID_REC: { struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tgc); VMOVE(mpt, tgc->v); break; } case ID_GRIP: { struct rt_grip_internal *gip = (struct rt_grip_internal *)ip->idb_ptr; RT_GRIP_CK_MAGIC(gip); VMOVE(mpt, gip->center); break; } case ID_ARS: { struct rt_ars_internal *ars = (struct rt_ars_internal *)ip->idb_ptr; RT_ARS_CK_MAGIC(ars); VMOVE(mpt, &ars->curves[0][0]); break; } case ID_RPC: { struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr; RT_RPC_CK_MAGIC(rpc); VMOVE(mpt, rpc->rpc_V); break; } case ID_RHC: { struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr; RT_RHC_CK_MAGIC(rhc); VMOVE(mpt, rhc->rhc_V); break; } case ID_EPA: { struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr; RT_EPA_CK_MAGIC(epa); VMOVE(mpt, epa->epa_V); break; } case ID_EHY: { struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr; RT_EHY_CK_MAGIC(ehy); VMOVE(mpt, ehy->ehy_V); break; } case ID_HYP: { struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(hyp); VMOVE(mpt, hyp->hyp_Vi); break; } case ID_ETO: { struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr; RT_ETO_CK_MAGIC(eto); VMOVE(mpt, eto->eto_V); break; } case ID_POLY: { struct rt_pg_face_internal *_poly; struct rt_pg_internal *pg = (struct rt_pg_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(pg); _poly = pg->poly; VMOVE(mpt, _poly->verts); break; } case ID_SKETCH: { struct rt_sketch_internal *skt = (struct rt_sketch_internal *)ip->idb_ptr; RT_SKETCH_CK_MAGIC(skt); VMOVE(mpt, skt->V); break; } case ID_EXTRUDE: { struct rt_extrude_internal *extr = (struct rt_extrude_internal *)ip->idb_ptr; RT_EXTRUDE_CK_MAGIC(extr); if (extr->skt && extr->skt->verts) { VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec, extr->skt->verts[0][1], extr->v_vec); } else { VMOVE(mpt, extr->V); } break; } case ID_NMG: { struct vertex *v; struct vertexuse *vu; struct edgeuse *eu; struct loopuse *lu; struct faceuse *fu; struct shell *s; struct nmgregion *r; struct model *m = (struct model *) ip->idb_ptr; NMG_CK_MODEL(m); /* set default first */ VSETALL(mpt, 0.0); if (BU_LIST_IS_EMPTY(&m->r_hd)) break; r = BU_LIST_FIRST(nmgregion, &m->r_hd); if (!r) break; NMG_CK_REGION(r); if (BU_LIST_IS_EMPTY(&r->s_hd)) break; s = BU_LIST_FIRST(shell, &r->s_hd); if (!s) break; NMG_CK_SHELL(s); if (BU_LIST_IS_EMPTY(&s->fu_hd)) fu = (struct faceuse *)NULL; else fu = BU_LIST_FIRST(faceuse, &s->fu_hd); if (fu) { NMG_CK_FACEUSE(fu); lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->lu_hd)) lu = (struct loopuse *)NULL; else lu = BU_LIST_FIRST(loopuse, &s->lu_hd); if (lu) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->eu_hd)) eu = (struct edgeuse *)NULL; else eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); if (eu) { NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); v = vu->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } } default: VSETALL(mpt, 0.0); bu_vls_printf(gedp->ged_result_str, "get_solid_keypoint: unrecognized solid type"); return GED_ERROR; } MAT4X3PNT(pt, mat, mpt); return GED_OK; }
/** * Make human-readable formatted presentation of this solid. First * line describes type of solid. Additional lines are indented one * tab, and give parameter values. */ int rt_superell_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local) { struct rt_superell_internal *tip = (struct rt_superell_internal *)ip->idb_ptr; fastf_t mag_a, mag_b, mag_c; char buf[256]; double angles[5]; vect_t unitv; RT_SUPERELL_CK_MAGIC(tip); bu_vls_strcat(str, "superellipsoid (SUPERELL)\n"); sprintf(buf, "\tV (%g, %g, %g)\n", INTCLAMP(tip->v[X] * mm2local), INTCLAMP(tip->v[Y] * mm2local), INTCLAMP(tip->v[Z] * mm2local)); bu_vls_strcat(str, buf); mag_a = MAGNITUDE(tip->a); mag_b = MAGNITUDE(tip->b); mag_c = MAGNITUDE(tip->c); sprintf(buf, "\tA (%g, %g, %g) mag=%g\n", INTCLAMP(tip->a[X] * mm2local), INTCLAMP(tip->a[Y] * mm2local), INTCLAMP(tip->a[Z] * mm2local), INTCLAMP(mag_a * mm2local)); bu_vls_strcat(str, buf); sprintf(buf, "\tB (%g, %g, %g) mag=%g\n", INTCLAMP(tip->b[X] * mm2local), INTCLAMP(tip->b[Y] * mm2local), INTCLAMP(tip->b[Z] * mm2local), INTCLAMP(mag_b * mm2local)); bu_vls_strcat(str, buf); sprintf(buf, "\tC (%g, %g, %g) mag=%g\n", INTCLAMP(tip->c[X] * mm2local), INTCLAMP(tip->c[Y] * mm2local), INTCLAMP(tip->c[Z] * mm2local), INTCLAMP(mag_c * mm2local)); bu_vls_strcat(str, buf); sprintf(buf, "\t<n, e> (%g, %g)\n", INTCLAMP(tip->n), INTCLAMP(tip->e)); bu_vls_strcat(str, buf); if (!verbose) return 0; VSCALE(unitv, tip->a, 1/mag_a); rt_find_fallback_angle(angles, unitv); rt_pr_fallback_angle(str, "\tA", angles); VSCALE(unitv, tip->b, 1/mag_b); rt_find_fallback_angle(angles, unitv); rt_pr_fallback_angle(str, "\tB", angles); VSCALE(unitv, tip->c, 1/mag_c); rt_find_fallback_angle(angles, unitv); rt_pr_fallback_angle(str, "\tC", angles); 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; }