int rt_gen_conic(struct xrays *rays, const struct xray *center_ray, fastf_t theta, vect_t up_vector, int rays_per_radius) { int count = 0; point_t start; vect_t orig_dir; fastf_t x, y; /* Setting radius to tan(theta) works because, as shown in the * following diagram, the ray that starts at the given point and * passes through orig_dir + (radius in any orthogonal direction) * has an angle of theta with the original ray; when the * resulting vector is normalized, the angle is preserved. */ fastf_t radius = tan(theta); fastf_t rsq = radius * radius; /* radius-squared, for use in the loop */ fastf_t gridsize = 2 * radius / (rays_per_radius - 1); vect_t a_dir, b_dir; register struct xrays *xrayp; VMOVE(start, center_ray->r_pt); VMOVE(orig_dir, center_ray->r_dir); /* Create vectors a_dir, b_dir that are orthogonal to orig_dir. */ VMOVE(b_dir, up_vector); VUNITIZE(b_dir); VCROSS(a_dir, orig_dir, up_vector); VUNITIZE(a_dir); for (y = -radius; y <= radius; y += gridsize) { vect_t tmp; printf("y:%f\n", y); VSCALE(tmp, b_dir, y); printf("y_partofit: %f,%f,%f\n", V3ARGS(tmp)); for (x = -radius; x <= radius; x += gridsize) { if (((x*x)/rsq + (y*y)/rsq) <= 1) { BU_ALLOC(xrayp, struct xrays); VMOVE(xrayp->ray.r_pt, start); VJOIN2(xrayp->ray.r_dir, orig_dir, x, a_dir, y, b_dir); VUNITIZE(xrayp->ray.r_dir); xrayp->ray.index = count++; xrayp->ray.magic = RT_RAY_MAGIC; BU_LIST_APPEND(&rays->l, &xrayp->l); } } } return count; }
HIDDEN int rt_pattern_rect_perspgrid(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir, const vect_t a_vec, const vect_t b_vec, const fastf_t a_theta, const fastf_t b_theta, const fastf_t a_num, const fastf_t b_num) { int count = 0; vect_t rdir; vect_t a_dir, b_dir; fastf_t x, y; fastf_t a_length = tan(a_theta); fastf_t b_length = tan(b_theta); fastf_t a_inc = 2 * a_length / (a_num - 1); fastf_t b_inc = 2 * b_length / (b_num - 1); VMOVE(a_dir, a_vec); VUNITIZE(a_dir); VMOVE(b_dir, b_vec); VUNITIZE(b_dir); /* Find out how much memory we'll need and get it */ for (y = -b_length; y <= b_length + BN_TOL_DIST; y += b_inc) { for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) { count++; } } *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, count + 1, "rays"); /* Now that we have memory, reset count so it can * be used to index into the array */ count = 0; /* This adds BN_TOL_DIST to the *_length variables in the * condition because in some cases, floating-point problems can * make extremely close numbers compare incorrectly. */ for (y = -b_length; y <= b_length + BN_TOL_DIST; y += b_inc) { for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) { VJOIN2(rdir, dir, x, a_dir, y, b_dir); VUNITIZE(rdir); (*rays)[6*count] = center_pt[0]; (*rays)[6*count+1] = center_pt[1]; (*rays)[6*count+2] = center_pt[2]; (*rays)[6*count+3] = rdir[0]; (*rays)[6*count+4] = rdir[1]; (*rays)[6*count+5] = rdir[2]; count++; } } *(ray_cnt) = count; return count; }
void ellipse_point_at_radian( point_t result, const vect_t center, const vect_t axis_a, const vect_t axis_b, fastf_t radian) { fastf_t cos_rad, sin_rad; cos_rad = cos(radian); sin_rad = sin(radian); VJOIN2(result, center, cos_rad, axis_a, sin_rad, axis_b); }
HIDDEN int rt_pattern_rect_orthogrid(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir, const vect_t a_vec, const vect_t b_vec, const fastf_t da, const fastf_t db) { int count = 0; point_t pt; vect_t a_dir; vect_t b_dir; fastf_t x, y; fastf_t a_length = MAGNITUDE(a_vec); fastf_t b_length = MAGNITUDE(b_vec); if (!rays || !ray_cnt) return -1; VMOVE(a_dir, a_vec); VUNITIZE(a_dir); VMOVE(b_dir, b_vec); VUNITIZE(b_dir); /* Find out how much memory we'll need and get it */ for (y = -b_length; y <= b_length; y += db) { for (x = -a_length; x <= a_length; x += da) { count++; } } *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, count + 1, "rays"); /* Now that we have memory, reset count so it can * be used to index into the array */ count = 0; /* Build the rays */ for (y = -b_length; y <= b_length; y += db) { for (x = -a_length; x <= a_length; x += da) { VJOIN2(pt, center_pt, x, a_dir, y, b_dir); (*rays)[6*count] = pt[0]; (*rays)[6*count+1] = pt[1]; (*rays)[6*count+2] = pt[2]; (*rays)[6*count+3] = dir[0]; (*rays)[6*count+4] = dir[1]; (*rays)[6*count+5] = dir[2]; count++; } } *(ray_cnt) = count; return count; }
HIDDEN int rt_pattern_circ_spiral(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir, const double radius, const int rays_per_ring, const int nring, const double delta) { int ring; double fraction = 1.0; double theta; double radial_scale; vect_t avec, bvec; int ray_index = 0; bn_vec_ortho(avec, dir); VCROSS(bvec, dir, avec); VUNITIZE(bvec); if (!rays || !ray_cnt) return -1; *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, (rays_per_ring * nring) + 1, "rays"); for (ring = 0; ring < nring; ring++) { register int i; theta = 0; fraction = ((double)(ring+1)) / nring; theta = delta * fraction; /* spiral skew */ radial_scale = radius * fraction; for (i=0; i < rays_per_ring; i++) { register double ct, st; point_t pt; /* pt = V + cos(theta) * A + sin(theta) * B */ ct = cos(theta) * radial_scale; st = sin(theta) * radial_scale; VJOIN2(pt, center_pt, ct, avec, st, bvec); (*rays)[6*ray_index] = pt[0]; (*rays)[6*ray_index+1] = pt[1]; (*rays)[6*ray_index+2] = pt[2]; (*rays)[6*ray_index+3] = dir[0]; (*rays)[6*ray_index+4] = dir[1]; (*rays)[6*ray_index+5] = dir[2]; theta += delta; ray_index++; } } *(ray_cnt) = ray_index; return ray_index; }
int rt_gen_frustum(struct xrays *rays, const struct xray *center_ray, const vect_t a_vec, const vect_t b_vec, const fastf_t a_theta, const fastf_t b_theta, const fastf_t a_num, const fastf_t UNUSED(b_num)) { int count = 0; point_t start; vect_t orig_dir; fastf_t x, y; fastf_t a_length = tan(a_theta); fastf_t b_length = tan(b_theta); fastf_t a_inc = 2 * a_length / (a_num - 1); vect_t a_dir, b_dir; register struct xrays *xrayp; VMOVE(start, center_ray->r_pt); VMOVE(orig_dir, center_ray->r_dir); VMOVE(a_dir, a_vec); VUNITIZE(a_dir); VMOVE(b_dir, b_vec); VUNITIZE(b_dir); /* This adds BN_TOL_DIST to the *_length variables in the * condition because in some cases, floating-point problems can * make extremely close numbers compare incorrectly. */ for (y = -b_length; y <= b_length + BN_TOL_DIST;) { for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) { BU_ALLOC(xrayp, struct xrays); VMOVE(xrayp->ray.r_pt, start); VJOIN2(xrayp->ray.r_dir, orig_dir, x, a_dir, y, b_dir); VUNITIZE(xrayp->ray.r_dir); xrayp->ray.index = count++; xrayp->ray.magic = RT_RAY_MAGIC; BU_LIST_APPEND(&rays->l, &xrayp->l); } } return count; }
int rt_gen_elliptical_grid(struct xrays *rays, const struct xray *center_ray, const fastf_t *avec, const fastf_t *bvec, fastf_t gridsize) { register struct xrays *xrayp; int count = 0; point_t C; vect_t dir; vect_t a_dir; vect_t b_dir; fastf_t a = MAGNITUDE(avec); fastf_t b = MAGNITUDE(bvec); fastf_t x, y; int acpr = a / gridsize; int bcpr = b / gridsize; VMOVE(a_dir, avec); VUNITIZE(a_dir); VMOVE(b_dir, bvec); VUNITIZE(b_dir); VMOVE(C, center_ray->r_pt); VMOVE(dir, center_ray->r_dir); /* make sure avec perpendicular to bvec perpendicular to ray direction */ BU_ASSERT(NEAR_ZERO(VDOT(avec, bvec), VUNITIZE_TOL)); BU_ASSERT(NEAR_ZERO(VDOT(avec, dir), VUNITIZE_TOL)); for (y=gridsize * (-bcpr); y <= b; y=y+gridsize) { for (x= gridsize * (-acpr); x <= a; x=x+gridsize) { if (((x*x)/(a*a) + (y*y)/(b*b)) < 1) { BU_ALLOC(xrayp, struct xrays); VJOIN2(xrayp->ray.r_pt, C, x, a_dir, y, b_dir); VMOVE(xrayp->ray.r_dir, dir); xrayp->ray.index = count++; xrayp->ray.magic = RT_RAY_MAGIC; BU_LIST_APPEND(&rays->l, &xrayp->l); } } } return count; }
/** * Compute the origin for this ray, based upon the number of samples * per pixel and the number of the current sample. For certain * ray-counts, it is highly advantageous to subdivide the pixel and * fire each ray in a specific sub-section of the pixel. */ static void jitter_start_pt(vect_t point, struct application *a, int samplenum, int pat_num) { fastf_t dx, dy; if (pat_num >= 0) { dx = a->a_x + pt_pats[pat_num].coords[samplenum*2] + (bn_rand_half(a->a_resource->re_randptr) * pt_pats[pat_num].rand_scale[X]); dy = a->a_y + pt_pats[pat_num].coords[samplenum*2 + 1] + (bn_rand_half(a->a_resource->re_randptr) * pt_pats[pat_num].rand_scale[Y]); } else { dx = a->a_x + bn_rand_half(a->a_resource->re_randptr); dy = a->a_y + bn_rand_half(a->a_resource->re_randptr); } VJOIN2(point, viewbase_model, dx, dx_model, dy, dy_model); }
int rt_gen_rect(struct xrays *rays, const struct xray *center_ray, const vect_t a_vec, const vect_t b_vec, const fastf_t da, const fastf_t db) { int count = 0; point_t orig_start; vect_t dir; fastf_t x, y; fastf_t a_length = MAGNITUDE(a_vec); fastf_t b_length = MAGNITUDE(b_vec); vect_t a_dir; vect_t b_dir; register struct xrays *xrayp; VMOVE(orig_start, center_ray->r_pt); VMOVE(dir, center_ray->r_dir); VMOVE(a_dir, a_vec); VUNITIZE(a_dir); VMOVE(b_dir, b_vec); VUNITIZE(b_dir); for (y = -b_length; y <= b_length; y += db) { for (x = -a_length; x <= a_length; x += da) { BU_ALLOC(xrayp, struct xrays); VJOIN2(xrayp->ray.r_pt, orig_start, x, a_dir, y, b_dir); VMOVE(xrayp->ray.r_dir, dir); xrayp->ray.index = count++; xrayp->ray.magic = RT_RAY_MAGIC; BU_LIST_APPEND(&rays->l, &xrayp->l); } } return count; }
int rt_raybundle_maker(struct xray *rp, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring) { register struct xray *rayp = rp+1; int ring; double fraction = 1.0; double theta; double delta; double radial_scale; int count = 0; rp[0].index = count++; rp[0].magic =RT_RAY_MAGIC; for (ring=0; ring < nring; ring++) { register int i; theta = 0; delta = M_2PI / rays_per_ring; fraction = ((double)(ring+1)) / nring; theta = delta * fraction; /* spiral skew */ radial_scale = radius * fraction; for (i=0; i < rays_per_ring; i++) { register double ct, st; /* pt = V + cos(theta) * A + sin(theta) * B */ ct = cos(theta) * radial_scale; st = sin(theta) * radial_scale; VJOIN2(rayp->r_pt, rp[0].r_pt, ct, avec, st, bvec); VMOVE(rayp->r_dir, rp[0].r_dir); rayp->index = count++; rayp->magic = RT_RAY_MAGIC; theta += delta; rayp++; } } return count; }
/* * Default keypoint in model space is established in "pt". Returns * GED_ERROR if unable to determine a keypoint, otherwise returns * GED_OK. */ int _ged_get_solid_keypoint(struct ged *const gedp, fastf_t *const pt, const struct rt_db_internal *const ip, const fastf_t *const mat) { point_t mpt; RT_CK_DB_INTERNAL(ip); switch (ip->idb_type) { case ID_CLINE: { struct rt_cline_internal *cli = (struct rt_cline_internal *)ip->idb_ptr; RT_CLINE_CK_MAGIC(cli); VMOVE(mpt, cli->v); break; } case ID_PARTICLE: { struct rt_part_internal *part = (struct rt_part_internal *)ip->idb_ptr; RT_PART_CK_MAGIC(part); VMOVE(mpt, part->part_V); break; } case ID_PIPE: { struct rt_pipe_internal *pipeip; struct wdb_pipept *pipe_seg; pipeip = (struct rt_pipe_internal *)ip->idb_ptr; RT_PIPE_CK_MAGIC(pipeip); pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head); VMOVE(mpt, pipe_seg->pp_coord); break; } case ID_METABALL: { struct rt_metaball_internal *metaball = (struct rt_metaball_internal *)ip->idb_ptr; struct wdb_metaballpt *metaballpt; RT_METABALL_CK_MAGIC(metaball); VSETALL(mpt, 0.0); metaballpt = BU_LIST_FIRST(wdb_metaballpt, &metaball->metaball_ctrl_head); VMOVE(mpt, metaballpt->coord); break; } case ID_ARBN: { struct rt_arbn_internal *arbn = (struct rt_arbn_internal *)ip->idb_ptr; size_t i, j, k; int good_vert = 0; RT_ARBN_CK_MAGIC(arbn); for (i = 0; i < arbn->neqn; i++) { for (j = i + 1; j < arbn->neqn; j++) { for (k = j + 1; k < arbn->neqn; k++) { if (!bn_mkpoint_3planes(mpt, arbn->eqn[i], arbn->eqn[j], arbn->eqn[k])) { size_t l; good_vert = 1; for (l = 0; l < arbn->neqn; l++) { if (l == i || l == j || l == k) continue; if (DIST_PT_PLANE(mpt, arbn->eqn[l]) > gedp->ged_wdbp->wdb_tol.dist) { good_vert = 0; break; } } if (good_vert) break; } } if (good_vert) break; } if (good_vert) break; } break; } case ID_EBM: { struct rt_ebm_internal *ebm = (struct rt_ebm_internal *)ip->idb_ptr; point_t pnt; RT_EBM_CK_MAGIC(ebm); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, ebm->mat, pnt); break; } case ID_BOT: { struct rt_bot_internal *bot = (struct rt_bot_internal *)ip->idb_ptr; VMOVE(mpt, bot->vertices); break; } case ID_DSP: { struct rt_dsp_internal *dsp = (struct rt_dsp_internal *)ip->idb_ptr; point_t pnt; RT_DSP_CK_MAGIC(dsp); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, dsp->dsp_stom, pnt); break; } case ID_HF: { struct rt_hf_internal *hf = (struct rt_hf_internal *)ip->idb_ptr; RT_HF_CK_MAGIC(hf); VMOVE(mpt, hf->v); break; } case ID_VOL: { struct rt_vol_internal *vol = (struct rt_vol_internal *)ip->idb_ptr; point_t pnt; RT_VOL_CK_MAGIC(vol); VSETALL(pnt, 0.0); MAT4X3PNT(mpt, vol->mat, pnt); break; } case ID_HALF: { struct rt_half_internal *haf = (struct rt_half_internal *)ip->idb_ptr; RT_HALF_CK_MAGIC(haf); VSCALE(mpt, haf->eqn, haf->eqn[H]); break; } case ID_ARB8: { struct rt_arb_internal *arb = (struct rt_arb_internal *)ip->idb_ptr; RT_ARB_CK_MAGIC(arb); VMOVE(mpt, arb->pt[0]); break; } case ID_ELL: case ID_SPH: { struct rt_ell_internal *ell = (struct rt_ell_internal *)ip->idb_ptr; RT_ELL_CK_MAGIC(ell); VMOVE(mpt, ell->v); break; } case ID_SUPERELL: { struct rt_superell_internal *superell = (struct rt_superell_internal *)ip->idb_ptr; RT_SUPERELL_CK_MAGIC(superell); VMOVE(mpt, superell->v); break; } case ID_TOR: { struct rt_tor_internal *tor = (struct rt_tor_internal *)ip->idb_ptr; RT_TOR_CK_MAGIC(tor); VMOVE(mpt, tor->v); break; } case ID_TGC: case ID_REC: { struct rt_tgc_internal *tgc = (struct rt_tgc_internal *)ip->idb_ptr; RT_TGC_CK_MAGIC(tgc); VMOVE(mpt, tgc->v); break; } case ID_GRIP: { struct rt_grip_internal *gip = (struct rt_grip_internal *)ip->idb_ptr; RT_GRIP_CK_MAGIC(gip); VMOVE(mpt, gip->center); break; } case ID_ARS: { struct rt_ars_internal *ars = (struct rt_ars_internal *)ip->idb_ptr; RT_ARS_CK_MAGIC(ars); VMOVE(mpt, &ars->curves[0][0]); break; } case ID_RPC: { struct rt_rpc_internal *rpc = (struct rt_rpc_internal *)ip->idb_ptr; RT_RPC_CK_MAGIC(rpc); VMOVE(mpt, rpc->rpc_V); break; } case ID_RHC: { struct rt_rhc_internal *rhc = (struct rt_rhc_internal *)ip->idb_ptr; RT_RHC_CK_MAGIC(rhc); VMOVE(mpt, rhc->rhc_V); break; } case ID_EPA: { struct rt_epa_internal *epa = (struct rt_epa_internal *)ip->idb_ptr; RT_EPA_CK_MAGIC(epa); VMOVE(mpt, epa->epa_V); break; } case ID_EHY: { struct rt_ehy_internal *ehy = (struct rt_ehy_internal *)ip->idb_ptr; RT_EHY_CK_MAGIC(ehy); VMOVE(mpt, ehy->ehy_V); break; } case ID_HYP: { struct rt_hyp_internal *hyp = (struct rt_hyp_internal *)ip->idb_ptr; RT_HYP_CK_MAGIC(hyp); VMOVE(mpt, hyp->hyp_Vi); break; } case ID_ETO: { struct rt_eto_internal *eto = (struct rt_eto_internal *)ip->idb_ptr; RT_ETO_CK_MAGIC(eto); VMOVE(mpt, eto->eto_V); break; } case ID_POLY: { struct rt_pg_face_internal *_poly; struct rt_pg_internal *pg = (struct rt_pg_internal *)ip->idb_ptr; RT_PG_CK_MAGIC(pg); _poly = pg->poly; VMOVE(mpt, _poly->verts); break; } case ID_SKETCH: { struct rt_sketch_internal *skt = (struct rt_sketch_internal *)ip->idb_ptr; RT_SKETCH_CK_MAGIC(skt); VMOVE(mpt, skt->V); break; } case ID_EXTRUDE: { struct rt_extrude_internal *extr = (struct rt_extrude_internal *)ip->idb_ptr; RT_EXTRUDE_CK_MAGIC(extr); if (extr->skt && extr->skt->verts) { VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec, extr->skt->verts[0][1], extr->v_vec); } else { VMOVE(mpt, extr->V); } break; } case ID_NMG: { struct vertex *v; struct vertexuse *vu; struct edgeuse *eu; struct loopuse *lu; struct faceuse *fu; struct shell *s; struct nmgregion *r; struct model *m = (struct model *) ip->idb_ptr; NMG_CK_MODEL(m); /* set default first */ VSETALL(mpt, 0.0); if (BU_LIST_IS_EMPTY(&m->r_hd)) break; r = BU_LIST_FIRST(nmgregion, &m->r_hd); if (!r) break; NMG_CK_REGION(r); if (BU_LIST_IS_EMPTY(&r->s_hd)) break; s = BU_LIST_FIRST(shell, &r->s_hd); if (!s) break; NMG_CK_SHELL(s); if (BU_LIST_IS_EMPTY(&s->fu_hd)) fu = (struct faceuse *)NULL; else fu = BU_LIST_FIRST(faceuse, &s->fu_hd); if (fu) { NMG_CK_FACEUSE(fu); lu = BU_LIST_FIRST(loopuse, &fu->lu_hd); NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->lu_hd)) lu = (struct loopuse *)NULL; else lu = BU_LIST_FIRST(loopuse, &s->lu_hd); if (lu) { NMG_CK_LOOPUSE(lu); if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) { eu = BU_LIST_FIRST(edgeuse, &lu->down_hd); NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; } else { vu = BU_LIST_FIRST(vertexuse, &lu->down_hd); NMG_CK_VERTEXUSE(vu); v = vu->v_p; } NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } if (BU_LIST_IS_EMPTY(&s->eu_hd)) eu = (struct edgeuse *)NULL; else eu = BU_LIST_FIRST(edgeuse, &s->eu_hd); if (eu) { NMG_CK_EDGEUSE(eu); NMG_CK_VERTEXUSE(eu->vu_p); v = eu->vu_p->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } vu = s->vu_p; if (vu) { NMG_CK_VERTEXUSE(vu); v = vu->v_p; NMG_CK_VERTEX(v); if (!v->vg_p) break; VMOVE(mpt, v->vg_p->coord); break; } } default: VSETALL(mpt, 0.0); bu_vls_printf(gedp->ged_result_str, "get_solid_keypoint: unrecognized solid type"); return GED_ERROR; } MAT4X3PNT(pt, mat, mpt); return GED_OK; }
/* * 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); }
/* * Given a u, v coordinate within the texture (0 <= u, v <= 1.0), * compute a new surface normal. * For now we come up with a local coordinate system, and * make bump perturbations from the red and blue channels of * an RGB image. * * Note that .pix files are stored left-to-right, bottom-to-top, * which works out very naturally for the indexing scheme. */ HIDDEN int bmp_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp) { register struct txt_specific *tp = (struct txt_specific *)dp; unsigned char *cp=NULL; fastf_t pertU, pertV; vect_t y; /* world coordinate axis vectors */ vect_t u, v; /* surface coord system vectors */ int i, j; /* bump map pixel indices */ /* * If no texture file present, or if * texture isn't and can't be read, give debug color. */ if ((bu_vls_strlen(&tp->tx_name) <= 0) || (!tp->tx_mp && !tp->tx_binunifp)) { VSET(swp->sw_color, swp->sw_uv.uv_u, 0, swp->sw_uv.uv_v); if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; } /* u is left->right index, v is line number bottom->top */ if (swp->sw_uv.uv_u < 0 || swp->sw_uv.uv_u > 1 || swp->sw_uv.uv_v < 0 || swp->sw_uv.uv_v > 1) { bu_log("bmp_render: bad u, v=%g, %g du, dv=%g, %g seg=%s\n", swp->sw_uv.uv_u, swp->sw_uv.uv_v, swp->sw_uv.uv_du, swp->sw_uv.uv_dv, pp->pt_inseg->seg_stp->st_name); VSET(swp->sw_color, 0, 1, 0); if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; } /* Find a local coordinate system */ VSET(y, 0, 1, 0); VCROSS(u, y, swp->sw_hit.hit_normal); VUNITIZE(u); VCROSS(v, swp->sw_hit.hit_normal, u); /* Find our RGB value */ i = swp->sw_uv.uv_u * (tp->tx_w-1); j = swp->sw_uv.uv_v * (tp->tx_n-1); if (tp->tx_mp) { cp = ((unsigned char *)(tp->tx_mp->buf)) + (j) * tp->tx_w * 3 + i * 3; } else if (tp->tx_binunifp) { cp = ((unsigned char *)(tp->tx_binunifp->u.uint8)) + (j) * tp->tx_w * 3 + i * 3; } else { /* not reachable */ bu_bomb("sh_text.c -- Unreachable code reached while reading datasource\n"); } pertU = ((fastf_t)(*cp) - 128.0) / 128.0; pertV = ((fastf_t)(*(cp+2)) - 128.0) / 128.0; if (rdebug&RDEBUG_LIGHT) { VPRINT("normal", swp->sw_hit.hit_normal); VPRINT("u", u); VPRINT("v", v); bu_log("cu = %d, cv = %d\n", *cp, *(cp+2)); bu_log("pertU = %g, pertV = %g\n", pertU, pertV); } VJOIN2(swp->sw_hit.hit_normal, swp->sw_hit.hit_normal, pertU, u, pertV, v); VUNITIZE(swp->sw_hit.hit_normal); if (rdebug&RDEBUG_LIGHT) { VPRINT("after", swp->sw_hit.hit_normal); } if (swp->sw_reflect > 0 || swp->sw_transmit > 0) (void)rr_render(ap, pp, swp); return 1; }
/** * 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"); } }
void rt_superell_16pts(fastf_t *ov, fastf_t *V, fastf_t *A, fastf_t *B) { static fastf_t c, d, e, f, g, h; e = h = .92388; /* cos(22.5 degrees) */ c = d = M_SQRT1_2; /* cos(45 degrees) */ g = f = .382683; /* cos(67.5 degrees) */ /* * For angle theta, compute surface point as * * V + cos(theta) * A + sin(theta) * B * * note that sin(theta) is cos(90-theta); arguments in degrees. */ VADD2(SUPERELLOUT(1), V, A); VJOIN2(SUPERELLOUT(2), V, e, A, f, B); VJOIN2(SUPERELLOUT(3), V, c, A, d, B); VJOIN2(SUPERELLOUT(4), V, g, A, h, B); VADD2(SUPERELLOUT(5), V, B); VJOIN2(SUPERELLOUT(6), V, -g, A, h, B); VJOIN2(SUPERELLOUT(7), V, -c, A, d, B); VJOIN2(SUPERELLOUT(8), V, -e, A, f, B); VSUB2(SUPERELLOUT(9), V, A); VJOIN2(SUPERELLOUT(10), V, -e, A, -f, B); VJOIN2(SUPERELLOUT(11), V, -c, A, -d, B); VJOIN2(SUPERELLOUT(12), V, -g, A, -h, B); VSUB2(SUPERELLOUT(13), V, B); VJOIN2(SUPERELLOUT(14), V, g, A, -h, B); VJOIN2(SUPERELLOUT(15), V, c, A, -d, B); VJOIN2(SUPERELLOUT(16), V, e, A, -f, B); }
int main( int argc, char *argv[] ) { struct application *ap; int c; int verbose = 0; int i, j; int grid_size = 64; fastf_t cell_size; vect_t model_size; vect_t xdir, zdir; int job_count=0; char **result_map = NULL; struct bu_ptbl objs; int my_session_id; int do_plot=0; struct timeval startTime; struct timeval endTime; double diff; point_t mdl_min; point_t mdl_max; struct bu_vlb *vlb; /* Things like bu_malloc() must have these initialized for use with parallel processing */ bu_semaphore_init( RT_SEM_LAST ); /* initialize the list of BRL-CAD objects to be raytraced (this is used for the "-o" option) */ bu_ptbl_init( &objs, 64, "objects" ); /* process command line args */ while ( (c=bu_getopt( argc, argv, "vps:o:" ) ) != -1 ) { switch ( c ) { case 'p': /* do print plot */ do_plot = 1; break; case 's': /* set the grid size (default is 64x64) */ grid_size = atoi( bu_optarg ); break; case 'v': /* turn on verbose logging */ verbose = 1; rts_set_verbosity( 1 ); break; case 'o': /* add an object name to the list of BRL-CAD objects to raytrace */ bu_ptbl_ins( &objs, (long *)bu_optarg ); break; default: /* ERROR */ bu_exit(1, usage, argv[0]); } } if (bu_debug & BU_DEBUG_MEM_CHECK) { bu_prmem("initial memory map"); bu_mem_barriercheck(); } /* shoot a ray ten times, cleaning and loading geometry each time */ for(i=0 ; i<10 ; i++) { /* load geometry */ my_session_id = loadGeometry( argv[bu_optind], &objs ); if ( my_session_id < 0 ) { bu_exit(2, "Failed to load geometry from file (%s)\n", argv[bu_optind] ); } get_model_extents( my_session_id, mdl_min, mdl_max ); VSET( xdir, 1, 0, 0 ); VSET( zdir, 0, 0, 1 ); VSUB2( model_size, mdl_max, mdl_min ); ap = NULL; getApplication(&ap); VJOIN2( ap->a_ray.r_pt, mdl_min, model_size[Z]/2.0, zdir, model_size[X]/2.0, xdir ); VSET( ap->a_ray.r_dir, 0, 1, 0 ); rts_shootray(ap); vlb = (struct bu_vlb*)ap->a_uptr; printHits(vlb); freeApplication(ap); /*rts_clean( my_session_id );*/ bu_log( "\n\n********* %d\n", i); if (bu_debug & BU_DEBUG_MEM_CHECK) { bu_prmem("memory after shutdown"); } } my_session_id = loadGeometry( argv[bu_optind], &objs ); /* submit some jobs */ fprintf( stderr, "\nfiring a grid (%dx%d) of rays at", grid_size, grid_size ); for ( i=0; i<(int)BU_PTBL_LEN( &objs ); i++ ) { fprintf( stderr, " %s", (char *)BU_PTBL_GET( &objs, i ) ); } fprintf( stderr, "...\n" ); if( do_plot ) { result_map = (char **)bu_calloc( grid_size, sizeof( char *), "result_map" ); for ( i=0; i<grid_size; i++ ) { result_map[i] = (char *)bu_calloc( (grid_size+1), sizeof( char ), "result_map[i]" ); } } cell_size = model_size[X] / grid_size; gettimeofday( &startTime, NULL ); for ( i=0; i<grid_size; i++ ) { if( verbose ) { fprintf( stderr, "shooting row %d\n", i ); } for ( j=0; j<grid_size; j++ ) { int hitCount; getApplication(&ap); ap->a_user = my_session_id; VJOIN2( ap->a_ray.r_pt, mdl_min, i*cell_size, zdir, j*cell_size, xdir ); ap->a_ray.index = ap->a_user; VSET( ap->a_ray.r_dir, 0, 1, 0 ); rts_shootray(ap); if( do_plot ) { hitCount = countHits(ap->a_uptr); if ( hitCount == 0 ) { result_map[i][j] = ' '; } else if ( hitCount <= 9 ) { result_map[i][j] = '0' + hitCount; } else { result_map[i][j] = '*'; } } freeApplication(ap); job_count++; } } gettimeofday( &endTime, NULL ); diff = endTime.tv_sec - startTime.tv_sec + (endTime.tv_usec - startTime.tv_usec) / 1000000.0; fprintf( stderr, "time for %d individual rays: %g second\n", job_count, diff ); if(do_plot) { for ( i=grid_size-1; i>=0; i-- ) { fprintf( stderr, "%s\n", result_map[i] ); } } return 0; }
void do_pixel(int cpu, int pat_num, int pixelnum) { struct application a; struct pixel_ext pe; vect_t stereo_point; /* Ref point on eye or view plane */ vect_t point; /* Ref point on eye or view plane */ vect_t colorsum = {(fastf_t)0.0, (fastf_t)0.0, (fastf_t)0.0}; int samplenum = 0; static const double one_over_255 = 1.0 / 255.0; const int pindex = (pixelnum * sizeof(RGBpixel)); if (lightmodel == 8) { /* Add timer here to start pixel-time for heat * graph, when asked. */ rt_prep_timer(); } /* Obtain fresh copy of global application struct */ a = APP; /* struct copy */ a.a_resource = &resource[cpu]; if (incr_mode) { register int i = 1<<incr_level; a.a_y = pixelnum/i; a.a_x = pixelnum - (a.a_y * i); /* a.a_x = pixelnum%i; */ if (incr_level != 0) { /* See if already done last pass */ if (((a.a_x & 1) == 0) && ((a.a_y & 1) == 0)) return; } a.a_x <<= (incr_nlevel-incr_level); a.a_y <<= (incr_nlevel-incr_level); } else { a.a_y = pixelnum/width; a.a_x = pixelnum - (a.a_y * width); /* a.a_x = pixelnum%width; */ } if (Query_one_pixel) { if (a.a_x == query_x && a.a_y == query_y) { rdebug = query_rdebug; RTG.debug = query_debug; } else { RTG.debug = rdebug = 0; } } if (sub_grid_mode) { if (a.a_x < sub_xmin || a.a_x > sub_xmax) return; if (a.a_y < sub_ymin || a.a_y > sub_ymax) return; } if (fullfloat_mode) { register struct floatpixel *fp; fp = &curr_float_frame[a.a_y*width + a.a_x]; if (fp->ff_frame >= 0) { return; /* pixel was reprojected */ } } /* Check the pixel map to determine if this image should be * rendered or not. */ if (pixmap) { a.a_user= 1; /* Force Shot Hit */ if (pixmap[pindex + RED] + pixmap[pindex + GRN] + pixmap[pindex + BLU]) { /* non-black pixmap pixel */ a.a_color[RED]= (double)(pixmap[pindex + RED]) * one_over_255; a.a_color[GRN]= (double)(pixmap[pindex + GRN]) * one_over_255; a.a_color[BLU]= (double)(pixmap[pindex + BLU]) * one_over_255; /* we're done */ view_pixel(&a); if ((size_t)a.a_x == width-1) { view_eol(&a); /* End of scan line */ } return; } } /* our starting point, used for non-jitter */ VJOIN2 (point, viewbase_model, a.a_x, dx_model, a.a_y, dy_model); /* not tracing the corners of a prism by default */ a.a_pixelext=(struct pixel_ext *)NULL; /* black or no pixmap, so compute the pixel(s) */ /* LOOP BELOW IS UNROLLED ONE SAMPLE SINCE THAT'S THE COMMON CASE. * * XXX - If you edit the unrolled or non-unrolled section, be sure * to edit the other section. */ if (hypersample == 0) { /* not hypersampling, so just do it */ /****************/ /* BEGIN UNROLL */ /****************/ if (jitter & JITTER_CELL) { jitter_start_pt(point, &a, samplenum, pat_num); } if (a.a_rt_i->rti_prismtrace) { /* compute the four corners */ pe.magic = PIXEL_EXT_MAGIC; VJOIN2(pe.corner[0].r_pt, viewbase_model, a.a_x, dx_model, a.a_y, dy_model); VJOIN2(pe.corner[1].r_pt, viewbase_model, (a.a_x+1), dx_model, a.a_y, dy_model); VJOIN2(pe.corner[2].r_pt, viewbase_model, (a.a_x+1), dx_model, (a.a_y+1), dy_model); VJOIN2(pe.corner[3].r_pt, viewbase_model, a.a_x, dx_model, (a.a_y+1), dy_model); a.a_pixelext = &pe; } if (rt_perspective > 0.0) { VSUB2(a.a_ray.r_dir, point, eye_model); VUNITIZE(a.a_ray.r_dir); VMOVE(a.a_ray.r_pt, eye_model); if (a.a_rt_i->rti_prismtrace) { VSUB2(pe.corner[0].r_dir, pe.corner[0].r_pt, eye_model); VSUB2(pe.corner[1].r_dir, pe.corner[1].r_pt, eye_model); VSUB2(pe.corner[2].r_dir, pe.corner[2].r_pt, eye_model); VSUB2(pe.corner[3].r_dir, pe.corner[3].r_pt, eye_model); } } else { VMOVE(a.a_ray.r_pt, point); VMOVE(a.a_ray.r_dir, APP.a_ray.r_dir); if (a.a_rt_i->rti_prismtrace) { VMOVE(pe.corner[0].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[1].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[2].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[3].r_dir, a.a_ray.r_dir); } } if (report_progress) { report_progress = 0; bu_log("\tframe %d, xy=%d, %d on cpu %d, samp=%d\n", curframe, a.a_x, a.a_y, cpu, samplenum); } a.a_level = 0; /* recursion level */ a.a_purpose = "main ray"; (void)rt_shootray(&a); if (stereo) { fastf_t right, left; right = CRT_BLEND(a.a_color); VSUB2(stereo_point, point, left_eye_delta); if (rt_perspective > 0.0) { VSUB2(a.a_ray.r_dir, stereo_point, eye_model); VUNITIZE(a.a_ray.r_dir); VADD2(a.a_ray.r_pt, eye_model, left_eye_delta); } else { VMOVE(a.a_ray.r_pt, stereo_point); } a.a_level = 0; /* recursion level */ a.a_purpose = "left eye ray"; (void)rt_shootray(&a); left = CRT_BLEND(a.a_color); VSET(a.a_color, left, 0, right); } VADD2(colorsum, colorsum, a.a_color); /**************/ /* END UNROLL */ /**************/ } else { /* hypersampling, so iterate */ for (samplenum=0; samplenum<=hypersample; samplenum++) { /* shoot at a point based on the jitter pattern number */ /**********************/ /* BEGIN NON-UNROLLED */ /**********************/ if (jitter & JITTER_CELL) { jitter_start_pt(point, &a, samplenum, pat_num); } if (a.a_rt_i->rti_prismtrace) { /* compute the four corners */ pe.magic = PIXEL_EXT_MAGIC; VJOIN2(pe.corner[0].r_pt, viewbase_model, a.a_x, dx_model, a.a_y, dy_model); VJOIN2(pe.corner[1].r_pt, viewbase_model, (a.a_x+1), dx_model, a.a_y, dy_model); VJOIN2(pe.corner[2].r_pt, viewbase_model, (a.a_x+1), dx_model, (a.a_y+1), dy_model); VJOIN2(pe.corner[3].r_pt, viewbase_model, a.a_x, dx_model, (a.a_y+1), dy_model); a.a_pixelext = &pe; } if (rt_perspective > 0.0) { VSUB2(a.a_ray.r_dir, point, eye_model); VUNITIZE(a.a_ray.r_dir); VMOVE(a.a_ray.r_pt, eye_model); if (a.a_rt_i->rti_prismtrace) { VSUB2(pe.corner[0].r_dir, pe.corner[0].r_pt, eye_model); VSUB2(pe.corner[1].r_dir, pe.corner[1].r_pt, eye_model); VSUB2(pe.corner[2].r_dir, pe.corner[2].r_pt, eye_model); VSUB2(pe.corner[3].r_dir, pe.corner[3].r_pt, eye_model); } } else { VMOVE(a.a_ray.r_pt, point); VMOVE(a.a_ray.r_dir, APP.a_ray.r_dir); if (a.a_rt_i->rti_prismtrace) { VMOVE(pe.corner[0].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[1].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[2].r_dir, a.a_ray.r_dir); VMOVE(pe.corner[3].r_dir, a.a_ray.r_dir); } } if (report_progress) { report_progress = 0; bu_log("\tframe %d, xy=%d, %d on cpu %d, samp=%d\n", curframe, a.a_x, a.a_y, cpu, samplenum); } a.a_level = 0; /* recursion level */ a.a_purpose = "main ray"; (void)rt_shootray(&a); if (stereo) { fastf_t right, left; right = CRT_BLEND(a.a_color); VSUB2(stereo_point, point, left_eye_delta); if (rt_perspective > 0.0) { VSUB2(a.a_ray.r_dir, stereo_point, eye_model); VUNITIZE(a.a_ray.r_dir); VADD2(a.a_ray.r_pt, eye_model, left_eye_delta); } else { VMOVE(a.a_ray.r_pt, stereo_point); } a.a_level = 0; /* recursion level */ a.a_purpose = "left eye ray"; (void)rt_shootray(&a); left = CRT_BLEND(a.a_color); VSET(a.a_color, left, 0, right); } VADD2(colorsum, colorsum, a.a_color); /********************/ /* END NON-UNROLLED */ /********************/ } /* for samplenum <= hypersample */ { /* scale the hypersampled results */ fastf_t f; f = 1.0 / (hypersample+1); VSCALE(a.a_color, colorsum, f); } } /* end unrolling else case */ /* bu_log("2: [%d, %d] : [%.2f, %.2f, %.2f]\n", pixelnum%width, pixelnum/width, a.a_color[0], a.a_color[1], a.a_color[2]); */ /* FIXME: this should work on windows after the bu_timer() is * created to replace the librt timing mechanism. */ #if !defined(_WIN32) || defined(__CYGWIN__) /* Add get_pixel_timer here to get total time taken to get pixel, when asked */ if (lightmodel == 8) { fastf_t pixelTime; fastf_t **timeTable; pixelTime = rt_get_timer(NULL,NULL); /* bu_log("PixelTime = %lf X:%d Y:%d\n", pixelTime, a.a_x, a.a_y); */ bu_semaphore_acquire(RT_SEM_LAST-2); timeTable = timeTable_init(width, height); timeTable_input(a.a_x, a.a_y, pixelTime, timeTable); bu_semaphore_release(RT_SEM_LAST-2); } #endif /* we're done */ view_pixel(&a); if ((size_t)a.a_x == width-1) { view_eol(&a); /* End of scan line */ } return; }