Ejemplo n.º 1
0
/**
 * 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 */

}
Ejemplo n.º 2
0
/**
 * 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;
}
Ejemplo n.º 3
0
int
main(int argc, char *argv[])
{
    bn_poly_t equation; /* holds our polynomial equation */
    bn_complex_t roots[BN_MAX_POLY_DEGREE]; /* stash up to four roots */
    int num_roots;

    if (argc > 1)
	bu_exit(1, "%s: unexpected argument(s)\n", argv[0]);

    /*********************************************
     * Linear polynomial (1st degree equation):
     *  A*X + B = 0
     * [0]   [1]     <=coefficients
     */
    equation.dgr = 1;
    equation.cf[0] = 1;  /* A */
    equation.cf[1] = -2;  /* B */

    /* print the equation */
    bu_log("\n*** LINEAR ***\n");
    bn_pr_poly("Solving for Linear", &equation);

    /* solve for the roots */
    num_roots = rt_poly_roots(&equation, roots, "My Linear Polynomial");
    if (num_roots == 0) {
	bu_log("No roots found!\n");
	return 0;
    } else if (num_roots < 0) {
	bu_log("The root solver failed to converge on a solution\n");
	return 1;
    }

    /*  A*X + B = 0
     *  1*X + -2 = 0
     *    X -  2 = 0
     *    X      = 2
     */
    /* print the roots */
    bu_log("The root should be 2\n");
    bn_pr_roots("My Linear Polynomial", roots, num_roots);


    /*********************************************
     * Quadratic polynomial (2nd degree equation):
     *  A*X^2 + B*X + C = 0
     * [0]     [1]   [2]     <=coefficients
     */
    equation.dgr = 2;
    equation.cf[0] = 1;  /* A */
    equation.cf[1] = 0;  /* B */
    equation.cf[2] = -4; /* C */

    /* print the equation */
    bu_log("\n*** QUADRATIC ***\n");
    bn_pr_poly("Solving for Quadratic", &equation);

    /* solve for the roots */
    num_roots = rt_poly_roots(&equation, roots, "My Quadratic Polynomial");
    if (num_roots == 0) {
	bu_log("No roots found!\n");
	return 0;
    } else if (num_roots < 0) {
	bu_log("The root solver failed to converge on a solution\n");
	return 1;
    }

    /*  A*X^2 + B*X +  C = 0
     *  1*X^2 + 0*X + -4 = 0
     *    X^2       -  4 = 0
     * (X - 2) * (X + 2) = 0
     *  X - 2 = 0, X + 2 = 0
     *  X = 2, X = -2
     */
    /* print the roots */
    bu_log("The roots should be 2 and -2\n");
    bn_pr_roots("My Quadratic Polynomial", roots, num_roots);


    /*****************************************
     * Cubic polynomial (3rd degree equation):
     *  A*X^3 + B*X^2 + C*X + D = 0
     * [0]     [1]     [2]   [3]     <=coefficients
     */
    equation.dgr = 3;
    equation.cf[0] = 45;
    equation.cf[1] = 24;
    equation.cf[2] = -7;
    equation.cf[3] = -2;

    /* print the equation */
    bu_log("\n*** CUBIC ***\n");
    bn_pr_poly("Solving for Cubic", &equation);

    /* solve for the roots */
    num_roots = rt_poly_roots(&equation, roots, "My Cubic Polynomial");
    if (num_roots == 0) {
	bu_log("No roots found!\n");
	return 0;
    } else if (num_roots < 0) {
	bu_log("The root solver failed to converge on a solution\n");
	return 1;
    }

    /* print the roots */
    bu_log("The roots should be 1/3, -1/5, and -2/3\n");
    bn_pr_roots("My Cubic Polynomial", roots, num_roots);


    /*******************************************
     * Quartic polynomial (4th degree equation):
     *  A*X^4 + B*X^3 + C*X^2 + D*X + E = 0
     * [0]     [1]     [2]     [3]   [4]     <=coefficients
     */
    equation.dgr = 4;
    equation.cf[0] = 2;
    equation.cf[1] = 4;
    equation.cf[2] = -26;
    equation.cf[3] = -28;
    equation.cf[4] = 48;

    /* print the equation */
    bu_log("\n*** QUARTIC ***\n");
    bn_pr_poly("Solving for Quartic", &equation);

    /* solve for the roots */
    num_roots = rt_poly_roots(&equation, roots, "My Quartic Polynomial");
    if (num_roots == 0) {
	bu_log("No roots found!\n");
	return 0;
    } else if (num_roots < 0) {
	bu_log("The root solver failed to converge on a solution\n");
	return 1;
    }

    /* print the roots */
    bu_log("The roots should be 3, 1, -2, -4\n");
    bn_pr_roots("My Quartic Polynomial", roots, num_roots);

    /*******************************************
     * Sextic polynomial (6th degree equation):
     *  A*X^6 + B*X^5 + C*X^4 + D*X^3 + E*X^2 + F*X + G = 0
     * [0]     [1]     [2]     [3]     [4]     [5]   [6]  <=coefficients
     */

    equation.dgr = 6;
    equation.cf[0] = 1;
    equation.cf[1] = -8;
    equation.cf[2] = 32;
    equation.cf[3] = -78;
    equation.cf[4] = 121;
    equation.cf[5] = -110;
    equation.cf[6] = 50;

    /* print the equation */
    bu_log("\n*** SEXTIC ***\n");
    bn_pr_poly("Solving for Sextic", &equation);

    /* solve for the roots */
    num_roots = rt_poly_roots(&equation, roots, "My Sextic Polynomial");
    if (num_roots == 0) {
	bu_log("No roots found!\n");
	return 0;
    } else if (num_roots < 0) {
	bu_log("The root solver failed to converge on a solution\n");
	return 1;
    }

    /* print the roots */
    bu_log("The roots should be 1 - i, 1 + i, 2 - i,2 + i, 1 - 2*i, 1 + 2*i \n");
    bn_pr_roots("My Sextic Polynomial", roots, num_roots);

    return 0;
}