void bn_mat_lookat(mat_t rot, const vect_t dir, int yflip) { mat_t first; mat_t second; mat_t prod12; mat_t third; vect_t x; vect_t z; vect_t t1; fastf_t hypot_xy; vect_t xproj; vect_t zproj; /* First, rotate D around Z axis to match +X axis (azimuth) */ hypot_xy = hypot(dir[X], dir[Y]); bn_mat_zrot(first, -dir[Y] / hypot_xy, dir[X] / hypot_xy); /* Next, rotate D around Y axis to match -Z axis (elevation) */ bn_mat_yrot(second, -hypot_xy, -dir[Z]); bn_mat_mul(prod12, second, first); /* Produce twist correction, by re-orienting projection of X axis */ VSET(x, 1, 0, 0); MAT4X3VEC(xproj, prod12, x); hypot_xy = hypot(xproj[X], xproj[Y]); if (hypot_xy < 1.0e-10) { bu_log("Warning: bn_mat_lookat: unable to twist correct, hypot=%g\n", hypot_xy); VPRINT("xproj", xproj); MAT_COPY(rot, prod12); return; } bn_mat_zrot(third, -xproj[Y] / hypot_xy, xproj[X] / hypot_xy); bn_mat_mul(rot, third, prod12); if (yflip) { VSET(z, 0, 0, 1); MAT4X3VEC(zproj, rot, z); /* If original Z inverts sign, flip sign on resulting Y */ if (zproj[Y] < 0.0) { MAT_COPY(prod12, rot); MAT_IDN(third); third[5] = -1; bn_mat_mul(rot, third, prod12); } } /* Check the final results */ MAT4X3VEC(t1, rot, dir); if (t1[Z] > -0.98) { bu_log("Error: bn_mat_lookat final= (%g, %g, %g)\n", V3ARGS(t1)); } }
/** * R E C _ N O R M * * Given ONE ray distance, return the normal and entry/exit point. * hit_surfno is a flag indicating if normal needs to be computed or not. */ void rt_rec_norm(struct hit *hitp, struct soltab *stp, struct xray *rp) { struct rec_specific *rec = (struct rec_specific *)stp->st_specific; VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir); switch (hitp->hit_surfno) { case REC_NORM_BODY: /* compute it */ hitp->hit_vpriv[Z] = 0.0; MAT4X3VEC(hitp->hit_normal, rec->rec_invRoS, hitp->hit_vpriv); VUNITIZE(hitp->hit_normal); break; case REC_NORM_TOP: VMOVE(hitp->hit_normal, rec->rec_Hunit); break; case REC_NORM_BOT: VREVERSE(hitp->hit_normal, rec->rec_Hunit); break; default: bu_log("rt_rec_norm: surfno=%d bad\n", hitp->hit_surfno); break; } }
int BrepHandler::extractCircularArc(const DirectoryEntry* de, const ParameterData& params) { point_t center, start, end; double offset_z = params.getReal(1); center[X] = params.getReal(2); center[Y] = params.getReal(3); center[Z] = offset_z; start[X] = params.getReal(4); start[Y] = params.getReal(5); start[Z] = offset_z; end[X] = params.getReal(6); end[Y] = params.getReal(7); end[Z] = offset_z; mat_t xform; MAT_IDN(xform); _iges->getTransformation(de->xform(), xform); // choose the circle/interval representation // so, calculate the circle params, and then the angle the arc subtends double dx = start[X] - center[X]; double dy = start[Y] - center[Y]; double radius = sqrt(dx*dx + dy*dy); point_t tcenter, tstart, tend; MAT4X3PNT(tcenter, xform, center); MAT4X3PNT(tstart, xform, start); MAT4X3PNT(tend, xform, end); vect_t normal = {0,0,1}; vect_t tnormal; MAT4X3VEC(tnormal, xform, normal); return handleCircularArc(radius, tcenter, tnormal, tstart, tend); }
/** * Import an superellipsoid/sphere from the database format to the * internal structure. Apply modeling transformations as wsuperell. */ int rt_superell_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip) { struct rt_superell_internal *eip; union record *rp; fastf_t vec[3*4 + 2]; if (dbip) RT_CK_DBI(dbip); BU_CK_EXTERNAL(ep); rp = (union record *)ep->ext_buf; /* Check record type */ if (rp->u_id != ID_SOLID) { bu_log("rt_superell_import4(): defective record\n"); return -1; } RT_CK_DB_INTERNAL(ip); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_SUPERELL; ip->idb_meth = &OBJ[ID_SUPERELL]; BU_ALLOC(ip->idb_ptr, struct rt_superell_internal); eip = (struct rt_superell_internal *)ip->idb_ptr; eip->magic = RT_SUPERELL_INTERNAL_MAGIC; /* Convert from database to internal format */ flip_fastf_float(vec, rp->s.s_values, 4, dbip->dbi_version < 0 ? 1 : 0); /* Apply modeling transformations */ if (mat == NULL) mat = bn_mat_identity; MAT4X3PNT(eip->v, mat, &vec[0*3]); MAT4X3VEC(eip->a, mat, &vec[1*3]); MAT4X3VEC(eip->b, mat, &vec[2*3]); MAT4X3VEC(eip->c, mat, &vec[3*3]); if (dbip->dbi_version < 0) { eip->n = flip_dbfloat(rp->s.s_values[12]); eip->e = flip_dbfloat(rp->s.s_values[13]); } else { eip->n = rp->s.s_values[12]; eip->e = rp->s.s_values[13]; } return 0; /* OK */ }
void ged_view_update(struct ged_view *gvp) { vect_t work, work1; vect_t temp, temp1; if (!gvp) return; bn_mat_mul(gvp->gv_model2view, gvp->gv_rotation, gvp->gv_center); gvp->gv_model2view[15] = gvp->gv_scale; bn_mat_inv(gvp->gv_view2model, gvp->gv_model2view); /* Find current azimuth, elevation, and twist angles */ VSET(work, 0.0, 0.0, 1.0); /* view z-direction */ MAT4X3VEC(temp, gvp->gv_view2model, work); VSET(work1, 1.0, 0.0, 0.0); /* view x-direction */ MAT4X3VEC(temp1, gvp->gv_view2model, work1); /* calculate angles using accuracy of 0.005, since display * shows 2 digits right of decimal point */ bn_aet_vec(&gvp->gv_aet[0], &gvp->gv_aet[1], &gvp->gv_aet[2], temp, temp1, (fastf_t)0.005); /* Force azimuth range to be [0, 360] */ if ((NEAR_EQUAL(gvp->gv_aet[1], 90.0, (fastf_t)0.005) || NEAR_EQUAL(gvp->gv_aet[1], -90.0, (fastf_t)0.005)) && gvp->gv_aet[0] < 0 && !NEAR_ZERO(gvp->gv_aet[0], (fastf_t)0.005)) gvp->gv_aet[0] += 360.0; else if (NEAR_ZERO(gvp->gv_aet[0], (fastf_t)0.005)) gvp->gv_aet[0] = 0.0; /* apply the perspective angle to model2view */ bn_mat_mul(gvp->gv_pmodel2view, gvp->gv_pmat, gvp->gv_model2view); if (gvp->gv_callback) (*gvp->gv_callback)(gvp, gvp->gv_clientData); }
int _ged_rotate_tgc(struct ged *gedp, struct rt_tgc_internal *tgc, const char *attribute, matp_t rmat) { RT_TGC_CK_MAGIC(tgc); switch (attribute[0]) { case 'h': case 'H': switch (attribute[1]) { case '\0': MAT4X3VEC(tgc->h, rmat, tgc->h); break; case 'a': case 'A': if ((attribute[2] == 'b' || attribute[2] == 'B') && attribute[3] == '\0') { MAT4X3VEC(tgc->a, rmat, tgc->a); MAT4X3VEC(tgc->b, rmat, tgc->b); MAT4X3VEC(tgc->c, rmat, tgc->c); MAT4X3VEC(tgc->d, rmat, tgc->d); } else { bu_vls_printf(gedp->ged_result_str, "bad tgc attribute - %s", attribute); return GED_ERROR; } break; default: bu_vls_printf(gedp->ged_result_str, "bad tgc attribute - %s", attribute); return GED_ERROR; } break; default: bu_vls_printf(gedp->ged_result_str, "bad tgc attribute - %s", attribute); return GED_ERROR; } return GED_OK; }
/** * Import an superellipsoid/sphere from the database format to the * internal structure. Apply modeling transformations as wsuperell. */ int rt_superell_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, 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); BU_CK_EXTERNAL(ep); BU_ASSERT_LONG(ep->ext_nbytes, ==, SIZEOF_NETWORK_DOUBLE * (ELEMENTS_PER_VECT*4 + 2)); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_SUPERELL; ip->idb_meth = &OBJ[ID_SUPERELL]; BU_ALLOC(ip->idb_ptr, struct rt_superell_internal); eip = (struct rt_superell_internal *)ip->idb_ptr; eip->magic = RT_SUPERELL_INTERNAL_MAGIC; /* Convert from database (network) to internal (host) format */ bu_cv_ntohd((unsigned char *)vec, ep->ext_buf, ELEMENTS_PER_VECT*4 + 2); /* Apply modeling transformations */ if (mat == NULL) mat = bn_mat_identity; MAT4X3PNT(eip->v, mat, &vec[0*ELEMENTS_PER_VECT]); MAT4X3VEC(eip->a, mat, &vec[1*ELEMENTS_PER_VECT]); MAT4X3VEC(eip->b, mat, &vec[2*ELEMENTS_PER_VECT]); MAT4X3VEC(eip->c, mat, &vec[3*ELEMENTS_PER_VECT]); eip->n = vec[4*ELEMENTS_PER_VECT]; eip->e = vec[4*ELEMENTS_PER_VECT + 1]; return 0; /* OK */ }
/** * Create a perspective matrix that transforms the +/1 viewing cube, * with the actual eye position (not at Z=+1) specified in viewing * coords, into a related space where the eye has been sheared onto * the Z axis and repositioned at Z=(0, 0, 1), with the same * perspective field of view as before. * * The Zbuffer clips off stuff with negative Z values. * * pmat = persp * xlate * shear */ void ged_mike_persp_mat(mat_t pmat, const point_t eye) { mat_t shear; mat_t persp; mat_t xlate; mat_t t1, t2; point_t sheared_eye; if (eye[Z] <= SMALL) { VPRINT("mike_persp_mat(): ERROR, z<0, eye", eye); return; } /* Shear "eye" to +Z axis */ MAT_IDN(shear); shear[2] = -eye[X]/eye[Z]; shear[6] = -eye[Y]/eye[Z]; MAT4X3VEC(sheared_eye, shear, eye); if (!NEAR_ZERO(sheared_eye[X], .01) || !NEAR_ZERO(sheared_eye[Y], .01)) { VPRINT("ERROR sheared_eye", sheared_eye); return; } /* Translate along +Z axis to put sheared_eye at (0, 0, 1). */ MAT_IDN(xlate); /* XXX should I use MAT_DELTAS_VEC_NEG()? X and Y should be 0 now */ MAT_DELTAS(xlate, 0, 0, 1-sheared_eye[Z]); /* Build perspective matrix inline, substituting fov=2*atan(1, Z) */ MAT_IDN(persp); /* From page 492 of Graphics Gems */ persp[0] = sheared_eye[Z]; /* scaling: fov aspect term */ persp[5] = sheared_eye[Z]; /* scaling: determines fov */ /* From page 158 of Rogers Mathematical Elements */ /* Z center of projection at Z=+1, r=-1/1 */ persp[14] = -1; bn_mat_mul(t1, xlate, shear); bn_mat_mul(t2, persp, t1); /* Now, move eye from Z=1 to Z=0, for clipping purposes */ MAT_DELTAS(xlate, 0, 0, -1); bn_mat_mul(pmat, xlate, t2); }
/** * Given ONE ray distance, return the normal and entry/exit point. */ void rt_superell_norm(struct hit *hitp, struct soltab *stp, struct xray *rp) { struct superell_specific *superell = (struct superell_specific *)stp->st_specific; vect_t xlated; fastf_t scale; VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir); VSUB2(xlated, hitp->hit_point, superell->superell_V); MAT4X3VEC(hitp->hit_normal, superell->superell_invRSSR, xlated); scale = 1.0 / MAGNITUDE(hitp->hit_normal); VSCALE(hitp->hit_normal, hitp->hit_normal, scale); return; }
/** * Convert from "network" doubles to machine specific. * Transform */ int rt_arbn_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip) { union record *rp; struct rt_arbn_internal *aip; size_t i; /* must be double for import and export */ double *scan; if (dbip) RT_CK_DBI(dbip); BU_CK_EXTERNAL(ep); rp = (union record *)ep->ext_buf; if (rp->u_id != DBID_ARBN) { bu_log("rt_arbn_import4: defective record, id=x%x\n", rp->u_id); return -1; } RT_CK_DB_INTERNAL(ip); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_ARBN; ip->idb_meth = &OBJ[ID_ARBN]; BU_ALLOC(ip->idb_ptr, struct rt_arbn_internal); aip = (struct rt_arbn_internal *)ip->idb_ptr; aip->magic = RT_ARBN_INTERNAL_MAGIC; aip->neqn = ntohl(*(uint32_t *)rp->n.n_neqn); if (aip->neqn <= 0) return -1; aip->eqn = (plane_t *)bu_malloc(aip->neqn*sizeof(plane_t), "arbn plane eqn[]"); scan = (double *)bu_malloc(aip->neqn*sizeof(double)*ELEMENTS_PER_PLANE, "scan array"); bu_cv_ntohd((unsigned char *)scan, (unsigned char *)(&rp[1]), aip->neqn*ELEMENTS_PER_PLANE); for (i = 0; i < aip->neqn; i++) { aip->eqn[i][X] = scan[(i*ELEMENTS_PER_PLANE)+0]; /* convert double to fastf_t */ aip->eqn[i][Y] = scan[(i*ELEMENTS_PER_PLANE)+1]; /* convert double to fastf_t */ aip->eqn[i][Z] = scan[(i*ELEMENTS_PER_PLANE)+2]; /* convert double to fastf_t */ aip->eqn[i][W] = scan[(i*ELEMENTS_PER_PLANE)+3]; /* convert double to fastf_t */ } bu_free(scan, "scan array"); /* Transform by the matrix */ if (mat == NULL) mat = bn_mat_identity; for (i = 0; i < aip->neqn; i++) { point_t orig_pt; point_t pt; vect_t norm; fastf_t factor; /* unitize the plane equation first */ factor = 1.0 / MAGNITUDE(aip->eqn[i]); VSCALE(aip->eqn[i], aip->eqn[i], factor); aip->eqn[i][W] = aip->eqn[i][W] * factor; /* Pick a point on the original halfspace */ VSCALE(orig_pt, aip->eqn[i], aip->eqn[i][W]); /* Transform the point, and the normal */ MAT4X3VEC(norm, mat, aip->eqn[i]); MAT4X3PNT(pt, mat, orig_pt); /* Measure new distance from origin to new point */ VUNITIZE(norm); VMOVE(aip->eqn[i], norm); aip->eqn[i][W] = VDOT(pt, norm); } return 0; }
/** * Intersect a ray with an superellipsoid, where all constant terms * have been precomputed by rt_superell_prep(). If an intersection * occurs, a struct seg will be acquired and filled in. * * Returns - * 0 MISS * >0 HIT */ int rt_superell_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead) { static int counter=10; struct superell_specific *superell = (struct superell_specific *)stp->st_specific; bn_poly_t equation; /* equation of superell to be solved */ vect_t translated; /* translated shot vector */ vect_t newShotPoint; /* P' */ vect_t newShotDir; /* D' */ vect_t normalizedShotPoint; /* P' with normalized dist from superell */ bn_complex_t complexRoot[4]; /* roots returned from poly solver */ double realRoot[4]; /* real ray distance values */ int i, j; struct seg *segp; /* translate ray point */ /* VSUB2(translated, rp->r_pt, superell->superell_V); */ (translated)[X] = (rp->r_pt)[X] - (superell->superell_V)[X]; (translated)[Y] = (rp->r_pt)[Y] - (superell->superell_V)[Y]; (translated)[Z] = (rp->r_pt)[Z] - (superell->superell_V)[Z]; /* scale and rotate point to get P' */ /* MAT4X3VEC(newShotPoint, superell->superell_SoR, translated); */ newShotPoint[X] = (superell->superell_SoR[0]*translated[X] + superell->superell_SoR[1]*translated[Y] + superell->superell_SoR[ 2]*translated[Z]) * 1.0/(superell->superell_SoR[15]); newShotPoint[Y] = (superell->superell_SoR[4]*translated[X] + superell->superell_SoR[5]*translated[Y] + superell->superell_SoR[ 6]*translated[Z]) * 1.0/(superell->superell_SoR[15]); newShotPoint[Z] = (superell->superell_SoR[8]*translated[X] + superell->superell_SoR[9]*translated[Y] + superell->superell_SoR[10]*translated[Z]) * 1.0/(superell->superell_SoR[15]); /* translate ray direction vector */ MAT4X3VEC(newShotDir, superell->superell_SoR, rp->r_dir); VUNITIZE(newShotDir); /* normalize distance from the superell. substitutes a corrected ray * point, which contains a translation along the ray direction to the * closest approach to vertex of the superell. Translating the ray * along the direction of the ray to the closest point near the * primitive's center vertex. New ray origin is hence, normalized. */ VSCALE(normalizedShotPoint, newShotDir, VDOT(newShotPoint, newShotDir)); VSUB2(normalizedShotPoint, newShotPoint, normalizedShotPoint); /* Now generate the polynomial equation for passing to the root finder */ equation.dgr = 2; /* (x^2 / A) + (y^2 / B) + (z^2 / C) - 1 */ equation.cf[0] = newShotPoint[X] * newShotPoint[X] * superell->superell_invmsAu + newShotPoint[Y] * newShotPoint[Y] * superell->superell_invmsBu + newShotPoint[Z] * newShotPoint[Z] * superell->superell_invmsCu - 1; /* (2xX / A) + (2yY / B) + (2zZ / C) */ equation.cf[1] = 2 * newShotDir[X] * newShotPoint[X] * superell->superell_invmsAu + 2 * newShotDir[Y] * newShotPoint[Y] * superell->superell_invmsBu + 2 * newShotDir[Z] * newShotPoint[Z] * superell->superell_invmsCu; /* (X^2 / A) + (Y^2 / B) + (Z^2 / C) */ equation.cf[2] = newShotDir[X] * newShotDir[X] * superell->superell_invmsAu + newShotDir[Y] * newShotDir[Y] * superell->superell_invmsBu + newShotDir[Z] * newShotDir[Z] * superell->superell_invmsCu; if ((i = rt_poly_roots(&equation, complexRoot, stp->st_dp->d_namep)) != 2) { if (i > 0) { bu_log("rt_superell_shot(): poly roots %d != 2\n", i); bn_pr_roots(stp->st_name, complexRoot, i); } else if (i < 0) { static int reported=0; bu_log("rt_superell_shot(): 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("rt_superell_shot(): Additional superellipsoid convergence failure details will be suppressed.\n"); reported=1; } } return 0; /* MISS */ } /* XXX BEGIN CUT */ /* Only real roots indicate an intersection in real space. * * Look at each root returned; if the imaginary part is zero * or sufficiently close, then use the real part as one value * of 't' for the intersections */ for (j=0, i=0; j < 2; j++) { if (NEAR_ZERO(complexRoot[j].im, 0.001)) realRoot[i++] = complexRoot[j].re; } /* reverse above translation by adding distance to all 'k' values. */ /* for (j = 0; j < i; ++j) realRoot[j] -= VDOT(newShotPoint, newShotDir); */ /* Here, 'i' is number of points found */ switch (i) { case 0: return 0; /* No hit */ default: bu_log("rt_superell_shot(): reduced 4 to %d roots\n", i); bn_pr_roots(stp->st_name, complexRoot, 4); return 0; /* No hit */ case 2: { /* Sort most distant to least distant. */ fastf_t u; if ((u=realRoot[0]) < realRoot[1]) { /* bubble larger towards [0] */ realRoot[0] = realRoot[1]; realRoot[1] = u; } } break; case 4: { short n; short lim; /* Inline rt_pt_sort(). Sorts realRoot[] into descending order. */ for (lim = i-1; lim > 0; lim--) { for (n = 0; n < lim; n++) { fastf_t u; if ((u=realRoot[n]) < realRoot[n+1]) { /* bubble larger towards [0] */ realRoot[n] = realRoot[n+1]; realRoot[n+1] = u; } } } } break; } if (counter > 0) { bu_log("rt_superell_shot(): realroot in %f out %f\n", realRoot[1], realRoot[0]); counter--; } /* Now, t[0] > t[npts-1] */ /* realRoot[1] is entry point, and realRoot[0] is farthest exit point */ RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; segp->seg_in.hit_dist = realRoot[1]; segp->seg_out.hit_dist = realRoot[0]; /* segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 0; */ /* Set aside vector for rt_superell_norm() later */ /* VJOIN1(segp->seg_in.hit_vpriv, newShotPoint, realRoot[1], newShotDir); */ /* VJOIN1(segp->seg_out.hit_vpriv, newShotPoint, realRoot[0], newShotDir); */ BU_LIST_INSERT(&(seghead->l), &(segp->l)); if (i == 2) { return 2; /* HIT */ } /* 4 points */ /* realRoot[3] is entry point, and realRoot[2] is exit point */ RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; segp->seg_in.hit_dist = realRoot[3]*superell->superell_e; segp->seg_out.hit_dist = realRoot[2]*superell->superell_e; segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 1; VJOIN1(segp->seg_in.hit_vpriv, newShotPoint, realRoot[3], newShotDir); VJOIN1(segp->seg_out.hit_vpriv, newShotPoint, realRoot[2], newShotDir); BU_LIST_INSERT(&(seghead->l), &(segp->l)); return 4; /* HIT */ /* XXX END CUT */ }
static void bn_mat4x3vec(fastf_t *o, mat_t m, vect_t i) { MAT4X3VEC(o, m, i); }
/** * Apply a transformation matrix to the specified 'ip' input revolve * object, storing the results in the specified 'op' out pointer or * creating a copy if NULL. */ int rt_revolve_xform( struct rt_db_internal *op, const mat_t mat, struct rt_db_internal *ip, int release, struct db_i *dbip, struct resource *resp) { struct rt_revolve_internal *rip, *rop; point_t tmp_vec; if (dbip) RT_CK_DBI(dbip); RT_CK_DB_INTERNAL(ip); RT_CK_RESOURCE(resp); rip = (struct rt_revolve_internal *)ip->idb_ptr; RT_REVOLVE_CK_MAGIC(rip); if (bu_debug&BU_DEBUG_MEM_CHECK) { bu_log("Barrier check at start of revolve_xform():\n"); bu_mem_barriercheck(); } if (op != ip) { RT_DB_INTERNAL_INIT(op); BU_ALLOC(rop, struct rt_revolve_internal); rop->magic = RT_REVOLVE_INTERNAL_MAGIC; bu_vls_init(&rop->sketch_name); bu_vls_vlscat(&rop->sketch_name, &rip->sketch_name); op->idb_ptr = (void *)rop; op->idb_meth = &OBJ[ID_REVOLVE]; op->idb_major_type = DB5_MAJORTYPE_BRLCAD; op->idb_type = ID_REVOLVE; if (ip->idb_avs.magic == BU_AVS_MAGIC) { bu_avs_init(&op->idb_avs, ip->idb_avs.count, "avs"); bu_avs_merge(&op->idb_avs, &ip->idb_avs); } } else { rop = (struct rt_revolve_internal *)ip->idb_ptr; } MAT4X3PNT(tmp_vec, mat, rip->v3d); VMOVE(rop->v3d, tmp_vec); MAT4X3VEC(tmp_vec, mat, rip->axis3d); VMOVE(rop->axis3d, tmp_vec); V2MOVE(rop->v2d, rip->v2d); V2MOVE(rop->axis2d, rip->axis2d); if (release && ip != op) { rop->skt = rip->skt; rip->skt = (struct rt_sketch_internal *)NULL; rt_db_free_internal(ip); } else if (rip->skt) { rop->skt = rt_copy_sketch(rip->skt); } else { rop->skt = (struct rt_sketch_internal *)NULL; } if (bu_debug&BU_DEBUG_MEM_CHECK) { bu_log("Barrier check at end of revolve_xform():\n"); bu_mem_barriercheck(); } return 0; }
/** * R T _ P G _ I M P O R T * * Read all the polygons in as a complex dynamic structure. * The caller is responsible for freeing the dynamic memory. * (vid rt_pg_ifree). */ int rt_pg_import4(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip) { struct rt_pg_internal *pgp; union record *rp; size_t i; size_t rno; /* current record number */ size_t p; /* current polygon index */ if (dbip) RT_CK_DBI(dbip); BU_CK_EXTERNAL(ep); rp = (union record *)ep->ext_buf; if (rp->u_id != ID_P_HEAD) { bu_log("rt_pg_import4: defective header record\n"); return -1; } RT_CK_DB_INTERNAL(ip); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_POLY; ip->idb_meth = &rt_functab[ID_POLY]; BU_ALLOC(ip->idb_ptr, struct rt_pg_internal); pgp = (struct rt_pg_internal *)ip->idb_ptr; pgp->magic = RT_PG_INTERNAL_MAGIC; pgp->npoly = (ep->ext_nbytes - sizeof(union record)) / sizeof(union record); if (pgp->npoly <= 0) { bu_log("rt_pg_import4: polysolid with no polygons!\n"); return -1; } if (pgp->npoly) pgp->poly = (struct rt_pg_face_internal *)bu_malloc( pgp->npoly * sizeof(struct rt_pg_face_internal), "rt_pg_face_internal"); pgp->max_npts = 0; if (mat == NULL) mat = bn_mat_identity; for (p=0; p < pgp->npoly; p++) { struct rt_pg_face_internal *pp; pp = &pgp->poly[p]; rno = p+1; if (rp[rno].q.q_id != ID_P_DATA) { bu_log("rt_pg_import4: defective data record\n"); return -1; } pp->npts = rp[rno].q.q_count; pp->verts = (fastf_t *)bu_malloc(pp->npts * 3 * sizeof(fastf_t), "pg verts[]"); pp->norms = (fastf_t *)bu_malloc(pp->npts * 3 * sizeof(fastf_t), "pg norms[]"); for (i=0; i < pp->npts; i++) { point_t pnt; vect_t vec; if (dbip->dbi_version < 0) { flip_fastf_float(pnt, rp[rno].q.q_verts[i], 1, 1); flip_fastf_float(vec, rp[rno].q.q_norms[i], 1, 1); } else { VMOVE(pnt, rp[rno].q.q_verts[i]); VMOVE(vec, rp[rno].q.q_norms[i]); } /* Note: side effect of importing dbfloat_t */ MAT4X3PNT(&pp->verts[i*3], mat, pnt); MAT4X3VEC(&pp->norms[i*3], mat, vec); } if (pp->npts > pgp->max_npts) pgp->max_npts = pp->npts; } if (pgp->max_npts < 3) { bu_log("rt_pg_import4: polysolid with all polygons of less than %zu vertices!\n", pgp->max_npts); /* XXX free storage */ return -1; } return 0; }
/* * F _ H I D E L I N E */ int f_hideline(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { FILE *plotfp; char visible; int i, numobjs; char *objname[MAXOBJECTS], title[1]; fastf_t len, u, step; float ratio; vect_t last_move; struct rt_i *rtip; struct resource resource; struct application a; vect_t temp; vect_t last, dir; register struct bn_vlist *vp; CHECK_DBI_NULL; if (argc < 2 || 4 < argc) { struct bu_vls vls; bu_vls_init(&vls); bu_vls_printf(&vls, "help H"); Tcl_Eval(interp, bu_vls_addr(&vls)); bu_vls_free(&vls); return TCL_ERROR; } if ((plotfp = fopen(argv[1], "w")) == NULL) { Tcl_AppendResult(interp, "f_hideline: unable to open \"", argv[1], "\" for writing.\n", (char *)NULL); return TCL_ERROR; } pl_space(plotfp, (int)GED_MIN, (int)GED_MIN, (int)GED_MAX, (int)GED_MAX); /* Build list of objects being viewed */ numobjs = 0; FOR_ALL_SOLIDS(sp) { for (i = 0; i < numobjs; i++) { if ( objname[i] == FIRST_SOLID(sp)->d_namep ) break; } if (i == numobjs) objname[numobjs++] = FIRST_SOLID(sp)->d_namep; } Tcl_AppendResult(interp, "Generating hidden-line drawing of the following regions:\n", (char *)NULL); for (i = 0; i < numobjs; i++) Tcl_AppendResult(interp, "\t", objname[i], "\n", (char *)NULL); /* Initialization for librt */ if ((rtip = rt_dirbuild(dbip->dbi_filename, title, 0)) == RTI_NULL) { Tcl_AppendResult(interp, "f_hideline: unable to open model file \"", dbip->dbi_filename, "\"\n", (char *)NULL); return TCL_ERROR; } a.a_hit = hit_headon; a.a_miss = hit_tangent; a.a_overlap = hit_overlap; a.a_rt_i = rtip; a.a_resource = &resource; a.a_level = 0; a.a_onehit = 1; a.a_diverge = 0; a.a_rbeam = 0; if (argc > 2) { sscanf(argv[2], "%f", &step); step = view_state->vs_Viewscale/step; sscanf(argv[3], "%f", &epsilon); epsilon *= view_state->vs_Viewscale/100; } else { step = view_state->vs_Viewscale/256; epsilon = 0.1*view_state->vs_Viewscale; } for (i = 0; i < numobjs; i++) if (rt_gettree(rtip, objname[i]) == -1) Tcl_AppendResult(interp, "f_hideline: rt_gettree failed on \"", objname[i], "\"\n", (char *)NULL); /* Crawl along the vectors raytracing as we go */ VSET(temp, 0.0, 0.0, -1.0); /* looking at model */ MAT4X3VEC(a.a_ray.r_dir, view_state->vs_view2model, temp); VUNITIZE(a.a_ray.r_dir); FOR_ALL_SOLIDS(sp) { ratio = sp->s_size / VIEWSIZE; /* ignore if small or big */ if (ratio >= dmp->dmr_bound || ratio < 0.001) continue; Tcl_AppendResult(interp, "Primitive\n", (char *)NULL); for ( BU_LIST_FOR( vp, bn_vlist, &(sp->s_vlist) ) ) { register int i; register int nused = vp->nused; register int *cmd = vp->cmd; register point_t *pt = vp->pt; for ( i = 0; i < nused; i++, cmd++, pt++ ) { Tcl_AppendResult(interp, "\tVector\n", (char *)NULL); switch ( *cmd ) { case BN_VLIST_POLY_START: case BN_VLIST_POLY_VERTNORM: break; case BN_VLIST_POLY_MOVE: case BN_VLIST_LINE_MOVE: /* move */ VMOVE(last, *pt); MOVE(last); break; case BN_VLIST_POLY_DRAW: case BN_VLIST_POLY_END: case BN_VLIST_LINE_DRAW: /* setup direction && length */ VSUB2(dir, *pt, last); len = MAGNITUDE(dir); VUNITIZE(dir); visible = FALSE; { struct bu_vls tmp_vls; bu_vls_init(&tmp_vls); bu_vls_printf(&tmp_vls, "\t\tDraw 0 -> %g, step %g\n", len, step); Tcl_AppendResult(interp, bu_vls_addr(&tmp_vls), (char *)NULL); bu_vls_free(&tmp_vls); } for (u = 0; u <= len; u += step) { VJOIN1(aim_point, last, u, dir); MAT4X3PNT(temp, view_state->vs_model2view, aim_point); temp[Z] = 100; /* parallel project */ MAT4X3PNT(a.a_ray.r_pt, view_state->vs_view2model, temp); if (rt_shootray(&a)) { if (!visible) { visible = TRUE; MOVE(aim_point); } } else { if (visible) { visible = FALSE; DRAW(aim_point); } } } if (visible) DRAW(aim_point); VMOVE(last, *pt); /* new last vertex */ } } } } fclose(plotfp); return TCL_OK; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_bot_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_bot_internal *bot; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; size_t i; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); bot = (struct rt_bot_internal *)ip->idb_ptr; RT_BOT_CK_MAGIC(bot); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; /* mirror each vertex */ for (i=0; i<bot->num_vertices; i++) { point_t pt; VMOVE(pt, &bot->vertices[i*3]); MAT4X3PNT(&bot->vertices[i*3], mirmat, pt); } /* Reverse each faces' order */ for (i=0; i<bot->num_faces; i++) { int save_face = bot->faces[i*3]; bot->faces[i*3] = bot->faces[i*3 + Z]; bot->faces[i*3 + Z] = save_face; } /* fix normals */ for (i=0; i<bot->num_normals; i++) { vectp_t np = &bot->normals[i*3]; vect_t n1; vect_t n2; mat_t mat; VMOVE(n1, np); VCROSS(n2, mirror_dir, n1); VUNITIZE(n2); ang = M_PI_2 - acos(VDOT(n1, mirror_dir)); bn_mat_arb_rot(mat, origin, n2, ang*2); MAT4X3VEC(np, mat, n1); } return 0; }
/** * R E C _ U V * * For a hit on the surface of an REC, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * * u is the rotation around the cylinder, and * v is the displacement along H. */ void rt_rec_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct rec_specific *rec = (struct rec_specific *)stp->st_specific; vect_t work; vect_t pprime; fastf_t len; fastf_t ratio; if (ap) RT_CK_APPLICATION(ap); /* hit_point is on surface; project back to unit cylinder, * creating a vector from vertex to hit point. */ VSUB2(work, hitp->hit_point, rec->rec_V); MAT4X3VEC(pprime, rec->rec_SoR, work); switch (hitp->hit_surfno) { case REC_NORM_BODY: /* Skin. x, y coordinates define rotation. radius = 1 */ ratio = pprime[Y]; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = pprime[Z]; /* height */ break; case REC_NORM_TOP: /* top plate */ len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]); ratio = pprime[Y]/len; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = len; /* rim v = 1 */ break; case REC_NORM_BOT: /* bottom plate */ len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]); ratio = pprime[Y]/len; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = 1 - len; /* rim v = 0 */ break; } /* Handle other half of acos() domain */ if (pprime[X] < 0) uvp->uv_u = 1.0 - uvp->uv_u; if (uvp->uv_u < 0) uvp->uv_u = 0; else if (uvp->uv_u > 1) uvp->uv_u = 1; if (uvp->uv_v < 0) uvp->uv_v = 0; else if (uvp->uv_v > 1) uvp->uv_v = 1; /* XXX uv_du should be relative to rotation, uv_dv relative to height */ uvp->uv_du = uvp->uv_dv = 0; }
/** * R E C _ V S H O T * * This is the Becker vector version */ void rt_rec_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap) /* An array of solid pointers */ /* An array of ray pointers */ /* array of segs (results returned) */ /* Number of ray/object pairs */ { int i; struct rec_specific *rec; vect_t dprime; /* D' */ vect_t pprime; /* P' */ fastf_t k1, k2; /* distance constants of solution */ vect_t xlated; /* translated vector */ struct hit hits[3]; /* 4 potential hit points */ struct hit *hitp; /* pointer to hit point */ fastf_t b; /* coeff of polynomial */ fastf_t root; /* root of radical */ fastf_t dx2dy2; if (ap) RT_CK_APPLICATION(ap); /* for each ray/right_elliptical_cylinder pair */ for (i = 0; i < n; i++) { if (stp[i] == 0) continue; /* stp[i] == 0 signals skip ray */ rec = (struct rec_specific *)stp[i]->st_specific; hitp = &hits[0]; /* out, Mat, vect */ MAT4X3VEC(dprime, rec->rec_SoR, rp[i]->r_dir); VSUB2(xlated, rp[i]->r_pt, rec->rec_V); MAT4X3VEC(pprime, rec->rec_SoR, xlated); if (ZERO(dprime[X]) && ZERO(dprime[Y])) goto check_plates; /* Find roots of eqn, using formula for quadratic w/ a=1 */ b = 2 * (dprime[X]*pprime[X] + dprime[Y]*pprime[Y]) * (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y])); if ((root = b*b - 4 * dx2dy2 * (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0) goto check_plates; root = sqrt(root); k1 = (root-b) * 0.5; k2 = (root+b) * (-0.5); /* * k1 and k2 are potential solutions to intersection with side. * See if they fall in range. */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; } /* * Check for hitting the end plates. */ check_plates: if (hitp < &hits[2] && !ZERO(dprime[Z])) { /* 0 or 1 hits so far, this is worthwhile */ k1 = -pprime[Z] / dprime[Z]; /* bottom plate */ k2 = (1.0 - pprime[Z]) / dprime[Z]; /* top plate */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime);/* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BOT; /* -H */ hitp++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime);/* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_TOP; /* +H */ hitp++; } } if (hitp != &hits[2]) { RT_REC_SEG_MISS(segp[i]); /* MISS */ } else { segp[i].seg_stp = stp[i]; if (hits[0].hit_dist < hits[1].hit_dist) { /* entry is [0], exit is [1] */ VMOVE(segp[i].seg_in.hit_vpriv, hits[0].hit_vpriv); segp[i].seg_in.hit_dist = hits[0].hit_dist; segp[i].seg_in.hit_surfno = hits[0].hit_surfno; VMOVE(segp[i].seg_out.hit_vpriv, hits[1].hit_vpriv); segp[i].seg_out.hit_dist = hits[1].hit_dist; segp[i].seg_out.hit_surfno = hits[1].hit_surfno; } else { /* entry is [1], exit is [0] */ VMOVE(segp[i].seg_in.hit_vpriv, hits[1].hit_vpriv); segp[i].seg_in.hit_dist = hits[1].hit_dist; segp[i].seg_in.hit_surfno = hits[1].hit_surfno; VMOVE(segp[i].seg_out.hit_vpriv, hits[0].hit_vpriv); segp[i].seg_out.hit_dist = hits[0].hit_dist; segp[i].seg_out.hit_surfno = hits[0].hit_surfno; } } } }
/** * R E C _ S H O T * * Intersect a ray with a right elliptical cylinder, * where all constant terms have * been precomputed by rt_rec_prep(). If an intersection occurs, * a struct seg will be acquired and filled in. * * Returns - * 0 MISS * >0 HIT */ int rt_rec_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead) { struct rec_specific *rec = (struct rec_specific *)stp->st_specific; vect_t dprime; /* D' */ vect_t pprime; /* P' */ fastf_t k1, k2; /* distance constants of solution */ vect_t xlated; /* translated vector */ struct hit hits[4]; /* 4 potential hit points */ struct hit *hitp; /* pointer to hit point */ int nhits = 0; /* Number of hit points */ memset(hits, 0, 4 * sizeof(struct hit)); hitp = &hits[0]; /* out, Mat, vect */ MAT4X3VEC(dprime, rec->rec_SoR, rp->r_dir); VSUB2(xlated, rp->r_pt, rec->rec_V); MAT4X3VEC(pprime, rec->rec_SoR, xlated); if (ZERO(dprime[X]) && ZERO(dprime[Y])) goto check_plates; /* Find roots of the equation, using formula for quadratic w/ a=1 */ { fastf_t b; /* coeff of polynomial */ fastf_t root; /* root of radical */ fastf_t dx2dy2; b = 2 * (dprime[X]*pprime[X] + dprime[Y]*pprime[Y]) * (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y])); if ((root = b*b - 4 * dx2dy2 * (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0) goto check_plates; root = sqrt(root); k1 = (root-b) * 0.5; k2 = (root+b) * (-0.5); } /* * k1 and k2 are potential solutions to intersection with side. * See if they fall in range. */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; nhits++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; nhits++; } /* * Check for hitting the end plates. */ check_plates: if (nhits < 2 && !ZERO(dprime[Z])) { /* 0 or 1 hits so far, this is worthwhile */ k1 = -pprime[Z] / dprime[Z]; /* bottom plate */ k2 = (1.0 - pprime[Z]) / dprime[Z]; /* top plate */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BOT; /* -H */ hitp++; nhits++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_magic = RT_HIT_MAGIC; hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_TOP; /* +H */ hitp++; nhits++; } } if (nhits == 0) return 0; /* MISS */ if (nhits == 2) { hit: if (hits[0].hit_dist < hits[1].hit_dist) { /* entry is [0], exit is [1] */ struct seg *segp; RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; segp->seg_in = hits[0]; /* struct copy */ segp->seg_out = hits[1]; /* struct copy */ BU_LIST_INSERT(&(seghead->l), &(segp->l)); } else { /* entry is [1], exit is [0] */ struct seg *segp; RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; segp->seg_in = hits[1]; /* struct copy */ segp->seg_out = hits[0]; /* struct copy */ BU_LIST_INSERT(&(seghead->l), &(segp->l)); } return 2; /* HIT */ } if (nhits == 1) { if (hits[0].hit_surfno != REC_NORM_BODY) bu_log("rt_rec_shot(%s): 1 intersection with end plate?\n", stp->st_name); /* * Ray is tangent to body of cylinder, * or a single hit on on an end plate (??) * This could be considered a MISS, * but to signal the condition, return 0-thickness hit. */ hits[1] = hits[0]; /* struct copy */ nhits++; goto hit; } if (nhits == 3) { fastf_t tol_dist = ap->a_rt_i->rti_tol.dist; /* * Check for case where two of the three hits * have the same distance, e.g. hitting at the rim. */ k1 = hits[0].hit_dist - hits[1].hit_dist; if (NEAR_ZERO(k1, tol_dist)) { if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 0&1\n", stp->st_name); hits[1] = hits[2]; /* struct copy */ nhits--; goto hit; } k1 = hits[1].hit_dist - hits[2].hit_dist; if (NEAR_ZERO(k1, tol_dist)) { if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name); nhits--; goto hit; } k1 = hits[0].hit_dist - hits[2].hit_dist; if (NEAR_ZERO(k1, tol_dist)) { if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name); nhits--; goto hit; } } /* nhits >= 3 */ bu_log("rt_rec_shot(%s): %d unique hits?!? %g, %g, %g, %g\n", stp->st_name, nhits, hits[0].hit_dist, hits[1].hit_dist, hits[2].hit_dist, hits[3].hit_dist); /* count just the first two, to have something */ goto hit; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_arbn_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_arbn_internal *arbn; size_t i; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); arbn = (struct rt_arbn_internal *)ip->idb_ptr; RT_ARBN_CK_MAGIC(arbn); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; for (i=0; i<arbn->neqn; i++) { point_t orig_pt; point_t pt; vect_t norm; fastf_t factor; /* unitize the plane equation first */ factor = 1.0 / MAGNITUDE(arbn->eqn[i]); VSCALE(arbn->eqn[i], arbn->eqn[i], factor); arbn->eqn[i][W] = arbn->eqn[i][W] * factor; /* Pick a point on the original halfspace */ VSCALE(orig_pt, arbn->eqn[i], arbn->eqn[i][W]); /* Transform the point, and the normal */ MAT4X3VEC(norm, mirmat, arbn->eqn[i]); MAT4X3PNT(pt, mirmat, orig_pt); /* Measure new distance from origin to new point */ VUNITIZE(norm); VMOVE(arbn->eqn[i], norm); arbn->eqn[i][W] = VDOT(pt, norm); } return 0; }
int hit(register struct application *ap, struct partition *PartHeadp, struct seg *segp) { register struct partition *pp; register struct soltab *stp; struct curvature cur; fastf_t out; point_t inpt, outpt; vect_t inormal, onormal; if ( (pp=PartHeadp->pt_forw) == PartHeadp ) return(0); /* Nothing hit?? */ if ( overlap_claimant_handling == 1 ) rt_rebuild_overlaps( PartHeadp, ap, 1 ); else if ( overlap_claimant_handling == 2 ) rt_rebuild_overlaps( PartHeadp, ap, 0 ); /* First, plot ray start to inhit */ if ( R_DEBUG&RDEBUG_RAYPLOT ) { if ( pp->pt_inhit->hit_dist > 0.0001 ) { VJOIN1( inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); pl_color( plotfp, 0, 0, 255 ); pdv_3line( plotfp, ap->a_ray.r_pt, inpt ); } } for (; pp != PartHeadp; pp = pp->pt_forw ) { matp_t inv_mat; Tcl_HashEntry *entry; bu_log("\n--- Hit region %s (in %s, out %s) reg_bit = %d\n", pp->pt_regionp->reg_name, pp->pt_inseg->seg_stp->st_name, pp->pt_outseg->seg_stp->st_name, pp->pt_regionp->reg_bit); entry = Tcl_FindHashEntry( (Tcl_HashTable *)ap->a_rt_i->Orca_hash_tbl, (const char *)(size_t)pp->pt_regionp->reg_bit ); if ( !entry ) { inv_mat = (matp_t)NULL; } else { inv_mat = (matp_t)Tcl_GetHashValue( entry ); bn_mat_print( "inv_mat", inv_mat ); } if ( pp->pt_overlap_reg ) { struct region *pp_reg; int j=-1; bu_log( " Claiming regions:\n" ); while ( (pp_reg=pp->pt_overlap_reg[++j]) ) bu_log( " %s\n", pp_reg->reg_name ); } /* inhit info */ stp = pp->pt_inseg->seg_stp; VJOIN1( inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); RT_HIT_NORMAL( inormal, pp->pt_inhit, stp, &(ap->a_ray), pp->pt_inflip ); RT_CURVATURE( &cur, pp->pt_inhit, pp->pt_inflip, stp ); rt_pr_hit( " In", pp->pt_inhit ); VPRINT( " Ipoint", inpt ); VPRINT( " Inormal", inormal ); bu_log( " PDir (%g, %g, %g) c1=%g, c2=%g\n", V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2); if ( inv_mat ) { point_t in_trans; MAT4X3PNT( in_trans, inv_mat, inpt ); bu_log( "\ttransformed ORCA inhit = (%g %g %g)\n", V3ARGS( in_trans ) ); } /* outhit info */ stp = pp->pt_outseg->seg_stp; VJOIN1( outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir ); RT_HIT_NORMAL( onormal, pp->pt_outhit, stp, &(ap->a_ray), pp->pt_outflip ); RT_CURVATURE( &cur, pp->pt_outhit, pp->pt_outflip, stp ); rt_pr_hit( " Out", pp->pt_outhit ); VPRINT( " Opoint", outpt ); VPRINT( " Onormal", onormal ); bu_log( " PDir (%g, %g, %g) c1=%g, c2=%g\n", V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2); if ( inv_mat ) { point_t out_trans; vect_t dir_trans; MAT4X3PNT( out_trans, inv_mat, outpt ); MAT4X3VEC( dir_trans, inv_mat, ap->a_ray.r_dir ); VUNITIZE( dir_trans ); bu_log( "\ttranformed ORCA outhit = (%g %g %g)\n", V3ARGS( out_trans ) ); bu_log( "\ttransformed ORCA ray direction = (%g %g %g)\n", V3ARGS( dir_trans ) ); } /* Plot inhit to outhit */ if ( R_DEBUG&RDEBUG_RAYPLOT ) { if ( (out = pp->pt_outhit->hit_dist) >= INFINITY ) out = 10000; /* to imply the direction */ VJOIN1( outpt, ap->a_ray.r_pt, out, ap->a_ray.r_dir ); pl_color( plotfp, 0, 255, 255 ); pdv_3line( plotfp, inpt, outpt ); } { struct region *regp = pp->pt_regionp; int i; if ( ap->attrs ) { bu_log( "\tattribute values:\n" ); i = 0; while ( ap->attrs[i] && regp->attr_values[i] ) { bu_log( "\t\t%s:\n", ap->attrs[i] ); bu_log( "\t\t\tstring rep = %s\n", BU_MRO_GETSTRING(regp->attr_values[i])); bu_log( "\t\t\tlong rep = %d\n", BU_MRO_GETLONG(regp->attr_values[i])); bu_log( "\t\t\tdouble rep = %f\n", BU_MRO_GETDOUBLE(regp->attr_values[i])); i++; } } } } return(1); }
/** * Convert from "network" doubles to machine specific. * Transform */ int rt_arbn_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip) { struct rt_arbn_internal *aip; size_t i; unsigned long neqn; int double_count; size_t byte_count; /* must be double for import and export */ double *eqn; RT_CK_DB_INTERNAL(ip); BU_CK_EXTERNAL(ep); if (dbip) RT_CK_DBI(dbip); neqn = ntohl(*(uint32_t *)ep->ext_buf); double_count = neqn * ELEMENTS_PER_PLANE; byte_count = double_count * SIZEOF_NETWORK_DOUBLE; BU_ASSERT_LONG(ep->ext_nbytes, ==, 4+ byte_count); ip->idb_major_type = DB5_MAJORTYPE_BRLCAD; ip->idb_type = ID_ARBN; ip->idb_meth = &OBJ[ID_ARBN]; BU_ALLOC(ip->idb_ptr, struct rt_arbn_internal); aip = (struct rt_arbn_internal *)ip->idb_ptr; aip->magic = RT_ARBN_INTERNAL_MAGIC; aip->neqn = neqn; if (aip->neqn <= 0) return -1; eqn = (double *)bu_malloc(byte_count, "arbn plane eqn[] temp buf"); bu_cv_ntohd((unsigned char *)eqn, (unsigned char *)ep->ext_buf + ELEMENTS_PER_PLANE, double_count); aip->eqn = (plane_t *)bu_malloc(double_count * sizeof(fastf_t), "arbn plane eqn[]"); for (i = 0; i < aip->neqn; i++) { HMOVE(aip->eqn[i], &eqn[i*ELEMENTS_PER_PLANE]); } bu_free(eqn, "arbn plane eqn[] temp buf"); /* Transform by the matrix, if we have one that is not the identity */ if (mat && !bn_mat_is_identity(mat)) { for (i = 0; i < aip->neqn; i++) { point_t orig_pt; point_t pt; vect_t norm; fastf_t factor; /* unitize the plane equation first */ factor = 1.0 / MAGNITUDE(aip->eqn[i]); VSCALE(aip->eqn[i], aip->eqn[i], factor); aip->eqn[i][W] = aip->eqn[i][W] * factor; /* Pick a point on the original halfspace */ VSCALE(orig_pt, aip->eqn[i], aip->eqn[i][W]); /* Transform the point, and the normal */ MAT4X3VEC(norm, mat, aip->eqn[i]); MAT4X3PNT(pt, mat, orig_pt); /* Measure new distance from origin to new point */ VUNITIZE(norm); VMOVE(aip->eqn[i], norm); aip->eqn[i][W] = VDOT(pt, norm); } } return 0; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_ell_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_ell_internal *ell; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; mat_t mat; point_t pt; vect_t a, b, c; vect_t n; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); ell = (struct rt_ell_internal *)ip->idb_ptr; RT_ELL_CK_MAGIC(ell); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; VMOVE(pt, ell->v); MAT4X3PNT(ell->v, mirmat, pt); VMOVE(a, ell->a); VUNITIZE(a); VCROSS(n, mirror_dir, ell->a); VUNITIZE(n); ang = M_PI_2 - acos(VDOT(a, mirror_dir)); bn_mat_arb_rot(mat, origin, n, ang*2); VMOVE(a, ell->a); MAT4X3VEC(ell->a, mat, a); VMOVE(b, ell->b); VUNITIZE(b); VCROSS(n, mirror_dir, ell->b); VUNITIZE(n); ang = M_PI_2 - acos(VDOT(b, mirror_dir)); bn_mat_arb_rot(mat, origin, n, ang*2); VMOVE(b, ell->b); MAT4X3VEC(ell->b, mat, b); VMOVE(c, ell->c); VUNITIZE(c); VCROSS(n, mirror_dir, ell->c); VUNITIZE(n); ang = M_PI_2 - acos(VDOT(c, mirror_dir)); bn_mat_arb_rot(mat, origin, n, ang*2); VMOVE(c, ell->c); MAT4X3VEC(ell->c, mat, c); return 0; }
/** * make a copy of a v4 solid by adding it to our book-keeping list, * adding it to the db directory, and writing it out to disk. */ static void copy_v4_solid(struct db_i *_dbip, struct directory *proto, struct clone_state *state, int idx) { struct directory *dp = (struct directory *)NULL; union record *rp = (union record *)NULL; size_t i, j; /* make n copies */ for (i = 0; i < state->n_copies; i++) { struct bu_vls *name; if (i==0) name = get_name(_dbip, proto, state, i); else { dp = db_lookup(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i-1]), LOOKUP_QUIET); if (!dp) { continue; } name = get_name(_dbip, dp, state, i); } /* XXX: this can probably be optimized. */ bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(name)); bu_vls_free(name); /* add the object to the directory */ dp = db_diradd(_dbip, bu_vls_addr(&obj_list.names[idx].dest[i]), RT_DIR_PHONY_ADDR, proto->d_len, proto->d_flags, &proto->d_minor_type); if ((dp == RT_DIR_NULL) || (db_alloc(_dbip, dp, proto->d_len) < 0)) { TCL_ALLOC_ERR; return; } /* get an in-memory reference to the object being copied */ if ((rp = db_getmrec(_dbip, proto)) == (union record *)0) { TCL_READ_ERR; return; } if (rp->u_id == ID_SOLID) { bu_strlcpy(rp->s.s_name, dp->d_namep, NAMESIZE); /* mirror */ if (state->miraxis != W) { /* XXX er, this seems rather wrong .. but it's v4 so punt */ rp->s.s_values[state->miraxis] += 2 * (state->mirpos - rp->s.s_values[state->miraxis]); for (j = 3+state->miraxis; j < 24; j++) rp->s.s_values[j] = -rp->s.s_values[j]; } /* translate */ if (state->trans[W] > SMALL_FASTF) /* assumes primitive's first parameter is its position */ VADD2(rp->s.s_values, rp->s.s_values, state->trans); /* rotate */ if (state->rot[W] > SMALL_FASTF) { mat_t r; vect_t vec, ovec; if (state->rpnt[W] > SMALL_FASTF) VSUB2(rp->s.s_values, rp->s.s_values, state->rpnt); MAT_IDN(r); bn_mat_angles(r, state->rot[X], state->rot[Y], state->rot[Z]); for (j = 0; j < 24; j+=3) { VMOVE(vec, rp->s.s_values+j); MAT4X3VEC(ovec, r, vec); VMOVE(rp->s.s_values+j, ovec); } if (state->rpnt[W] > SMALL_FASTF) VADD2(rp->s.s_values, rp->s.s_values, state->rpnt); } } else bu_log("mods not available on %s\n", proto->d_namep); /* write the object to disk */ if (db_put(_dbip, dp, rp, 0, dp->d_len) < 0) { bu_log("ERROR: clone internal error writing to the database\n"); return; } } if (rp) bu_free((char *)rp, "copy_solid record[]"); return; }
/** * In theory, the grid can be specified by providing any two of * these sets of parameters: * * number of pixels (width, height) * viewsize (in model units, mm) * number of grid cells (cell_width, cell_height) * * however, for now, it is required that the view size always be * specified, and one or the other parameter be provided. */ void grid_setup(void) { vect_t temp; mat_t toEye; if (viewsize <= 0.0) bu_exit(EXIT_FAILURE, "viewsize <= 0"); /* model2view takes us to eye_model location & orientation */ MAT_IDN(toEye); MAT_DELTAS_VEC_NEG(toEye, eye_model); Viewrotscale[15] = 0.5*viewsize; /* Viewscale */ bn_mat_mul(model2view, Viewrotscale, toEye); bn_mat_inv(view2model, model2view); /* Determine grid cell size and number of pixels */ if (cell_newsize) { if (cell_width <= 0.0) cell_width = cell_height; if (cell_height <= 0.0) cell_height = cell_width; width = (viewsize / cell_width) + 0.99; height = (viewsize / (cell_height*aspect)) + 0.99; cell_newsize = 0; } else { /* Chop -1.0..+1.0 range into parts */ cell_width = viewsize / width; cell_height = viewsize / (height*aspect); } /* * Optional GIFT compatibility, mostly for RTG3. Round coordinates * of lower left corner to fall on integer- valued coordinates, in * "gift_grid_rounding" units. */ if (gift_grid_rounding > 0.0) { point_t v_ll; /* view, lower left */ point_t m_ll; /* model, lower left */ point_t hv_ll; /* hv, lower left*/ point_t hv_wanted; vect_t hv_delta; vect_t m_delta; mat_t model2hv; mat_t hv2model; /* Build model2hv matrix, including mm2inches conversion */ MAT_COPY(model2hv, Viewrotscale); model2hv[15] = gift_grid_rounding; bn_mat_inv(hv2model, model2hv); VSET(v_ll, -1, -1, 0); MAT4X3PNT(m_ll, view2model, v_ll); MAT4X3PNT(hv_ll, model2hv, m_ll); VSET(hv_wanted, floor(hv_ll[X]), floor(hv_ll[Y]), floor(hv_ll[Z])); VSUB2(hv_delta, hv_ll, hv_wanted); MAT4X3PNT(m_delta, hv2model, hv_delta); VSUB2(eye_model, eye_model, m_delta); MAT_DELTAS_VEC_NEG(toEye, eye_model); bn_mat_mul(model2view, Viewrotscale, toEye); bn_mat_inv(view2model, model2view); } /* Create basis vectors dx and dy for emanation plane (grid) */ VSET(temp, 1, 0, 0); MAT3X3VEC(dx_unit, view2model, temp); /* rotate only */ VSCALE(dx_model, dx_unit, cell_width); VSET(temp, 0, 1, 0); MAT3X3VEC(dy_unit, view2model, temp); /* rotate only */ VSCALE(dy_model, dy_unit, cell_height); if (stereo) { /* Move left 2.5 inches (63.5mm) */ VSET(temp, -63.5*2.0/viewsize, 0, 0); bu_log("red eye: moving %f relative screen (left)\n", temp[X]); MAT4X3VEC(left_eye_delta, view2model, temp); VPRINT("left_eye_delta", left_eye_delta); } /* "Lower left" corner of viewing plane */ if (rt_perspective > 0.0) { fastf_t zoomout; zoomout = 1.0 / tan(DEG2RAD * rt_perspective / 2.0); VSET(temp, -1, -1/aspect, -zoomout); /* viewing plane */ /* * divergence is perspective angle divided by the number of * pixels in that angle. Extra factor of 0.5 is because * perspective is a full angle while divergence is the tangent * (slope) of a half angle. */ APP.a_diverge = tan(DEG2RAD * rt_perspective * 0.5 / width); APP.a_rbeam = 0; } else { /* all rays go this direction */ VSET(temp, 0, 0, -1); MAT4X3VEC(APP.a_ray.r_dir, view2model, temp); VUNITIZE(APP.a_ray.r_dir); VSET(temp, -1, -1/aspect, 0); /* eye plane */ APP.a_rbeam = 0.5 * viewsize / width; APP.a_diverge = 0; } if (ZERO(APP.a_rbeam) && ZERO(APP.a_diverge)) bu_exit(EXIT_FAILURE, "zero-radius beam"); MAT4X3PNT(viewbase_model, view2model, temp); if (jitter & JITTER_FRAME) { /* Move the frame in a smooth circular rotation in the plane */ fastf_t ang; /* radians */ fastf_t dx, dy; ang = curframe * frame_delta_t * M_2PI / 10; /* 10 sec period */ dx = cos(ang) * 0.5; /* +/- 1/4 pixel width in amplitude */ dy = sin(ang) * 0.5; VJOIN2(viewbase_model, viewbase_model, dx, dx_model, dy, dy_model); } if (cell_width <= 0 || cell_width >= INFINITY || cell_height <= 0 || cell_height >= INFINITY) { bu_log("grid_setup: cell size ERROR (%g, %g) mm\n", cell_width, cell_height); bu_exit(EXIT_FAILURE, "cell size"); } if (width <= 0 || height <= 0) { bu_log("grid_setup: ERROR bad image size (%zu, %zu)\n", width, height); bu_exit(EXIT_FAILURE, "bad size"); } }
/* * This routine is called (at prep time) * once for each region which uses this shader. * Any shader-specific initialization should be done here. * * Returns: * 1 success * 0 success, but delete region * -1 failure */ HIDDEN int bbd_setup(struct region *rp, struct bu_vls *matparm, void **dpp, const struct mfuncs *mfp, struct rt_i *rtip) { register struct bbd_specific *bbd_sp; struct rt_db_internal intern; struct rt_tgc_internal *tgc; int s; mat_t mat; struct bbd_img *bi; double angle; vect_t vtmp; int img_num; vect_t vv; /* check the arguments */ RT_CHECK_RTI(rtip); BU_CK_VLS(matparm); RT_CK_REGION(rp); if (rdebug&RDEBUG_SHADE) bu_log("bbd_setup(%s)\n", rp->reg_name); RT_CK_TREE(rp->reg_treetop); if (rp->reg_treetop->tr_a.tu_op != OP_SOLID) { bu_log("--- Warning: Region %s shader %s", rp->reg_name, mfp->mf_name); bu_bomb("Shader should be used on region of single (rec/rcc) primitive\n"); } RT_CK_SOLTAB(rp->reg_treetop->tr_a.tu_stp); if (rp->reg_treetop->tr_a.tu_stp->st_id != ID_REC) { bu_log("--- Warning: Region %s shader %s", rp->reg_name, mfp->mf_name); bu_log("Shader should be used on region of single REC/RCC primitive %d\n", rp->reg_treetop->tr_a.tu_stp->st_id); bu_bomb("oops\n"); } /* Get memory for the shader parameters and shader-specific data */ BU_GET(bbd_sp, struct bbd_specific); *dpp = bbd_sp; /* initialize the default values for the shader */ memcpy(bbd_sp, &bbd_defaults, sizeof(struct bbd_specific)); bu_vls_init(&bbd_sp->img_filename); BU_LIST_INIT(&bbd_sp->imgs); bbd_sp->rtip = rtip; /* because new_image() needs this */ bbd_sp->img_count = 0; /* parse the user's arguments for this use of the shader. */ if (bu_struct_parse(matparm, bbd_parse_tab, (char *)bbd_sp, NULL) < 0) return -1; if (bbd_sp->img_count > MAX_IMAGES) { bu_log("too many images (%zu) in shader for %s sb < %d\n", bbd_sp->img_count, rp->reg_name, MAX_IMAGES); bu_bomb("excessive image count\n"); } MAT_IDN(mat); RT_DB_INTERNAL_INIT(&intern); s = rt_db_get_internal(&intern, rp->reg_treetop->tr_a.tu_stp->st_dp, rtip->rti_dbip, mat, &rt_uniresource); if (intern.idb_minor_type != ID_TGC && intern.idb_minor_type != ID_REC) { bu_log("What did I get? %d\n", intern.idb_minor_type); } if (s < 0) { bu_log("%s:%d didn't get internal", __FILE__, __LINE__); bu_bomb(""); } tgc = (struct rt_tgc_internal *)intern.idb_ptr; RT_TGC_CK_MAGIC(tgc); angle = M_PI / (double)bbd_sp->img_count; img_num = 0; VMOVE(vv, tgc->h); VUNITIZE(vv); for (BU_LIST_FOR(bi, bbd_img, &bbd_sp->imgs)) { static const point_t o = VINIT_ZERO; bn_mat_arb_rot(mat, o, vv, angle*img_num); /* compute plane equation */ MAT4X3VEC(bi->img_plane, mat, tgc->a); VUNITIZE(bi->img_plane); bi->img_plane[H] = VDOT(tgc->v, bi->img_plane); MAT4X3VEC(vtmp, mat, tgc->b); VADD2(bi->img_origin, tgc->v, vtmp); /* image origin in 3d space */ /* calculate image u vector */ VREVERSE(bi->img_x, vtmp); VUNITIZE(bi->img_x); bi->img_xlen = MAGNITUDE(vtmp) * 2; /* calculate image v vector */ VMOVE(bi->img_y, tgc->h); VUNITIZE(bi->img_y); bi->img_ylen = MAGNITUDE(tgc->h); if (rdebug&RDEBUG_SHADE) { HPRINT("\nimg_plane", bi->img_plane); VPRINT("vtmp", vtmp); VPRINT("img_origin", bi->img_origin); bu_log("img_xlen:%g ", bi->img_xlen); VPRINT("img_x", bi->img_x); bu_log("img_ylen:%g ", bi->img_ylen); VPRINT("img_y", bi->img_y); } img_num++; } rt_db_free_internal(&intern); if (rdebug&RDEBUG_SHADE) { bu_struct_print(" Parameters:", bbd_print_tab, (char *)bbd_sp); } return 1; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_half_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_half_internal *half; mat_t mirmat; mat_t rmat; mat_t temp; vect_t nvec; vect_t xvec; vect_t mirror_dir; point_t mirror_pt; fastf_t ang; vect_t n1; vect_t n2; static fastf_t tol_dist_sq = 0.0005 * 0.0005; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); half = (struct rt_half_internal *)ip->idb_ptr; RT_HALF_CK_MAGIC(half); MAT_IDN(mirmat); VMOVE(mirror_dir, plane); VSCALE(mirror_pt, plane, plane[W]); /* Build mirror transform matrix, for those who need it. */ /* First, perform a mirror down the X axis */ mirmat[0] = -1.0; /* Create the rotation matrix */ VSET(xvec, 1, 0, 0); VCROSS(nvec, xvec, mirror_dir); VUNITIZE(nvec); ang = -acos(VDOT(xvec, mirror_dir)); bn_mat_arb_rot(rmat, origin, nvec, ang*2.0); /* Add the rotation to mirmat */ MAT_COPY(temp, mirmat); bn_mat_mul(mirmat, temp, rmat); /* Add the translation to mirmat */ mirmat[3 + X*4] += mirror_pt[X] * mirror_dir[X]; mirmat[3 + Y*4] += mirror_pt[Y] * mirror_dir[Y]; mirmat[3 + Z*4] += mirror_pt[Z] * mirror_dir[Z]; /* FIXME: this is not using the mirmat we just computed, not clear * it's even right given it's only taking the mirror direction * into account and not the mirror point. */ VMOVE(n1, half->eqn); VCROSS(n2, mirror_dir, n1); VUNITIZE(n2); ang = M_PI_2 - acos(VDOT(n1, mirror_dir)); bn_mat_arb_rot(rmat, origin, n2, ang*2); MAT4X3VEC(half->eqn, rmat, n1); if (!NEAR_EQUAL(VDOT(n1, half->eqn), 1.0, tol_dist_sq)) { point_t ptA; point_t ptB; point_t ptC; vect_t h; fastf_t mag; fastf_t cosa; VSCALE(ptA, n1, half->eqn[H]); VADD2(ptB, ptA, mirror_dir); VSUB2(h, ptB, ptA); mag = MAGNITUDE(h); VUNITIZE(h); cosa = VDOT(h, mirror_dir); VSCALE(ptC, half->eqn, -mag * cosa); VADD2(ptC, ptC, ptA); half->eqn[H] = VDOT(half->eqn, ptC); } return 0; }
/* * Returns - * -2 unknown keyword * -1 error in processing keyword * 0 OK */ int multi_words( char *words[], int nwords ) { if ( strcmp( words[0], "rot" ) == 0 ) { mat_t mat; /* Expects rotations rx, ry, rz, in degrees */ if ( nwords < 4 ) return(-1); MAT_IDN( mat ); bn_mat_angles( mat, atof( words[1] ), atof( words[2] ), atof( words[3] ) ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "xlate" ) == 0 ) { mat_t mat; if ( nwords < 4 ) return(-1); /* Expects translations tx, ty, tz */ MAT_IDN( mat ); MAT_DELTAS( mat, atof( words[1] ), atof( words[2] ), atof( words[3] ) ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "rot_at" ) == 0 ) { mat_t mat; mat_t mat1; mat_t mat2; mat_t mat3; /* JG - Expects x, y, z, rx, ry, rz */ /* Translation back to the origin by (-x, -y, -z) */ /* is done first, then the rotation, and finally */ /* back into the original position by (+x, +y, +z). */ if ( nwords < 7 ) return(-1); MAT_IDN( mat1 ); MAT_IDN( mat2 ); MAT_IDN( mat3 ); MAT_DELTAS( mat1, -atof( words[1] ), -atof( words[2] ), -atof( words[3] ) ); bn_mat_angles( mat2, atof( words[4] ), atof( words[5] ), atof( words[6] ) ); MAT_DELTAS( mat3, atof( words[1] ), atof( words[2] ), atof( words[3] ) ); bn_mat_mul( mat, mat2, mat1 ); bn_mat_mul2( mat3, mat ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "orient" ) == 0 ) { register int i; mat_t mat; double args[8]; /* Expects tx, ty, tz, rx, ry, rz, [scale]. */ /* All rotation is done first, then translation */ /* Note: word[0] and args[0] are the keyword */ if ( nwords < 6+1 ) return(-1); for ( i=1; i<6+1; i++ ) args[i] = 0; args[7] = 1.0; /* optional arg, default to 1 */ for ( i=1; i<nwords; i++ ) args[i] = atof( words[i] ); MAT_IDN( mat ); bn_mat_angles( mat, args[4], args[5], args[6] ); MAT_DELTAS( mat, args[1], args[2], args[3] ); if ( NEAR_ZERO( args[7], VDIVIDE_TOL ) ) { /* Nearly zero, signal error */ fprintf(stderr, "Orient scale arg is near zero ('%s')\n", words[7] ); return(-1); } else { mat[15] = 1 / args[7]; } out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "ae" ) == 0 ) { mat_t mat; fastf_t az, el; if ( nwords < 3 ) return(-1); /* Expects azimuth, elev, optional twist */ az = atof(words[1]); el = atof(words[2]); #if 0 if ( nwords == 3 ) twist = 0.0; else twist = atof(words[3]); #endif MAT_IDN( mat ); /* XXX does not take twist, for now XXX */ bn_mat_ae( mat, az, el ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "arb_rot_pt" ) == 0 ) { mat_t mat; point_t pt1, pt2; vect_t dir; fastf_t ang; if ( nwords < 1+3+3+1 ) return(-1); /* Expects point1, point2, angle */ VSET( pt1, atof(words[1]), atof(words[2]), atof(words[3]) ); VSET( pt2, atof(words[4]), atof(words[5]), atof(words[6]) ); ang = atof(words[7]) * bn_degtorad; VSUB2( dir, pt2, pt2 ); VUNITIZE(dir); MAT_IDN( mat ); bn_mat_arb_rot( mat, pt1, dir, ang ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "arb_rot_dir" ) == 0 ) { mat_t mat; point_t pt1; vect_t dir; fastf_t ang; if ( nwords < 1+3+3+1 ) return(-1); /* Expects point1, dir, angle */ VSET( pt1, atof(words[1]), atof(words[2]), atof(words[3]) ); VSET( dir, atof(words[4]), atof(words[5]), atof(words[6]) ); ang = atof(words[7]) * bn_degtorad; VUNITIZE(dir); MAT_IDN( mat ); bn_mat_arb_rot( mat, pt1, dir, ang ); out_mat( mat, stdout ); return(0); } if ( strcmp( words[0], "quat" ) == 0 ) { mat_t mat; quat_t quat; /* Usage: quat x, y, z, w */ if ( nwords < 5 ) return -1; QSET( quat, atof(words[1]), atof(words[2]), atof(words[3]), atof(words[4]) ); quat_quat2mat( mat, quat ); out_mat( mat, stdout); return 0; } if ( strcmp( words[0], "fromto" ) == 0 ) { mat_t mat; point_t cur; point_t next; vect_t from; vect_t to; /* Usage: fromto +Z cur_xyz next_xyz */ if ( nwords < 8 ) return -1; if ( strcmp( words[1], "+X" ) == 0 ) { VSET( from, 1, 0, 0 ); } else if ( strcmp( words[1], "-X" ) == 0 ) { VSET( from, -1, 0, 0 ); } else if ( strcmp( words[1], "+Y" ) == 0 ) { VSET( from, 0, 1, 0 ); } else if ( strcmp( words[1], "-Y" ) == 0 ) { VSET( from, 0, -1, 0 ); } else if ( strcmp( words[1], "+Z" ) == 0 ) { VSET( from, 0, 0, 1 ); } else if ( strcmp( words[1], "-Z" ) == 0 ) { VSET( from, 0, 0, -1 ); } else { fprintf(stderr, "fromto '%s' is not +/-XYZ\n", words[1]); return -1; } VSET( cur, atof(words[2]), atof(words[3]), atof(words[4]) ); VSET( next, atof(words[5]), atof(words[6]), atof(words[7]) ); VSUB2( to, next, cur ); VUNITIZE(to); bn_mat_fromto( mat, from, to ); /* Check to see if it worked. */ { vect_t got; MAT4X3VEC( got, mat, from ); if ( VDOT( got, to ) < 0.9 ) { bu_log("\ntabsub ERROR: At t=%s, bn_mat_fromto failed!\n", chanwords[0] ); VPRINT("\tfrom", from); VPRINT("\tto", to); VPRINT("\tgot", got); } } out_mat( mat, stdout ); return 0; } return(-2); /* Unknown keyword */ }
/* * R A Y H I T * * Rayhit() is called by rt_shootray() when the ray hits one or more objects. * A per-shotline header record is written, followed by information about * each object hit. * * Note that the GIFT-3 format uses a different convention for the "zero" * distance along the ray. RT has zero at the ray origin (emanation plain), * while GIFT has zero at the screen plain translated so that it contains * the model origin. This difference is compensated for by adding the * 'dcorrection' distance correction factor. * * Also note that the GIFT-3 format requires information about the start * point of the ray in two formats. First, the h, v coordinates of the * grid cell CENTERS (in screen space coordinates) are needed. * Second, the ACTUAL h, v coordinates fired from are needed. * * An optional rtg3.pl UnixPlot file is written, permitting a * color vector display of ray-model intersections. */ int rayhit(struct application *ap, register struct partition *PartHeadp, struct seg *segp) { register struct partition *pp = PartHeadp->pt_forw; int comp_count; /* component count */ fastf_t dfirst, dlast; /* ray distances */ static fastf_t dcorrection = 0; /* RT to GIFT dist corr */ int card_count; /* # comp. on this card */ const char *fmt; /* printf() format string */ struct bu_vls str; char buf[128]; /* temp. sprintf() buffer */ point_t hv; /* GIFT h, v coords, in inches */ point_t hvcen; int prev_id=-1; point_t first_hit; int first; if ( pp == PartHeadp ) return(0); /* nothing was actually hit?? */ if ( ap->a_rt_i->rti_save_overlaps ) rt_rebuild_overlaps( PartHeadp, ap, 1 ); part_compact(ap, PartHeadp, TOL); /* count components in partitions */ comp_count = 0; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { if ( pp->pt_regionp->reg_regionid > 0 ) { prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else if ( prev_id <= 0 ) { /* normally air would be output along with a solid partition, but this will require a '111' partition */ prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else prev_id = pp->pt_regionp->reg_regionid; } pp = PartHeadp->pt_back; if ( pp!=PartHeadp && pp->pt_regionp->reg_regionid <= 0 ) comp_count++; /* a trailing '111' ident */ if ( comp_count == 0 ) return( 0 ); /* Set up variable length string, to buffer this shotline in. * Note that there is one component per card, and that each card * (line) is 80 characters long. Hence the parameters given to * rt-vls-extend(). */ bu_vls_init( &str ); bu_vls_extend( &str, 80 * (comp_count+1) ); /* * Find the H, V coordinates of the grid cell center. * RT uses the lower left corner of each cell. */ { point_t center; fastf_t dx; fastf_t dy; dx = ap->a_x + 0.5; dy = ap->a_y + 0.5; VJOIN2( center, viewbase_model, dx, dx_model, dy, dy_model ); MAT4X3PNT( hvcen, model2hv, center ); } /* * Find exact h, v coordinates of actual ray start by * projecting start point into GIFT h, v coordinates. */ MAT4X3PNT( hv, model2hv, ap->a_ray.r_pt ); /* * In RT, rays are launched from the plane of the screen, * and ray distances are relative to the start point. * In GIFT-3 output files, ray distances are relative to * the (H, V) plane translated so that it contains the origin. * A distance correction is required to convert between the two. * Since this really should be computed only once, not every time, * the trip_count flag was added. */ { static int trip_count; vect_t tmp; vect_t viewZdir; if ( trip_count == 0) { VSET( tmp, 0, 0, -1 ); /* viewing direction */ MAT4X3VEC( viewZdir, view2model, tmp ); VUNITIZE( viewZdir ); /* dcorrection will typically be negative */ dcorrection = VDOT( ap->a_ray.r_pt, viewZdir ); trip_count = 1; } } /* This code is for diagnostics. * bu_log("dcorrection=%g\n", dcorrection); */ /* dfirst and dlast have been made negative to account for GIFT looking * in the opposite direction of RT. */ dfirst = -(PartHeadp->pt_forw->pt_inhit->hit_dist + dcorrection); dlast = -(PartHeadp->pt_back->pt_outhit->hit_dist + dcorrection); #if 0 /* This code is to note any occurances of negative distances. */ if ( PartHeadp->pt_forw->pt_inhit->hit_dist < 0) { bu_log("ERROR: dfirst=%g at partition x%x\n", dfirst, PartHeadp->pt_forw ); bu_log("\tdcorrection = %f\n", dcorrection ); bu_log("\tray start point is ( %f %f %f ) in direction ( %f %f %f )\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) ); VJOIN1( PartHeadp->pt_forw->pt_inhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( PartHeadp->pt_back->pt_outhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_outhit->hit_dist, ap->a_ray.r_dir ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } /* End of bug trap. */ #endif /* * Output the ray header. The GIFT statements that * would have generated this are: * 410 write(1, 411) hcen, vcen, h, v, ncomp, dfirst, dlast, a, e * 411 format(2f7.1, 2f9.3, i3, 2f8.2,' A', f6.1,' E', f6.1) */ #define SHOT_FMT "%7.1f%7.1f%9.3f%9.3f%3d%8.2f%8.2f A%6.1f E%6.1f" if ( rt_perspective > 0 ) { bn_ae_vec( &azimuth, &elevation, ap->a_ray.r_dir ); } bu_vls_printf( &str, SHOT_FMT, hvcen[0], hvcen[1], hv[0], hv[1], comp_count, dfirst * MM2IN, dlast * MM2IN, azimuth, elevation ); /* * As an aid to debugging, take advantage of the fact that * there are more than 80 columns on UNIX "cards", and * add debugging information to the end of the line to * allow this shotline to be reproduced offline. * -b gives the shotline x, y coordinates when re-running RTG3, * -p and -d are used with RTSHOT * The easy way to activate this is with the harmless -!1 option * when running RTG3. */ if ( R_DEBUG || bu_debug || RT_G_DEBUG ) { bu_vls_printf( &str, " -b%d,%d -p %26.20e %26.20e %26.20e -d %26.20e %26.20e %26.20e\n", ap->a_x, ap->a_y, V3ARGS(ap->a_ray.r_pt), V3ARGS(ap->a_ray.r_dir) ); } else { bu_vls_putc( &str, '\n' ); } /* loop here to deal with individual components */ card_count = 0; prev_id = -1; first = 1; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { /* * The GIFT statements that would have produced * this output are: * do 632 i=icomp, iend * if (clos(icomp).gt.999.99.or.slos(i).gt.999.9) goto 635 * 632 continue * write(1, 633)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 633 format(1x, 3(i4, f6.2, 2f5.1, i1, f5.1)) * goto 670 * 635 write(1, 636)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 636 format(1x, 3(i4, f6.1, 2f5.1, i1, f5.0)) */ fastf_t comp_thickness; /* component line of sight thickness */ fastf_t in_obliq; /* in obliquity angle */ fastf_t out_obliq; /* out obliquity angle */ int region_id; /* solid region's id */ int air_id; /* air id */ fastf_t dot_prod; /* dot product of normal and ray dir */ fastf_t air_thickness; /* air line of sight thickness */ vect_t normal; /* surface normal */ register struct partition *nextpp = pp->pt_forw; region_id = pp->pt_regionp->reg_regionid; if ( region_id <= 0 && prev_id > 0 ) { /* air region output with previous partition */ prev_id = region_id; continue; } comp_thickness = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist; /* The below code is meant to catch components with zero or * negative thicknesses. This is not supposed to be possible, * but the condition has been seen. */ #if 0 if ( comp_thickness <= 0 ) { VJOIN1( pp->pt_inhit->hit_point, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( pp->pt_outhit->hit_point, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir ); bu_log("ERROR: comp_thickness=%g for region id = %d at h=%g, v=%g (x=%d, y=%d), partition at x%x\n", comp_thickness, region_id, hv[0], hv[1], ap->a_x, ap->a_y, pp ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); bu_log("Send this output to the BRL-CAD Developers ([email protected])\n"); if ( ! (RT_G_DEBUG & DEBUG_ARB8)) { rt_g.debug |= DEBUG_ARB8; rt_shootray(ap); rt_g.debug &= ~DEBUG_ARB8; } } #endif if ( nextpp == PartHeadp ) { if ( region_id <= 0 ) { /* last partition is air, need a 111 'phantom armor' before AND after */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before and after air region %s\n", pp->pt_regionp->reg_name ); region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else { /* Last partition, no air follows, use code 9 */ air_id = 9; air_thickness = 0.0; } } else if ( region_id <= 0 ) { /* air region, need a 111 'phantom armor' */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before air region %s\n", pp->pt_regionp->reg_name ); prev_id = region_id; region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else if ( nextpp->pt_regionp->reg_regionid <= 0 && nextpp->pt_regionp->reg_aircode != 0 ) { /* Next partition is air region */ air_id = nextpp->pt_regionp->reg_aircode; air_thickness = nextpp->pt_outhit->hit_dist - nextpp->pt_inhit->hit_dist; prev_id = air_id; } else { /* 2 solid regions, maybe with gap */ air_id = 0; air_thickness = nextpp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist; if ( air_thickness < 0.0 ) air_thickness = 0.0; if ( !NEAR_ZERO( air_thickness, 0.1 ) ) { air_id = 1; /* air gap */ if ( R_DEBUG & RDEBUG_HITS ) bu_log("air gap added\n"); } else { air_thickness = 0.0; } prev_id = region_id; } /* * Compute the obliquity angles in degrees, ie, * the "declension" angle down off the normal vector. * RT normals always point outwards; * the "inhit" normal points opposite the ray direction, * the "outhit" normal points along the ray direction. * Hence the one sign change. * XXX this should probably be done with atan2() */ if ( first ) { first = 0; VJOIN1( first_hit, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); } out: RT_HIT_NORMAL( normal, pp->pt_inhit, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); in_obliq = acos( -dot_prod ) * bn_radtodeg; RT_HIT_NORMAL( normal, pp->pt_outhit, pp->pt_outseg->seg_stp, &(ap->a_ray), pp->pt_outflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); out_obliq = acos( dot_prod ) * bn_radtodeg; /* Check for exit obliquties greater than 90 degrees. */ #if 0 if ( in_obliq > 90 || in_obliq < 0 ) { bu_log("ERROR: in_obliquity=%g\n", in_obliq); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } if ( out_obliq > 90 || out_obliq < 0 ) { bu_log("ERROR: out_obliquity=%g\n", out_obliq); VPRINT(" r_dir", ap->a_ray.r_dir); VPRINT("normal", normal); bu_log("dot=%g, acos(dot)=%g\n", VDOT( ap->a_ray.r_dir, normal ), acos( VDOT( ap->a_ray.r_dir, normal ) ) ); /* Print the defective one */ rt_pr_pt( ap->a_rt_i, pp ); /* Print the whole ray's partition list */ rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } #endif if ( in_obliq > 90.0 ) in_obliq = 90.0; if ( in_obliq < 0.0 ) in_obliq = 0.0; if ( out_obliq > 90.0 ) out_obliq = 90.0; if ( out_obliq < 0.0 ) out_obliq = 0.0; /* * Handle 3-components per card output format, with * a leading space in front of the first component. */ if ( card_count == 0 ) { bu_vls_strcat( &str, " " ); } comp_thickness *= MM2IN; /* Check thickness fields for format overflow */ if ( comp_thickness > 999.99 || air_thickness*MM2IN > 999.9 ) fmt = "%4d%6.1f%5.1f%5.1f%1d%5.0f"; else fmt = "%4d%6.2f%5.1f%5.1f%1d%5.1f"; #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_acquire( BU_SEM_SYSCALL ); #endif snprintf(buf, 128, fmt, region_id, comp_thickness, in_obliq, out_obliq, air_id, air_thickness*MM2IN ); #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_release( BU_SEM_SYSCALL ); #endif bu_vls_strcat( &str, buf ); card_count++; if ( card_count >= 3 ) { bu_vls_strcat( &str, "\n" ); card_count = 0; } /* A color rtg3.pl UnixPlot file of output commands * is generated. This is processed by plot(1) * plotting filters such as pl-fb or pl-sgi. * Portions of a ray passing through air within the * model are represented in blue, while portions * passing through a solid are assigned green. * This will always be done single CPU, * to prevent output garbling. (See view_init). */ if (R_DEBUG & RDEBUG_RAYPLOT) { vect_t inpt; vect_t outpt; VJOIN1(inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir); VJOIN1(outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir); pl_color(plotfp, 0, 255, 0); /* green */ pdv_3line(plotfp, inpt, outpt); if (air_thickness > 0) { vect_t air_end; VJOIN1(air_end, ap->a_ray.r_pt, pp->pt_outhit->hit_dist + air_thickness, ap->a_ray.r_dir); pl_color(plotfp, 0, 0, 255); /* blue */ pdv_3cont(plotfp, air_end); } } if ( nextpp == PartHeadp && air_id != 9 ) { /* need to output a 111 'phantom armor' at end of shotline */ air_id = 9; air_thickness = 0.0; region_id = 111; comp_thickness = 0.0; goto out; } } /* If partway through building the line, add a newline */ if ( card_count > 0 ) { /* * Note that GIFT zero-fills the unused component slots, * but neither COVART II nor COVART III require it, * so just end the line here. */ bu_vls_strcat( &str, "\n" ); } /* Single-thread through file output. * COVART will accept non-sequential ray data provided the * ray header and its associated data are not separated. CAVEAT: * COVART will not accept headers out of sequence. */ bu_semaphore_acquire( BU_SEM_SYSCALL ); fputs( bu_vls_addr( &str ), outfp ); if ( shot_fp ) { fprintf( shot_fp, "%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %ld %.5f %.5f %.5f\n", azimuth, elevation, V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ), line_num, V3ARGS( first_hit) ); line_num += 1 + (comp_count / 3 ); if ( comp_count % 3 ) line_num++; } /* End of single-thread region */ bu_semaphore_release( BU_SEM_SYSCALL ); /* Release vls storage */ bu_vls_free( &str ); return(0); }
void bn_mat_fromto( mat_t m, const fastf_t *from, const fastf_t *to, const struct bn_tol *tol) { vect_t test_to; vect_t unit_from, unit_to; fastf_t dot; point_t origin = VINIT_ZERO; /** * The method used here is from Graphics Gems, A. Glassner, ed. * page 531, "The Use of Coordinate Frames in Computer Graphics", * by Ken Turkowski, Example 6. */ mat_t Q, Qt; mat_t R; mat_t A; mat_t temp; vect_t N, M; vect_t w_prime; /* image of "to" ("w") in Qt */ VMOVE(unit_from, from); VUNITIZE(unit_from); /* aka "v" */ VMOVE(unit_to, to); VUNITIZE(unit_to); /* aka "w" */ /* If from and to are the same or opposite, special handling is * needed, because the cross product isn't defined. asin(0.00001) * = 0.0005729 degrees (1/2000 degree) */ if (bn_lseg3_lseg3_parallel(origin, from, origin, to, tol)) { dot = VDOT(from, to); if (dot > SMALL_FASTF) { MAT_IDN(m); return; } else { bn_vec_perp(N, unit_from); } } else { VCROSS(N, unit_from, unit_to); VUNITIZE(N); /* should be unnecessary */ } VCROSS(M, N, unit_from); VUNITIZE(M); /* should be unnecessary */ /* Almost everything here is done with pre-multiplys: vector * mat */ MAT_IDN(Q); VMOVE(&Q[0], unit_from); VMOVE(&Q[4], M); VMOVE(&Q[8], N); bn_mat_trn(Qt, Q); /* w_prime = w * Qt */ MAT4X3VEC(w_prime, Q, unit_to); /* post-multiply by transpose */ MAT_IDN(R); VMOVE(&R[0], w_prime); VSET(&R[4], -w_prime[Y], w_prime[X], w_prime[Z]); VSET(&R[8], 0, 0, 1); /* is unnecessary */ bn_mat_mul(temp, R, Q); bn_mat_mul(A, Qt, temp); bn_mat_trn(m, A); /* back to post-multiply style */ /* Verify that it worked */ MAT4X3VEC(test_to, m, unit_from); if (UNLIKELY(!bn_lseg3_lseg3_parallel(origin, unit_to, origin, test_to, tol))) { dot = VDOT(unit_to, test_to); bu_log("bn_mat_fromto() ERROR! from (%g, %g, %g) to (%g, %g, %g) went to (%g, %g, %g), dot=%g?\n", V3ARGS(from), V3ARGS(to), V3ARGS(test_to), dot); } }