/* add all hit point info to info list */ HIDDEN int add_hit_pnts(struct application *app, struct partition *partH, struct seg *UNUSED(segs)) { struct partition *pp; struct soltab *stp; /*point_t hit_pnt; vect_t hit_normal;*/ struct rt_point_container *c = (struct rt_point_container *)(app->a_uptr); struct npoints *npt; if (c->pnt_cnt > c->capacity-1) { c->capacity *= 4; c->pts = (struct npoints *)bu_realloc((char *)c->pts, c->capacity * sizeof(struct npoints), "enlarge results array"); } RT_CK_APPLICATION(app); /*struct bu_vls *fp = (struct bu_vls *)(app->a_uptr);*/ /* add all hit points */ for (pp = partH->pt_forw; pp != partH; pp = pp->pt_forw) { npt = &(c->pts[c->pnt_cnt]); /* add "in" hit point info */ stp = pp->pt_inseg->seg_stp; /* hack fix for bad tgc surfaces */ if (bu_strncmp("rec", stp->st_meth->ft_label, 3) == 0 || bu_strncmp("tgc", stp->st_meth->ft_label, 3) == 0) { /* correct invalid surface number */ if (pp->pt_inhit->hit_surfno < 1 || pp->pt_inhit->hit_surfno > 3) { pp->pt_inhit->hit_surfno = 2; } if (pp->pt_outhit->hit_surfno < 1 || pp->pt_outhit->hit_surfno > 3) { pp->pt_outhit->hit_surfno = 2; } } VJOIN1(npt->in.p, app->a_ray.r_pt, pp->pt_inhit->hit_dist, app->a_ray.r_dir); RT_HIT_NORMAL(npt->in.n, pp->pt_inhit, stp, &(app->a_ray), pp->pt_inflip); npt->in.is_set = 1; //bu_vls_printf(fp, "%f %f %f %f %f %f\n", hit_pnt[0], hit_pnt[1], hit_pnt[2], hit_normal[0], hit_normal[1], hit_normal[2]); /* add "out" hit point info (unless half-space) */ stp = pp->pt_inseg->seg_stp; if (bu_strncmp("half", stp->st_meth->ft_label, 4) != 0) { VJOIN1(npt->out.p, app->a_ray.r_pt, pp->pt_outhit->hit_dist, app->a_ray.r_dir); RT_HIT_NORMAL(npt->out.n, pp->pt_outhit, stp, &(app->a_ray), pp->pt_outflip); npt->out.is_set = 1; //bu_vls_printf(fp, "%f %f %f %f %f %f\n", hit_pnt[0], hit_pnt[1], hit_pnt[2], hit_normal[0], hit_normal[1], hit_normal[2]); } c->pnt_cnt++; } return 1; }
int BrlCadInterface::hit(application *ap, struct partition *PartHeadp, seg *segs) { register struct partition *pp; register struct hit *hitp; register struct soltab *stp; struct curvature cur; point_t pt; vect_t inormal; vect_t onormal; double curv; int N = 0; //for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) { pp = PartHeadp->pt_forw; { ++N; hitp = pp->pt_inhit; stp = pp->pt_inseg->seg_stp; VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip); RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp); curv = max(fabs(cur.crv_c1), fabs(cur.crv_c2)); m_InRadius = 1.0/max(1e-10, curv); m_XIn[0] = pt[0]; m_XIn[1] = pt[1]; m_XIn[2] = pt[2]; m_InNormal[0] = inormal[0]; m_InNormal[1] = inormal[1]; m_InNormal[2] = inormal[2]; hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); RT_HIT_NORMAL( onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip ); RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp); curv = max(fabs(cur.crv_c1), fabs(cur.crv_c2)); m_OutRadius = 1.0/max(1e-10, curv); m_XOut[0] = pt[0]; m_XOut[1] = pt[1]; m_XOut[2] = pt[2]; m_OutNormal[0] = onormal[0]; m_OutNormal[1] = onormal[1]; m_OutNormal[2] = onormal[2]; } m_Hit = true; return(0); }
/** * Given the data returned by a previous call to frshot(), compute the * surface normal at the entry point to the indicated solid. * * In order to save storage, and copying time, frshot() saved only the * minimum amount of data required. Here, the hit and xray structures * are reconstructed, suitable for passing to RT_HIT_NORMAL. */ void BU_FORTRAN(frnorm, FRNORM)(double *normal, /* output only */ int *idx, /* input only */ double *indist, struct context *context, double *UNUSED(pt), double *UNUSED(dir)) { register struct context *ctp; struct hit hit; struct soltab *stp; register int i; i = *idx - 1; /* Selects which inhit is used */ /* Reconstruct the hit structure */ hit.hit_dist = indist[i]; ctp = &context[i]; stp = ctp->co_stp; VMOVE(hit.hit_vpriv, ctp->co_vpriv); hit.hit_private = ctp->co_priv; /* The new macro doesn't use ray argument */ RT_HIT_NORMAL(normal, &hit, stp, NULL, ctp->co_inflip); }
int rayhit2(struct application *ap, register struct partition *pt, struct seg *UNUSED(segp)) { struct partition *pp = pt->pt_forw; struct hit *hitp = pt->pt_forw->pt_inhit; struct cell *c = (struct cell *)ap->a_uptr; c->c_ishit = 1; c->c_region = pp->pt_regionp; c->c_id = pp->pt_regionp->reg_regionid; VMOVE(c->c_rdir, ap->a_ray.r_dir); VJOIN1(c->c_hit, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); RT_HIT_NORMAL(c->c_normal, hitp, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip); c->c_dist = hitp->hit_dist; return 1; }
/* * 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); }
/** * rt_shootray() was told to call this on a hit. * * This callback routine utilizes the application structure which * describes the current state of the raytrace. * * This callback routine is provided a circular linked list of * partitions, each one describing one in and out segment of one * region for each region encountered. * * The 'segs' segment list is unused in this example. */ int hit(struct application *ap, struct partition *PartHeadp, struct seg *segs) { /* iterating over partitions, this will keep track of the current * partition we're working on. */ struct partition *pp; /* will serve as a pointer for the entry and exit hitpoints */ struct hit *hitp; /* will serve as a pointer to the solid primitive we hit */ struct soltab *stp; /* will contain surface curvature information at the entry */ struct curvature cur; /* will contain our hit point coordinate */ point_t pt; /* will contain normal vector where ray enters geometry */ vect_t inormal; /* will contain normal vector where ray exits geometry */ vect_t onormal; /* iterate over each partition until we get back to the head. * each partition corresponds to a specific homogeneous region of * material. */ for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) { /* print the name of the region we hit as well as the name of * the primitives encountered on entry and exit. */ bu_log("\n--- Hit region %s (in %s, out %s)\n", pp->pt_regionp->reg_name, pp->pt_inseg->seg_stp->st_name, pp->pt_outseg->seg_stp->st_name ); /* entry hit point, so we type less */ hitp = pp->pt_inhit; /* construct the actual (entry) hit-point from the ray and the * distance to the intersection point (i.e., the 't' value). */ VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); /* primitive we encountered on entry */ stp = pp->pt_inseg->seg_stp; /* compute the normal vector at the entry point, flipping the * normal if necessary. */ RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip); /* print the entry hit point info */ rt_pr_hit(" In", hitp); VPRINT( " Ipoint", pt); VPRINT( " Inormal", inormal); /* This next macro fills in the curvature information which * consists on a principle direction vector, and the inverse * radii of curvature along that direction and perpendicular * to it. Positive curvature bends toward the outward * pointing normal. */ RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp); /* print the entry curvature information */ VPRINT("PDir", cur.crv_pdir); bu_log(" c1=%g\n", cur.crv_c1); bu_log(" c2=%g\n", cur.crv_c2); /* exit point, so we type less */ hitp = pp->pt_outhit; /* construct the actual (exit) hit-point from the ray and the * distance to the intersection point (i.e., the 't' value). */ VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); /* primitive we exited from */ stp = pp->pt_outseg->seg_stp; /* compute the normal vector at the exit point, flipping the * normal if necessary. */ RT_HIT_NORMAL(onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip); /* print the exit hit point info */ rt_pr_hit(" Out", hitp); VPRINT( " Opoint", pt); VPRINT( " Onormal", onormal); } /* A more complicated application would probably fill in a new * local application structure and describe, for example, a * reflected or refracted ray, and then call rt_shootray() for * those rays. */ /* Hit routine callbacks generally return 1 on hit or 0 on miss. * This value is returned by rt_shootray(). */ return 1; }
//******************************************************************* // NAME hit_func // // INPUTS // ap - application structure // PartHeadp - pointer to the beginning of the trace list // // DESCRIPTION // Called when a shotline produces a hit. This user defined // callback copies the in and out hit points into structures and // stores them in the ray's result list. //******************************************************************* static int hit_func(struct application *ap, struct partition *PartHeadp, struct seg *) { /* iterating over partitions, this will keep track of the current * partition we're working on. */ struct partition *pp; /* will serve as a pointer for the entry and exit hitpoints */ struct hit *hitp; /* will serve as a pointer to the solid primitive we hit */ struct soltab *stp; /* output variables */ Interface::ray_results *result = (Interface::ray_results *) ap->a_uptr; Interface::one_hit singleHit; VMOVE(result->origin, ap->a_ray.r_pt); result->x = ap->a_x; result->y = ap->a_y; /* iterate over each partition until we get back to the head. * each partition corresponds to a specific homogeneous region of * material. */ for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) { /* entry hit point, so we type less */ hitp = pp->pt_inhit; /* primitive we encountered on entry */ stp = pp->pt_inseg->seg_stp; /* clear data struct */ ONE_HIT_INIT(singleHit); /* record IN hit point */ VJOIN1(singleHit.point, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); /* calculate IN normal vector */ /* compute the normal vector at the entry point, flipping the * normal if necessary. */ RT_HIT_NORMAL(singleHit.normal, hitp, stp, &(ap->a_ray), pp->pt_inflip); /* save IN solid and surface numbers */ /* singleHit.solidNumber = stp->st_bit; */ singleHit.solidName = stp->st_dp->d_namep; singleHit.solidSurface = hitp->hit_surfno; /* push hit to the result list */ result->hitData.push_back(singleHit); /* exit point, so we type less */ hitp = pp->pt_outhit; /* primitive we exited from */ stp = pp->pt_outseg->seg_stp; /* clear data struct */ ONE_HIT_INIT(singleHit); /* record OUT hit point */ VJOIN1(singleHit.point, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); /* calculate OUT normal vector */ /* compute the normal vector at the exit point, flipping the * normal if necessary. */ RT_HIT_NORMAL(singleHit.normal, hitp, stp, &(ap->a_ray), pp->pt_outflip); /* save OUT solid and surface numbers */ /* singleHit.solidNumber = stp->st_bit; */ singleHit.solidName = stp->st_dp->d_namep; singleHit.solidSurface = hitp->hit_surfno; /* push hit to the result list */ result->hitData.push_back(singleHit); } return 1; }
int handle_main_ray(struct application *ap, register struct partition *PartHeadp, struct seg *segp) { register struct partition *pp; register struct hit *hitp; /* which hit */ struct application a2; struct cell me; struct cell below; struct cell left; struct cell above; struct cell right; double intensity = 1.0; int edge = 0; int cpu; int oc = 1; RGBpixel col; RT_APPLICATION_INIT(&a2); memset(&me, 0, sizeof(struct cell)); memset(&below, 0, sizeof(struct cell)); memset(&left, 0, sizeof(struct cell)); cpu = ap->a_resource->re_cpu; if (PartHeadp == NULL || segp == NULL) { /* The main shotline missed. pack the application struct */ me.c_ishit = 0; me.c_dist = MISS_DIST; me.c_id = MISS_ID; me.c_region = 0; VSETALL(me.c_hit, MISS_DIST); VSETALL(me.c_normal, 0); VMOVE(me.c_rdir, ap->a_ray.r_dir); } else { pp = PartHeadp->pt_forw; hitp = pp->pt_inhit; /* * Stuff the information for this cell. */ me.c_ishit = 1; me.c_id = pp->pt_regionp->reg_regionid; me.c_dist = hitp->hit_dist; me.c_region = pp->pt_regionp; VMOVE(me.c_rdir, ap->a_ray.r_dir); VJOIN1(me.c_hit, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); RT_HIT_NORMAL(me.c_normal, hitp, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip); } /* * Now, fire a ray for both the cell below and if necessary, the * cell to the left. */ a2.a_hit = rayhit2; a2.a_miss = raymiss2; a2.a_onehit = 1; a2.a_rt_i = ap->a_rt_i; a2.a_resource = ap->a_resource; a2.a_logoverlap = ap->a_logoverlap; VSUB2(a2.a_ray.r_pt, ap->a_ray.r_pt, dy_model); /* below */ VMOVE(a2.a_ray.r_dir, ap->a_ray.r_dir); a2.a_uptr = (void *)&below; rt_shootray(&a2); if (ap->a_x == 0) { /* * For the first pixel in a scanline, we have to shoot to the * left. For each pixel afterword, we save the current cell * info to be used as the left side cell info for the * following pixel */ VSUB2(a2.a_ray.r_pt, ap->a_ray.r_pt, dx_model); /* left */ VMOVE(a2.a_ray.r_dir, ap->a_ray.r_dir); a2.a_uptr = (void *)&left; rt_shootray(&a2); } else { left.c_ishit = saved[cpu]->c_ishit; left.c_id = saved[cpu]->c_id; left.c_dist = saved[cpu]->c_dist; left.c_region = saved[cpu]->c_region; VMOVE(left.c_rdir, saved[cpu]->c_rdir); VMOVE(left.c_hit, saved[cpu]->c_hit); VMOVE(left.c_normal, saved[cpu]->c_normal); } if (both_sides) { VADD2(a2.a_ray.r_pt, ap->a_ray.r_pt, dy_model); /* above */ VMOVE(a2.a_ray.r_dir, ap->a_ray.r_dir); a2.a_uptr = (void *)&above; rt_shootray(&a2); VADD2(a2.a_ray.r_pt, ap->a_ray.r_pt, dx_model); /* right */ VMOVE(a2.a_ray.r_dir, ap->a_ray.r_dir); a2.a_uptr = (void *)&right; rt_shootray(&a2); } /* * Is this pixel an edge? */ if (both_sides) { edge = is_edge(&intensity, ap, &me, &left, &below, &right, &above); } else { edge = is_edge(&intensity, ap, &me, &left, &below, NULL, NULL); } /* * Does this pixel occlude the second geometry? Note that we must * check on edges as well since right side and top edges are * actually misses. */ if (occlusion_mode != OCCLUSION_MODE_NONE) if (me.c_ishit || edge) oc = occludes(ap, &me); /* * Perverse Pixel Painting Paradigm(tm) If a pixel should be * written to the fb, writeable is set. */ if (occlusion_mode == OCCLUSION_MODE_EDGES) writeable[cpu][ap->a_x] = (edge && oc); else if (occlusion_mode == OCCLUSION_MODE_HITS) writeable[cpu][ap->a_x] = ((me.c_ishit || edge) && oc); else if (occlusion_mode == OCCLUSION_MODE_DITHER) { if (edge && oc) writeable[cpu][ap->a_x] = 1; else if (me.c_ishit && oc) { /* * Dither mode. * * For occluding non-edges, only write every other pixel. */ if (oc == 1 && ((ap->a_x + ap->a_y) % 2) == 0) writeable[cpu][ap->a_x] = 1; else if (oc == 2) writeable[cpu][ap->a_x] = 1; else writeable[cpu][ap->a_x] = 0; } else { writeable[cpu][ap->a_x] = 0; } } else { if (edge) writeable[cpu][ap->a_x] = 1; else writeable[cpu][ap->a_x] = 0; } if (edge) { if (both_sides) { choose_color(col, intensity, &me, &left, &below, &right, &above); } else { choose_color(col, intensity, &me, &left, &below, NULL, NULL); } scanline[cpu][ap->a_x*3+RED] = col[RED]; scanline[cpu][ap->a_x*3+GRN] = col[GRN]; scanline[cpu][ap->a_x*3+BLU] = col[BLU]; } else { scanline[cpu][ap->a_x*3+RED] = bgcolor[RED]; scanline[cpu][ap->a_x*3+GRN] = bgcolor[GRN]; scanline[cpu][ap->a_x*3+BLU] = bgcolor[BLU]; } /* * Save the cell info for the next pixel. */ saved[cpu]->c_ishit = me.c_ishit; saved[cpu]->c_id = me.c_id; saved[cpu]->c_dist = me.c_dist; saved[cpu]->c_region = me.c_region; VMOVE(saved[cpu]->c_rdir, me.c_rdir); VMOVE(saved[cpu]->c_hit, me.c_hit); VMOVE(saved[cpu]->c_normal, me.c_normal); return edge; }
/* User supplied hit function. */ int hit(struct application *UNUSED(ap_p), struct partition *PartHeadp, struct seg *UNUSED(segp)) { /* START # 0H */ struct partition *pp; struct hit *hitp; struct soltab *stp; int icur=0; /* Current region hit. */ int iprev; /* Previous region hit. */ int iair; /* Type of air or region came from, */ /* 0=>region, 1=>exterior air, 2=>crew */ /* air, 5=>engine air, 6=>closed */ /* compartment air, 7=>exhaust air, */ /* 8=>generic air 1, 9=>generic air 2. */ /* * printf("In hit function.\n"); * (void)fflush(stdout); */ /* Set beginning parameters. */ iprev = -1; iair = 1; /* Comes from exterior air. */ /* * printf("Beginning loop again.\n"); * (void)fflush(stdout); */ pp = PartHeadp->pt_forw; for (; pp != PartHeadp; pp = pp->pt_forw) { /* START # 1H */ if (iair == 1) { /* Ray comes from nothing (exterior air). */ /* START # 2H */ if (pp->pt_regionp->reg_regionid > (short)0) { /* Hit region. */ /* START # 3H */ /* Region number hit. */ icur = (int)(pp->pt_regionp->reg_bit); /* Find leaving point. */ hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; RT_HIT_NORMAL(hitp->hit_normal, hitp, stp, &(ap_p->a_ray), pp->pt_outflip); iprev = icur; iair = 0; /* A region was just hit. */ /* END # 3H */ } else { /* Hit air. */ /* START # 4H */ iair = pp->pt_regionp->reg_aircode; } /* END # 4H */ /* END # 2H */ } else if (iair == 5) { /* Ray comes from engine air. */ /* START # 5H */ if (pp->pt_regionp->reg_regionid > (short)0) { /* Hit region. */ /* START # 6H */ /* Region number hit. */ icur = (int)(pp->pt_regionp->reg_bit); /* Only execute the following two statements if iprev >= 0. */ if (iprev < (-1)) { fprintf(stderr, "ERROR -- iprev = %d\n", iprev); (void)fflush(stderr); } if (iprev == (-1)) { fprintf(stderr, "iprev = %d - entered ", iprev); fprintf(stderr, "through engine air\n"); (void)fflush(stderr); } if (iprev > (-1)) { /* Add one to number of rays leaving previous region. */ info[iprev].lvrays++; /* Add one to the number of rays leaving current region */ /* for the backward ray. */ info[icur].lvrays++; /* Add one to number of rays leaving previous region and */ /* intercepted by current region. */ info[iprev].intrays[icur]++; /* Add one to the number of rays leaving the current */ /* region and intersecting the previous region for the */ /* backward ray. */ info[icur].intrays[iprev]++; } /* Find leave point. */ hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; RT_HIT_NORMAL(hitp->hit_normal, hitp, stp, &(ap_p->a_ray), pp->pt_outflip); iprev = icur; iair = 0; /* Hit a region. */ /* END # 6H */ } else { /* Hit air. */ iair = 5; /* Since coming through engine air */ /* assume should still be engine air. */ } /* END # 5H */ } else if (iair == 0) { /* Ray comes from a region. */ /* START # 7H */ if (pp->pt_regionp->reg_regionid > (short)0) { /* Hit a region. */ /* START # 8H */ /* Region number hit. */ icur = (int)(pp->pt_regionp->reg_bit); /* Find leaving point. */ hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; RT_HIT_NORMAL(hitp->hit_normal, hitp, stp, &(ap_p->a_ray), pp->pt_outflip); iprev = icur; iair = 0; /* Hit a region. */ /* END # 8H */ } else { /* Hit air. */ /* START # 9H */ /* Increment allvrays if the ray is leaving through */ /* engine air. Make sure this is only done once. */ if ((iair != 5) && (pp->pt_regionp->reg_aircode == 5)) info[icur].allvrays++; if (iair != 5) iair = pp->pt_regionp->reg_aircode; } /* END # 9H */ /* END # 7H */ } else { /* Ray comes from any interior air. */ /* START # 10H */ if (pp->pt_regionp->reg_regionid > (short)0) { /* Hits region. */ /* START # 11H */ /* Region number hit. */ icur = (int)(pp->pt_regionp->reg_bit); /* Find leaving point. */ hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; RT_HIT_NORMAL(hitp->hit_normal, hitp, stp, &(ap_p->a_ray), pp->pt_outflip); iprev = icur; iair = 0; /* Hit region. */ /* END # 11H */ } else { /* Hits air. */ iair = pp->pt_regionp->reg_aircode; } } /* END # 10H */ } /* END # 1H */ if (iprev == (-1)) { /* Went through air only. */ return 1; /* Indicates miss. */ } else { return 0; } } /* END # 0H */
int hit(register struct application *ap, struct partition *PartHeadp, struct seg *segp) { register struct partition *pp; register struct soltab *stp; struct curvature cur; fastf_t out; point_t inpt, outpt; vect_t inormal, onormal; if ( (pp=PartHeadp->pt_forw) == PartHeadp ) return(0); /* Nothing hit?? */ if ( overlap_claimant_handling == 1 ) rt_rebuild_overlaps( PartHeadp, ap, 1 ); else if ( overlap_claimant_handling == 2 ) rt_rebuild_overlaps( PartHeadp, ap, 0 ); /* First, plot ray start to inhit */ if ( R_DEBUG&RDEBUG_RAYPLOT ) { if ( pp->pt_inhit->hit_dist > 0.0001 ) { VJOIN1( inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); pl_color( plotfp, 0, 0, 255 ); pdv_3line( plotfp, ap->a_ray.r_pt, inpt ); } } for (; pp != PartHeadp; pp = pp->pt_forw ) { matp_t inv_mat; Tcl_HashEntry *entry; bu_log("\n--- Hit region %s (in %s, out %s) reg_bit = %d\n", pp->pt_regionp->reg_name, pp->pt_inseg->seg_stp->st_name, pp->pt_outseg->seg_stp->st_name, pp->pt_regionp->reg_bit); entry = Tcl_FindHashEntry( (Tcl_HashTable *)ap->a_rt_i->Orca_hash_tbl, (const char *)(size_t)pp->pt_regionp->reg_bit ); if ( !entry ) { inv_mat = (matp_t)NULL; } else { inv_mat = (matp_t)Tcl_GetHashValue( entry ); bn_mat_print( "inv_mat", inv_mat ); } if ( pp->pt_overlap_reg ) { struct region *pp_reg; int j=-1; bu_log( " Claiming regions:\n" ); while ( (pp_reg=pp->pt_overlap_reg[++j]) ) bu_log( " %s\n", pp_reg->reg_name ); } /* inhit info */ stp = pp->pt_inseg->seg_stp; VJOIN1( inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); RT_HIT_NORMAL( inormal, pp->pt_inhit, stp, &(ap->a_ray), pp->pt_inflip ); RT_CURVATURE( &cur, pp->pt_inhit, pp->pt_inflip, stp ); rt_pr_hit( " In", pp->pt_inhit ); VPRINT( " Ipoint", inpt ); VPRINT( " Inormal", inormal ); bu_log( " PDir (%g, %g, %g) c1=%g, c2=%g\n", V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2); if ( inv_mat ) { point_t in_trans; MAT4X3PNT( in_trans, inv_mat, inpt ); bu_log( "\ttransformed ORCA inhit = (%g %g %g)\n", V3ARGS( in_trans ) ); } /* outhit info */ stp = pp->pt_outseg->seg_stp; VJOIN1( outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir ); RT_HIT_NORMAL( onormal, pp->pt_outhit, stp, &(ap->a_ray), pp->pt_outflip ); RT_CURVATURE( &cur, pp->pt_outhit, pp->pt_outflip, stp ); rt_pr_hit( " Out", pp->pt_outhit ); VPRINT( " Opoint", outpt ); VPRINT( " Onormal", onormal ); bu_log( " PDir (%g, %g, %g) c1=%g, c2=%g\n", V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2); if ( inv_mat ) { point_t out_trans; vect_t dir_trans; MAT4X3PNT( out_trans, inv_mat, outpt ); MAT4X3VEC( dir_trans, inv_mat, ap->a_ray.r_dir ); VUNITIZE( dir_trans ); bu_log( "\ttranformed ORCA outhit = (%g %g %g)\n", V3ARGS( out_trans ) ); bu_log( "\ttransformed ORCA ray direction = (%g %g %g)\n", V3ARGS( dir_trans ) ); } /* Plot inhit to outhit */ if ( R_DEBUG&RDEBUG_RAYPLOT ) { if ( (out = pp->pt_outhit->hit_dist) >= INFINITY ) out = 10000; /* to imply the direction */ VJOIN1( outpt, ap->a_ray.r_pt, out, ap->a_ray.r_dir ); pl_color( plotfp, 0, 255, 255 ); pdv_3line( plotfp, inpt, outpt ); } { struct region *regp = pp->pt_regionp; int i; if ( ap->attrs ) { bu_log( "\tattribute values:\n" ); i = 0; while ( ap->attrs[i] && regp->attr_values[i] ) { bu_log( "\t\t%s:\n", ap->attrs[i] ); bu_log( "\t\t\tstring rep = %s\n", BU_MRO_GETSTRING(regp->attr_values[i])); bu_log( "\t\t\tlong rep = %d\n", BU_MRO_GETLONG(regp->attr_values[i])); bu_log( "\t\t\tdouble rep = %f\n", BU_MRO_GETDOUBLE(regp->attr_values[i])); i++; } } } } return(1); }
/* * Callback function to be called whenever a refraction ray hits an object */ int osl_refraction_hit(struct application *ap, struct partition *PartHeadp, struct seg *finished_segs) { /* iterating over partitions, this will keep track of the current * partition we're working on. */ struct partition *pp; /* will serve as a pointer for the entry and exit hitpoints */ struct hit *hitp; /* will serve as a pointer to the solid primitive we hit */ struct soltab *stp; /* will contain surface curvature information at the entry */ struct curvature cur; /* will contain our hit point coordinate */ point_t pt; /* will contain normal vector where ray enters geometry */ vect_t inormal; /* will contain normal vector where ray exits geometry */ vect_t onormal; struct shadework sw; /* iterate over each partition until we get back to the head. * each partition corresponds to a specific homogeneous region of * material. */ for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) { register const struct mfuncs *mfp; register const struct region *rp; memset((char *)&sw, 0, sizeof(sw)); sw.sw_transmit = sw.sw_reflect = 0.0; sw.sw_refrac_index = 1.0; sw.sw_extinction = 0; sw.sw_xmitonly = 0; /* want full data */ sw.sw_inputs = 0; /* no fields filled yet */ sw.sw_segs = finished_segs; VSETALL(sw.sw_color, 1); VSETALL(sw.sw_basecolor, 1); rp = pp->pt_regionp; mfp = (struct mfuncs *)pp->pt_regionp->reg_mfuncs; /* Determine the hit point */ sw.sw_hit = *(pp->pt_outhit); /* struct copy */ VJOIN1(sw.sw_hit.hit_point, ap->a_ray.r_pt, sw.sw_hit.hit_dist, ap->a_ray.r_dir); /* Determine the normal point */ stp = pp->pt_outseg->seg_stp; RT_HIT_NORMAL(sw.sw_hit.hit_normal, &(sw.sw_hit), stp, &(ap->a_ray), pp->pt_outflip); /* Invoke the actual shader (may be a tree of them) */ if (mfp && mfp->mf_render) (void)mfp->mf_render(ap, pp, &sw, rp->reg_udata); VMOVE(ap->a_color, sw.sw_color); } return 1; }
/* * R R _ H I T * * This routine is called when an internal reflection ray hits something * (which is ordinarily the case). * * Generally, there will be one or two partitions on the hit list. * The values for pt_outhit for the second partition should not be used, * as a_onehit was set to 3, getting a maximum of 3 valid hit points. * * Explicit Returns - * 0 dreadful internal error * 1 treat as escaping ray & reshoot * 2 Proper exit point determined, with Implicit Returns: * a_uvec exit Point * a_vvec exit Normal (inward pointing) * a_refrac_index RI of *next* material */ HIDDEN int rr_hit(struct application *ap, struct partition *PartHeadp, struct seg *UNUSED(segp)) { register struct partition *pp; register struct hit *hitp; register struct soltab *stp; struct partition *psave = (struct partition *)NULL; struct shadework sw; struct application appl; int ret; RT_AP_CHECK(ap); RT_APPLICATION_INIT(&appl); for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) if (pp->pt_outhit->hit_dist > 0.0) break; if (pp == PartHeadp) { if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) { bu_log("rr_hit: %d, %d no hit out front?\n", ap->a_x, ap->a_y); ret = 0; /* error */ goto out; } ret = 1; /* treat as escaping ray */ goto out; } /* * Ensure that the partition we are given is part of the same * region that we started in. When the internal reflection * is happening very near an edge or corner, this is not always * the case, and either (a) a small sliver of some other region * is found to be in the way, or (b) the ray completely misses the * region that it started in, although not by much. */ psave = pp; if (R_DEBUG&RDEBUG_REFRACT) bu_log("rr_hit(%s)\n", psave->pt_regionp->reg_name); for (; pp != PartHeadp; pp = pp->pt_forw) if (pp->pt_regionp == (struct region *)(ap->a_uptr)) break; if (pp == PartHeadp) { if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) { bu_log("rr_hit: %d, %d Ray internal to %s landed unexpectedly in %s\n", ap->a_x, ap->a_y, ((struct region *)(ap->a_uptr))->reg_name, psave->pt_regionp->reg_name); ret = 0; /* error */ goto out; } ret = 1; /* treat as escaping ray */ goto out; } /* * At one time, this was a check for pp->pt_inhit->hit_dist * being NEAR zero. That was a mistake, because we may have * been at the edge of a subtracted out center piece when * internal reflection happened, except that floating point * error (being right on the surface of the interior solid) * prevented us from "seeing" that solid on the next ray, * causing our ray endpoints to be quite far from the starting * point, yet with the ray still validly inside the glass region. * * There is a major problem if the entry point * is further ahead than the firing point, i.e., >0. * * Because this error has not yet been encountered, it is * considered dreadful. Some recovery may be possible. * * For now, this seems to happen when a reflected ray starts outside * the glass and doesn't even intersect the glass, so treat it as * an escaping ray. */ if (pp->pt_inhit->hit_dist > 10) { stp = pp->pt_inseg->seg_stp; if (R_DEBUG&RDEBUG_REFRACT) bu_log("rr_hit: %d, %d %s inhit %g > 10.0! (treating as escaping ray)\n", ap->a_x, ap->a_y, pp->pt_regionp->reg_name, pp->pt_inhit->hit_dist); ret = 1; /* treat as escaping ray */ goto out; } /* * If there is a very small crack in the glass, perhaps formed * by a small error when taking the Union of two solids, * attempt to find the real exit point. * NOTE that this is usually taken care of inside librt * in the bool_weave code, but it is inexpensive to check for it * here. If this case is detected, push on, and log it. * This code is not expected to be needed. */ while (pp->pt_forw != PartHeadp) { register fastf_t d; d = pp->pt_forw->pt_inhit->hit_dist - pp->pt_outhit->hit_dist; if (!NEAR_ZERO(d, AIR_GAP_TOL)) break; if (pp->pt_forw->pt_regionp != pp->pt_regionp) break; if (R_DEBUG&(RDEBUG_SHOWERR|RDEBUG_REFRACT)) bu_log( "rr_hit: %d, %d fusing small crack in glass %s\n", ap->a_x, ap->a_y, pp->pt_regionp->reg_name); pp = pp->pt_forw; } hitp = pp->pt_outhit; stp = pp->pt_outseg->seg_stp; if (hitp->hit_dist >= INFINITY) { bu_log("rr_hit: %d, %d infinite glass (%g, %g) %s\n", ap->a_x, ap->a_y, pp->pt_inhit->hit_dist, hitp->hit_dist, pp->pt_regionp->reg_name); ret = 0; /* dreadful error */ goto out; } VJOIN1(hitp->hit_point, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir); RT_HIT_NORMAL(ap->a_vvec, hitp, stp, &(ap->a_ray), pp->pt_outflip); /* For refraction, want exit normal to point inward. */ VREVERSE(ap->a_vvec, ap->a_vvec); VMOVE(ap->a_uvec, hitp->hit_point); ap->a_cumlen += (hitp->hit_dist - pp->pt_inhit->hit_dist); ap->a_refrac_index = RI_AIR; /* Default medium: air */ /* * Look ahead, and see if there is more glass to come. * If so, obtain its refractive index, to enable correct * calculation of the departing refraction angle. */ if (pp->pt_forw != PartHeadp) { register fastf_t d; d = pp->pt_forw->pt_inhit->hit_dist - hitp->hit_dist; if (NEAR_ZERO(d, AIR_GAP_TOL)) { /* * Make a private copy of the application struct, * because viewshade() may change various fields. */ appl = *ap; /* struct copy */ memset((char *)&sw, 0, sizeof(sw)); sw.sw_transmit = sw.sw_reflect = 0.0; /* Set default in case shader doesn't fill this in. */ sw.sw_refrac_index = RI_AIR; /* Set special flag so that we get only shader * parameters (refractive index, in this case). * We don't even care about transmitted energy. */ sw.sw_xmitonly = 2; sw.sw_inputs = 0; /* no fields filled yet */ #ifdef RT_MULTISPECTRAL sw.msw_color = bn_tabdata_get_constval(1.0, spectrum); sw.msw_basecolor = bn_tabdata_get_constval(1.0, spectrum); #else VSETALL(sw.sw_color, 1); VSETALL(sw.sw_basecolor, 1); #endif if (R_DEBUG&(RDEBUG_SHADE|RDEBUG_REFRACT)) bu_log("rr_hit calling viewshade to discover refractive index\n"); (void)viewshade(&appl, pp->pt_forw, &sw); #ifdef RT_MULTISPECTRAL bu_free(sw.msw_color, "sw.msw_color"); bu_free(sw.msw_basecolor, "sw.msw_basecolor"); #endif if (R_DEBUG&(RDEBUG_SHADE|RDEBUG_REFRACT)) bu_log("rr_hit refractive index = %g\n", sw.sw_refrac_index); if (sw.sw_transmit > 0) { ap->a_refrac_index = sw.sw_refrac_index; if (R_DEBUG&RDEBUG_SHADE) { bu_log("rr_hit a_refrac_index=%g (trans=%g)\n", ap->a_refrac_index, sw.sw_transmit); } ret= 3; /* OK -- more glass follows */ goto out; } } } ret = 2; /* OK -- no more glass */ out: if (R_DEBUG&RDEBUG_REFRACT) bu_log("rr_hit(%s) return=%d\n", psave ? psave->pt_regionp->reg_name : "", ret); return ret; }
static int radhit(register struct application *ap, struct partition *PartHeadp, struct seg *segHeadp) { register struct partition *pp; register struct hit *hitp; struct application sub_ap; fastf_t f; vect_t to_eye, work; int depth; for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) if ( pp->pt_outhit->hit_dist >= 0.0 ) break; if ( pp == PartHeadp ) { bu_log("radhit: no hit out front?\n"); return(0); } if (R_DEBUG&RDEBUG_HITS) { rt_pr_pt( ap->a_rt_i, pp ); } hitp = pp->pt_inhit; if ( hitp->hit_dist >= INFINITY ) { bu_log("radhit: entry beyond infinity\n"); return(1); } /* Check to see if eye is "inside" the solid */ if ( hitp->hit_dist < 0 ) { /* XXX */ bu_log("radhit: GAK, eye inside solid (%g)\n", hitp->hit_dist ); for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) rt_pr_pt( ap->a_rt_i, pp ); return(0); } rayp = &rayinfo[ ap->a_level ]; RT_HIT_NORMAL( rayp->norm, hitp, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip ); if (R_DEBUG&RDEBUG_HITS) { rt_pr_hit( " In", hitp ); } rayp->dist = hitp->hit_dist; rayp->reg = pp->pt_regionp->reg_regionid; rayp->sol = pp->pt_inseg->seg_stp->st_id; rayp->surf = hitp->hit_surfno; RT_CURVATURE( &(rayp->curvature), hitp, pp->pt_inflip, pp->pt_inseg->seg_stp ); if ( VDOT( rayp->norm, ap->a_ray.r_dir ) < 0 ) { bu_log(" debug: flipping curvature\n"); rayp->curvature.crv_c1 = - rayp->curvature.crv_c1; rayp->curvature.crv_c2 = - rayp->curvature.crv_c2; } VMOVE( rayp->ip, hitp->hit_point ); /* Compute the specular direction */ VREVERSE( to_eye, ap->a_ray.r_dir ); f = 2 * VDOT( to_eye, rayp->norm ); VSCALE( work, rayp->norm, f ); /* I have been told this has unit length */ VSUB2( rayp->spec, work, to_eye ); /* Save info for 1st ray */ if ( ap->a_level == 0 ) { firstray = ap->a_ray; /* struct copy */ rayp->sight = 1; /* the 1st intersect is always visible */ } else { /* Check for visibility */ rayp->sight = isvisible( ap, hitp, rayp->norm ); } /* * Shoot another ray in the specular direction. */ if ( ap->a_level < numreflect-1 ) { sub_ap = *ap; /* struct copy */ sub_ap.a_level = ap->a_level+1; VMOVE( sub_ap.a_ray.r_pt, hitp->hit_point ); VMOVE( sub_ap.a_ray.r_dir, rayp->spec ); depth = rt_shootray( &sub_ap ); } else { bu_log( "radhit: max reflections exceeded [%d %d]\n", ap->a_x, ap->a_y ); depth = 0; } if ( ap->a_level == 0 ) { /* We're the 1st ray, output the raylist */ dumpall( ap, depth+1 ); } return(depth+1); /* report hit to main routine */ }
static int radhit( struct application *ap, struct partition *PartHeadp ) { register struct partition *pp; register struct hit *hitp; struct application sub_ap; struct rayinfo *rayp; fastf_t f; vect_t to_eye, work; int depth; int cpu_num; for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw ) if ( pp->pt_outhit->hit_dist >= 0.0 ) break; if ( pp == PartHeadp ) { bu_log("radhit: no hit out front?\n"); return 0; } if (R_DEBUG&RDEBUG_HITS) { rt_pr_pt( ap->a_rt_i, pp ); } hitp = pp->pt_inhit; if ( hitp->hit_dist >= INFINITY ) { bu_log("radhit: entry beyond infinity\n"); return 1; } /* Check to see if eye is "inside" the solid */ if ( hitp->hit_dist < 0 ) { /* XXX */ return 0; } if (R_DEBUG&RDEBUG_HITS) { rt_pr_hit( " In", hitp ); } if ( ap->a_resource == RESOURCE_NULL) cpu_num = 0; else cpu_num = ap->a_resource->re_cpu; rayp = &rayinfo[cpu_num][ ap->a_level +1 ]; rayp->x = ap->a_x; rayp->y = ap->a_y; rayp->dist = hitp->hit_dist; rayp->reg = pp->pt_regionp->reg_regionid; rayp->sol = pp->pt_inseg->seg_stp->st_id; rayp->surf = hitp->hit_surfno; RT_HIT_NORMAL( rayp->norm, hitp, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip ); RT_CURVATURE( &(rayp->curvature), hitp, pp->pt_inflip, pp->pt_inseg->seg_stp ); if ( VDOT( hitp->hit_normal, ap->a_ray.r_dir ) < 0 ) { bu_log(" debug: curvature flip\n"); rayp->curvature.crv_c1 = - rayp->curvature.crv_c1; rayp->curvature.crv_c2 = - rayp->curvature.crv_c2; } VMOVE( rayp->ip, hitp->hit_point ); VMOVE( rayp->dir, ap->a_ray.r_dir); /* Compute the specular direction */ VREVERSE( to_eye, ap->a_ray.r_dir ); f = 2 * VDOT( to_eye, rayp->norm ); VSCALE( work, rayp->norm, f ); /* I have been told this has unit length */ VSUB2( rayp->spec, work, to_eye ); VUNITIZE( rayp->spec ); /* Save info for 1st ray */ if ( ap->a_level == 0 ) { firstray[cpu_num] = ap->a_ray; /* struct copy */ rayp->sight = 1; /* the 1st intersect is always visible */ } else { /* Check for visibility */ rayp->sight = isvisible( ap, hitp, rayp->norm ); } /* * Shoot another ray in the specular direction. */ if ( ap->a_level < numreflect-1 ) { sub_ap = *ap; /* struct copy */ sub_ap.a_level = ap->a_level+1; sub_ap.a_purpose = "secondary ray"; VMOVE( sub_ap.a_ray.r_pt, hitp->hit_point ); VMOVE( sub_ap.a_ray.r_dir, rayp->spec ); depth = rt_shootray( &sub_ap ); } else { depth = 0; } if ( ap->a_level == 0 ) { rayinfo[cpu_num][0].x = ap->a_x; rayinfo[cpu_num][0].y = ap->a_y; rayinfo[cpu_num][0].surf = depth+1; rayinfo[cpu_num][0].ip[0] = ap->a_ray.r_pt[0]; rayinfo[cpu_num][0].ip[1] = ap->a_ray.r_pt[1]; rayinfo[cpu_num][0].ip[2] = ap->a_ray.r_pt[2]; radar_physics( cpu_num, depth + 1 ); #ifdef SAR dumpall( ap, cpu_num, depth + 1); #endif } return depth+1; /* report hit to main routine */ }