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 T _ D S P _ M I R R O R * * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_dsp_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_dsp_internal *dsp; 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); dsp = (struct rt_dsp_internal *)ip->idb_ptr; RT_EBM_CK_MAGIC(dsp); 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]; bn_mat_mul(temp, mirmat, dsp->dsp_mtos); MAT_COPY(dsp->dsp_mtos, temp); return 0; }
void db_dup_full_path(struct db_full_path *newp, const struct db_full_path *oldp) { unsigned int i = 0; RT_CK_FULL_PATH(newp); RT_CK_FULL_PATH(oldp); newp->fp_maxlen = oldp->fp_maxlen; newp->fp_len = oldp->fp_len; if (oldp->fp_len <= 0) { newp->fp_names = (struct directory **)0; newp->fp_bool = (int *)0; return; } newp->fp_names = (struct directory **)bu_malloc(newp->fp_maxlen * sizeof(struct directory *), "db_full_path array (duplicate)"); memcpy((char *)newp->fp_names, (char *)oldp->fp_names, newp->fp_len * sizeof(struct directory *)); newp->fp_bool = (int *)bu_malloc(newp->fp_maxlen * sizeof(int), "db_full_path bool array (duplicate)"); memcpy((char *)newp->fp_bool, (char *)oldp->fp_bool, newp->fp_len * sizeof(int)); newp->fp_mat = (matp_t *)bu_calloc(newp->fp_maxlen, sizeof(matp_t), "db_full_path mat array (duplicate)"); for (i = 0; i < newp->fp_len; i++) { if (oldp->fp_mat[i]) { newp->fp_mat[i] = (matp_t)bu_calloc(1, sizeof(mat_t), "transformation matrix"); MAT_COPY(newp->fp_mat[i], oldp->fp_mat[i]); } } }
/** * P L O T _ L O A D M A T R I X * * Load a new transformation matrix. This will be followed by * many calls to plot_draw(). */ HIDDEN int plot_loadMatrix(struct dm *dmp, fastf_t *mat, int which_eye) { Tcl_Obj *obj; if (!dmp) return TCL_ERROR; obj = Tcl_GetObjResult(dmp->dm_interp); if (Tcl_IsShared(obj)) obj = Tcl_DuplicateObj(obj); if (((struct plot_vars *)dmp->dm_vars.priv_vars)->debug) { struct bu_vls tmp_vls = BU_VLS_INIT_ZERO; Tcl_AppendStringsToObj(obj, "plot_loadMatrix()\n", (char *)NULL); bu_vls_printf(&tmp_vls, "which eye = %d\t", which_eye); bu_vls_printf(&tmp_vls, "transformation matrix = \n"); bu_vls_printf(&tmp_vls, "%g %g %g %g\n", mat[0], mat[4], mat[8], mat[12]); bu_vls_printf(&tmp_vls, "%g %g %g %g\n", mat[1], mat[5], mat[9], mat[13]); bu_vls_printf(&tmp_vls, "%g %g %g %g\n", mat[2], mat[6], mat[10], mat[14]); bu_vls_printf(&tmp_vls, "%g %g %g %g\n", mat[3], mat[7], mat[11], mat[15]); Tcl_AppendStringsToObj(obj, bu_vls_addr(&tmp_vls), (char *)NULL); bu_vls_free(&tmp_vls); } MAT_COPY(plotmat, mat); Tcl_SetObjResult(dmp->dm_interp, obj); return TCL_OK; }
static int orient_find_neighbor(int *utag, int ublk1 ,int ublk2, int mat[3][3]) { int ublk_match; int ibnd; int ibnd_match; int mat_temp1[3][3]; int mat_temp2[3][3]; BndMapping_t *ubnd; ubnd = umap[ublk1].bnd; ublk_match = -1; ibnd_match = -1; for (ibnd = 0; ibnd < umap[ublk1].nbnd; ibnd++) { if ((ubnd[ibnd].orientation[0] != 0) && (utag[ubnd[ibnd].iblk] == 0)) { ublk_match = ubnd[ibnd].iblk; ibnd_match = ibnd; if (ublk_match == ublk2) break; } } if (ublk_match >= 0) { utag[ublk_match] = 1; MAT_ZERO(mat_temp1); MAT_ZERO(mat_temp2); MAT_EXPAND(mat_temp1,ubnd[ibnd_match].orientation); MAT_X_MAT(mat_temp2,mat_temp1,mat); MAT_COPY(mat,mat_temp2); } return(ublk_match); }
void bn_mat_mul2(register const mat_t i, register mat_t o) { mat_t temp; bn_mat_mul(temp, i, o); MAT_COPY(o, temp); }
matp_t bn_mat_dup(const mat_t in) { mat_t *out; BU_ALLOC(out, mat_t); MAT_COPY(*out, in); return (matp_t)out; }
/* * V I E W _ 2 I N I T * * View_2init is called by do_frame(), which in turn is called by * main() in rt.c. It writes the view-specific COVART header. * */ void view_2init(struct application *ap) { if ( outfp == NULL ) bu_exit(EXIT_FAILURE, "outfp is NULL\n"); /* * Overall header, to be read by COVART format: * 9220 FORMAT( BZ, I5, 10A4 ) * number of views, title * Initially, do only one view per run of RTG3. */ fprintf(outfp, "%5d %s %s\n", 1, save_file, save_obj); /* * Header for each view, to be read by COVART format: * 9230 FORMAT( BZ, 2( 5X, E15.8), 30X, E10.3 ) * azimuth, elevation, grid_spacing * NOTE that GIFT provides several other numbers that are not used * by COVART; this should be investigated. * NOTE that grid_spacing is assumed to be square (by COVART), * and that the units have been converted from MM to IN. * COVART, given the appropriate code, will take, IN, M, * FT, MM, and CM. However, GIFT output is expected to be IN. * NOTE that variables "azimuth and elevation" are not valid * when the -M flag is used. * NOTE: %10g was changed to %10f so that a decimal point is generated * even when the number is an integer. Otherwise the client codes * get confused get confused and are unable to convert the number to * scientific notation. */ fprintf(outfp, " %-15.8f %-15.8f %10f\n", azimuth, elevation, cell_width*MM2IN ); /* * GIFT uses an H, V coordinate system that is anchored at the * model origin, but rotated according to the view. * For convenience later, build a matrix that will take * a point in model space (with units of mm), and convert it * to a point in HV space, with units of inches. */ MAT_COPY( model2hv, Viewrotscale ); model2hv[15] = 1/MM2IN; line_num += 2; }
int mat_build(fastf_t *mat1, fastf_t *mat2, fastf_t *regismat) { vect_t adelta, bdelta; /* deltas for mod1 and mod2 */ vect_t delta; /* difference bet. mod1 and mod2 deltas */ fastf_t scale; /* At this point it is important to check that the rotation part * of the matices is within a certain tolerance: ie. that the * two images were raytraced from the same angle. No overlays will * be possible if they are not at the same rotation. */ /* Now record the deltas: the translation part of the matrix. */ VSET(adelta, mat1[MDX], mat1[MDY], mat1[MDZ]); VSET(bdelta, mat2[MDX], mat2[MDY], mat2[MDZ]); /* Take the difference between the deltas. Also scale the size * of the model (scale). These will be used to register two * pixel files later on. */ VSUB2(delta, adelta, bdelta); scale = mat1[15]/mat2[15]; VPRINT("delta", delta); fprintf(stderr, "scale: %.6f\n", scale); /* If the first log corresponds to a UNIX-Plot file, following * applies. Since UNIX-Plot files are in model coordinates, the * mod2view2 ("model2pix") is also the registration matrix. In * this case, pl-fb needs to learn that the UNIX-Plot file's space * runs from -1 -> 1 in x and y. This can be done by adding an * alternate space command in that program. Therefore the below * applies. * What if the first log corresponds to a hi-res pixel file to be * registered with a lo-res pixel file? Then the above calculated * deltas are used. This will be implemented later. */ MAT_COPY( regismat, mat2); bn_mat_print("regismat", regismat); return(1); /* OK */ }
int ged_perspective(struct ged *gedp, int argc, const char *argv[]) { /* intentionally double for scan */ double perspective; static const char *usage = "[angle]"; GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR); GED_CHECK_VIEW(gedp, GED_ERROR); GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR); /* initialize result */ bu_vls_trunc(gedp->ged_result_str, 0); /* get the perspective angle */ if (argc == 1) { bu_vls_printf(gedp->ged_result_str, "%g", gedp->ged_gvp->gv_perspective); return GED_OK; } /* set perspective angle */ if (argc == 2) { if (sscanf(argv[1], "%lf", &perspective) != 1) { bu_vls_printf(gedp->ged_result_str, "bad perspective angle - %s", argv[1]); return GED_ERROR; } gedp->ged_gvp->gv_perspective = perspective; if (SMALL_FASTF < gedp->ged_gvp->gv_perspective) { ged_persp_mat(gedp->ged_gvp->gv_pmat, gedp->ged_gvp->gv_perspective, (fastf_t)1.0f, (fastf_t)0.01f, (fastf_t)1.0e10f, (fastf_t)1.0f); } else { MAT_COPY(gedp->ged_gvp->gv_pmat, bn_mat_identity); } ged_view_update(gedp->ged_gvp); return GED_OK; } bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage); return GED_ERROR; }
int mk_dsp(struct rt_wdb *fp, const char *name, const char *file, size_t xdim, size_t ydim, const matp_t mat) /* name of file containing elevation data */ /* X dimension of file (w cells) */ /* Y dimension of file (n cells) */ /* convert solid coords to model space */ { struct rt_dsp_internal *dsp; BU_ALLOC(dsp, struct rt_dsp_internal); dsp->magic = RT_DSP_INTERNAL_MAGIC; bu_vls_init(&dsp->dsp_name); bu_vls_strcat(&dsp->dsp_name, file); dsp->dsp_xcnt = xdim; dsp->dsp_ycnt = ydim; MAT_COPY(dsp->dsp_stom, mat); return wdb_export(fp, name, (void *)dsp, ID_DSP, mk_conv2mm); }
void db_append_full_path(struct db_full_path *dest, const struct db_full_path *src) { unsigned int i = 0; RT_CK_FULL_PATH(dest); RT_CK_FULL_PATH(src); db_extend_full_path(dest, src->fp_len); memcpy((char *)&dest->fp_names[dest->fp_len], (char *)&src->fp_names[0], src->fp_len * sizeof(struct directory *)); memcpy((char *)&dest->fp_bool[dest->fp_len], (char *)&src->fp_bool[0], src->fp_len * sizeof(int)); for (i = 0; i < src->fp_len; i++) { if (src->fp_mat[i]) { dest->fp_mat[dest->fp_len + i] = (matp_t)bu_calloc(1, sizeof(mat_t), "transformation matrix"); MAT_COPY(dest->fp_mat[dest->fp_len + i], src->fp_mat[i]); } } dest->fp_len += src->fp_len; }
void db_dup_path_tail(struct db_full_path *newp, const struct db_full_path *oldp, off_t start) { unsigned int i = 0; RT_CK_FULL_PATH(newp); RT_CK_FULL_PATH(oldp); if (start < 0 || (size_t)start > oldp->fp_len-1) bu_bomb("db_dup_path_tail: start offset out of range\n"); newp->fp_maxlen = newp->fp_len = oldp->fp_len - start; if (newp->fp_len <= 0) { newp->fp_names = (struct directory **)0; newp->fp_bool = (int *)0; newp->fp_mat = (matp_t *)0; return; } newp->fp_names = (struct directory **)bu_malloc( newp->fp_maxlen * sizeof(struct directory *), "db_full_path array (duplicate)"); memcpy((char *)newp->fp_names, (char *)&oldp->fp_names[start], newp->fp_len * sizeof(struct directory *)); newp->fp_bool = (int *)bu_malloc( newp->fp_maxlen * sizeof(int), "db_full_path bool array (duplicate)"); memcpy((char *)newp->fp_bool, (char *)&oldp->fp_bool[start], newp->fp_len * sizeof(int)); newp->fp_mat = (matp_t *)bu_calloc(newp->fp_maxlen, sizeof(matp_t), "db_full_path mat array (duplicate)"); for (i = start; i < newp->fp_len; i++) { if (oldp->fp_mat[i]) { newp->fp_mat[i] = (matp_t)bu_calloc(1, sizeof(mat_t), "transformation matrix"); MAT_COPY(newp->fp_mat[i], oldp->fp_mat[i]); } } }
/** * 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; }
/* * Process a space command. * Behavior depends on setting of several flags. * * Implicit Returns - * In all cases, sets space_min and space_max. */ int model_rpp(const fastf_t *min, const fastf_t *max) { if (space_set) { bu_log("plot3rot: additional SPACE command ignored\n"); bu_log("got: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(min), V3ARGS(max)); bu_log("still using: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(space_min), V3ARGS(space_max)); return 0; } if (rpp) { point_t rot_center; /* center of rotation */ mat_t xlate; mat_t resize; mat_t t1, t2; VADD2SCALE(rot_center, min, max, 0.5); /* Create the matrix which encodes this */ MAT_IDN(xlate); MAT_DELTAS_VEC_NEG(xlate, rot_center); MAT_IDN(resize); resize[15] = 1/scale; bn_mat_mul(t1, resize, xlate); bn_mat_mul(t2, rmat, t1); MAT_COPY(rmat, t2); if (verbose) { bn_mat_print("rmat", rmat); } if (Mflag) { /* Don't rebound, just expand size of space * around center point. * Has advantage of the output space() not being * affected by changes in rotation, * which may be significant for animation scripts. */ vect_t diag; double v; VSUB2(diag, max, min); v = MAGNITUDE(diag)*0.5 + 0.5; VSET(space_min, -v, -v, -v); VSET(space_max, v, v, v); } else { /* re-bound the space() rpp with a tighter one * after rotating & scaling it. */ bn_rotate_bbox(space_min, space_max, rmat, min, max); } space_set = 1; } else { VMOVE(space_min, min); VMOVE(space_max, max); space_set = 1; } if (forced_space) { /* Put forced space back */ VMOVE(space_min, forced_space_min); VMOVE(space_max, forced_space_max); space_set = 1; } if (verbose) { bu_log("got: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(min), V3ARGS(max)); bu_log("put: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(space_min), V3ARGS(space_max)); } return 1; }
/** * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_nurb_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_nurb_internal *nurb; 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; int i; int j; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); nurb = (struct rt_nurb_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(nurb); 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<nurb->nsrf; i++) { fastf_t *ptr; int tmp; int orig_size[2]; int ncoords; int m; int l; /* swap knot vectors between u and v */ ptr = nurb->srfs[i]->u.knots; tmp = nurb->srfs[i]->u.k_size; nurb->srfs[i]->u.knots = nurb->srfs[i]->v.knots; nurb->srfs[i]->u.k_size = nurb->srfs[i]->v.k_size; nurb->srfs[i]->v.knots = ptr; nurb->srfs[i]->v.k_size = tmp; /* swap order */ tmp = nurb->srfs[i]->order[0]; nurb->srfs[i]->order[0] = nurb->srfs[i]->order[1]; nurb->srfs[i]->order[1] = tmp; /* swap mesh size */ orig_size[0] = nurb->srfs[i]->s_size[0]; orig_size[1] = nurb->srfs[i]->s_size[1]; nurb->srfs[i]->s_size[0] = orig_size[1]; nurb->srfs[i]->s_size[1] = orig_size[0]; /* allocate memory for a new control mesh */ ncoords = RT_NURB_EXTRACT_COORDS(nurb->srfs[i]->pt_type); ptr = (fastf_t *)bu_calloc(orig_size[0]*orig_size[1]*ncoords, sizeof(fastf_t), "rt_mirror: ctl mesh ptr"); /* mirror each control point */ for (j=0; j<orig_size[0]*orig_size[1]; j++) { point_t pt; VMOVE(pt, &nurb->srfs[i]->ctl_points[j*ncoords]); MAT4X3PNT(&nurb->srfs[i]->ctl_points[j*ncoords], mirmat, pt); } /* copy mirrored control points into new mesh * while swapping u and v */ m = 0; for (j=0; j<orig_size[0]; j++) { for (l=0; l<orig_size[1]; l++) { VMOVEN(&ptr[(l*orig_size[0]+j)*ncoords], &nurb->srfs[i]->ctl_points[m*ncoords], ncoords); m++; } } /* free old mesh */ bu_free((char *)nurb->srfs[i]->ctl_points, "rt_mirror: ctl points"); /* put new mesh in place */ nurb->srfs[i]->ctl_points = ptr; } return 0; }
/** * 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; }
-x# -y# -z# Rotation about axis in degrees\n\ -X# -Y# -Z# Translation along axis\n\ -s# Scale factor\n\ -a# -e# Azimuth/Elevation from front view\n\ (usually first, in this order, implies -M)\n\ -g MGED front view to display coordinates (usually last)\n\ -M Autoscale space command like RT model RPP\n\ -m# Takes a 4X4 matrix as an argument\n\ -v Verbose\n\ -S# Space: takes a quoted string of six floats\n"; /* * M O D E L _ R P P * * Process a space command. * Behavior depends on setting of several flags. * * Implicit Returns - * In all cases, sets space_min and space_max. */ int model_rpp(const fastf_t *min, const fastf_t *max) { if ( space_set ) { fprintf(stderr, "plrot: additional SPACE command ignored\n"); fprintf(stderr, "got: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(min), V3ARGS(max) ); fprintf(stderr, "still using: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(space_min), V3ARGS(space_max) ); return 0; } if ( rpp ) { point_t rot_center; /* center of rotation */ mat_t xlate; mat_t resize; mat_t t1, t2; VADD2SCALE( rot_center, min, max, 0.5 ); /* Create the matrix which encodes this */ MAT_IDN( xlate ); MAT_DELTAS_VEC_NEG( xlate, rot_center); MAT_IDN( resize ); resize[15] = 1/scale; bn_mat_mul( t1, resize, xlate ); bn_mat_mul( t2, rmat, t1 ); MAT_COPY( rmat, t2 ); if ( verbose ) { bn_mat_print("rmat", rmat); } if ( Mflag ) { /* Don't rebound, just expand size of space * around center point. * Has advantage of the output space() not being * affected by changes in rotation, * which may be significant for animation scripts. */ vect_t diag; double v; VSUB2( diag, max, min ); v = MAGNITUDE(diag)*0.5 + 0.5; VSET( space_min, -v, -v, -v ); VSET( space_max, v, v, v ); } else { /* re-bound the space() rpp with a tighter one * after rotating & scaling it. */ bn_rotate_bbox( space_min, space_max, rmat, min, max ); } space_set = 1; } else { VMOVE( space_min, min ); VMOVE( space_max, max ); space_set = 1; } if ( forced_space ) { /* Put forced space back */ VMOVE( space_min, forced_space_min ); VMOVE( space_max, forced_space_max ); space_set = 1; } if ( verbose ) { fprintf(stderr, "got: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(min), V3ARGS(max) ); fprintf(stderr, "put: space (%g, %g, %g) (%g, %g, %g)\n", V3ARGS(space_min), V3ARGS(space_max) ); } return( 1 ); }
/** * R E A D _ M A T */ void read_mat (struct rt_i *rtip) { double scan[16] = MAT_INIT_ZERO; char *buf; int status = 0x0; mat_t m; mat_t q; while ((buf = rt_read_cmd(stdin)) != (char *) 0) { if (bu_strncmp(buf, "eye_pt", 6) == 0) { if (sscanf(buf + 6, "%lf%lf%lf", &scan[X], &scan[Y], &scan[Z]) != 3) { bu_exit(1, "nirt: read_mat(): Failed to read eye_pt\n"); } target(X) = scan[X]; target(Y) = scan[Y]; target(Z) = scan[Z]; status |= RMAT_SAW_EYE; } else if (bu_strncmp(buf, "orientation", 11) == 0) { if (sscanf(buf + 11, "%lf%lf%lf%lf", &scan[X], &scan[Y], &scan[Z], &scan[W]) != 4) { bu_exit(1, "nirt: read_mat(): Failed to read orientation\n"); } MAT_COPY(q, scan); quat_quat2mat(m, q); if (nirt_debug & DEBUG_MAT) bn_mat_print("view matrix", m); azimuth() = atan2(-m[0], m[1]) / DEG2RAD; elevation() = atan2(m[10], m[6]) / DEG2RAD; status |= RMAT_SAW_ORI; } else if (bu_strncmp(buf, "viewrot", 7) == 0) { if (sscanf(buf + 7, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &scan[0], &scan[1], &scan[2], &scan[3], &scan[4], &scan[5], &scan[6], &scan[7], &scan[8], &scan[9], &scan[10], &scan[11], &scan[12], &scan[13], &scan[14], &scan[15]) != 16) { bu_exit(1, "nirt: read_mat(): Failed to read viewrot\n"); } MAT_COPY(m, scan); if (nirt_debug & DEBUG_MAT) bn_mat_print("view matrix", m); azimuth() = atan2(-m[0], m[1]) / DEG2RAD; elevation() = atan2(m[10], m[6]) / DEG2RAD; status |= RMAT_SAW_VR; } } if ((status & RMAT_SAW_EYE) == 0) { bu_exit(1, "nirt: read_mat(): Was given no eye_pt\n"); } if ((status & (RMAT_SAW_ORI | RMAT_SAW_VR)) == 0) { bu_exit(1, "nirt: read_mat(): Was given no orientation or viewrot\n"); } direct(X) = -m[8]; direct(Y) = -m[9]; direct(Z) = -m[10]; dir2ae(); targ2grid(); shoot("", 0, rtip); }
/** * 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; }
static void tree_solids(union tree *tp, struct tree_bark *tb, int op, struct resource *resp) { RT_CK_TREE(tp); switch (tp->tr_op) { case OP_NOP: return; case OP_SOLID: { struct reg_db_internals *dbint; matp_t mp; long sol_id = 0; struct rt_ell_internal *ell_p; vect_t v; int ret; BU_ALLOC(dbint, struct reg_db_internals); BU_LIST_INIT_MAGIC(&(dbint->l), DBINT_MAGIC); if (tp->tr_a.tu_stp->st_matp) mp = tp->tr_a.tu_stp->st_matp; else mp = (matp_t)bn_mat_identity; /* Get the internal form of this solid & add it to the list */ ret = rt_db_get_internal(&dbint->ip, tp->tr_a.tu_stp->st_dp, tb->dbip, mp, resp); if (ret < 0) { bu_log("Failure reading %s object from database.\n", OBJ[sol_id].ft_name); return; } RT_CK_DB_INTERNAL(&dbint->ip); dbint->st_p = tp->tr_a.tu_stp; sol_id = dbint->ip.idb_type; if (sol_id < 0) { bu_log("Primitive ID %ld out of bounds\n", sol_id); bu_bomb(""); } if (sol_id != ID_ELL) { if (op == OP_UNION) bu_log("Non-ellipse \"union\" primitive of \"%s\" being ignored\n", tb->name); if (rdebug&RDEBUG_SHADE) bu_log(" got a primitive type %ld \"%s\". This primitive ain't no ellipse bucko!\n", sol_id, OBJ[sol_id].ft_name); break; } ell_p = (struct rt_ell_internal *)dbint->ip.idb_ptr; if (rdebug&RDEBUG_SHADE) bu_log(" got a primitive type %ld \"%s\"\n", sol_id, OBJ[sol_id].ft_name); RT_ELL_CK_MAGIC(ell_p); if (rdebug&RDEBUG_SHADE) { VPRINT("point", ell_p->v); VPRINT("a", ell_p->a); VPRINT("b", ell_p->b); VPRINT("c", ell_p->c); } /* create the matrix that maps the coordinate system defined * by the ellipse into model space, and get inverse for use * in the _render() proc */ MAT_IDN(mp); VMOVE(v, ell_p->a); VUNITIZE(v); mp[0] = v[0]; mp[4] = v[1]; mp[8] = v[2]; VMOVE(v, ell_p->b); VUNITIZE(v); mp[1] = v[0]; mp[5] = v[1]; mp[9] = v[2]; VMOVE(v, ell_p->c); VUNITIZE(v); mp[2] = v[0]; mp[6] = v[1]; mp[10] = v[2]; MAT_DELTAS_VEC(mp, ell_p->v); MAT_COPY(dbint->ell2model, mp); bn_mat_inv(dbint->model2ell, mp); /* find scaling of gaussian puff in ellipsoid space */ VSET(dbint->one_sigma, MAGNITUDE(ell_p->a) / tb->gs->gauss_sigma, MAGNITUDE(ell_p->b) / tb->gs->gauss_sigma, MAGNITUDE(ell_p->c) / tb->gs->gauss_sigma); if (rdebug&RDEBUG_SHADE) { VPRINT("sigma", dbint->one_sigma); } BU_LIST_APPEND(tb->l, &(dbint->l)); break; } case OP_UNION: tree_solids(tp->tr_b.tb_left, tb, tp->tr_op, resp); tree_solids(tp->tr_b.tb_right, tb, tp->tr_op, resp); break; case OP_NOT: bu_log("Warning: 'Not' region operator in %s\n", tb->name); tree_solids(tp->tr_b.tb_left, tb, tp->tr_op, resp); break; case OP_GUARD:bu_log("Warning: 'Guard' region operator in %s\n", tb->name); tree_solids(tp->tr_b.tb_left, tb, tp->tr_op, resp); break; case OP_XNOP:bu_log("Warning: 'XNOP' region operator in %s\n", tb->name); tree_solids(tp->tr_b.tb_left, tb, tp->tr_op, resp); break; case OP_INTERSECT: case OP_SUBTRACT: case OP_XOR: /* XXX this can get us in trouble if 1 solid is subtracted * from less than all the "union" solids of the region. */ tree_solids(tp->tr_b.tb_left, tb, tp->tr_op, resp); tree_solids(tp->tr_b.tb_right, tb, tp->tr_op, resp); return; default: bu_bomb("rt_tree_region_assign: bad op\n"); } }
/** * 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 bn_mat_inverse(register mat_t output, const mat_t input) { register int i, j; /* Indices */ int k; /* Indices */ int z[4]; /* Temporary */ fastf_t b[4]; /* Temporary */ fastf_t c[4]; /* Temporary */ MAT_COPY(output, input); /* Duplicate */ /* Initialization */ for (j = 0; j < 4; j++) { z[j] = j; } /* Main Loop */ for (i = 0; i < 4; i++) { register fastf_t y; /* local temporary */ k = i; y = output[i * 4 + i]; for (j = i + 1; j < 4; j++) { register fastf_t w; /* local temporary */ w = output[i * 4 + j]; if (fabs(w) > fabs(y)) { k = j; y = w; } } if (ZERO(y)) { /* SINGULAR */ return 0; } y = 1.0 / y; for (j = 0; j < 4; j++) { register fastf_t temp; /* Local */ c[j] = output[j * 4 + k]; output[j * 4 + k] = output[j * 4 + i]; output[j * 4 + i] = - c[j] * y; temp = output[i * 4 + j] * y; b[j] = temp; output[i * 4 + j] = temp; } output[i * 4 + i] = y; j = z[i]; z[i] = z[k]; z[k] = j; for (k = 0; k < 4; k++) { if (k == i) { continue; } for (j = 0; j < 4; j++) { if (j == i) { continue; } output[k * 4 + j] = output[k * 4 + j] - b[j] * c[k]; } } } /* Second Loop */ for (i = 0; i < 4; i++) { while ((k = z[i]) != i) { int p; /* Local temp */ for (j = 0; j < 4; j++) { register fastf_t w; /* Local temp */ w = output[i * 4 + j]; output[i * 4 + j] = output[k * 4 + j]; output[k * 4 + j] = w; } p = z[i]; z[i] = z[k]; z[k] = p; } } return 1; }
/** * make a copy of a v5 solid by adding it to our book-keeping list, * adding it to the db directory, and writing it out to disk. */ static void copy_v5_solid(struct db_i *_dbip, struct directory *proto, struct clone_state *state, int idx) { size_t i; mat_t matrix; MAT_IDN(matrix); /* mirror */ if (state->miraxis != W) { matrix[state->miraxis*5] = -1.0; matrix[3 + state->miraxis*4] -= 2 * (matrix[3 + state->miraxis*4] - state->mirpos); } /* translate */ if (state->trans[W] > SMALL_FASTF) MAT_DELTAS_ADD_VEC(matrix, state->trans); /* rotation */ if (state->rot[W] > SMALL_FASTF) { mat_t m2, t; bn_mat_angles(m2, state->rot[X], state->rot[Y], state->rot[Z]); if (state->rpnt[W] > SMALL_FASTF) { mat_t m3; bn_mat_xform_about_pt(m3, m2, state->rpnt); bn_mat_mul(t, matrix, m3); } else bn_mat_mul(t, matrix, m2); MAT_COPY(matrix, t); } /* make n copies */ for (i = 0; i < state->n_copies; i++) { char *argv[6] = {"wdb_copy", (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL}; struct bu_vls *name; int ret; struct directory *dp = (struct directory *)NULL; struct rt_db_internal intern; if (i==0) dp = proto; 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); /* get new name */ bu_vls_strcpy(&obj_list.names[idx].dest[i], bu_vls_addr(name)); /* actually copy the primitive to the new name */ argv[1] = proto->d_namep; argv[2] = bu_vls_addr(name); ret = wdb_copy_cmd(_dbip->dbi_wdbp, 3, (const char **)argv); if (ret != TCL_OK) bu_log("WARNING: failure cloning \"%s\" to \"%s\"\n", proto->d_namep, bu_vls_addr(name)); /* get the original objects matrix */ if (rt_db_get_internal(&intern, dp, _dbip, matrix, &rt_uniresource) < 0) { bu_log("ERROR: clone internal error copying %s\n", proto->d_namep); bu_vls_free(name); return; } RT_CK_DB_INTERNAL(&intern); /* pull the new name */ dp = db_lookup(_dbip, bu_vls_addr(name), LOOKUP_QUIET); bu_vls_free(name); if (!dp) { bu_vls_free(name); continue; } /* write the new matrix to the new object */ if (rt_db_put_internal(dp, wdbp->dbip, &intern, &rt_uniresource) < 0) bu_log("ERROR: clone internal error copying %s\n", proto->d_namep); rt_db_free_internal(&intern); } /* end iteration over each copy */ 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"); } }
/** * R T _ A R S _ M I R R O R * * Given a pointer to an internal GED database object, mirror the * object's values about the given transformation matrix. */ int rt_ars_mirror(struct rt_db_internal *ip, register const plane_t plane) { struct rt_ars_internal *ars; 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; size_t j; fastf_t *tmp_curve; static point_t origin = {0.0, 0.0, 0.0}; RT_CK_DB_INTERNAL(ip); ars = (struct rt_ars_internal *)ip->idb_ptr; RT_ARS_CK_MAGIC(ars); 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<ars->ncurves; i++) { for (j=0; j<ars->pts_per_curve; j++) { point_t pt; VMOVE(pt, &ars->curves[i][j*3]); MAT4X3PNT(&ars->curves[i][j*3], mirmat, pt); } } /* now reverse order of vertices in each curve */ tmp_curve = (fastf_t *)bu_calloc(3*ars->pts_per_curve, sizeof(fastf_t), "rt_mirror: tmp_curve"); for (i=0; i<ars->ncurves; i++) { /* reverse vertex order */ for (j=0; j<ars->pts_per_curve; j++) { VMOVE(&tmp_curve[(ars->pts_per_curve-j-1)*3], &ars->curves[i][j*3]); } /* now copy back */ memcpy(ars->curves[i], tmp_curve, ars->pts_per_curve*3*sizeof(fastf_t)); } bu_free((char *)tmp_curve, "rt_mirror: tmp_curve"); return 0; }
int get_args(int argc, register char **argv) { register int c; mat_t tmp, m; int i, num; double mtmp[16]; MAT_IDN( rmat ); scale = 1.0; while ( (c = bu_getopt( argc, argv, "S:m:vMga:e:x:y:z:X:Y:Z:s:" )) != EOF ) { switch ( c ) { case 'M': /* take model RPP from space() command */ rpp++; Mflag = 1; /* don't rebound */ break; case 'g': bn_mat_angles( tmp, -90.0, 0.0, -90.0 ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'a': bn_mat_angles( tmp, 0.0, 0.0, -atof(bu_optarg) ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); rpp++; break; case 'e': bn_mat_angles( tmp, 0.0, -atof(bu_optarg), 0.0 ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); rpp++; break; case 'x': bn_mat_angles( tmp, atof(bu_optarg), 0.0, 0.0 ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'y': bn_mat_angles( tmp, 0.0, atof(bu_optarg), 0.0 ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'z': bn_mat_angles( tmp, 0.0, 0.0, atof(bu_optarg) ); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'm': num = sscanf(&bu_optarg[0], "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &mtmp[0], &mtmp[1], &mtmp[2], &mtmp[3], &mtmp[4], &mtmp[5], &mtmp[6], &mtmp[7], &mtmp[8], &mtmp[9], &mtmp[10], &mtmp[11], &mtmp[12], &mtmp[13], &mtmp[14], &mtmp[15]); if ( num != 16) { fprintf(stderr, "Num of arguments to -m only %d, should be 16\n", num); bu_exit (1, NULL); } /* Now copy the array of doubles into mat. */ for (i=0; i < 16; i++ ) { rmat[i] = mtmp[i]; } break; case 'X': MAT_IDN( tmp ); tmp[MDX] = atof(bu_optarg); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'Y': MAT_IDN( tmp ); tmp[MDY] = atof(bu_optarg); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 'Z': MAT_IDN( tmp ); tmp[MDZ] = atof(bu_optarg); MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); break; case 's': scale *= atof(bu_optarg); /* * If rpp flag has already been set, defer * application of scale until after the * xlate to space-center, in model_rpp(). * Otherwise, do it here, in the sequence * seen in the arg list. */ if ( !rpp ) { MAT_IDN( tmp ); tmp[15] = 1/scale; MAT_COPY( m, rmat ); bn_mat_mul( rmat, tmp, m ); scale = 1.0; } break; case 'v': verbose++; break; case 'S': num = sscanf(bu_optarg, "%lf %lf %lf %lf %lf %lf", &mtmp[0], &mtmp[1], &mtmp[2], &mtmp[3], &mtmp[4], &mtmp[5]); VSET(forced_space_min, mtmp[0], mtmp[1], mtmp[2]); VSET(forced_space_max, mtmp[3], mtmp[4], mtmp[5]); /* Write it now, in case input does not have one */ pdv_3space( stdout, forced_space_min, forced_space_max ); forced_space = 1; break; default: /* '?' */ return(0); /* Bad */ } } if ( isatty(fileno(stdout)) || (isatty(fileno(stdin)) && (bu_optind >= argc)) ) { return(0); /* Bad */ } return(1); /* OK */ }
/** * R T _ F I N D _ I D E N T I C A L _ S O L I D * * See if solid "dp" as transformed by "mat" already exists in the * soltab list. If it does, return the matching stp, otherwise, * create a new soltab structure, enrole it in the list, and return a * pointer to that. * * "mat" will be a null pointer when an identity matrix is signified. * This greatly speeds the comparison process. * * The two cases can be distinguished by the fact that stp->st_id will * be 0 for a new soltab structure, and non-zero for an existing one. * * This routine will run in parallel. * * In order to avoid a race between searching the soltab list and * adding new solids to it, the new solid to be added *must* be * enrolled in the list before exiting the critical section. * * To limit the size of the list to be searched, there are many lists. * The selection of which list is determined by the hash value * computed from the solid's name. This is the same optimization used * in searching the directory lists. * * This subroutine is the critical bottleneck in parallel tree walking. * * It is safe, and much faster, to use several different critical * sections when searching different lists. * * There are only 4 dedicated semaphores defined, TREE0 through TREE3. * This unfortunately limits the code to having only 4 CPUs doing list * searching at any one time. Hopefully, this is enough parallelism * to keep the rest of the CPUs doing I/O and actual solid prepping. * * Since the algorithm has been reduced from an O((nsolid/128)**2) * search on the entire rti_solidheads[hash] list to an O(ninstance) * search on the dp->d_use_head list for this one solid, the critical * section should be relatively short-lived. Having the 3-way split * should provide ample opportunity for parallelism through here, * while still ensuring that the necessary variables are protected. * * There are two critical variables which *both* need to be protected: * the specific rti_solidhead[hash] list head, and the specific * dp->d_use_hd list head. Fortunately, since the selection of * critical section is based upon db_dirhash(dp->d_namep), any other * processor that wants to search this same 'dp' will get the same * hash as the current thread, and will thus wait for the appropriate * semaphore to be released. Similarly, any other thread that wants * to search the same rti_solidhead[hash] list as the current thread * will be using the same hash, and will thus wait for the proper * semaphore. */ HIDDEN struct soltab *rt_find_identical_solid(register const matp_t mat, register struct directory *dp, struct rt_i *rtip) { register struct soltab *stp = RT_SOLTAB_NULL; int hash; RT_CK_DIR(dp); RT_CK_RTI(rtip); hash = db_dirhash( dp->d_namep ); /* Enter the appropriate dual critical-section */ ACQUIRE_SEMAPHORE_TREE(hash); /* * If solid has not been referenced yet, the search can be * skipped. If solid is being referenced a _lot_, it certainly * isn't all going to be in the same place, so don't bother * searching. Consider the case of a million instances of the * same tree submodel solid. */ if ( dp->d_uses > 0 && dp->d_uses < 100 && rtip->rti_dont_instance == 0 ) { struct bu_list *mid; /* Search dp->d_use_hd list for other instances */ for ( BU_LIST_FOR( mid, bu_list, &dp->d_use_hd ) ) { stp = BU_LIST_MAIN_PTR( soltab, mid, l2 ); RT_CK_SOLTAB(stp); if ( stp->st_matp == (matp_t)0 ) { if ( mat == (matp_t)0 ) { /* Both have identity matrix */ goto more_checks; } continue; } if ( mat == (matp_t)0 ) continue; /* doesn't match */ if ( !bn_mat_is_equal(mat, stp->st_matp, &rtip->rti_tol)) continue; more_checks: /* Don't instance this solid from some other model * instance. As this is nearly always equal, check it * last */ if ( stp->st_rtip != rtip ) continue; /* * stp now points to re-referenced solid. stp->st_id is * non-zero, indicating pre-existing solid. */ RT_CK_SOLTAB(stp); /* sanity */ /* Only increment use counter for non-dead solids. */ if ( !(stp->st_aradius <= -1) ) stp->st_uses++; /* dp->d_uses is NOT incremented, because number of * soltab's using it has not gone up. */ if ( RT_G_DEBUG & DEBUG_SOLIDS ) { bu_log( mat ? "rt_find_identical_solid: %s re-referenced %d\n" : "rt_find_identical_solid: %s re-referenced %d (identity mat)\n", dp->d_namep, stp->st_uses ); } /* Leave the appropriate dual critical-section */ RELEASE_SEMAPHORE_TREE(hash); return stp; } } /* * Create and link a new solid into the list. * * Ensure the search keys "dp", "st_mat" and "st_rtip" are stored * now, while still inside the critical section, because they are * searched on, above. */ BU_GETSTRUCT(stp, soltab); stp->l.magic = RT_SOLTAB_MAGIC; stp->l2.magic = RT_SOLTAB2_MAGIC; stp->st_rtip = rtip; stp->st_dp = dp; dp->d_uses++; stp->st_uses = 1; /* stp->st_id is intentionally left zero here, as a flag */ if ( mat ) { stp->st_matp = (matp_t)bu_malloc( sizeof(mat_t), "st_matp" ); MAT_COPY( stp->st_matp, mat ); } else { stp->st_matp = (matp_t)0; } /* Add to the appropriate soltab list head */ /* PARALLEL NOTE: Uses critical section on rt_solidheads element */ BU_LIST_INSERT( &(rtip->rti_solidheads[hash]), &(stp->l) ); /* Also add to the directory structure list head */ /* PARALLEL NOTE: Uses critical section on this 'dp' */ BU_LIST_INSERT( &dp->d_use_hd, &(stp->l2) ); /* * Leave the 4-way critical-section protecting dp and [hash] */ RELEASE_SEMAPHORE_TREE(hash); /* Enter an exclusive critical section to protect nsolids. * nsolids++ needs to be locked to a SINGLE thread */ bu_semaphore_acquire(RT_SEM_STATS); stp->st_bit = rtip->nsolids++; bu_semaphore_release(RT_SEM_STATS); /* * Fill in the last little bit of the structure in full parallel * mode, outside of any critical section. */ /* Init tables of regions using this solid. Usually small. */ bu_ptbl_init( &stp->st_regions, 7, "st_regions ptbl" ); return stp; }