コード例 #1
0
ファイル: xxx.c プロジェクト: kanzure/brlcad
/**
 * Intersect a ray with a xxx.  If an intersection occurs, a struct
 * seg will be acquired and filled in.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_xxx_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct xxx_specific *xxx;

    if (!stp) return -1;
    RT_CK_SOLTAB(stp);
    xxx = (struct xxx_specific *)stp->st_specific;
    if (!xxx) return -1;
    if (rp) RT_CK_RAY(rp);
    if (ap) RT_CK_APPLICATION(ap);
    if (!seghead) return -1;

/* the EXAMPLE_NEW_SEGMENT block shows how one might add a new result
 * if the ray did hit the primitive.  the segment values would need to
 * be adjusted accordingly to match real values instead of -1.
 */
#ifdef EXAMPLE_NEW_SEGMENT
    /* allocate a segment */
    RT_GET_SEG(segp, ap->a_resource);
    segp->seg_stp = stp; /* stash a pointer to the primitive */

    segp->seg_in.hit_dist = -1; /* XXX set to real distance to entry point */
    segp->seg_out.hit_dist = -1; /* XXX set to real distance to exit point */
    segp->seg_in.hit_surfno = -1; /* XXX set to a non-negative ID for entry surface */
    segp->seg_out.hit_surfno = -1;  /* XXX set to a non-negative ID for exit surface */

    /* add segment to list of those encountered for this primitive */
    BU_LIST_INSERT(&(seghead->l), &(segp->l));

    return 2; /* num surface intersections == in + out == 2 */
#endif

    return 0;			/* MISS */
}
コード例 #2
0
ファイル: vshoot.c プロジェクト: kanzure/brlcad
/**
 * Given a ray, shoot it at all the relevant parts of the model,
 * (building the HeadSeg chain), and then call rt_boolregions() to
 * build and evaluate the partition chain.  If the ray actually hit
 * anything, call the application's a_hit() routine with a pointer to
 * the partition chain, otherwise, call the application's a_miss()
 * routine.
 *
 * It is important to note that rays extend infinitely only in the
 * positive direction.  The ray is composed of all points P, where
 *
 * P = r_pt + K * r_dir
 *
 * for K ranging from 0 to +infinity.  There is no looking backwards.
 *
 * It is also important to note that the direction vector r_dir must
 * have unit length; this is mandatory, and is not ordinarily checked,
 * in the name of efficiency.
 *
 * Input:  Pointer to an application structure, with these mandatory fields:
 * a_ray.r_pt Starting point of ray to be fired
 * a_ray.r_dir UNIT VECTOR with direction to fire in (dir cosines)
 * a_hit Routine to call when something is hit
 * a_miss Routine to call when ray misses everything
 *
 * Calls user's a_miss() or a_hit() routine as appropriate.  Passes
 * a_hit() routine list of partitions, with only hit_dist fields
 * valid.  Normal computation deferred to user code, to avoid needless
 * computation here.
 *
 * Returns: whatever the application function returns (an int).
 *
 * NOTE: The application functions may call rt_shootray() recursively.
 * Thus, none of the local variables may be static.
 *
 * An open issue for execution in a PARALLEL environment is locking of
 * the statistics variables.
 */
int
rt_vshootray(struct application *ap)
{
    struct seg *HeadSeg;
    int ret;
    vect_t inv_dir;	/* inverses of ap->a_ray.r_dir */
    struct bu_bitv *solidbits;	/* bits for all solids shot so far */
    struct bu_ptbl *regionbits;	/* bits for all involved regions */
    char *status;
    struct partition InitialPart;	/* Head of Initial Partitions */
    struct partition FinalPart;	/* Head of Final Partitions */
    int nrays = 1;			/* for now */
    int vlen;
    int id;
    int i;
    struct soltab **ary_stp;	/* array of pointers */
    struct xray **ary_rp;	/* array of pointers */
    struct seg *ary_seg;	/* array of structures */
    struct rt_i *rtip;
    int done;

#define BACKING_DIST (-2.0)		/* mm to look behind start point */
    rtip = ap->a_rt_i;
    RT_AP_CHECK(ap);
    if (!ap->a_resource) {
	ap->a_resource = &rt_uniresource;
    }
    RT_CK_RESOURCE(ap->a_resource);

    if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) {
	bu_log("\n**********mshootray cpu=%d  %d, %d lvl=%d (%s)\n",
	       ap->a_resource->re_cpu,
	       ap->a_x, ap->a_y,
	       ap->a_level,
	       ap->a_purpose != (char *)0 ? ap->a_purpose : "?");
	VPRINT("Pnt", ap->a_ray.r_pt);
	VPRINT("Dir", ap->a_ray.r_dir);
    }

    rtip->rti_nrays++;
    if (rtip->needprep)
	rt_prep(rtip);

    /* Allocate dynamic memory */
    vlen = nrays * rtip->rti_maxsol_by_type;
    ary_stp = (struct soltab **)bu_calloc(vlen, sizeof(struct soltab *),
					  "*ary_stp[]");
    ary_rp = (struct xray **)bu_calloc(vlen, sizeof(struct xray *),
				       "*ary_rp[]");
    ary_seg = (struct seg *)bu_calloc(vlen, sizeof(struct seg),
				      "ary_seg[]");

    /**** for each ray, do this ****/

    InitialPart.pt_forw = InitialPart.pt_back = &InitialPart;
    FinalPart.pt_forw = FinalPart.pt_back = &FinalPart;

    HeadSeg = RT_SEG_NULL;

    solidbits = rt_get_solidbitv(rtip->nsolids, ap->a_resource);

    if (BU_LIST_IS_EMPTY(&ap->a_resource->re_region_ptbl)) {
	BU_ALLOC(regionbits, struct bu_ptbl);
	bu_ptbl_init(regionbits, 7, "rt_shootray() regionbits ptbl");
    } else {
	regionbits = BU_LIST_FIRST(bu_ptbl, &ap->a_resource->re_region_ptbl);
	BU_LIST_DEQUEUE(&regionbits->l);
	BU_CK_PTBL(regionbits);
    }

    /* Compute the inverse of the direction cosines */
    if (!ZERO(ap->a_ray.r_dir[X])) {
	inv_dir[X]=1.0/ap->a_ray.r_dir[X];
    } else {
	inv_dir[X] = INFINITY;
	ap->a_ray.r_dir[X] = 0.0;
    }
    if (!ZERO(ap->a_ray.r_dir[Y])) {
	inv_dir[Y]=1.0/ap->a_ray.r_dir[Y];
    } else {
	inv_dir[Y] = INFINITY;
	ap->a_ray.r_dir[Y] = 0.0;
    }
    if (!ZERO(ap->a_ray.r_dir[Z])) {
	inv_dir[Z]=1.0/ap->a_ray.r_dir[Z];
    } else {
	inv_dir[Z] = INFINITY;
	ap->a_ray.r_dir[Z] = 0.0;
    }

    /*
     * XXX handle infinite solids here, later.
     */

    /*
     * If ray does not enter the model RPP, skip on.
     * If ray ends exactly at the model RPP, trace it.
     */
    if (!rt_in_rpp(&ap->a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max)  ||
	ap->a_ray.r_max < 0.0) {
	rtip->nmiss_model++;
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISS model";
	goto out;
    }

    /* For each type of solid to be shot at, assemble the vectors */
    for (id = 1; id <= ID_MAX_SOLID; id++) {
	register int nsol;

	if ((nsol = rtip->rti_nsol_by_type[id]) <= 0) continue;

	/* For each instance of this solid type */
	for (i = nsol-1; i >= 0; i--) {
	    ary_stp[i] = rtip->rti_sol_by_type[id][i];
	    ary_rp[i] = &(ap->a_ray);	/* XXX, sb [ray] */
	    ary_seg[i].seg_stp = SOLTAB_NULL;
	    BU_LIST_INIT(&ary_seg[i].l);
	}
	/* bounding box check */
	/* bit vector per ray check */
	/* mark elements to be skipped with ary_stp[] = SOLTAB_NULL */
	ap->a_rt_i->nshots += nsol;	/* later: skipped ones */
	if (OBJ[id].ft_vshot) {
	    OBJ[id].ft_vshot(ary_stp, ary_rp, ary_seg, nsol, ap);
	} else {
	    vshot_stub(ary_stp, ary_rp, ary_seg, nsol, ap);
	}


	/* set bits for all solids shot at for each ray */

	/* append resulting seg list to input for boolweave */
	for (i = nsol-1; i >= 0; i--) {
	    register struct seg *seg2;

	    if (ary_seg[i].seg_stp == SOLTAB_NULL) {
		/* MISS */
		ap->a_rt_i->nmiss++;
		continue;
	    }
	    ap->a_rt_i->nhits++;

	    /* For now, do it the slow way.  sb [ray] */
	    /* MUST dup it -- all segs have to live till after a_hit() */
	    RT_GET_SEG(seg2, ap->a_resource);
	    *seg2 = ary_seg[i];	/* struct copy */
	    /* rt_boolweave(seg2, &InitialPart, ap); */
	    bu_bomb("FIXME: need to call boolweave here");

	    /* Add seg chain to list of used segs awaiting reclaim */

#if 0
	    /* FIXME: need to use waiting_segs/finished_segs here in
	     * conjunction with rt_boolweave()
	     {
	     register struct seg *seg3 = seg2;
	     while (seg3->seg_next != RT_SEG_NULL)
	     seg3 = seg3->seg_next;
	     seg3->seg_next = HeadSeg;
	     HeadSeg = seg2;
	     }
	    */
#endif
	}
    }

    /*
     * Ray has finally left known space.
     */
    if (InitialPart.pt_forw == &InitialPart) {
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISSed all primitives";
	goto freeup;
    }

    /*
     * All intersections of the ray with the model have been computed.
     * Evaluate the boolean trees over each partition.
     */
    done = rt_boolfinal(&InitialPart, &FinalPart, BACKING_DIST, INFINITY, regionbits, ap, solidbits);

    if (done > 0) goto hitit;

    if (FinalPart.pt_forw == &FinalPart) {
	if (ap->a_miss)
	    ret = ap->a_miss(ap);
	else
	    ret = 0;
	status = "MISS bool";
	goto freeup;
    }

    /*
     * Ray/model intersections exist.  Pass the list to the user's
     * a_hit() routine.  Note that only the hit_dist elements of
     * pt_inhit and pt_outhit have been computed yet.  To compute both
     * hit_point and hit_normal, use the
     *
     * RT_HIT_NORMAL(NULL, hitp, stp, rayp, 0);
     *
     * macro.  To compute just hit_point, use
     *
     * VJOIN1(hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir);
     */
hitit:
    if (RT_G_DEBUG&DEBUG_SHOOT) rt_pr_partitions(rtip, &FinalPart, "a_hit()");

    if (ap->a_hit)
	ret = ap->a_hit(ap, &FinalPart, HeadSeg/* &finished_segs */);
    else
	ret = 0;
    status = "HIT";

    /*
     * Processing of this ray is complete.  Free dynamic resources.
     */
freeup:
    {
	register struct partition *pp;

	/* Free up initial partition list */
	for (pp = InitialPart.pt_forw; pp != &InitialPart;) {
	    register struct partition *newpp;
	    newpp = pp;
	    pp = pp->pt_forw;
	    FREE_PT(newpp, ap->a_resource);
	}
	/* Free up final partition list */
	for (pp = FinalPart.pt_forw; pp != &FinalPart;) {
	    register struct partition *newpp;
	    newpp = pp;
	    pp = pp->pt_forw;
	    FREE_PT(newpp, ap->a_resource);
	}
    }

    /* Segs can't be freed until after a_hit() has returned */
#if 0
    /* FIXME: depends on commented out code above */
    if (HeadSeg)
	RT_FREE_SEG_LIST(HeadSeg, ap->a_resource);
#endif

out:
    bu_free((char *)ary_stp, "*ary_stp[]");
    bu_free((char *)ary_rp, "*ary_rp[]");
    bu_free((char *)ary_seg, "ary_seg[]");

    if (solidbits != NULL) {
	bu_bitv_free(solidbits);
    }
    if (RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) {
	bu_log("----------mshootray cpu=%d  %d, %d lvl=%d (%s) %s ret=%d\n",
	       ap->a_resource->re_cpu,
	       ap->a_x, ap->a_y,
	       ap->a_level,
	       ap->a_purpose != (char *)0 ? ap->a_purpose : "?",
	       status, ret);
    }
    return ret;
}
コード例 #3
0
ファイル: poly.c プロジェクト: cogitokat/brlcad
/**
 * R T _ P G _ S H O T
 *
 * Function -
 * Shoot a ray at a polygonal object.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_pg_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct tri_specific *trip =
	(struct tri_specific *)stp->st_specific;
#define MAXHITS 128		/* # surfaces hit, must be even */
    struct hit hits[MAXHITS];
    struct hit *hp;
    size_t nhits;

    nhits = 0;
    hp = &hits[0];

    /* consider each face */
    for (; trip; trip = trip->tri_forw) {
	fastf_t dn;		/* Direction dot Normal */
	fastf_t abs_dn;
	fastf_t k;
	fastf_t alpha, beta;
	vect_t wxb;		/* vertex - ray_start */
	vect_t xp;		/* wxb cross ray_dir */

	/*
	 * Ray Direction dot N.  (N is outward-pointing normal)
	 * wn points inwards, and is not unit length.
	 */
	dn = VDOT(trip->tri_wn, rp->r_dir);

	/*
	 * If ray lies directly along the face, (i.e., dot product
	 * is zero), drop this face.
	 */
	abs_dn = dn >= 0.0 ? dn : (-dn);
	if (abs_dn < SQRT_SMALL_FASTF)
	    continue;
	VSUB2(wxb, trip->tri_A, rp->r_pt);
	VCROSS(xp, wxb, rp->r_dir);

	/* Check for exceeding along the one side */
	alpha = VDOT(trip->tri_CA, xp);
	if (dn < 0.0) alpha = -alpha;
	if (alpha < 0.0 || alpha > abs_dn)
	    continue;

	/* Check for exceeding along the other side */
	beta = VDOT(trip->tri_BA, xp);
	if (dn > 0.0) beta = -beta;
	if (beta < 0.0 || beta > abs_dn)
	    continue;
	if (alpha+beta > abs_dn)
	    continue;
	k = VDOT(wxb, trip->tri_wn) / dn;

	/* For hits other than the first one, might check
	 * to see it this is approx. equal to previous one */

	/* If dn < 0, we should be entering the solid.
	 * However, we just assume in/out sorting later will work.
	 * Really should mark and check this!
	 */
	VJOIN1(hp->hit_point, rp->r_pt, k, rp->r_dir);

	/* HIT is within planar face */
	hp->hit_magic = RT_HIT_MAGIC;
	hp->hit_dist = k;
	VMOVE(hp->hit_normal, trip->tri_N);
	hp->hit_surfno = trip->tri_surfno;
	if (++nhits >= MAXHITS) {
	    bu_log("rt_pg_shot(%s): too many hits (%zu)\n", stp->st_name, nhits);
	    break;
	}
	hp++;
    }
    if (nhits == 0)
	return 0;		/* MISS */

    /* Sort hits, Near to Far */
    rt_hitsort(hits, nhits);

    /* Remove duplicate hits.
       We remove one of a pair of hits when they are
       1) close together, and
       2) both "entry" or both "exit" occurrences.
       Two immediate "entry" or two immediate "exit" hits suggest
       that we hit both of two joined faces, while we want to hit only
       one.  An "entry" followed by an "exit" (or vice versa) suggests
       that we grazed an edge, and thus we should leave both
       in the hit list. */

    {
	size_t i, j;

	for (i=0; i<nhits-1; i++) {
	    fastf_t dist;

	    dist = hits[i].hit_dist - hits[i+1].hit_dist;
	    if (NEAR_ZERO(dist, ap->a_rt_i->rti_tol.dist) &&
		VDOT(hits[i].hit_normal, rp->r_dir) *
		VDOT(hits[i+1].hit_normal, rp->r_dir) > 0)
	    {
		for (j=i; j<nhits-1; j++)
		    hits[j] = hits[j+1];
		nhits--;
		i--;
	    }
	}
    }


    if (nhits == 1)
	nhits = 0;

    if (nhits&1) {
	size_t i;
	static int nerrors = 0;		/* message counter */
	/*
	 * If this condition exists, it is almost certainly due to
	 * the dn==0 check above.  Thus, we will make the last
	 * surface rather thin.
	 * This at least makes the
	 * presence of this solid known.  There may be something
	 * better we can do.
	 */

	if (nerrors++ < 6) {
	    bu_log("rt_pg_shot(%s): WARNING %zu hits:\n", stp->st_name, nhits);
	    bu_log("\tray start = (%g %g %g) ray dir = (%g %g %g)\n",
		   V3ARGS(rp->r_pt), V3ARGS(rp->r_dir));
	    for (i=0; i < nhits; i++) {
		point_t tmp_pt;

		VJOIN1(tmp_pt, rp->r_pt, hits[i].hit_dist, rp->r_dir);
		if (VDOT(rp->r_dir, hits[i].hit_normal) < 0.0)
		    bu_log("\tentrance at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS(tmp_pt));
		else
		    bu_log("\texit at dist=%f (%g %g %g)\n", hits[i].hit_dist, V3ARGS(tmp_pt));
	    }
	}

	if (nhits > 2) {
	    fastf_t dot1, dot2;
	    size_t j;

	    /* likely an extra hit,
	     * look for consecutive entrances or exits */

	    dot2 = 1.0;
	    i = 0;
	    while (i<nhits) {
		dot1 = dot2;
		dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
		if (dot1 > 0.0 && dot2 > 0.0) {
		    /* two consecutive exits,
		     * manufacture an entrance at same distance
		     * as second exit.
		     */
		    for (j=nhits; j>i; j--)
			hits[j] = hits[j-1];	/* struct copy */

		    VREVERSE(hits[i].hit_normal, hits[i].hit_normal);
		    dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
		    nhits++;
		    bu_log("\t\tadding fictitious entry at %f (%s)\n", hits[i].hit_dist, stp->st_name);
		} else if (dot1 < 0.0 && dot2 < 0.0) {
		    /* two consecutive entrances,
		     * manufacture an exit between them.
		     */

		    for (j=nhits; j>i; j--)
			hits[j] = hits[j-1];	/* struct copy */

		    hits[i] = hits[i-1];	/* struct copy */
		    VREVERSE(hits[i].hit_normal, hits[i-1].hit_normal);
		    dot2 = VDOT(rp->r_dir, hits[i].hit_normal);
		    nhits++;
		    bu_log("\t\tadding fictitious exit at %f (%s)\n", hits[i].hit_dist, stp->st_name);
		}
		i++;
	    }

	} else {
	    hits[nhits] = hits[nhits-1];	/* struct copy */
	    VREVERSE(hits[nhits].hit_normal, hits[nhits-1].hit_normal);
	    bu_log("\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name);
	    nhits++;
	}
    }

    if (nhits&1) {
	if (nhits < MAXHITS) {
	    hits[nhits] = hits[nhits-1];	/* struct copy */
	    VREVERSE(hits[nhits].hit_normal, hits[nhits-1].hit_normal);
	    bu_log("\t\tadding fictitious hit at %f (%s)\n", hits[nhits].hit_dist, stp->st_name);
	    nhits++;
	} else
	    nhits--;
    }

    /* nhits is even, build segments */
    {
	struct seg *segp;
	size_t i;
	for (i=0; i < nhits; i += 2) {
	    RT_GET_SEG(segp, ap->a_resource);
	    segp->seg_stp = stp;
	    segp->seg_in = hits[i];		/* struct copy */
	    segp->seg_out = hits[i+1];	/* struct copy */
	    BU_LIST_INSERT(&(seghead->l), &(segp->l));
	}
    }
    return nhits;			/* HIT */
}
コード例 #4
0
ファイル: revolve.c プロジェクト: kanzure/brlcad
/**
 * Intersect a ray with a revolve.  If an intersection occurs, a struct
 * seg will be acquired and filled in.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_revolve_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct revolve_specific *rev =
	(struct revolve_specific *)stp->st_specific;
    struct seg *segp;

    struct hit *hitp;
    struct hit *hits[MAX_HITS], hit[MAX_HITS];

    size_t i, j, nseg, nhits;
    int in, out;

    fastf_t k, m, h, aa, bb;
    point_t dp, pr, xlated;
    vect_t vr, ur, norm, normS, normE;

    fastf_t start, end, angle;

    vect_t dir;
    point_t hit1, hit2;
    point2d_t hit2d, pt1, pt2;
    fastf_t a, b, c, disc, k1, k2, t1, t2;
    uint32_t *lng;
    struct line_seg *lsg;
    struct carc_seg *csg;

    nhits = 0;

    for (i=0; i<MAX_HITS; i++) hits[i] = &hit[i];

    vr[X] = VDOT(rev->xUnit, rp->r_dir);
    vr[Y] = VDOT(rev->yUnit, rp->r_dir);
    vr[Z] = VDOT(rev->zUnit, rp->r_dir);

    VSUB2(xlated, rp->r_pt, rev->v3d);
    pr[X] = VDOT(rev->xUnit, xlated);
    pr[Y] = VDOT(rev->yUnit, xlated);
    pr[Z] = VDOT(rev->zUnit, xlated);

    VMOVE(ur, vr);
    VUNITIZE(ur);

    if (rev->ang < M_2PI) {
	VREVERSE(normS, rev->yUnit);	/* start normal */
	start = (VDOT(normS, rev->v3d) - VDOT(normS, rp->r_pt)) / VDOT(normS, rp->r_dir);

	VCROSS(normE, rev->zUnit, rev->rEnd);	/* end normal */
	end = (VDOT(normE, rev->v3d) - VDOT(normE, rp->r_pt)) / VDOT(normE, rp->r_dir);

	VJOIN1(hit1, pr, start, vr);
	hit2d[Y] = hit1[Z];
	hit2d[X] = sqrt(hit1[X]*hit1[X] + hit1[Y]*hit1[Y]);

	VJOIN1(hit2, xlated, start, rp->r_dir);
	if (VDOT(rev->xUnit, hit2) < 0) {
	    /* set the sign of the 2D point's x coord */
	    hit2d[X] = -hit2d[X];
	}

	if (rt_sketch_contains(rev->skt, hit2d)) {
	    hit2d[X] = -hit2d[X];
	    if (rev->ang > M_PI && rt_sketch_contains(rev->skt, hit2d)) {
		/* skip it */
	    } else {
		hitp = hits[nhits++];
		hitp->hit_magic = RT_HIT_MAGIC;
		hitp->hit_dist = start;
		hitp->hit_surfno = (hit2d[X]>0) ? START_FACE_NEG : START_FACE_POS;
		VSET(hitp->hit_vpriv, -hit2d[X], hit2d[Y], 0);
	    }
	}

	VJOIN1(hit1, pr, end, vr);
	hit2d[Y] = hit1[Z];
	hit2d[X] = sqrt(hit1[X]*hit1[X] + hit1[Y]*hit1[Y]);

	VJOIN1(hit2, xlated, end, rp->r_dir);
	if (VDOT(rev->rEnd, hit2) < 0) {
	    /* set the sign of the 2D point's x coord */
	    hit2d[X] = -hit2d[X];
	}

	if (rt_sketch_contains(rev->skt, hit2d)) {
	    hit2d[X] = -hit2d[X];
	    if (rev->ang > M_PI && rt_sketch_contains(rev->skt, hit2d)) {
		/* skip it */
	    } else {
		if (nhits >= MAX_HITS) return -1; /* too many hits */
		hitp = hits[nhits++];
		hitp->hit_magic = RT_HIT_MAGIC;
		hitp->hit_dist = end;
		hitp->hit_surfno = (hit2d[X]>0) ? END_FACE_NEG : END_FACE_POS;
		VSET(hitp->hit_vpriv, -hit2d[X], hit2d[Y], 0);
	    }
	}
    }

    /**
     * calculate hyperbola parameters
     *
     * [ (x*x) / aa^2 ] - [ (y-h)^2 / bb^2 ] = 1
     *
     * x = aa cosh(t - k);
     * y = h + bb sinh(t - k);
     */

    VREVERSE(dp, pr);
    VSET(norm, ur[X], ur[Y], 0);

    k = VDOT(dp, norm) / VDOT(ur, norm);
    h = pr[Z] + k*vr[Z];

    if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) {
	aa = sqrt(pr[X]*pr[X] + pr[Y]*pr[Y]);
	bb = MAX_FASTF;
    } else {
	aa = sqrt((pr[X] + k*vr[X])*(pr[X] + k*vr[X]) + (pr[Y] + k*vr[Y])*(pr[Y] + k*vr[Y]));
	bb = sqrt(aa*aa * (1.0/(1 - ur[Z]*ur[Z]) - 1.0));
    }

    /**
     * if (ur[Z] == 1) {
     *	    bb = inf;
     *	    // ray becomes a line parallel to sketch's y-axis instead of a hyberbola
     * }
     * if (ur[Z] == 0) {
     *	    bb = 0;
     *	    // ray becomes a line parallel to sketch's x-axis instead of a hyperbola
     *	    // all hits must have x > aa
     * }
     */

    /* handle open sketches */
    if (!NEAR_ZERO(ur[Z], RT_DOT_TOL)) {
	for (i=0; i<rev->skt->vert_count && rev->ends[i] != -1; i++) {
	    V2MOVE(pt1, rev->skt->verts[rev->ends[i]]);
	    hit2d[Y] = pt1[Y];
	    if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) {
		/* ur[Z] == 1 */
		hit2d[X] = aa;
	    } else {
		hit2d[X] = aa*sqrt((hit2d[Y]-h)*(hit2d[Y]-h)/(bb*bb) + 1);
	    }
	    if (pt1[X] < 0) hit2d[X] = -fabs(hit2d[X]);
	    if (fabs(hit2d[X]) < fabs(pt1[X])) {
		/* valid hit */
		if (nhits >= MAX_HITS) return -1; /* too many hits */
		hitp = hits[nhits++];
		hitp->hit_magic = RT_HIT_MAGIC;
		hitp->hit_dist = (hit2d[Y] - pr[Z]) / vr[Z];
		hitp->hit_surfno = HORIZ_SURF;
		VJOIN1(hitp->hit_vpriv, pr, hitp->hit_dist, vr);
		hitp->hit_point[X] = hit2d[X];
		hitp->hit_point[Y] = hit2d[Y];
		hitp->hit_point[Z] = 0;

		angle = atan2(hitp->hit_vpriv[Y], hitp->hit_vpriv[X]);
		if (pt1[X] < 0) {
		    angle += M_PI;
		} else if (angle < 0) {
		    angle += M_2PI;
		}
		hit2d[X] = -hit2d[X];
		if (angle > rev->ang) {
		    nhits--;
		    continue;
		} else if ((angle + M_PI < rev->ang || angle - M_PI > 0)
			   && rt_sketch_contains(rev->skt, hit2d)
			   && hit2d[X] > 0) {
		    nhits--;
		    continue;
		}
		/* X and Y are used for uv(), Z is used for norm() */
		hitp->hit_vpriv[X] = pt1[X];
		hitp->hit_vpriv[Y] = angle;
		if (i+1 < rev->skt->vert_count && rev->ends[i+1] != -1 &&
		    NEAR_EQUAL(rev->skt->verts[rev->ends[i]][Y],
			       rev->skt->verts[rev->ends[i+1]][Y], SMALL)) {
		    hitp->hit_vpriv[Z] = rev->skt->verts[rev->ends[i+1]][X];
		    i++;
		    if (fabs(hit2d[X]) < fabs(hitp->hit_vpriv[Z])) {
			nhits--;
		    }
		} else {
		    hitp->hit_vpriv[Z] = 0;
		}
	    }
	}
    }

    /* find hyperbola intersection with each sketch segment */
    nseg = rev->skt->curve.count;
    for (i=0; i<nseg; i++) {
	lng = (uint32_t *)rev->skt->curve.segment[i];

	switch (*lng) {
	    case CURVE_LSEG_MAGIC:
		lsg = (struct line_seg *)lng;
		V2MOVE(pt1, rev->skt->verts[lsg->start]);
		V2MOVE(pt2, rev->skt->verts[lsg->end]);
		V2SUB2(dir, pt2, pt1);
		if (ZERO(dir[X])) {
		    m = 1.0;
		} else {
		    m = dir[Y] / dir[X];
		}

		if (NEAR_EQUAL(fabs(ur[Z]), 1.0, RT_DOT_TOL)) {
		    /* ray is vertical line at x=aa */
		    if (FMIN(pt1[X], pt2[X]) < aa && aa < FMAX(pt1[X], pt2[X])) {
			/* check the positive side of the sketch (x > 0) */
			k1 = (m * (aa - pt1[X]) + pt1[Y] - pr[Z]) / vr[Z];
			VJOIN1(hit1, pr, k1, vr);
			angle = atan2(hit1[Y], hit1[X]);
			hit2d[X] = -aa;		/* use neg to check for overlap in contains() */
			hit2d[Y] = hit1[Z];
			if (angle < 0) {
			    angle += M_2PI;
			}
			if (angle < rev->ang &&
			    !((angle + M_PI < rev->ang || angle - M_PI > 0)
			      && rt_sketch_contains(rev->skt, hit2d))) {
			    if (nhits >= MAX_HITS) return -1; /* too many hits */
			    hitp = hits[nhits++];
			    hitp->hit_point[X] = -hit2d[X];
			    hitp->hit_point[Y] = hit2d[Y];
			    hitp->hit_point[Z] = 0;
			    VMOVE(hitp->hit_vpriv, hit1);
			    if (ZERO(m)) {
				hitp->hit_vpriv[Z] = 0.0;
			    } else {
				hitp->hit_vpriv[Z] = -1.0/m;
			    }
			    hitp->hit_magic = RT_HIT_MAGIC;
			    hitp->hit_dist = k1;
			    hitp->hit_surfno = i;
			}
		    }
		    if (FMIN(pt1[X], pt2[X]) < -aa && -aa < FMAX(pt1[X], pt2[X])) {
			/* check negative side of the sketch (x < 0) */
			k1 = (m * (-aa - pt1[X]) + pt1[Y] - pr[Z]) / vr[Z];
			VJOIN1(hit1, pr, k1, vr);
			angle = atan2(hit1[Y], hit1[X]);
			hit2d[X] = aa;		/* use neg to check for overlap in contains() */
			hit2d[Y] = hit1[Z];
			if (angle < 0) {
			    angle += M_PI;
			}
			if (angle < rev->ang &&
			    !((angle + M_PI < rev->ang || angle - M_PI > 0)
			      && rt_sketch_contains(rev->skt, hit2d))) {
			    if (nhits >= MAX_HITS) return -1; /* too many hits */
			    hitp = hits[nhits++];
			    hitp->hit_point[X] = -hit2d[X];
			    hitp->hit_point[Y] = hit2d[Y];
			    hitp->hit_point[Z] = 0;
			    VMOVE(hitp->hit_vpriv, hit1);
			    if (ZERO(m)) {
				hitp->hit_vpriv[Z] = 0.0;
			    } else {
				hitp->hit_vpriv[Z] = 1.0/m;
			    }
			    hitp->hit_magic = RT_HIT_MAGIC;
			    hitp->hit_dist = k1;
			    hitp->hit_surfno = i;
			}
		    }
		} else if (NEAR_ZERO(ur[Z], RT_DOT_TOL)) {
		    /* ray is horizontal line at y = h; hit2d[X] > aa */
		    if (FMIN(pt1[Y], pt2[Y]) < h && h < FMAX(pt1[Y], pt2[Y])) {
			if (ZERO(m)) {
			    hit2d[X] = pt1[X];
			} else {
			    hit2d[X] = pt1[X] + (h-pt1[Y])/m;
			}
			hit2d[Y] = h;
			if (fabs(hit2d[X]) > aa) {
			    k1 = k + sqrt(hit2d[X]*hit2d[X] - aa*aa);
			    k2 = k - sqrt(hit2d[X]*hit2d[X] - aa*aa);

			    VJOIN1(hit1, pr, k1, vr);
			    angle = atan2(hit1[Y], hit1[X]);
			    if (hit2d[X] < 0) {
				angle += M_PI;
			    } else if (angle < 0) {
				angle += M_2PI;
			    }
			    hit2d[X] = -hit2d[X];
			    if (angle < rev->ang &&
				!((angle + M_PI < rev->ang || angle - M_PI > 0)
				  && rt_sketch_contains(rev->skt, hit2d))) {
				if (nhits >= MAX_HITS) return -1; /* too many hits */
				hitp = hits[nhits++];
				hitp->hit_point[X] = -hit2d[X];
				hitp->hit_point[Y] = hit2d[Y];
				hitp->hit_point[Z] = 0;
				VMOVE(hitp->hit_vpriv, hit1);
				if (ZERO(m)) {
				    hitp->hit_vpriv[Z] = 0.0;
				} else {
				    hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m;
				}
				hitp->hit_magic = RT_HIT_MAGIC;
				hitp->hit_dist = k1;
				hitp->hit_surfno = i;
			    }

			    VJOIN1(hit2, pr, k2, vr);
			    angle = atan2(hit2[Y], hit2[X]);
			    if (-hit2d[X] < 0) {
				angle += M_PI;
			    } else if (angle < 0) {
				angle += M_2PI;
			    }
			    if (angle < rev->ang &&
				!((angle + M_PI < rev->ang || angle - M_PI > 0)
				  && rt_sketch_contains(rev->skt, hit2d))) {
				if (nhits >= MAX_HITS) return -1; /* too many hits */
				hitp = hits[nhits++];
				hitp->hit_point[X] = -hit2d[X];
				hitp->hit_point[Y] = hit2d[Y];
				hitp->hit_point[Z] = 0;
				VMOVE(hitp->hit_vpriv, hit2);
				if (ZERO(m)) {
				    hitp->hit_vpriv[Z] = 0.0;
				} else {
				    hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m;
				}
				hitp->hit_magic = RT_HIT_MAGIC;
				hitp->hit_dist = k2;
				hitp->hit_surfno = i;
			    }
			}
		    }
		} else {

		    a = dir[X]*dir[X]/(aa*aa) - dir[Y]*dir[Y]/(bb*bb);
		    b = 2*(dir[X]*pt1[X]/(aa*aa) - dir[Y]*(pt1[Y]-h)/(bb*bb));
		    c = pt1[X]*pt1[X]/(aa*aa) - (pt1[Y]-h)*(pt1[Y]-h)/(bb*bb) - 1;
		    disc = b*b - (4.0 * a * c);
		    if (!NEAR_ZERO(a, RT_PCOEF_TOL)) {
			if (disc > 0) {
			    disc = sqrt(disc);
			    t1 =  (-b + disc) / (2.0 * a);
			    t2 =  (-b - disc) / (2.0 * a);
			    k1 = (pt1[Y]-pr[Z] + t1*dir[Y])/vr[Z];
			    k2 = (pt1[Y]-pr[Z] + t2*dir[Y])/vr[Z];

			    if (t1 > 0 && t1 < 1) {
				if (nhits >= MAX_HITS) return -1; /* too many hits */
				VJOIN1(hit1, pr, k1, vr);
				angle = atan2(hit1[Y], hit1[X]);
				V2JOIN1(hit2d, pt1, t1, dir);
				if (hit2d[X] < 0) {
				    angle += M_PI;
				} else if (angle < 0) {
				    angle += M_2PI;
				}
				hit2d[X] = -hit2d[X];
				if (angle < rev->ang) {
				    if ((angle + M_PI < rev->ang || angle - M_PI > 0)
					&& rt_sketch_contains(rev->skt, hit2d)) {
					/* overlap, so ignore it */
				    } else {
					hitp = hits[nhits++];
					hitp->hit_point[X] = -hit2d[X];
					hitp->hit_point[Y] = hit2d[Y];
					hitp->hit_point[Z] = 0;
					VMOVE(hitp->hit_vpriv, hit1);
					if (ZERO(m)) {
					    hitp->hit_vpriv[Z] = 0.0;
					} else {
					    hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m;
					}
					hitp->hit_magic = RT_HIT_MAGIC;
					hitp->hit_dist = k1;
					hitp->hit_surfno = i;
				    }
				}
			    }
			    if (t2 > 0 && t2 < 1) {
				if (nhits >= MAX_HITS) return -1; /* too many hits */
				VJOIN1(hit2, pr, k2, vr);
				angle = atan2(hit2[Y], hit2[X]);
				V2JOIN1(hit2d, pt1, t2, dir);
				if (hit2d[X] < 0) {
				    angle += M_PI;
				} else if (angle < 0) {
				    angle += M_2PI;
				}
				hit2d[X] = -hit2d[X];
				if (angle < rev->ang) {
				    if ((angle + M_PI < rev->ang || angle - M_PI > 0)
					&& rt_sketch_contains(rev->skt, hit2d)) {
					/* overlap, so ignore it */
				    } else {
					hitp = hits[nhits++];
					hitp->hit_point[X] = -hit2d[X];
					hitp->hit_point[Y] = hit2d[Y];
					hitp->hit_point[Z] = 0;
					VMOVE(hitp->hit_vpriv, hit2);
					if (ZERO(m)) {
					    hitp->hit_vpriv[Z] = 0.0;
					} else {
					    hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m;
					}
					hitp->hit_magic = RT_HIT_MAGIC;
					hitp->hit_dist = k2;
					hitp->hit_surfno = i;
				    }
				}
			    }
			}
		    } else if (!NEAR_ZERO(b, RT_PCOEF_TOL)) {
			t1 = -c / b;
			k1 = (pt1[Y]-pr[Z] + t1*dir[Y])/vr[Z];
			if (t1 > 0 && t1 < 1) {
			    if (nhits >= MAX_HITS) return -1; /* too many hits */

			    VJOIN1(hit1, pr, k1, vr);
			    angle = atan2(hit1[Y], hit1[X]);
			    V2JOIN1(hit2d, pt1, t1, dir);
			    if (hit2d[X] < 0) {
				angle += M_PI;
			    } else if (angle < 0) {
				angle += M_2PI;
			    }
			    hit2d[X] = -hit2d[X];
			    if (angle < rev->ang) {
				if ((angle + M_PI < rev->ang || angle - M_PI > 0)
				    && rt_sketch_contains(rev->skt, hit2d)) {
				    /* overlap, so ignore it */
				} else {
				    hitp = hits[nhits++];
				    hitp->hit_point[X] = -hit2d[X];
				    hitp->hit_point[Y] = hit2d[Y];
				    hitp->hit_point[Z] = 0;
				    VMOVE(hitp->hit_vpriv, hit1);
				    if (ZERO(m)) {
					hitp->hit_vpriv[Z] = 0.0;
				    } else {
					hitp->hit_vpriv[Z] = (hit2d[X]>0) ? 1.0/m : -1.0/m;
				    }
				    hitp->hit_magic = RT_HIT_MAGIC;
				    hitp->hit_dist = k1;
				    hitp->hit_surfno = i;
				}
			    }
			}
		    }
		}
		break;
	    case CURVE_CARC_MAGIC:
		/*
		  circle: (x-cx)^2 + (y-cy)^2 = cr^2
		  x = (1/2cx)y^2 + (-cy/cx)y + (1/2cx)(cy^2 + cx^2 - cr^2) + (1/2cx)(x^2)
		  x = f(y) + (1/2cx)x^2

		  hyperbola:
		  [(x-hx)/a]^2 - [(y-hy)/b]^2 = 1
		  x^2 = (a^2/b^2)y^2 + (-2*hy*a^2/b^2)y + (hy^2 * a^2/b^2) + a^2
		  x^2 = g(y)

		  plug the second equation into the first to get:
		  x = f(y) + (1/2cx)g(y)
		  then square that to get:
		  x^2 = {f(y) + (1/2cx)g(y)}^2 = g(y)
		  move all to one side to get:
		  0 = {f(y) + (1/2cx)g(y)}^2 - g(y)
		  this is a fourth order polynomial in y.
		*/
		{
		    bn_poly_t circleX;	/* f(y) */
		    bn_poly_t hypXsq;		/* g(y) */
		    bn_poly_t hypXsq_scaled;	/* g(y) / (2*cx) */
		    bn_poly_t sum;		/* f(y) + g(y)/(2cx) */
		    bn_poly_t sum_sq;		/* {f(y) + g(y)/(2cx)}^2 */
		    bn_poly_t answer;		/* {f(y) + g(y)/(2cx)}^2 - g(y) */
		    bn_complex_t roots[4];
		    int rootcnt;

		    fastf_t cx, cy, crsq = 0;	/* carc's (x, y) coords and radius^2 */
		    point2d_t center, radius;

		    /* calculate circle parameters */
		    csg = (struct carc_seg *)lng;

		    if (csg->radius <= 0.0) {
			/* full circle, "end" is center and "start" is on the circle */
			V2MOVE(center, rev->skt->verts[csg->end]);
			V2SUB2(radius, rev->skt->verts[csg->start], center);
			crsq = MAG2SQ(radius);
		    } else {
			point_t startpt, endpt, midpt;
			vect_t s_to_m;
			vect_t bisector;
			vect_t vertical;
			fastf_t distance;
			fastf_t magsq_s2m;

			VSET(vertical, 0, 0, 1);
			V2MOVE(startpt, rev->skt->verts[csg->start]);
			startpt[Z] = 0.0;
			V2MOVE(endpt, rev->skt->verts[csg->end]);
			endpt[Z] = 0.0;

			VBLEND2(midpt, 0.5, startpt, 0.5, endpt);
			VSUB2(s_to_m, midpt, startpt);
			VCROSS(bisector, vertical, s_to_m);
			VUNITIZE(bisector);
			magsq_s2m = MAGSQ(s_to_m);
			if (magsq_s2m > csg->radius*csg->radius) {
			    fastf_t max_radius;

			    max_radius = sqrt(magsq_s2m);
			    if (NEAR_EQUAL(max_radius, csg->radius, RT_LEN_TOL)) {
				csg->radius = max_radius;
			    } else {
				bu_log("Impossible radius for circular arc in extrusion (%s), is %g, cannot be more than %g!\n",
				       stp->st_dp->d_namep, csg->radius, sqrt(magsq_s2m));
				bu_log("Difference is %g\n", max_radius - csg->radius);
				return -1;
			    }
			}
			distance = sqrt(csg->radius*csg->radius - magsq_s2m);

			/* save arc center */
			if (csg->center_is_left) {
			    V2JOIN1(center, midpt, distance, bisector);
			} else {
			    V2JOIN1(center, midpt, -distance, bisector);
			}
		    }

		    cx = center[X];
		    cy = center[Y];

		    circleX.dgr = 2;
		    hypXsq.dgr = 2;
		    hypXsq_scaled.dgr = 2;
		    sum.dgr = 2;
		    sum_sq.dgr = 4;
		    answer.dgr = 4;

		    circleX.cf[0] = (cy*cy + cx*cx - crsq)/(2.0*cx);
		    circleX.cf[1] = -cy/cx;
		    circleX.cf[2] = 1/(2.0*cx);

		    hypXsq_scaled.cf[0] = hypXsq.cf[0] = aa*aa + h*h*aa*aa/(bb*bb);
		    hypXsq_scaled.cf[1] = hypXsq.cf[1] = -2.0*h*aa*aa/(bb*bb);
		    hypXsq_scaled.cf[2] = hypXsq.cf[2] = (aa*aa)/(bb*bb);

		    bn_poly_scale(&hypXsq_scaled, 1.0 / (2.0 * cx));
		    bn_poly_add(&sum, &hypXsq_scaled, &circleX);
		    bn_poly_mul(&sum_sq, &sum, &sum);
		    bn_poly_sub(&answer, &sum_sq, &hypXsq);

		    /* It is known that the equation is 4th order.  Therefore, if the
		     * root finder returns other than 4 roots, error.
		     */
		    rootcnt = rt_poly_roots(&answer, roots, stp->st_dp->d_namep);
		    if (rootcnt != 4) {
			if (rootcnt > 0) {
			    bu_log("tor:  rt_poly_roots() 4!=%d\n", rootcnt);
			    bn_pr_roots(stp->st_name, roots, rootcnt);
			} else if (rootcnt < 0) {
			    static int reported=0;
			    bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
			    if (!reported) {
				VPRINT("while shooting from:\t", rp->r_pt);
				VPRINT("while shooting at:\t", rp->r_dir);
				bu_log("Additional torus convergence failure details will be suppressed.\n");
				reported=1;
			    }
			}
		    }

		    break;
		}
	    case CURVE_BEZIER_MAGIC:
		break;
	    case CURVE_NURB_MAGIC:
		break;
	    default:
		bu_log("rt_revolve_prep: ERROR: unrecognized segment type!\n");
		break;
	}

    }

    if (nhits%2 != 0) {
	bu_log("odd number of hits: %zu\n", nhits);
	for (i=0; i<nhits; i++) {
	    bu_log("\t(%6.2f, %6.2f)\t%6.2f\t%2d\n",
		   hits[i]->hit_point[X], hits[i]->hit_point[Y], hits[i]->hit_dist, hits[i]->hit_surfno);
	}
	return -1;
    }

    /* sort hitpoints (an arbitrary number of hits depending on sketch) */
    for (i=0; i<nhits; i+=2) {
	in = out = -1;
	for (j=0; j<nhits; j++) {
	    if (hits[j] == NULL) continue;
	    if (in == -1) {
		in = j;
		continue;
	    }
	    /* store shortest dist as 'in', second shortest as 'out' */
	    if (hits[j]->hit_dist <= hits[in]->hit_dist) {
		out = in;
		in = j;
	    } else if (out == -1 || hits[j]->hit_dist <= hits[out]->hit_dist) {
		out = j;
	    }
	}
	if (in == -1 || out == -1) {
	    bu_log("failed to find valid segment. nhits: %zu\n", nhits);
	    break;
	}

	if (ZERO(hits[in]->hit_dist - hits[out]->hit_dist)) {
	    hits[in] = NULL;
	    hits[out] = NULL;
	    continue;
	}

	RT_GET_SEG(segp, ap->a_resource);
	segp->seg_stp = stp;

	segp->seg_in = *hits[in];
	hits[in] = NULL;
	segp->seg_out = *hits[out];
	hits[out] = NULL;
	BU_LIST_INSERT(&(seghead->l), &(segp->l));
    }

    return nhits;
}
コード例 #5
0
ファイル: superell.c プロジェクト: kanzure/brlcad
/**
 * Intersect a ray with an superellipsoid, where all constant terms
 * have been precomputed by rt_superell_prep().  If an intersection
 * occurs, a struct seg will be acquired and filled in.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_superell_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    static int counter=10;

    struct superell_specific *superell = (struct superell_specific *)stp->st_specific;
    bn_poly_t equation; /* equation of superell to be solved */
    vect_t translated;  /* translated shot vector */
    vect_t newShotPoint; /* P' */
    vect_t newShotDir; /* D' */
    vect_t normalizedShotPoint; /* P' with normalized dist from superell */
    bn_complex_t complexRoot[4]; /* roots returned from poly solver */
    double realRoot[4];  /* real ray distance values */
    int i, j;
    struct seg *segp;

    /* translate ray point */
    /* VSUB2(translated, rp->r_pt, superell->superell_V); */
    (translated)[X] = (rp->r_pt)[X] - (superell->superell_V)[X];
    (translated)[Y] = (rp->r_pt)[Y] - (superell->superell_V)[Y];
    (translated)[Z] = (rp->r_pt)[Z] - (superell->superell_V)[Z];

    /* scale and rotate point to get P' */

    /* MAT4X3VEC(newShotPoint, superell->superell_SoR, translated); */
    newShotPoint[X] = (superell->superell_SoR[0]*translated[X] + superell->superell_SoR[1]*translated[Y] + superell->superell_SoR[ 2]*translated[Z]) * 1.0/(superell->superell_SoR[15]);
    newShotPoint[Y] = (superell->superell_SoR[4]*translated[X] + superell->superell_SoR[5]*translated[Y] + superell->superell_SoR[ 6]*translated[Z]) * 1.0/(superell->superell_SoR[15]);
    newShotPoint[Z] = (superell->superell_SoR[8]*translated[X] + superell->superell_SoR[9]*translated[Y] + superell->superell_SoR[10]*translated[Z]) * 1.0/(superell->superell_SoR[15]);

    /* translate ray direction vector */
    MAT4X3VEC(newShotDir, superell->superell_SoR, rp->r_dir);
    VUNITIZE(newShotDir);

    /* normalize distance from the superell.  substitutes a corrected ray
     * point, which contains a translation along the ray direction to the
     * closest approach to vertex of the superell.  Translating the ray
     * along the direction of the ray to the closest point near the
     * primitive's center vertex.  New ray origin is hence, normalized.
     */
    VSCALE(normalizedShotPoint, newShotDir,
           VDOT(newShotPoint, newShotDir));
    VSUB2(normalizedShotPoint, newShotPoint, normalizedShotPoint);

    /* Now generate the polynomial equation for passing to the root finder */

    equation.dgr = 2;

    /* (x^2 / A) + (y^2 / B) + (z^2 / C) - 1 */
    equation.cf[0] = newShotPoint[X] * newShotPoint[X] * superell->superell_invmsAu + newShotPoint[Y] * newShotPoint[Y] * superell->superell_invmsBu + newShotPoint[Z] * newShotPoint[Z] * superell->superell_invmsCu - 1;
    /* (2xX / A) + (2yY / B) + (2zZ / C) */
    equation.cf[1] = 2 * newShotDir[X] * newShotPoint[X] * superell->superell_invmsAu + 2 * newShotDir[Y] * newShotPoint[Y] * superell->superell_invmsBu + 2 * newShotDir[Z] * newShotPoint[Z] * superell->superell_invmsCu;
    /* (X^2 / A) + (Y^2 / B) + (Z^2 / C) */
    equation.cf[2] = newShotDir[X] * newShotDir[X] * superell->superell_invmsAu + newShotDir[Y] * newShotDir[Y] * superell->superell_invmsBu + newShotDir[Z] * newShotDir[Z] * superell->superell_invmsCu;

    if ((i = rt_poly_roots(&equation, complexRoot, stp->st_dp->d_namep)) != 2) {
        if (i > 0) {
            bu_log("rt_superell_shot():  poly roots %d != 2\n", i);
            bn_pr_roots(stp->st_name, complexRoot, i);
        } else if (i < 0) {
            static int reported=0;
            bu_log("rt_superell_shot():  The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
            if (!reported) {
                VPRINT("while shooting from:\t", rp->r_pt);
                VPRINT("while shooting at:\t", rp->r_dir);
                bu_log("rt_superell_shot():  Additional superellipsoid convergence failure details will be suppressed.\n");
                reported=1;
            }
        }
        return 0; /* MISS */
    }

    /* XXX BEGIN CUT */
    /* Only real roots indicate an intersection in real space.
     *
     * Look at each root returned; if the imaginary part is zero
     * or sufficiently close, then use the real part as one value
     * of 't' for the intersections
     */
    for (j=0, i=0; j < 2; j++) {
        if (NEAR_ZERO(complexRoot[j].im, 0.001))
            realRoot[i++] = complexRoot[j].re;
    }

    /* reverse above translation by adding distance to all 'k' values. */
    /* for (j = 0; j < i; ++j)
       realRoot[j] -= VDOT(newShotPoint, newShotDir);
    */

    /* Here, 'i' is number of points found */
    switch (i) {
    case 0:
        return 0;		/* No hit */

    default:
        bu_log("rt_superell_shot():  reduced 4 to %d roots\n", i);
        bn_pr_roots(stp->st_name, complexRoot, 4);
        return 0;		/* No hit */

    case 2:
    {
        /* Sort most distant to least distant. */
        fastf_t u;
        if ((u=realRoot[0]) < realRoot[1]) {
            /* bubble larger towards [0] */
            realRoot[0] = realRoot[1];
            realRoot[1] = u;
        }
    }
    break;
    case 4:
    {
        short n;
        short lim;

        /* Inline rt_pt_sort().  Sorts realRoot[] into descending order. */
        for (lim = i-1; lim > 0; lim--) {
            for (n = 0; n < lim; n++) {
                fastf_t u;
                if ((u=realRoot[n]) < realRoot[n+1]) {
                    /* bubble larger towards [0] */
                    realRoot[n] = realRoot[n+1];
                    realRoot[n+1] = u;
                }
            }
        }
    }
    break;
    }

    if (counter > 0) {
        bu_log("rt_superell_shot():  realroot in %f out %f\n", realRoot[1], realRoot[0]);
        counter--;
    }


    /* Now, t[0] > t[npts-1] */
    /* realRoot[1] is entry point, and realRoot[0] is farthest exit point */
    RT_GET_SEG(segp, ap->a_resource);
    segp->seg_stp = stp;
    segp->seg_in.hit_dist = realRoot[1];
    segp->seg_out.hit_dist = realRoot[0];
    /* segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 0; */
    /* Set aside vector for rt_superell_norm() later */
    /* VJOIN1(segp->seg_in.hit_vpriv, newShotPoint, realRoot[1], newShotDir); */
    /* VJOIN1(segp->seg_out.hit_vpriv, newShotPoint, realRoot[0], newShotDir); */
    BU_LIST_INSERT(&(seghead->l), &(segp->l));

    if (i == 2) {
        return 2;			/* HIT */
    }

    /* 4 points */
    /* realRoot[3] is entry point, and realRoot[2] is exit point */
    RT_GET_SEG(segp, ap->a_resource);
    segp->seg_stp = stp;
    segp->seg_in.hit_dist = realRoot[3]*superell->superell_e;
    segp->seg_out.hit_dist = realRoot[2]*superell->superell_e;
    segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 1;
    VJOIN1(segp->seg_in.hit_vpriv, newShotPoint, realRoot[3], newShotDir);
    VJOIN1(segp->seg_out.hit_vpriv, newShotPoint, realRoot[2], newShotDir);
    BU_LIST_INSERT(&(seghead->l), &(segp->l));
    return 4;			/* HIT */
    /* XXX END CUT */

}
コード例 #6
0
ファイル: hyp.c プロジェクト: kanzure/brlcad
/**
 * Intersect a ray with a hyp.  If an intersection occurs, a struct
 * seg will be acquired and filled in.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_hyp_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct hyp_specific *hyp =	(struct hyp_specific *)stp->st_specific;
    struct seg *segp;

    struct hit hits[5];	/* 4 potential hits (top, bottom, 2 sides) */
    struct hit *hitp;	/* pointer to hitpoint */

    vect_t dp;
    vect_t pp;
    fastf_t k1, k2;
    vect_t xlated;

    fastf_t a, b, c;
    fastf_t disc;
    fastf_t hitX, hitY;

    fastf_t height;

    hitp = &hits[0];

    dp[X] = VDOT(hyp->hyp_Aunit, rp->r_dir);
    dp[Y] = VDOT(hyp->hyp_Bunit, rp->r_dir);
    dp[Z] = VDOT(hyp->hyp_Hunit, rp->r_dir);

    VSUB2(xlated, rp->r_pt, hyp->hyp_V);
    pp[X] = VDOT(hyp->hyp_Aunit, xlated);
    pp[Y] = VDOT(hyp->hyp_Bunit, xlated);
    pp[Z] = VDOT(hyp->hyp_Hunit, xlated);

    /* find roots to quadratic (hitpoints) */
    a = hyp->hyp_rx*dp[X]*dp[X] + hyp->hyp_ry*dp[Y]*dp[Y] - hyp->hyp_rz*dp[Z]*dp[Z];
    b = 2.0 * (hyp->hyp_rx*pp[X]*dp[X] + hyp->hyp_ry*pp[Y]*dp[Y] - hyp->hyp_rz*pp[Z]*dp[Z]);
    c = hyp->hyp_rx*pp[X]*pp[X] + hyp->hyp_ry*pp[Y]*pp[Y] - hyp->hyp_rz*pp[Z]*pp[Z] - 1.0;

    disc = b*b - (4.0 * a * c);
    if (!NEAR_ZERO(a, RT_PCOEF_TOL)) {
	if (disc > 0) {
	    disc = sqrt(disc);

	    k1 = (-b + disc) / (2.0 * a);
	    k2 = (-b - disc) / (2.0 * a);

	    VJOIN1(hitp->hit_vpriv, pp, k1, dp);
	    height = hitp->hit_vpriv[Z];
	    if (fabs(height) <= hyp->hyp_Hmag) {
		hitp->hit_magic = RT_HIT_MAGIC;
		hitp->hit_dist = k1;
		hitp->hit_surfno = HYP_NORM_BODY;
		hitp++;
	    }

	    VJOIN1(hitp->hit_vpriv, pp, k2, dp);
	    height = hitp->hit_vpriv[Z];
	    if (fabs(height) <= hyp->hyp_Hmag) {
		hitp->hit_magic = RT_HIT_MAGIC;
		hitp->hit_dist = k2;
		hitp->hit_surfno = HYP_NORM_BODY;
		hitp++;
	    }
	}
    } else if (!NEAR_ZERO(b, RT_PCOEF_TOL)) {
	k1 = -c / b;
	VJOIN1(hitp->hit_vpriv, pp, k1, dp);
	if (hitp->hit_vpriv[Z] >= -hyp->hyp_Hmag
	    && hitp->hit_vpriv[Z] <= hyp->hyp_Hmag) {
	    hitp->hit_magic = RT_HIT_MAGIC;
	    hitp->hit_dist = k1;
	    hitp->hit_surfno = HYP_NORM_BODY;
	    hitp++;
	}
    }

    /* check top & bottom plates */
    k1 = (hyp->hyp_Hmag - pp[Z]) / dp[Z];
    k2 = (-hyp->hyp_Hmag - pp[Z]) / dp[Z];

    VJOIN1(hitp->hit_vpriv, pp, k1, dp);
    hitX = hitp->hit_vpriv[X];
    hitY = hitp->hit_vpriv[Y];
    /* check if hitpoint is on the top surface */
    if ((hyp->hyp_rx*hitX*hitX + hyp->hyp_ry*hitY*hitY) < hyp->hyp_bounds) {
	hitp->hit_magic = RT_HIT_MAGIC;
	hitp->hit_dist = k1;
	hitp->hit_surfno = HYP_NORM_TOP;
	hitp++;
    }

    VJOIN1(hitp->hit_vpriv, pp, k2, dp);
    hitX = hitp->hit_vpriv[X];
    hitY = hitp->hit_vpriv[Y];
    /* check if hitpoint is on the bottom surface */
    if ((hyp->hyp_rx*hitX*hitX + hyp->hyp_ry*hitY*hitY) < hyp->hyp_bounds) {
	hitp->hit_magic = RT_HIT_MAGIC;
	hitp->hit_dist = k2;
	hitp->hit_surfno = HYP_NORM_BOTTOM;
	hitp++;
    }

    if (hitp == &hits[0] || hitp == &hits[1] || hitp == &hits[3]) {
	return 0;	/* MISS */
    }

    if (hitp == &hits[2]) {
	/* 2 hits */
	if (hits[0].hit_dist < hits[1].hit_dist) {
	    /* entry is [0], exit is [1] */
	    RT_GET_SEG(segp, ap->a_resource);
	    segp->seg_stp = stp;
	    segp->seg_in = hits[0];	/* struct copy */
	    segp->seg_out = hits[1];	/* struct copy */
	    BU_LIST_INSERT(&(seghead->l), &(segp->l));
	} else {
	    /* entry is [1], exit is [0] */

	    RT_GET_SEG(segp, ap->a_resource);
	    segp->seg_stp = stp;
	    segp->seg_in = hits[1];	/* struct copy */
	    segp->seg_out = hits[0];	/* struct copy */
	    BU_LIST_INSERT(&(seghead->l), &(segp->l));
	}
	return 2;			/* HIT */
    } else {
	/* 4 hits:  0, 1 are sides, 2, 3 are top/bottom*/
	struct hit sorted[4];

	if (hits[0].hit_dist > hits[1].hit_dist) {
	    sorted[1] = hits[1];
	    sorted[2] = hits[0];
	} else {
	    sorted[1] = hits[0];
	    sorted[2] = hits[1];
	}
	if (hits[2].hit_dist > hits[3].hit_dist) {
	    sorted[0] = hits[3];
	    sorted[3] = hits[2];
	} else {
	    sorted[0] = hits[2];
	    sorted[3] = hits[3];
	}

	if (sorted[0].hit_dist > sorted[1].hit_dist
	    || sorted[1].hit_dist > sorted[2].hit_dist
	    || sorted[2].hit_dist > sorted[3].hit_dist) {
	    bu_log("sorting error\n");
	}

	/* hit segments are now (0, 1) and (2, 3) */
	RT_GET_SEG(segp, ap->a_resource);
	segp->seg_stp = stp;
	segp->seg_in = sorted[0];	/* struct copy */
	segp->seg_out = sorted[1];	/* struct copy */
	BU_LIST_INSERT(&(seghead->l), &(segp->l));

	RT_GET_SEG(segp, ap->a_resource);
	segp->seg_stp = stp;
	segp->seg_in = sorted[2];	/* struct copy */
	segp->seg_out = sorted[3];	/* struct copy */
	BU_LIST_INSERT(&(seghead->l), &(segp->l));

	return 4;
    }
}
コード例 #7
0
int
rt_metaball_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct rt_metaball_internal *mb = (struct rt_metaball_internal *)stp->st_specific;
    struct seg *segp = NULL;
    int retval = 0;
    fastf_t step, distleft;
    point_t p, inc;
    const point_t *cp = (const point_t *)&p;

    /* switching behavior to retain old code for performance and correctness
     * comparisons. */
#define SHOOTALGO 3

#if SHOOTALGO == 2
    int fhin = 1;
#endif

    step = mb->initstep;
    distleft = (rp->r_max-rp->r_min) + step * 3.0;

    VMOVE(p, rp->r_pt);
    VSCALE(inc, rp->r_dir, step); /* assume it's normalized and we want to creep at step */

    /* walk back out of the solid */
    while (rt_metaball_point_value(cp, mb) >= mb->threshold) {
#if SHOOTALGO == 2
	fhin = -1;
#endif
	distleft += step;
	VSUB2(p, p, inc);
    }

#if SHOOTALGO == 2
    /* we hit, but not as fine-grained as we want. So back up one step,
     * cut the step size in half and start over...
     */
    {
	int mb_stat = 0, segsleft = abs(ap->a_onehit);
	point_t delta;

#define STEPBACK { distleft += step; VSUB2(p, p, inc); step *= .5; VSCALE(inc, inc, .5); }
#define STEPIN(x) { \
    --segsleft; \
    ++retval; \
    VSUB2(delta, p, rp->r_pt); \
    segp->seg_##x.hit_dist = fhin * MAGNITUDE(delta); \
    segp->seg_##x.hit_surfno = 0; }
	while (mb_stat == 0 && distleft >= -0) {
	    int in;

	    distleft -= step;
	    VADD2(p, p, inc);
	    in = rt_metaball_point_value(cp, mb) > mb->threshold;
	    if (mb_stat == 1)
		if ( !in )
		    if (step<=mb->finalstep) {
			STEPIN(out)
			step = mb->initstep;
			mb_stat = 0;
			if (ap->a_onehit != 0 || segsleft <= 0)
			    return retval;
		    } else
			STEPBACK
	    else
		if ( in )
		    if (step<=mb->finalstep) {
			RT_GET_SEG(segp, ap->a_resource);
			segp->seg_stp = stp;
			STEPIN(in)
			fhin = 1;
			BU_LIST_INSERT(&(seghead->l), &(segp->l));
			/* reset the ray-walk stuff */
			mb_stat = 1;
			VADD2(p, p, inc);	/* set p to a point inside */
			step = mb->initstep;
		    } else
			STEPBACK
	}
    }
#undef STEPBACK
#undef STEPIN
#elif SHOOTALGO == 3
    {
	int mb_stat = 0, segsleft = abs(ap->a_onehit);
	point_t lastpoint;

	while (distleft >= 0.0 || mb_stat == 1) {
	    /* advance to the next point */
	    distleft -= step;
	    VMOVE(lastpoint, p);
	    VADD2(p, p, inc);
	    if (mb_stat == 1) {
		if (rt_metaball_point_value(cp, mb) < mb->threshold) {
		    point_t intersect, delta;
		    const point_t *pA = (const point_t *)&lastpoint;
		    const point_t *pB = (const point_t *)&p;
		    rt_metaball_find_intersection(&intersect, mb, pA, pB, step, mb->finalstep);
		    VMOVE(segp->seg_out.hit_point, intersect);
		    --segsleft;
		    ++retval;
		    VSUB2(delta, intersect, rp->r_pt);
		    segp->seg_out.hit_dist = MAGNITUDE(delta);
		    segp->seg_out.hit_surfno = 0;
		    mb_stat = 0;
		    if (ap->a_onehit != 0 && segsleft <= 0)
			return retval;
		}
	    } else {
		if (rt_metaball_point_value(cp, mb) > mb->threshold) {
		    point_t intersect, delta;
		    const point_t *pA = (const point_t *)&lastpoint;
		    const point_t *pB = (const point_t *)&p;
		    rt_metaball_find_intersection(&intersect, mb, pA, pB, step, mb->finalstep);
		    RT_GET_SEG(segp, ap->a_resource);
		    segp->seg_stp = stp;
		    --segsleft;
		    ++retval;
		    VMOVE(segp->seg_in.hit_point, intersect);
		    VSUB2(delta, intersect, rp->r_pt);
		    segp->seg_in.hit_dist = MAGNITUDE(delta);
		    segp->seg_in.hit_surfno = 0;
		    BU_LIST_INSERT(&(seghead->l), &(segp->l));

		    mb_stat = 1;
		    step = mb->initstep;
		}
	    }
	}
    }

#else
# error "pick a valid algo."
#endif

    return retval;
}
コード例 #8
0
ファイル: rec.c プロジェクト: cogitokat/brlcad
/**
 * R E C _ S H O T
 *
 * Intersect a ray with a right elliptical cylinder,
 * where all constant terms have
 * been precomputed by rt_rec_prep().  If an intersection occurs,
 * a struct seg will be acquired and filled in.
 *
 * Returns -
 * 0 MISS
 * >0 HIT
 */
int
rt_rec_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct rec_specific *rec =
	(struct rec_specific *)stp->st_specific;
    vect_t dprime;		/* D' */
    vect_t pprime;		/* P' */
    fastf_t k1, k2;		/* distance constants of solution */
    vect_t xlated;		/* translated vector */
    struct hit hits[4];	/* 4 potential hit points */
    struct hit *hitp;	/* pointer to hit point */
    int nhits = 0;	/* Number of hit points */

    memset(hits, 0, 4 * sizeof(struct hit));

    hitp = &hits[0];

    /* out, Mat, vect */
    MAT4X3VEC(dprime, rec->rec_SoR, rp->r_dir);
    VSUB2(xlated, rp->r_pt, rec->rec_V);
    MAT4X3VEC(pprime, rec->rec_SoR, xlated);

    if (ZERO(dprime[X]) && ZERO(dprime[Y]))
	goto check_plates;

    /* Find roots of the equation, using formula for quadratic w/ a=1 */
    {
	fastf_t b;		/* coeff of polynomial */
	fastf_t root;		/* root of radical */
	fastf_t dx2dy2;

	b = 2 * (dprime[X]*pprime[X] + dprime[Y]*pprime[Y]) *
	    (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y]));
	if ((root = b*b - 4 * dx2dy2 *
	     (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0)
	    goto check_plates;
	root = sqrt(root);

	k1 = (root-b) * 0.5;
	k2 = (root+b) * (-0.5);
    }

    /*
     * k1 and k2 are potential solutions to intersection with side.
     * See if they fall in range.
     */
    VJOIN1(hitp->hit_vpriv, pprime, k1, dprime);		/* hit' */
    if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) {
	hitp->hit_magic = RT_HIT_MAGIC;
	hitp->hit_dist = k1;
	hitp->hit_surfno = REC_NORM_BODY;	/* compute N */
	hitp++; nhits++;
    }

    VJOIN1(hitp->hit_vpriv, pprime, k2, dprime);		/* hit' */
    if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) {
	hitp->hit_magic = RT_HIT_MAGIC;
	hitp->hit_dist = k2;
	hitp->hit_surfno = REC_NORM_BODY;	/* compute N */
	hitp++; nhits++;
    }

    /*
     * Check for hitting the end plates.
     */
 check_plates:
    if (nhits < 2  &&  !ZERO(dprime[Z])) {
	/* 0 or 1 hits so far, this is worthwhile */
	k1 = -pprime[Z] / dprime[Z];		/* bottom plate */
	k2 = (1.0 - pprime[Z]) / dprime[Z];	/* top plate */

	VJOIN1(hitp->hit_vpriv, pprime, k1, dprime);	/* hit' */
	if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
	    hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) {
	    hitp->hit_magic = RT_HIT_MAGIC;
	    hitp->hit_dist = k1;
	    hitp->hit_surfno = REC_NORM_BOT;	/* -H */
	    hitp++; nhits++;
	}

	VJOIN1(hitp->hit_vpriv, pprime, k2, dprime);	/* hit' */
	if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
	    hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) {
	    hitp->hit_magic = RT_HIT_MAGIC;
	    hitp->hit_dist = k2;
	    hitp->hit_surfno = REC_NORM_TOP;	/* +H */
	    hitp++; nhits++;
	}
    }
    if (nhits == 0) return 0;	/* MISS */
    if (nhits == 2) {
    hit:
	if (hits[0].hit_dist < hits[1].hit_dist) {
	    /* entry is [0], exit is [1] */
	    struct seg *segp;

	    RT_GET_SEG(segp, ap->a_resource);
	    segp->seg_stp = stp;
	    segp->seg_in = hits[0];		/* struct copy */
	    segp->seg_out = hits[1];	/* struct copy */
	    BU_LIST_INSERT(&(seghead->l), &(segp->l));
	} else {
	    /* entry is [1], exit is [0] */
	    struct seg *segp;

	    RT_GET_SEG(segp, ap->a_resource);
	    segp->seg_stp = stp;
	    segp->seg_in = hits[1];		/* struct copy */
	    segp->seg_out = hits[0];	/* struct copy */
	    BU_LIST_INSERT(&(seghead->l), &(segp->l));
	}
	return 2;			/* HIT */
    }
    if (nhits == 1) {
	if (hits[0].hit_surfno != REC_NORM_BODY)
	    bu_log("rt_rec_shot(%s): 1 intersection with end plate?\n", stp->st_name);
	/*
	 * Ray is tangent to body of cylinder,
	 * or a single hit on on an end plate (??)
	 * This could be considered a MISS,
	 * but to signal the condition, return 0-thickness hit.
	 */
	hits[1] = hits[0];	/* struct copy */
	nhits++;
	goto hit;
    }
    if (nhits == 3) {
	fastf_t tol_dist = ap->a_rt_i->rti_tol.dist;
	/*
	 * Check for case where two of the three hits
	 * have the same distance, e.g. hitting at the rim.
	 */
	k1 = hits[0].hit_dist - hits[1].hit_dist;
	if (NEAR_ZERO(k1, tol_dist)) {
	    if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 0&1\n", stp->st_name);
	    hits[1] = hits[2];	/* struct copy */
	    nhits--;
	    goto hit;
	}
	k1 = hits[1].hit_dist - hits[2].hit_dist;
	if (NEAR_ZERO(k1, tol_dist)) {
	    if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name);
	    nhits--;
	    goto hit;
	}
	k1 = hits[0].hit_dist - hits[2].hit_dist;
	if (NEAR_ZERO(k1, tol_dist)) {
	    if (RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name);
	    nhits--;
	    goto hit;
	}
    }
    /* nhits >= 3 */
    bu_log("rt_rec_shot(%s): %d unique hits?!?  %g, %g, %g, %g\n",
	   stp->st_name, nhits,
	   hits[0].hit_dist,
	   hits[1].hit_dist,
	   hits[2].hit_dist,
	   hits[3].hit_dist);

    /* count just the first two, to have something */
    goto hit;
}
コード例 #9
0
ファイル: arbn.c プロジェクト: kanzure/brlcad
/**
 * Intersect a ray with an ARBN.
 * Find the largest "in" distance and the smallest "out" distance.
 * Cyrus & Beck algorithm for convex polyhedra.
 *
 * Returns -
 *  0 MISS
 * >0 HIT
 */
int
rt_arbn_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead)
{
    struct rt_arbn_internal *aip =
	(struct rt_arbn_internal *)stp->st_specific;
    int i;
    int iplane, oplane;
    fastf_t in, out;	/* ray in/out distances */

    in = -INFINITY;
    out = INFINITY;
    iplane = oplane = -1;

    for (i = aip->neqn-1; i >= 0; i--) {
	fastf_t slant_factor;	/* Direction dot Normal */
	fastf_t norm_dist;
	fastf_t s;

	norm_dist = VDOT(aip->eqn[i], rp->r_pt) - aip->eqn[i][3];
	if ((slant_factor = -VDOT(aip->eqn[i], rp->r_dir)) < -1.0e-10) {
	    /* exit point, when dir.N < 0.  out = min(out, s) */
	    if (out > (s = norm_dist/slant_factor)) {
		out = s;
		oplane = i;
	    }
	} else if (slant_factor > 1.0e-10) {
	    /* entry point, when dir.N > 0.  in = max(in, s) */
	    if (in < (s = norm_dist/slant_factor)) {
		in = s;
		iplane = i;
	    }
	} else {
	    /* ray is parallel to plane when dir.N == 0.
	     * If it is outside the solid, stop now
	     * Allow very small amount of slop, to catch
	     * rays that lie very nearly in the plane of a face.
	     */
	    if (norm_dist > SQRT_SMALL_FASTF)
		return 0;	/* MISS */
	}
	if (in > out)
	    return 0;	/* MISS */
    }

    /* Validate */
    if (iplane == -1 || oplane == -1) {
	bu_log("rt_arbn_shoot(%s): 1 hit => MISS\n",
	       stp->st_name);
	return 0;	/* MISS */
    }
    if (in >= out || out >= INFINITY)
	return 0;	/* MISS */

    {
	struct seg *segp;

	RT_GET_SEG(segp, ap->a_resource);
	segp->seg_stp = stp;
	segp->seg_in.hit_dist = in;
	segp->seg_in.hit_surfno = iplane;

	segp->seg_out.hit_dist = out;
	segp->seg_out.hit_surfno = oplane;
	BU_LIST_INSERT(&(seghead->l), &(segp->l));
    }
    return 2;			/* HIT */
}