/* 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;
}
Example #2
0
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);
}
Example #3
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);
}
Example #4
0
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;
}
Example #5
0
/*
 *			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);
}
Example #6
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;
    }
Example #8
0
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;
}
Example #9
0
/* 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 */
Example #10
0
int hit(register struct application *ap, struct partition *PartHeadp, struct seg *segp)
{
    register struct partition *pp;
    register struct soltab *stp;
    struct curvature cur;
    fastf_t out;
    point_t inpt, outpt;
    vect_t	inormal, onormal;

    if ( (pp=PartHeadp->pt_forw) == PartHeadp )
	return(0);		/* Nothing hit?? */

    if ( overlap_claimant_handling == 1 )
	rt_rebuild_overlaps( PartHeadp, ap, 1 );
    else if ( overlap_claimant_handling == 2 )
	rt_rebuild_overlaps( PartHeadp, ap, 0 );

    /* First, plot ray start to inhit */
    if ( R_DEBUG&RDEBUG_RAYPLOT )  {
	if ( pp->pt_inhit->hit_dist > 0.0001 )  {
	    VJOIN1( inpt, ap->a_ray.r_pt,
		    pp->pt_inhit->hit_dist, ap->a_ray.r_dir );
	    pl_color( plotfp, 0, 0, 255 );
	    pdv_3line( plotfp, ap->a_ray.r_pt, inpt );
	}
    }
    for (; pp != PartHeadp; pp = pp->pt_forw )  {
	matp_t inv_mat;
	Tcl_HashEntry *entry;

	bu_log("\n--- Hit region %s (in %s, out %s) reg_bit = %d\n",
	       pp->pt_regionp->reg_name,
	       pp->pt_inseg->seg_stp->st_name,
	       pp->pt_outseg->seg_stp->st_name,
	       pp->pt_regionp->reg_bit);

	entry = Tcl_FindHashEntry( (Tcl_HashTable *)ap->a_rt_i->Orca_hash_tbl,
				   (const char *)(size_t)pp->pt_regionp->reg_bit );
	if ( !entry ) {
	    inv_mat = (matp_t)NULL;
	}
	else {
	    inv_mat = (matp_t)Tcl_GetHashValue( entry );
	    bn_mat_print( "inv_mat", inv_mat );
	}

	if ( pp->pt_overlap_reg )
	{
	    struct region *pp_reg;
	    int j=-1;

	    bu_log( "    Claiming regions:\n" );
	    while ( (pp_reg=pp->pt_overlap_reg[++j]) )
		bu_log( "        %s\n", pp_reg->reg_name );
	}

	/* inhit info */
	stp = pp->pt_inseg->seg_stp;
	VJOIN1( inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir );
	RT_HIT_NORMAL( inormal, pp->pt_inhit, stp, &(ap->a_ray), pp->pt_inflip );
	RT_CURVATURE( &cur, pp->pt_inhit, pp->pt_inflip, stp );

	rt_pr_hit( "  In", pp->pt_inhit );
	VPRINT(    "  Ipoint", inpt );
	VPRINT(    "  Inormal", inormal );
	bu_log(    "   PDir (%g, %g, %g) c1=%g, c2=%g\n",
		   V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2);

	if ( inv_mat ) {
	    point_t in_trans;

	    MAT4X3PNT( in_trans, inv_mat, inpt );
	    bu_log( "\ttransformed ORCA inhit = (%g %g %g)\n", V3ARGS( in_trans ) );
	}

	/* outhit info */
	stp = pp->pt_outseg->seg_stp;
	VJOIN1( outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir );
	RT_HIT_NORMAL( onormal, pp->pt_outhit, stp, &(ap->a_ray), pp->pt_outflip );
	RT_CURVATURE( &cur, pp->pt_outhit, pp->pt_outflip, stp );

	rt_pr_hit( "  Out", pp->pt_outhit );
	VPRINT(    "  Opoint", outpt );
	VPRINT(    "  Onormal", onormal );
	bu_log(    "   PDir (%g, %g, %g) c1=%g, c2=%g\n",
		   V3ARGS(cur.crv_pdir), cur.crv_c1, cur.crv_c2);

	if ( inv_mat ) {
	    point_t out_trans;
	    vect_t dir_trans;

	    MAT4X3PNT( out_trans, inv_mat, outpt );
	    MAT4X3VEC( dir_trans, inv_mat, ap->a_ray.r_dir );
	    VUNITIZE( dir_trans );
	    bu_log( "\ttranformed ORCA outhit = (%g %g %g)\n", V3ARGS( out_trans ) );
	    bu_log( "\ttransformed ORCA ray direction = (%g %g %g)\n", V3ARGS( dir_trans ) );
	}

	/* Plot inhit to outhit */
	if ( R_DEBUG&RDEBUG_RAYPLOT )  {
	    if ( (out = pp->pt_outhit->hit_dist) >= INFINITY )
		out = 10000;	/* to imply the direction */

	    VJOIN1( outpt,
		    ap->a_ray.r_pt, out,
		    ap->a_ray.r_dir );
	    pl_color( plotfp, 0, 255, 255 );
	    pdv_3line( plotfp, inpt, outpt );
	}

	{
	    struct region *regp = pp->pt_regionp;
	    int i;

	    if ( ap->attrs ) {
		bu_log( "\tattribute values:\n" );
		i = 0;
		while ( ap->attrs[i] && regp->attr_values[i] ) {
		    bu_log( "\t\t%s:\n", ap->attrs[i] );
		    bu_log( "\t\t\tstring rep = %s\n",
			    BU_MRO_GETSTRING(regp->attr_values[i]));
		    bu_log( "\t\t\tlong rep = %d\n",
			    BU_MRO_GETLONG(regp->attr_values[i]));
		    bu_log( "\t\t\tdouble rep = %f\n",
			    BU_MRO_GETDOUBLE(regp->attr_values[i]));
		    i++;
		}
	    }
	}
    }
    return(1);
}
/*
 * 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;
}
Example #12
0
/*
 * 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;
}
Example #13
0
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 */
}
Example #14
0
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 */
}