inline void
rt_metaball_norm_internal(vect_t *n, point_t *p, struct rt_metaball_internal *mb)
{
    struct wdb_metaballpt *mbpt;
    vect_t v;
    fastf_t a;

    VSETALL(*n, 0.0);

    switch (mb->method) {
	case METABALL_METABALL: bu_log("Sorry, strict metaballs are not yet implemented\n");
	    break;
	case METABALL_ISOPOTENTIAL:
	    for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) {
		VSUB2(v, *p, mbpt->coord);
		a = MAGSQ(v);
		VJOIN1(*n, *n, fabs(mbpt->fldstr)*mbpt->fldstr / (SQ(a)), v);	/* f/r^4 */
	    }
	    break;
	case METABALL_BLOB:
	    for (BU_LIST_FOR(mbpt, wdb_metaballpt, &mb->metaball_ctrl_head)) {
		VSUB2(v, *p, mbpt->coord);
		a = MAGSQ(v);
		VJOIN1(*n, *n, 2.0*mbpt->sweat/SQ(mbpt->fldstr)*exp(mbpt->sweat*(1-(a/SQ(mbpt->fldstr)))) , v);
	    }
	    break;
	default: bu_log("unknown metaball method\n"); break;
    }
    VUNITIZE(*n);
}
Exemple #2
0
struct hyp_specific *
hyp_internal_to_specific(struct rt_hyp_internal *hyp_in) {
    struct hyp_specific *hyp;
    BU_GET(hyp, struct hyp_specific);

    hyp->hyp_r1 = hyp_in->hyp_bnr * MAGNITUDE(hyp_in->hyp_A);
    hyp->hyp_r2 = hyp_in->hyp_bnr * hyp_in->hyp_b;
    hyp->hyp_c = sqrt(4 * MAGSQ(hyp_in->hyp_A) / MAGSQ(hyp_in->hyp_Hi) * (1 - hyp_in->hyp_bnr * hyp_in->hyp_bnr));

    VSCALE(hyp->hyp_H, hyp_in->hyp_Hi, 0.5);
    VADD2(hyp->hyp_V, hyp_in->hyp_Vi, hyp->hyp_H);
    VMOVE(hyp->hyp_Au, hyp_in->hyp_A);
    VUNITIZE(hyp->hyp_Au);

    hyp->hyp_rx = 1.0 / (hyp->hyp_r1 * hyp->hyp_r1);
    hyp->hyp_ry = 1.0 / (hyp->hyp_r2 * hyp->hyp_r2);
    hyp->hyp_rz = (hyp->hyp_c * hyp->hyp_c) / (hyp->hyp_r1 * hyp->hyp_r1);

    /* calculate height to use for top/bottom intersection planes */
    hyp->hyp_Hmag = MAGNITUDE(hyp->hyp_H);
    hyp->hyp_bounds = hyp->hyp_rz*hyp->hyp_Hmag*hyp->hyp_Hmag + 1.0;

    /* setup unit vectors for hyp_specific */
    VMOVE(hyp->hyp_Hunit, hyp->hyp_H);
    VMOVE(hyp->hyp_Aunit, hyp->hyp_Au);
    VCROSS(hyp->hyp_Bunit, hyp->hyp_Hunit, hyp->hyp_Aunit);

    VUNITIZE(hyp->hyp_Aunit);
    VUNITIZE(hyp->hyp_Bunit);
    VUNITIZE(hyp->hyp_Hunit);

    return hyp;
}
Exemple #3
0
static int
find_closest_color(float color[3])
{
    int icolor[3];
    int i;
    int dist_sq;
    int color_num;

    VSCALE(icolor, color, 255);

    color_num = 0;
    dist_sq = MAGSQ(icolor);

    for (i = 1; i < 256; i++) {
	int tmp_dist;
	int diff[3];

	VSUB2(diff, icolor, &rgb[i*3]);
	tmp_dist = MAGSQ(diff);
	if (tmp_dist < dist_sq) {
	    dist_sq = tmp_dist;
	    color_num = i;
	}
    }

    return color_num;
}
Exemple #4
0
/**
 * Given a pointer to a GED database record, and a transformation
 * matrix, determine if this is a valid HYP, and if so, precompute
 * various terms of the formula.
 *
 * Returns -
 * 0  HYP is OK
 * !0 Error in description
 *
 * Implicit return -
 * A struct hyp_specific is created, and its address is stored in
 * stp->st_specific for use by hyp_shot().
 */
int
rt_hyp_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
{
    struct rt_hyp_internal *hyp_ip;
    struct hyp_specific *hyp;

    RT_CK_DB_INTERNAL(ip);

    hyp_ip = (struct rt_hyp_internal *)ip->idb_ptr;
    RT_HYP_CK_MAGIC(hyp_ip);

    /* TODO: check that this is a valid hyperboloid (assume it is, for now)  */

    /* set soltab ID */
    stp->st_id = ID_HYP;
    stp->st_meth = &OBJ[ID_HYP];

    hyp =  hyp_internal_to_specific(hyp_ip);
    stp->st_specific = (void *)hyp;

    /* calculate bounding sphere */
    VMOVE(stp->st_center, hyp->hyp_V);
    stp->st_aradius = sqrt((hyp->hyp_c*hyp->hyp_c + 1)*MAGSQ(hyp->hyp_H)
			   + (hyp->hyp_r1*hyp->hyp_r1));
    stp->st_bradius = stp->st_aradius;

    /* calculate bounding RPP */
    if (rt_hyp_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1;
    return 0;			/* OK */
}
int
bn_mat_is_non_unif(const mat_t m)
{
    double mag[3];

    mag[0] = MAGSQ(m);
    mag[1] = MAGSQ(&m[4]);
    mag[2] = MAGSQ(&m[8]);

    if (fabs(1.0 - (mag[1] / mag[0])) > .0005 ||
	fabs(1.0 - (mag[2] / mag[0])) > .0005) {

	return 1;
    }

    if (!ZERO(m[12]) || !ZERO(m[13]) || !ZERO(m[14])) {
	return 2;
    }

    return 0;
}
fastf_t
rt_metaball_point_value_iso(const point_t *p, const struct bu_list *points)
{
    struct wdb_metaballpt *mbpt;
    fastf_t ret = 0.0;
    point_t v;

    for (BU_LIST_FOR(mbpt, wdb_metaballpt, points)) {
	VSUB2(v, mbpt->coord, *p);
	ret += fabs(mbpt->fldstr) * mbpt->fldstr / MAGSQ(v);	/* f/r^2 */
    }
    return ret;
}
Exemple #7
0
int TriIntersections::InsertPoint(
    ON_3dPoint P,
    uint8_t direction,
    EdgeIndex ei
    )
{
    /* first check to see if the point is on the other side of the
     * starting/ending point and return an error if it is
     */
    if ((VDOT((P - edges[ei][0]), (edges[ei][1] - edges[ei][0])) < 0) || (VDOT((P - *edges[ei].Last()), (edges[ei][0] - *edges[ei].Last())) < 0)) {
	return -1;
    }
    double valtobeat = MAGSQ(P - edges[ei][0]);
    for (int i = 1; i < edges[ei].Count(); i++) {
	if (MAGSQ(edges[ei][i] - edges[ei][0]) > valtobeat) {
	    edges[ei].Insert(i, P);
	    dir[ei].Insert(i, direction);
	    return i;
	}
    }

    return 0;
}
fastf_t
rt_metaball_point_value_blob(const point_t *p, const struct bu_list *points)
{
    struct wdb_metaballpt *mbpt;
    fastf_t ret = 0.0;
    point_t v;

    for (BU_LIST_FOR(mbpt, wdb_metaballpt, points)) {
	/* TODO: test if sweat is sufficient enough that r=0 returns a positive value? */
	/* TODO: test to see if negative contribution needs to be wiped out? */
	VSUB2(v, mbpt->coord, *p);
	ret += 1.0 / exp((mbpt->sweat/(mbpt->fldstr*mbpt->fldstr)) * MAGSQ(v) - mbpt->sweat);
    }
    return ret;
}
Exemple #9
0
/*
 *  True if the intersection distance is >= distance back to the
 *  origin of the first ray in a chain.
 *  Called via isvisible on a hit.
 */
static int
hiteye(struct application *ap, struct partition *PartHeadp, struct seg *segHeadp)
{
    register struct partition *pp;
    register struct hit *hitp;
    vect_t work;

    for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw )
	if ( pp->pt_outhit->hit_dist > 0 )  break;
    if ( pp == PartHeadp )  {
	bu_log("hiteye:  no hit out front?\n");
	return(1);
    }
    hitp = pp->pt_inhit;
    if ( hitp->hit_dist >= INFINITY )  {
	bu_log("hiteye:  entry beyond infinity\n");
	return(1);
    }
    /* The current ray segment exits "in front" of me,
     * find out where it went in.
     * Check to see if eye is "inside" of the solid.
     */
    if ( hitp->hit_dist < -1.0e-10 )  {
	/*
	 * If we are under 1.0 units inside of a solid, we pushed
	 * into it ourselves in trying to get away from the surface.
	 * Otherwise, its hard to tell how we got in here!
	 */
	if ( hitp->hit_dist < -1.001 ) {
	    bu_log("hiteye: *** GAK2, 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);
    }

    VSUB2( work, firstray.r_pt, ap->a_ray.r_pt );
    if ( hitp->hit_dist * hitp->hit_dist > MAGSQ(work) )
	return(1);
    else
	return(0);
}
void
bn_vec_ortho(register vect_t out, register const vect_t in)
{
    register int j, k;
    register fastf_t f;
    register int i;

    if (UNLIKELY(NEAR_ZERO(MAGSQ(in), SQRT_SMALL_FASTF))) {
	bu_log("bn_vec_ortho(): zero magnitude input vector %g %g %g\n", V3ARGS(in));
	VSETALL(out, 0);
	return;
    }

    /* Find component closest to zero */
    f = fabs(in[X]);
    i = X;
    j = Y;
    k = Z;
    if (fabs(in[Y]) < f) {
	f = fabs(in[Y]);
	i = Y;
	j = Z;
	k = X;
    }
    if (fabs(in[Z]) < f) {
	i = Z;
	j = X;
	k = Y;
    }
    f = hypot(in[j], in[k]);
    if (UNLIKELY(ZERO(f))) {
	bu_log("bn_vec_ortho(): zero hypot on %g %g %g\n", V3ARGS(in));
	VSETALL(out, 0);
	return;
    }
    f = 1.0 / f;
    out[i] = 0.0;
    out[j] = -in[k] * f;
    out[k] =  in[j] * f;

    return;
}
Exemple #11
0
/*
 *  True if the intersection distance is >= distance back to the
 *  origin of the first ray in a chain.
 *  Called via isvisible on a hit.
 */
static int
hiteye( struct application *ap, struct partition *PartHeadp )
{
    register struct partition *pp;
    register struct hit *hitp;
    vect_t work;
    int cpu_num;

    for ( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw )
	if ( pp->pt_outhit->hit_dist > 0 )  break;
    if ( pp == PartHeadp )  {
	bu_log("hiteye:  no hit out front?\n");
	return 1;
    }
    hitp = pp->pt_inhit;
    if ( hitp->hit_dist >= INFINITY )  {
	bu_log("hiteye:  entry beyond infinity\n");
	return 1;
    }
    /* The current ray segment exits "in front" of me,
     * find out where it went in.
     * Check to see if eye is "inside" of the solid.
     */
    if ( hitp->hit_dist < -1.0e-10 )  {
	return 0;
    }

    if ( ap->a_resource == RESOURCE_NULL)
	cpu_num = 0;
    else
	cpu_num = ap->a_resource->re_cpu;

    VSUB2( work, firstray[cpu_num].r_pt, ap->a_ray.r_pt );
    if ( hitp->hit_dist * hitp->hit_dist > MAGSQ(work) )
	return 1;
    else
	return 0;
}
Exemple #12
0
/**
 * Given a pointer to a GED database record, and a transformation
 * matrix, determine if this is a valid superellipsoid, and if so,
 * precompute various terms of the formula.
 *
 * Returns -
 * 0 SUPERELL is OK
 * !0 Error in description
 *
 * Implicit return - A struct superell_specific is created, and its
 * address is stored in stp->st_specific for use by rt_superell_shot()
 */
int
rt_superell_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
{

    struct superell_specific *superell;
    struct rt_superell_internal *eip;
    fastf_t magsq_a, magsq_b, magsq_c;
    mat_t R, TEMP;
    vect_t Au, Bu, Cu;	/* A, B, C with unit length */
    fastf_t f;

    eip = (struct rt_superell_internal *)ip->idb_ptr;
    RT_SUPERELL_CK_MAGIC(eip);

    /* Validate that |A| > 0, |B| > 0, |C| > 0 */
    magsq_a = MAGSQ(eip->a);
    magsq_b = MAGSQ(eip->b);
    magsq_c = MAGSQ(eip->c);

    if (magsq_a < rtip->rti_tol.dist_sq || magsq_b < rtip->rti_tol.dist_sq || magsq_c < rtip->rti_tol.dist_sq) {
        bu_log("rt_superell_prep():  superell(%s) near-zero length A(%g), B(%g), or C(%g) vector\n",
               stp->st_name, magsq_a, magsq_b, magsq_c);
        return 1;		/* BAD */
    }
    if (eip->n < rtip->rti_tol.dist || eip->e < rtip->rti_tol.dist) {
        bu_log("rt_superell_prep():  superell(%s) near-zero length <n, e> curvature (%g, %g) causes problems\n",
               stp->st_name, eip->n, eip->e);
        /* BAD */
    }
    if (eip->n > 10000.0 || eip->e > 10000.0) {
        bu_log("rt_superell_prep():  superell(%s) very large <n, e> curvature (%g, %g) causes problems\n",
               stp->st_name, eip->n, eip->e);
        /* BAD */
    }

    /* Create unit length versions of A, B, C */
    f = 1.0/sqrt(magsq_a);
    VSCALE(Au, eip->a, f);
    f = 1.0/sqrt(magsq_b);
    VSCALE(Bu, eip->b, f);
    f = 1.0/sqrt(magsq_c);
    VSCALE(Cu, eip->c, f);

    /* Validate that A.B == 0, B.C == 0, A.C == 0 (check dir only) */
    f = VDOT(Au, Bu);
    if (! NEAR_ZERO(f, rtip->rti_tol.dist)) {
        bu_log("rt_superell_prep():  superell(%s) A not perpendicular to B, f=%f\n", stp->st_name, f);
        return 1;		/* BAD */
    }
    f = VDOT(Bu, Cu);
    if (! NEAR_ZERO(f, rtip->rti_tol.dist)) {
        bu_log("rt_superell_prep():  superell(%s) B not perpendicular to C, f=%f\n", stp->st_name, f);
        return 1;		/* BAD */
    }
    f = VDOT(Au, Cu);
    if (! NEAR_ZERO(f, rtip->rti_tol.dist)) {
        bu_log("rt_superell_prep():  superell(%s) A not perpendicular to C, f=%f\n", stp->st_name, f);
        return 1;		/* BAD */
    }

    /* Solid is OK, compute constant terms now */

    BU_GET(superell, struct superell_specific);
    stp->st_specific = (void *)superell;

    superell->superell_n = eip->n;
    superell->superell_e = eip->e;

    VMOVE(superell->superell_V, eip->v);

    VSET(superell->superell_invsq, 1.0/magsq_a, 1.0/magsq_b, 1.0/magsq_c);
    VMOVE(superell->superell_Au, Au);
    VMOVE(superell->superell_Bu, Bu);
    VMOVE(superell->superell_Cu, Cu);

    /* compute the inverse magnitude square for equations during shot */
    superell->superell_invmsAu = 1.0 / magsq_a;
    superell->superell_invmsBu = 1.0 / magsq_b;
    superell->superell_invmsCu = 1.0 / magsq_c;

    /* compute the rotation matrix */
    MAT_IDN(R);
    VMOVE(&R[0], Au);
    VMOVE(&R[4], Bu);
    VMOVE(&R[8], Cu);
    bn_mat_trn(superell->superell_invR, R);

    /* computer invRSSR */
    MAT_IDN(superell->superell_invRSSR);
    MAT_IDN(TEMP);
    TEMP[0] = superell->superell_invsq[0];
    TEMP[5] = superell->superell_invsq[1];
    TEMP[10] = superell->superell_invsq[2];
    bn_mat_mul(TEMP, TEMP, R);
    bn_mat_mul(superell->superell_invRSSR, superell->superell_invR, TEMP);

    /* compute Scale(Rotate(vect)) */
    MAT_IDN(superell->superell_SoR);
    VSCALE(&superell->superell_SoR[0], eip->a, superell->superell_invsq[0]);
    VSCALE(&superell->superell_SoR[4], eip->b, superell->superell_invsq[1]);
    VSCALE(&superell->superell_SoR[8], eip->c, superell->superell_invsq[2]);

    /* Compute bounding sphere */
    VMOVE(stp->st_center, eip->v);
    f = magsq_a;
    if (magsq_b > f)
        f = magsq_b;
    if (magsq_c > f)
        f = magsq_c;
    stp->st_aradius = stp->st_bradius = sqrt(f);

    /* Compute bounding RPP */
    if (rt_superell_bbox(ip, &(stp->st_min), &(stp->st_max), &rtip->rti_tol)) return 1;

    return 0;			/* OK */
}
Exemple #13
0
/**
 * Calculate a bounding RPP for a superell
 */
int
rt_superell_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {

    struct rt_superell_internal *eip;
    fastf_t magsq_a, magsq_b, magsq_c;
    vect_t Au, Bu, Cu;
    mat_t R;
    vect_t w1, w2, P;	/* used for bounding RPP */
    fastf_t f;

    eip = (struct rt_superell_internal *)ip->idb_ptr;
    RT_SUPERELL_CK_MAGIC(eip);

    magsq_a = MAGSQ(eip->a);
    magsq_b = MAGSQ(eip->b);
    magsq_c = MAGSQ(eip->c);


    /* Create unit length versions of A, B, C */
    f = 1.0/sqrt(magsq_a);
    VSCALE(Au, eip->a, f);
    f = 1.0/sqrt(magsq_b);
    VSCALE(Bu, eip->b, f);
    f = 1.0/sqrt(magsq_c);
    VSCALE(Cu, eip->c, f);

    MAT_IDN(R);
    VMOVE(&R[0], Au);
    VMOVE(&R[4], Bu);
    VMOVE(&R[8], Cu);

    /* Compute bounding RPP */
    VSET(w1, magsq_a, magsq_b, magsq_c);

    /* X */
    VSET(P, 1.0, 0, 0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[X] = eip->v[X] - f;	/* V.P +/- f */
    (*max)[X] = eip->v[X] + f;

    /* Y */
    VSET(P, 0, 1.0, 0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[Y] = eip->v[Y] - f;	/* V.P +/- f */
    (*max)[Y] = eip->v[Y] + f;

    /* Z */
    VSET(P, 0, 0, 1.0);		/* bounding plane normal */
    MAT3X3VEC(w2, R, P);		/* map plane to local coord syst */
    VELMUL(w2, w2, w2);		/* square each term */
    f = VDOT(w1, w2);
    f = sqrt(f);
    (*min)[Z] = eip->v[Z] - f;	/* V.P +/- f */
    (*max)[Z] = eip->v[Z] + f;

    return 0;
}
Exemple #14
0
/**
 * Returns -
 * -1 failure
 * 0 OK.  *r points to nmgregion that holds this tessellation.
 */
int
rt_hyp_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
{
    fastf_t c, dtol, f, mag_a, mag_h, ntol, r1, r2, r3, cprime;
    fastf_t **ellipses = NULL;
    fastf_t theta_new;
    int *pts_dbl, face, i, j, nseg;
    int jj, nell;
    mat_t invRoS;
    mat_t SoR;
    struct rt_hyp_internal *iip;
    struct hyp_specific *xip;
    struct rt_pt_node *pos_a, *pos_b, *pts_a, *pts_b;
    struct shell *s;
    struct faceuse **outfaceuses = NULL;
    struct faceuse *fu_top;
    struct loopuse *lu;
    struct edgeuse *eu;
    struct vertex *vertp[3];
    struct vertex ***vells = (struct vertex ***)NULL;
    vect_t A, Au, B, Bu, Hu, V;
    struct bu_ptbl vert_tab;

    MAT_ZERO(invRoS);
    MAT_ZERO(SoR);

    RT_CK_DB_INTERNAL(ip);
    iip = (struct rt_hyp_internal *)ip->idb_ptr;
    RT_HYP_CK_MAGIC(iip);

    xip = hyp_internal_to_specific(iip);

    /*
     * make sure hyp description is valid
     */

    /* compute |A| |H| */
    mag_a = MAGSQ(xip->hyp_Au);	/* should already be unit vector */
    mag_h = MAGNITUDE(xip->hyp_H);
    c = xip->hyp_c;
    cprime = c / mag_h;
    r1 = xip->hyp_r1;
    r2 = xip->hyp_r2;
    r3 = r1 / c;
    /* Check for |H| > 0, |A| == 1, r1 > 0, r2 > 0, c > 0 */
    if (NEAR_ZERO(mag_h, RT_LEN_TOL)
	|| !NEAR_EQUAL(mag_a, 1.0, RT_LEN_TOL)
	|| r1 <= 0.0 || r2 <= 0.0 || c <= 0.) {
	return 1;		/* BAD */
    }

    /* Check for A.H == 0 */
    f = VDOT(xip->hyp_Au, xip->hyp_H) / mag_h;
    if (! NEAR_ZERO(f, RT_DOT_TOL)) {
	return 1;		/* BAD */
    }

    /* make unit vectors in A, H, and HxA directions */
    VMOVE(Hu, xip->hyp_H);
    VUNITIZE(Hu);
    VMOVE(Au, xip->hyp_Au);
    VCROSS(Bu, Hu, Au);

    dtol = primitive_get_absolute_tolerance(ttol, 2.0 * r2);

    /* To ensure normal tolerance, remain below this angle */
    if (ttol->norm > 0.0)
	ntol = ttol->norm;
    else
	/* tolerate everything */
	ntol = M_PI;

    /*
     * build hyp from 2 hyperbolas
     */

    /* calculate major axis hyperbola */
    BU_ALLOC(pts_a, struct rt_pt_node);

    /* set base, center, and top points */
    pos_a = pts_a;
    VSET(pos_a->p, sqrt((mag_h*mag_h) * (c*c) + (r1*r1)), 0, -mag_h);
    BU_ALLOC(pos_a->next, struct rt_pt_node);
    pos_a = pos_a->next;
    VSET(pos_a->p, r1, 0, 0);
    BU_ALLOC(pos_a->next, struct rt_pt_node);
    pos_a = pos_a->next;
    VSET(pos_a->p, sqrt((mag_h*mag_h) * (c*c) + (r1*r1)), 0, mag_h);
    pos_a->next = NULL;

    /* refine hyp according to tolerances */
    i = 1;
    {
	point_t p0, p1, p2;
	fastf_t mm, len, dist, ang0, ang2;
	vect_t v01, v02; /* vectors from p0->p1 and p0->p2 */
	vect_t nLine, nHyp;
	struct rt_pt_node *add;

	while (i) {
	    pos_a = pts_a;
	    i = 0;
	    while (pos_a->next) {

		VMOVE(p0, pos_a->p);
		VMOVE(p2, pos_a->next->p);
		/* either X or Y will be zero; so adding handles either case */
		mm = (p2[Z] - p0[Z]) / ((p2[X]+p2[Y]) - (p0[X]+p0[Y]));
		if (!ZERO(p0[X])) {
		    p1[X] = fabs(mm*c*r1) / sqrt(mm*mm*c*c - 1.0);
		    p1[Y] = 0.0;
		    p1[Z] = sqrt(p1[X]*p1[X] - r1*r1) / c;
		} else {
		    p1[X] = 0.0;
		    p1[Y] = fabs(mm*r2*r2*c) / sqrt(mm*mm*r2*r2*c*c - r1*r1);
		    p1[Z] = (r3/r2) * sqrt(p1[Y]*p1[Y] - r2*r2);
		}
		if (p0[Z] + p2[Z] < 0) p1[Z] = -p1[Z];

		VSUB2(v01, p1, p0);
		VSUB2(v02, p2, p0);
		VUNITIZE(v02);
		len = VDOT(v01, v02);
		VSCALE(v02, v02, len);
		VSUB2(nLine, v01, v02);
		dist = MAGNITUDE(nLine);
		VUNITIZE(nLine);

		VSET(nHyp, p0[X] / (r1*r1), p0[Y] / (r2*r2), p0[Z] / (r3*r3));
		VUNITIZE(nHyp);
		ang0 = fabs(acos(VDOT(nLine, nHyp)));
		VSET(nHyp, p2[X] / (r1*r1), p2[Y] / (r2*r2), p2[Z] / (r3*r3));
		VUNITIZE(nHyp);
		ang2 = fabs(acos(VDOT(nLine, nHyp)));

		if (dist > dtol || ang0 > ntol || ang2 > ntol) {
		    /* split segment */
		    BU_ALLOC(add, struct rt_pt_node);
		    VMOVE(add->p, p1);
		    add->next = pos_a->next;
		    pos_a->next = add;
		    pos_a = pos_a->next;
		    i = 1;
		}
		pos_a = pos_a->next;
	    }
	}

    }

    /* calculate minor axis hyperbola */
    BU_ALLOC(pts_b, struct rt_pt_node);

    pos_a = pts_a;
    pos_b = pts_b;
    i = 0;
    while (pos_a) {
	pos_b->p[Z] = pos_a->p[Z];
	pos_b->p[X] = 0;
	pos_b->p[Y] = r2 * sqrt(pos_b->p[Z] * pos_b->p[Z]/(r3*r3) + 1.0);
	pos_a = pos_a->next;
	if (pos_a) {
	    BU_ALLOC(pos_b->next, struct rt_pt_node);
	    pos_b = pos_b->next;
	} else {
	    pos_b->next = NULL;
	}
	i++;
    }
Exemple #15
0
int
rt_hyp_plot(struct bu_list *vhead, struct rt_db_internal *incoming, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *UNUSED(tol), const struct rt_view_info *UNUSED(info))
{
    int i, j;		/* loop indices */
    struct rt_hyp_internal *hyp_in;
    struct hyp_specific *hyp;
    vect_t majorAxis[8],	/* vector offsets along major axis */
	minorAxis[8],		/* vector offsets along minor axis */
	heightAxis[7],		/* vector offsets for layers */
	Bunit;			/* unit vector along semi-minor axis */
    vect_t ell[16];		/* stores 16 points to draw ellipses */
    vect_t ribs[16][7];		/* assume 7 layers for now */
    fastf_t scale;		/* used to calculate semi-major/minor axes for top/bottom */
    fastf_t cos22_5 = 0.9238795325112867385;
    fastf_t cos67_5 = 0.3826834323650898373;

    BU_CK_LIST_HEAD(vhead);
    RT_CK_DB_INTERNAL(incoming);
    hyp_in = (struct rt_hyp_internal *)incoming->idb_ptr;
    RT_HYP_CK_MAGIC(hyp_in);

    hyp = hyp_internal_to_specific(hyp_in);

    VCROSS(Bunit, hyp->hyp_H, hyp->hyp_Au);
    VUNITIZE(Bunit);

    VMOVE(heightAxis[0], hyp->hyp_H);
    VSCALE(heightAxis[1], heightAxis[0], 0.5);
    VSCALE(heightAxis[2], heightAxis[0], 0.25);
    VSETALL(heightAxis[3], 0);
    VREVERSE(heightAxis[4], heightAxis[2]);
    VREVERSE(heightAxis[5], heightAxis[1]);
    VREVERSE(heightAxis[6], heightAxis[0]);

    for (i = 0; i < 7; i++) {
	/* determine Z height depending on i */
	scale = sqrt(MAGSQ(heightAxis[i])*(hyp->hyp_c * hyp->hyp_c)/(hyp->hyp_r1 * hyp->hyp_r1) + 1);

	/* calculate vectors for offset */
	VSCALE(majorAxis[0], hyp->hyp_Au, hyp->hyp_r1 * scale);
	VSCALE(majorAxis[1], majorAxis[0], cos22_5);
	VSCALE(majorAxis[2], majorAxis[0], M_SQRT1_2);
	VSCALE(majorAxis[3], majorAxis[0], cos67_5);
	VREVERSE(majorAxis[4], majorAxis[3]);
	VREVERSE(majorAxis[5], majorAxis[2]);
	VREVERSE(majorAxis[6], majorAxis[1]);
	VREVERSE(majorAxis[7], majorAxis[0]);

	VSCALE(minorAxis[0], Bunit, hyp->hyp_r2 * scale);
	VSCALE(minorAxis[1], minorAxis[0], cos22_5);
	VSCALE(minorAxis[2], minorAxis[0], M_SQRT1_2);
	VSCALE(minorAxis[3], minorAxis[0], cos67_5);
	VREVERSE(minorAxis[4], minorAxis[3]);
	VREVERSE(minorAxis[5], minorAxis[2]);
	VREVERSE(minorAxis[6], minorAxis[1]);
	VREVERSE(minorAxis[7], minorAxis[0]);

	/* calculate ellipse */
	VADD3(ell[ 0], hyp->hyp_V, heightAxis[i], majorAxis[0]);
	VADD4(ell[ 1], hyp->hyp_V, heightAxis[i], majorAxis[1], minorAxis[3]);
	VADD4(ell[ 2], hyp->hyp_V, heightAxis[i], majorAxis[2], minorAxis[2]);
	VADD4(ell[ 3], hyp->hyp_V, heightAxis[i], majorAxis[3], minorAxis[1]);
	VADD3(ell[ 4], hyp->hyp_V, heightAxis[i], minorAxis[0]);
	VADD4(ell[ 5], hyp->hyp_V, heightAxis[i], majorAxis[4], minorAxis[1]);
	VADD4(ell[ 6], hyp->hyp_V, heightAxis[i], majorAxis[5], minorAxis[2]);
	VADD4(ell[ 7], hyp->hyp_V, heightAxis[i], majorAxis[6], minorAxis[3]);
	VADD3(ell[ 8], hyp->hyp_V, heightAxis[i], majorAxis[7]);
	VADD4(ell[ 9], hyp->hyp_V, heightAxis[i], majorAxis[6], minorAxis[4]);
	VADD4(ell[10], hyp->hyp_V, heightAxis[i], majorAxis[5], minorAxis[5]);
	VADD4(ell[11], hyp->hyp_V, heightAxis[i], majorAxis[4], minorAxis[6]);
	VADD3(ell[12], hyp->hyp_V, heightAxis[i], minorAxis[7]);
	VADD4(ell[13], hyp->hyp_V, heightAxis[i], majorAxis[3], minorAxis[6]);
	VADD4(ell[14], hyp->hyp_V, heightAxis[i], majorAxis[2], minorAxis[5]);
	VADD4(ell[15], hyp->hyp_V, heightAxis[i], majorAxis[1], minorAxis[4]);

	/* draw ellipse */
	RT_ADD_VLIST(vhead, ell[15], BN_VLIST_LINE_MOVE);
	for (j = 0; j < 16; j++) {
	    RT_ADD_VLIST(vhead, ell[j], BN_VLIST_LINE_DRAW);
	}

	/* add ellipse's points to ribs */
	for (j = 0; j < 16; j++) {
	    VMOVE(ribs[j][i], ell[j]);
	}
    }

    /* draw ribs */
    for (i = 0; i < 16; i++) {
	RT_ADD_VLIST(vhead, ribs[i][0], BN_VLIST_LINE_MOVE);
	for (j = 1; j < 7; j++) {
	    RT_ADD_VLIST(vhead, ribs[i][j], BN_VLIST_LINE_DRAW);
	}

    }

    BU_PUT(hyp, struct hyp_specific);

    return 0;
}
Exemple #16
0
/**
 * R E C _ B B O X
 *
 * Calculate the RPP for an REC
 */
int
rt_rec_bbox(struct rt_db_internal *ip, point_t *min, point_t *max, const struct bn_tol *UNUSED(tol)) {
    mat_t R;
    vect_t P, w1;
    fastf_t f, tmp, z;
    double magsq_h, magsq_a, magsq_b, magsq_c, magsq_d;
    double mag_h, mag_a, mag_b;
    struct rt_tgc_internal *tip;

    RT_CK_DB_INTERNAL(ip);

    tip = (struct rt_tgc_internal *)ip->idb_ptr;
    RT_TGC_CK_MAGIC(tip);

    mag_h = sqrt(magsq_h = MAGSQ(tip->h));
    mag_a = sqrt(magsq_a = MAGSQ(tip->a));
    mag_b = sqrt(magsq_b = MAGSQ(tip->b));
    magsq_c = MAGSQ(tip->c);
    magsq_d = MAGSQ(tip->d);

    MAT_IDN(R);
    f = 1.0/mag_a;
    VSCALE(&R[0], tip->a, f);
    f = 1.0/mag_b;
    VSCALE(&R[4], tip->b, f);
    f = 1.0/mag_h;
    VSCALE(&R[8], tip->h, f);

    /* X */
    VSET(P, 1.0, 0, 0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[X] = tip->v[X] - f;	/* V.P +/- f */
    (*max)[X] = tip->v[X] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[X] - f + z < (*min)[X])
	(*min)[X] = tip->v[X] - f + z;
    if (tip->v[X] + f + z > (*max)[X])
	(*max)[X] = tip->v[X] + f + z;

    /* Y */
    VSET(P, 0, 1.0, 0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[Y] = tip->v[Y] - f;	/* V.P +/- f */
    (*max)[Y] = tip->v[Y] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[Y] - f + z < (*min)[Y])
	(*min)[Y] = tip->v[Y] - f + z;
    if (tip->v[Y] + f + z > (*max)[Y])
	(*max)[Y] = tip->v[Y] + f + z;

    /* Z */
    VSET(P, 0, 0, 1.0);		/* bounding plane normal */
    MAT3X3VEC(w1, R, P);		/* map plane into local coord syst */
    /* 1st end ellipse (no Z part) */
    tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    (*min)[Z] = tip->v[Z] - f;	/* V.P +/- f */
    (*max)[Z] = tip->v[Z] + f;
    /* 2nd end ellipse */
    z = w1[Z] * mag_h;		/* Z part */
    tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
    if (tmp > SMALL)
	f = sqrt(tmp);		/* XY part */
    else
	f = 0;
    if (tip->v[Z] - f + z < (*min)[Z])
	(*min)[Z] = tip->v[Z] - f + z;
    if (tip->v[Z] + f + z > (*max)[Z])
	(*max)[Z] = tip->v[Z] + f + z;

    return 0;
}
Exemple #17
0
/**
 * finds the intersection point between segments x1, x2 and x3, x4 and
 * stores the result in x we assume that the segments are coplanar.
 *
 * return values:
 *
 * 0: no intersection
 * 1: intersection in a point
 * 2: intersection in a line
 *
 *
 *            x1*                  *x3
 *                \               /
 *                 \             /
 *                  \           /
 *                   \         /
 *                    \       /
 *                     \     /
 *                      \   /
 *                       \ /
 *                        *   <----x
 *                       / \
 *                      /   \
 *                     /     \
 *                    /       \
 *                   /         \
 *                  /           \
 *               x4*             *x2
 *
 *
 *
 * the equations for the lines are:
 *
 * P(s) = x1 + s (x2 - x1) s in [0, 1]
 * Q(t) = x3 + t (x4 - x3) t in [0, 1]
 *
 * so we need to find s and t s.t. P(s) = Q(t)
 * So some vector calculus tells us that:
 *
 *       (CXB) dot (AXB)
 * s =   ---------------
 *           |AXB|^2
 *
 *      (-CXA) dot (BXA)
 * t =  ----------------
 *           |BXA|^2
 *
 *
 * Where we define:
 *
 * A = (x2-x1)
 * B = (x4-x3)
 * C = (x3-x1)
 *
 * This equation blows up if |AXB|^2 is 0 (in which case |BXA|^2 is
 * also 0), which indicates that the lines are parallel which is kind
 * of a pain.
 */
int SegmentSegmentIntersect(
    const ON_3dPoint& x1,
    const ON_3dPoint& x2,
    const ON_3dPoint& x3,
    const ON_3dPoint& x4,
    ON_3dPoint x[2],       /* segments could in degenerate cases intersect in another segment*/
    double tol
    )
{
    ON_3dPoint A = (x2 - x1);
    ON_3dPoint B = (x4 - x3);
    ON_3dPoint C = (x3 - x1);

    double AXB[3];
    VCROSS(AXB, A, B);
    double BXA[3];
    VCROSS(BXA, B, A);
    double CXB[3];
    VCROSS(CXB, C, B);
    double negC[3];
    VSCALE(negC, C, -1.0);
    double negCXA[3];
    VCROSS(negCXA, negC, A);

    if (VNEAR_ZERO(AXB, tol)) {/* the lines are parallel **commence sad music*/
	/* this is a potential bug if someone gets cheeky and passes us x2==x1*/
	double coincident_test[3];
	VCROSS(coincident_test, x4 - x2, x4 - x1);
	if (VNEAR_ZERO(coincident_test, tol)) {
	    /* the lines are coincident, meaning the segments lie on the same
	     * line but they could:
	     *	--not intersect at all
	     *  --intersect in a point
	     *  --intersect in a segment
	     * So here's the plan we. We're going to use dot products,
	     * The aspect of dot products that's important:
	     * A dot B is positive if A and B point the same way
	     * and negative when they point in opposite directions
	     * so --> dot --> is positive, but <-- dot --> is negative
	     * so if (x3-x1) dot (x4-x1) is negative, then x1 lies on the segment (x3, x4)
	     * which means that x1 should be one of the points we return so we just go
	     * through and find which points are contained in the other segment
	     * and those are our return values
	     */
	    int points = 0;
	    if (x1 == x3 || x1 == x4) {
		x[points] = x1;
		points++;
	    }
	    if (x2 == x3 || x2 == x4) {
		x[points] = x2;
		points++;
	    }
	    if (VDOT((x3 - x1), (x4 - x1)) < 0) {
		x[points] = x1;
		points++;
	    }
	    if (VDOT((x3 - x2), (x4 - x2)) < 0) {
		x[points] = x2;
		points++;
	    }
	    if (VDOT((x1 - x3), (x2 - x3)) < 0) {
		x[points] = x3;
		points++;
	    }
	    if (VDOT((x1 - x4), (x2 - x4)) < 0) {
		x[points] = x4;
		points++;
	    }

	    assert(points <= 2);
	    return points;
	}
    } else {
	double s = VDOT(CXB, AXB)/MAGSQ(AXB);
	double t = VDOT(negCXA, BXA)/MAGSQ(BXA);
	/* now we need to perform some tests to make sure we're not
	 * outside these bounds by tiny little amounts */
	if (-tol <= s && s <= 1.0 + tol && -tol <= t && t <= 1.0 + tol) {
	    ON_3dPoint Ps = x1 + s * (x2 - x1); /* The answer according to equation P*/
	    ON_3dPoint Qt = x3 + t * (x4 - x3); /* The answer according to equation Q*/
	    assert(VNEAR_EQUAL(Ps, Qt, tol)); /* check to see if they agree, just a sanity check*/
	    x[0] = Ps;
	    return 1;
	} else {
	    /* this happens when the lines through x1, x2 and x3, x4 intersect but not the segments*/
	    return 0;
	}
    }
    return 0;
}
Exemple #18
0
int
read_arbn(char *name)
{
    int	npt;			/* # vertex pts to be read in */
    int	npe;			/* # planes from 3 vertex points */
    int	neq;			/* # planes from equation */
    int	nae;			/* # planes from az, el & vertex index */
    int	nface;			/* total number of faces */
    double	*input_points = (double *)0;
    double	*vertex = (double *)0;	/* vertex list of final solid */
    int	last_vertex;		/* index of first unused vertex */
    int	max_vertex;		/* size of vertex array */
    int	*used = (int *)0;	/* plane eqn use count */
    plane_t	*eqn = (plane_t *)0;	/* plane equations */
    int	cur_eq = 0;		/* current (free) equation number */
    int	symm = 0;		/* symmetry about Y used */
    register int	i;
    int	j;
    int	k;
    register int	m;
    point_t	cent;			/* centroid of arbn */
    struct bn_tol	tol;

    /* XXX The tolerance here is sheer guesswork */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.005;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    npt = getint( scard, 10+0*10, 10 );
    npe = getint( scard, 10+1*10, 10 );
    neq = getint( scard, 10+2*10, 10 );
    nae = getint( scard, 10+3*10, 10 );

    nface = npe + neq + nae;
    if ( npt < 1 )  {
        /* Having one point is necessary to compute centroid */
        printf("arbn defined without at least one point\n");
bad:
        if (npt>0) eat( (npt+1)/2 );	/* vertex input_points */
        if (npe>0) eat( (npe+5)/6 );	/* vertex pt index numbers */
        if (neq>0) eat( neq );		/* plane eqns? */
        if (nae>0) eat( (nae+1)/2 );	/* az el & vertex index? */
        return(-1);
    }

    /* Allocate storage for plane equations */
    eqn = (plane_t *)bu_malloc(nface*sizeof(plane_t), "eqn");

    /* Allocate storage for per-plane use count */
    used = (int *)bu_malloc(nface*sizeof(int), "used");

    if ( npt >= 1 )  {
        /* Obtain vertex input_points */
        input_points = (double *)bu_malloc(npt*3*sizeof(double), "input_points");

        if ( getxsoldata( input_points, npt*3, sol_work ) < 0 )
            goto bad;
    }

    /* Get planes defined by three points, 6 per card */
    for ( i=0; i<npe; i += 6 )  {
        if ( get_line( scard, sizeof(scard), "arbn vertex point indices" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        for ( j=0; j<6; j++ )  {
            int	q, r, s;
            point_t	a, b, c;

            q = getint( scard, 10+j*10+0, 4 );
            r = getint( scard, 10+j*10+4, 3 );
            s = getint( scard, 10+j*10+7, 3 );

            if ( q == 0 || r == 0 || s == 0 ) continue;

            if ( q < 0 )  {
                VMOVE( a, &input_points[((-q)-1)*3] );
                a[Y] = -a[Y];
                symm = 1;
            } else {
                VMOVE( a, &input_points[((q)-1)*3] );
            }

            if ( r < 0 )  {
                VMOVE( b, &input_points[((-r)-1)*3] );
                b[Y] = -b[Y];
                symm = 1;
            } else {
                VMOVE( b, &input_points[((r)-1)*3] );
            }

            if ( s < 0 )  {
                VMOVE( c, &input_points[((-s)-1)*3] );
                c[Y] = -c[Y];
                symm = 1;
            } else {
                VMOVE( c, &input_points[((s)-1)*3] );
            }
            if ( bn_mk_plane_3pts( eqn[cur_eq], a, b, c, &tol ) < 0 )  {
                printf("arbn degenerate plane\n");
                VPRINT("a", a);
                VPRINT("b", b);
                VPRINT("c", c);
                continue;
            }
            cur_eq++;
        }
    }

    /* Get planes defined by their equation */
    for ( i=0; i < neq; i++ )  {
        register double	scale;
        if ( get_line( scard, sizeof(scard), "arbn plane equation card" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        eqn[cur_eq][0] = getdouble( scard, 10+0*10, 10 );
        eqn[cur_eq][1] = getdouble( scard, 10+1*10, 10 );
        eqn[cur_eq][2] = getdouble( scard, 10+2*10, 10 );
        eqn[cur_eq][3] = getdouble( scard, 10+3*10, 10 );
        scale = MAGNITUDE(eqn[cur_eq]);
        if ( scale < SMALL )  {
            printf("arbn plane normal too small\n");
            continue;
        }
        scale = 1/scale;
        VSCALE( eqn[cur_eq], eqn[cur_eq], scale );
        eqn[cur_eq][3] *= scale;
        cur_eq++;
    }

    /* Get planes defined by azimuth, elevation, and pt, 2 per card */
    for ( i=0; i < nae;  i += 2 )  {
        if ( get_line( scard, sizeof(scard), "arbn az/el card" ) == EOF )  {
            printf("too few cards for arbn %d\n",
                   sol_work);
            return(-1);
        }
        for ( j=0; j<2; j++ )  {
            double	az, el;
            int	vert_no;
            double	cos_el;
            point_t	pt;

            az = getdouble( scard, 10+j*30+0*10, 10 ) * bn_degtorad;
            el = getdouble( scard, 10+j*30+1*10, 10 ) * bn_degtorad;
            vert_no = getint( scard, 10+j*30+2*10, 10 );
            if ( vert_no == 0 )  break;
            cos_el = cos(el);
            eqn[cur_eq][X] = cos(az)*cos_el;
            eqn[cur_eq][Y] = sin(az)*cos_el;
            eqn[cur_eq][Z] = sin(el);

            if ( vert_no < 0 )  {
                VMOVE( pt, &input_points[((-vert_no)-1)*3] );
                pt[Y] = -pt[Y];
            } else {
                VMOVE( pt, &input_points[((vert_no)-1)*3] );
            }
            eqn[cur_eq][3] = VDOT(pt, eqn[cur_eq]);
            cur_eq++;
        }
    }
    if ( nface != cur_eq )  {
        printf("arbn expected %d faces, got %d\n", nface, cur_eq);
        return(-1);
    }

    /* Average all given points together to find centroid */
    /* This is why there must be at least one (two?) point given */
    VSETALL(cent, 0);
    for ( i=0; i<npt; i++ )  {
        VADD2( cent, cent, &input_points[i*3] );
    }
    VSCALE( cent, cent, 1.0/npt );
    if ( symm )  cent[Y] = 0;

    /* Point normals away from centroid */
    for ( i=0; i<nface; i++ )  {
        double	dist;

        dist = VDOT( eqn[i], cent ) - eqn[i][3];
        /* If dist is negative, 'cent' is inside halfspace */
#define DIST_TOL	(1.0e-8)
#define DIST_TOL_SQ	(1.0e-10)
        if ( dist < -DIST_TOL )  continue;
        if ( dist > DIST_TOL )  {
            /* Flip halfspace over */
            VREVERSE( eqn[i], eqn[i] );
            eqn[i][3] = -eqn[i][3];
        } else {
            /* Centroid lies on this face */
            printf("arbn centroid lies on face\n");
            return(-1);
        }

    }

    /* Release storage for input points */
    bu_free( (char *)input_points, "input_points" );
    input_points = (double *)0;


    /*
     *  ARBN must be convex.  Test for concavity.
     *  Byproduct is an enumeration of all the verticies.
     */
    last_vertex = max_vertex = 0;

    /* Zero face use counts */
    for ( i=0; i<nface; i++ )  {
        used[i] = 0;
    }
    for ( i=0; i<nface-2; i++ )  {
        for ( j=i+1; j<nface-1; j++ )  {
            double	dot;
            int	point_count;	/* # points on this line */

            /* If normals are parallel, no intersection */
            dot = VDOT( eqn[i], eqn[j] );
            if ( !NEAR_ZERO( dot, 0.999999 ) )  continue;

            point_count = 0;
            for ( k=j+1; k<nface; k++ )  {
                point_t	pt;

                if ( bn_mkpoint_3planes( pt, eqn[i], eqn[j], eqn[k] ) < 0 )  continue;

                /* See if point is outside arb */
                for ( m=0; m<nface; m++ )  {
                    if ( i==m || j==m || k==m )  continue;
                    if ( VDOT(pt, eqn[m])-eqn[m][3] > DIST_TOL )
                        goto next_k;
                }
                /* See if vertex already was found */
                for ( m=0; m<last_vertex; m++ )  {
                    vect_t	dist;
                    VSUB2( dist, pt, &vertex[m*3] );
                    if ( MAGSQ(dist) < DIST_TOL_SQ )
                        goto next_k;
                }

                /*
                 *  Add point to vertex array.
                 *  If more room needed, realloc.
                 */
                if ( last_vertex >= max_vertex )  {
                    if ( max_vertex == 0 )   {
                        max_vertex = 3;
                        vertex = (double *)bu_malloc( max_vertex*3*sizeof(double), "vertex" );
                    } else {
                        max_vertex *= 10;
                        vertex = (double *)bu_realloc( (char *)vertex, max_vertex*3*sizeof(double), "vertex" );
                    }
                }

                VMOVE( &vertex[last_vertex*3], pt );
                last_vertex++;
                point_count++;

                /* Increment "face used" counts */
                used[i]++;
                used[j]++;
                used[k]++;
next_k:
                ;
            }
            if ( point_count > 2 )  {
                printf("arbn: warning, point_count on line=%d\n", point_count);
            }
        }
    }

    /* If any planes were not used, then arbn is not convex */
    for ( i=0; i<nface; i++ )  {
        if ( used[i] != 0 )  continue;	/* face was used */
        printf("arbn face %d unused, solid is not convex\n", i);
        return(-1);
    }

    /* Write out the solid ! */
    i = mk_arbn( outfp, name, nface, eqn );

    if ( input_points )  bu_free( (char *)input_points, "input_points" );
    if ( vertex )  bu_free( (char *)vertex, "vertex" );
    if ( eqn )  bu_free( (char *)eqn, "eqn" );
    if ( used )  bu_free( (char *)used, "used" );

    return(i);
}
Exemple #19
0
/*
 *			G E T S O L I D
 *
 *  Returns -
 *	-1	error
 *	 0	conversion OK
 *	 1	EOF
 */
int
getsolid(void)
{
    char	given_solid_num[16];
    char	solid_type[16];
    int	i;
    double	r1, r2;
    vect_t	work;
    double	m1, m2;		/* Magnitude temporaries */
    char	*name=NULL;
    double	dd[4*6];	/* 4 cards of 6 nums each */
    point_t	tmp[8];		/* 8 vectors of 3 nums each */
    int	ret;
#define D(_i)	(&(dd[_i*3]))
#define T(_i)	(&(tmp[_i][0]))

    if ( (i = get_line( scard, sizeof(scard), "solid card" )) == EOF )  {
        printf("getsolid: unexpected EOF\n");
        return( 1 );
    }

    switch ( version )  {
    case 5:
        bu_strlcpy( given_solid_num, scard+0, sizeof(given_solid_num) );
        given_solid_num[5] = '\0';
        bu_strlcpy( solid_type, scard+5, sizeof(solid_type) );
        solid_type[5] = '\0';
        break;
    case 4:
        bu_strlcpy( given_solid_num, scard+0, sizeof(given_solid_num) );
        given_solid_num[3] = '\0';
        bu_strlcpy( solid_type, scard+3, sizeof(solid_type) );
        solid_type[7] = '\0';
        break;
    case 1:
        /* DoE/MORSE version, believed to be original MAGIC format */
        bu_strlcpy( given_solid_num, scard+5, sizeof(given_solid_num) );
        given_solid_num[4] = '\0';
        bu_strlcpy( solid_type, scard+2, sizeof(solid_type) );
        break;
    default:
        fprintf(stderr, "getsolid() version %d unimplemented\n", version);
        bu_exit(1, NULL);
        break;
    }
    /* Trim trailing spaces */
    trim_trail_spaces( given_solid_num );
    trim_trail_spaces( solid_type );

    /* another solid - increment solid counter
     * rather than using number from the card, which may go into
     * pseudo-hex format in version 4 models (due to 3 column limit).
     */
    sol_work++;
    if ( version == 5 )  {
        if ( (i = getint( scard, 0, 5 )) != sol_work )  {
            printf("expected solid card %d, got %d, abort\n",
                   sol_work, i );
            return(1);
        }
    }

    /* Reduce solid type to lower case */
    {
        register char	*cp;
        register char	c;

        cp = solid_type;
        while ( (c = *cp) != '\0' )  {
            if ( !isascii(c) )  {
                *cp++ = '?';
            } else if ( isupper(c) )  {
                *cp++ = tolower(c);
            } else {
                cp++;
            }
        }
    }

    namecvt( sol_work, &name, 's' );
    if (verbose) col_pr( name );

    if ( strcmp( solid_type, "end" ) == 0 )  {
        /* DoE/MORSE version 1 format */
        bu_free( name, "name" );
        return(1);		/* END */
    }

    if ( strcmp( solid_type, "ars" ) == 0 )  {
        int		ncurves;
        int		pts_per_curve;
        double		**curve;

        ncurves = getint( scard, 10, 10 );
        pts_per_curve = getint( scard, 20, 10 );

        /* Allocate curves pointer array */
        curve = (double **)bu_malloc((ncurves+1)*sizeof(double *), "curve");

        /* Allocate space for a curve, and read it in */
        for ( i=0; i<ncurves; i++ )  {
            curve[i] = (double *)bu_malloc((pts_per_curve+1)*3*sizeof(double), "curve[i]" );

            /* Get data for this curve */
            if ( getxsoldata( curve[i], pts_per_curve*3, sol_work ) < 0 )  {
                printf("ARS %d: getxsoldata failed, curve %d\n",
                       sol_work, i);
                return(-1);
            }
        }
        if ( (ret = mk_ars( outfp, name, ncurves, pts_per_curve, curve )) < 0 )  {
            printf("mk_ars(%s) failed\n", name );
            /* Need to free memory; 'ret' is returned below */
        }

        for ( i=0; i<ncurves; i++ )  {
            bu_free( (char *)curve[i], "curve[i]" );
        }
        bu_free( (char *)curve, "curve" );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "rpp" ) == 0 )  {
        double	min[3], max[3];

        if ( getsoldata( dd, 2*3, sol_work ) < 0 )
            return(-1);
        VSET( min, dd[0], dd[2], dd[4] );
        VSET( max, dd[1], dd[3], dd[5] );
        ret = mk_rpp( outfp, name, min, max );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "box" ) == 0 )  {
        if ( getsoldata( dd, 4*3, sol_work ) < 0 )
            return(-1);
        VMOVE( T(0), D(0) );
        VADD2( T(1), D(0), D(2) );
        VADD3( T(2), D(0), D(2), D(1) );
        VADD2( T(3), D(0), D(1) );

        VADD2( T(4), D(0), D(3) );
        VADD3( T(5), D(0), D(3), D(2) );
        VADD4( T(6), D(0), D(3), D(2), D(1) );
        VADD3( T(7), D(0), D(3), D(1) );
        ret = mk_arb8( outfp, name, &tmp[0][X] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "raw" ) == 0 ||
            strcmp( solid_type, "wed" ) == 0		/* DoE name */
       )  {
        if ( getsoldata( dd, 4*3, sol_work ) < 0 )
            return(-1);
        VMOVE( T(0), D(0) );
        VADD2( T(1), D(0), D(2) );
        VMOVE( T(2), T(1) );
        VADD2( T(3), D(0), D(1) );

        VADD2( T(4), D(0), D(3) );
        VADD3( T(5), D(0), D(3), D(2) );
        VMOVE( T(6), T(5) );
        VADD3( T(7), D(0), D(3), D(1) );
        ret = mk_arb8( outfp, name, &tmp[0][X] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "rvw" ) == 0 )  {
        /* Right Vertical Wedge (Origin: DoE/MORSE) */
        double	a2, theta, phi, h2;
        double	a2theta;
        double	angle1, angle2;
        vect_t	a, b, c;

        if ( getsoldata( dd, 1*3+4, sol_work ) < 0 )
            return(-1);
        a2 = dd[3];		/* XY side length */
        theta = dd[4];
        phi = dd[5];
        h2 = dd[6];		/* height in +Z */

        angle1 = (phi+theta-90) * bn_degtorad;
        angle2 = (phi+theta) * bn_degtorad;
        a2theta = a2 * tan(theta * bn_degtorad);

        VSET( a, a2theta*cos(angle1), a2theta*sin(angle1), 0 );
        VSET( b, -a2*cos(angle2), -a2*sin(angle2), 0 );
        VSET( c, 0, 0, h2 );

        VSUB2( T(0), D(0), b );
        VMOVE( T(1), D(0) );
        VMOVE( T(2), D(0) );
        VADD2( T(3), T(0), a );

        VADD2( T(4), T(0), c );
        VADD2( T(5), T(1), c );
        VMOVE( T(6), T(5) );
        VADD2( T(7), T(3), c );
        ret = mk_arb8( outfp, name, &tmp[0][X] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arw" ) == 0) {
        /* ARbitrary Wedge --- ERIM */
        if ( getsoldata( dd, 4*3, sol_work ) < 0)
            return(-1);
        VMOVE( T(0), D(0) );
        VADD2( T(1), D(0), D(2) );
        VADD3( T(2), D(0), D(2), D(3) );
        VADD2( T(3), D(0), D(3) );

        VADD2( T(4), D(0), D(1) );
        VMOVE( T(5), T(4) );

        VADD3( T(6), D(0), D(1), D(3) );
        VMOVE( T(7), T(6) );
        ret = mk_arb8( outfp, name, &tmp[0][X]);
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arb8" ) == 0 )  {
        if ( getsoldata( dd, 8*3, sol_work ) < 0 )
            return(-1);
        ret = mk_arb8( outfp, name, dd );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arb7" ) == 0 )  {
        if ( getsoldata( dd, 7*3, sol_work ) < 0 )
            return(-1);
        VMOVE( D(7), D(4) );
        ret = mk_arb8( outfp, name, dd );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arb6" ) == 0 )  {
        if ( getsoldata( dd, 6*3, sol_work ) < 0 )
            return(-1);
        /* Note that the ordering is important, as data is in D(4), D(5) */
        VMOVE( D(7), D(5) );
        VMOVE( D(6), D(5) );
        VMOVE( D(5), D(4) );
        ret = mk_arb8( outfp, name, dd );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arb5" ) == 0 )  {
        if ( getsoldata( dd, 5*3, sol_work ) < 0 )
            return(-1);
        VMOVE( D(5), D(4) );
        VMOVE( D(6), D(4) );
        VMOVE( D(7), D(4) );
        ret = mk_arb8( outfp, name, dd );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arb4" ) == 0 )  {
        if ( getsoldata( dd, 4*3, sol_work ) < 0 )
            return(-1);
        ret = mk_arb4( outfp, name, dd );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "rcc" ) == 0 )  {
        /* V, H, r */
        if ( getsoldata( dd, 2*3+1, sol_work ) < 0 )
            return(-1);
        ret = mk_rcc( outfp, name, D(0), D(1), dd[6] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "rec" ) == 0 )  {
        /* V, H, A, B */
        if ( getsoldata( dd, 4*3, sol_work ) < 0 )
            return(-1);
        ret = mk_tgc( outfp, name, D(0), D(1),
                      D(2), D(3), D(2), D(3) );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "trc" ) == 0 )  {
        /* V, H, r1, r2 */
        if ( getsoldata( dd, 2*3+2, sol_work ) < 0 )
            return(-1);
        ret = mk_trc_h( outfp, name, D(0), D(1), dd[6], dd[7] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "tec" ) == 0 )  {
        /* V, H, A, B, p */
        if ( getsoldata( dd, 4*3+1, sol_work ) < 0 )
            return(-1);
        r1 = 1.0/dd[12];	/* P */
        VSCALE( D(4), D(2), r1 );
        VSCALE( D(5), D(3), r1 );
        ret = mk_tgc( outfp, name, D(0), D(1),
                      D(2), D(3), D(4), D(5) );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "tgc" ) == 0 )  {
        /* V, H, A, B, r1, r2 */
        if ( getsoldata( dd, 4*3+2, sol_work ) < 0 )
            return(-1);
        r1 = dd[12] / MAGNITUDE( D(2) );	/* A/|A| * C */
        r2 = dd[13] / MAGNITUDE( D(3) );	/* B/|B| * D */
        VSCALE( D(4), D(2), r1 );
        VSCALE( D(5), D(3), r2 );
        ret = mk_tgc( outfp, name, D(0), D(1),
                      D(2), D(3), D(4), D(5) );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "sph" ) == 0 )  {
        /* V, radius */
        if ( getsoldata( dd, 1*3+1, sol_work ) < 0 )
            return(-1);
        ret = mk_sph( outfp, name, D(0), dd[3] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strncmp( solid_type, "wir", 3 ) == 0 )  {
        int			numpts;		/* points per wire */
        int			num;
        int			i;
        double			dia;
        double			*pts;		/* 3 entries per pt */
        struct	wdb_pipept	*ps;
        struct	bu_list		head;		/* allow a whole struct for head */

        /* This might be getint( solid_type, 3, 2 ); for non-V5 */
        numpts = getint( scard, 8, 2 );
        num = numpts * 3 + 1;			/* 3 entries per pt */

        /* allocate space for the points array */
        pts = ( double *)bu_malloc(num * sizeof( double), "pts" );

        if ( getsoldata( pts, num, sol_work ) < 0 )  {
            return(-1);
        }
        dia = pts[num-1] * 2.0;	/* radius X 2.0 == diameter */

        /* allocate nodes on a list and store all information in
         * the appropriate location.
         */
        BU_LIST_INIT( &head );
        for ( i = 0; i < numpts; i++ )  {
            /* malloc a new structure */
            ps = (struct wdb_pipept *)bu_malloc(sizeof( struct wdb_pipept), "ps");

            ps->l.magic = WDB_PIPESEG_MAGIC;
            VMOVE( ps->pp_coord, &pts[i*3]);	/* 3 pts at a time */
            ps->pp_id = 0;				/* solid */
            ps->pp_od = dia;
            ps->pp_bendradius = dia;
            BU_LIST_INSERT( &head, &ps->l );
        }

        if ( mk_pipe( outfp, name, &head ) < 0 )
            return(-1);
        mk_pipe_free( &head );
        bu_free( name, "name" );
        return(0);		/* OK */
    }

    if ( strcmp( solid_type, "rpc" ) == 0 )  {
        /* V, H, B, r */
        if ( getsoldata( dd, 3*3+1, sol_work ) < 0 )
            return(-1);
        ret = mk_rpc( outfp, name, D(0), D(1),
                      D(2), dd[9] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "rhc" ) == 0 )  {
        /* V, H, B, r, c */
        if ( getsoldata( dd, 3*3+2, sol_work ) < 0 )
            return(-1);
        ret = mk_rhc( outfp, name, D(0), D(1),
                      D(2), dd[9], dd[10] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "epa" ) == 0 )  {
        /* V, H, Au, r1, r2 */
        if ( getsoldata( dd, 3*3+2, sol_work ) < 0 )
            return(-1);
        ret = mk_epa( outfp, name, D(0), D(1),
                      D(2), dd[9], dd[10] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "ehy" ) == 0 )  {
        /* V, H, Au, r1, r2, c */
        if ( getsoldata( dd, 3*3+3, sol_work ) < 0 )
            return(-1);
        ret = mk_ehy( outfp, name, D(0), D(1),
                      D(2), dd[9], dd[10], dd[11] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "eto" ) == 0 )  {
        /* V, N, C, r, rd */
        if ( getsoldata( dd, 3*3+2, sol_work ) < 0 )
            return(-1);
        ret = mk_eto( outfp, name, D(0), D(1),
                      D(2), dd[9], dd[10] );
        bu_free( name, "name" );
        return(ret);
    }


    if ( version <= 4 && strcmp( solid_type, "ell" ) == 0 )  {
        /* Foci F1, F2, major axis length L */
        vect_t	v;

        /*
         * For simplicity, we convert ELL to ELL1, then
         * fall through to ELL1 code.
         * Format of ELL is F1, F2, len
         * ELL1 format is V, A, r
         */
        if ( getsoldata( dd, 2*3+1, sol_work ) < 0 )
            return(-1);
        VADD2SCALE( v, D(0), D(1), 0.5 ); /* V is midpoint */

        VSUB2( work, D(1), D(0) );	/* work holds F2 -  F1 */
        m1 = MAGNITUDE( work );
        r2 = 0.5 * dd[6] / m1;
        VSCALE( D(1), work, r2 );	/* A */

        dd[6] = sqrt( MAGSQ( D(1) ) -
                      (m1 * 0.5)*(m1 * 0.5) );	/* r */
        VMOVE( D(0), v );
        goto ell1;
    }

    if ( (version == 5 && strcmp( solid_type, "ell" ) == 0)  ||
            strcmp( solid_type, "ell1" ) == 0 )  {
        /* V, A, r */
        /* GIFT4 name is "ell1", GIFT5 name is "ell" */
        if ( getsoldata( dd, 2*3+1, sol_work ) < 0 )
            return(-1);

ell1:
        r1 = dd[6];		/* R */
        VMOVE( work, D(0) );
        work[0] += bn_pi;
        work[1] += bn_pi;
        work[2] += bn_pi;
        VCROSS( D(2), work, D(1) );
        m1 = r1/MAGNITUDE( D(2) );
        VSCALE( D(2), D(2), m1 );

        VCROSS( D(3), D(1), D(2) );
        m2 = r1/MAGNITUDE( D(3) );
        VSCALE( D(3), D(3), m2 );

        /* Now we have V, A, B, C */
        ret = mk_ell( outfp, name, D(0), D(1), D(2), D(3) );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "ellg" ) == 0 )  {
        /* V, A, B, C */
        if ( getsoldata( dd, 4*3, sol_work ) < 0 )
            return(-1);
        ret = mk_ell( outfp, name, D(0), D(1), D(2), D(3) );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "tor" ) == 0 )  {
        /* V, N, r1, r2 */
        if ( getsoldata( dd, 2*3+2, sol_work ) < 0 )
            return(-1);
        ret = mk_tor( outfp, name, D(0), D(1), dd[6], dd[7] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "haf" ) == 0 )  {
        /* N, d */
        if ( getsoldata( dd, 1*3+1, sol_work ) < 0 )
            return(-1);
        ret = mk_half( outfp, name, D(0), -dd[3] );
        bu_free( name, "name" );
        return(ret);
    }

    if ( strcmp( solid_type, "arbn" ) == 0 )  {
        ret = read_arbn( name );
        bu_free( name, "name" );
    }

    /*
     *  The solid type string is defective,
     *  or that solid is not currently supported.
     */
    printf("getsolid:  no support for solid type '%s'\n", solid_type );
    return(-1);
}
Exemple #20
0
/**
 * Mirror an object about some axis at a specified point on the axis.
 * It is the caller's responsibility to retain and free the internal.
 *
 * Returns the modified internal object or NULL on error.
 **/
struct rt_db_internal *
rt_mirror(struct db_i *dbip,
	  struct rt_db_internal *ip,
	  point_t mirror_pt,
	  vect_t mirror_dir,
	  struct resource *resp)
{
    int id;
    int err;
    static fastf_t tol_dist_sq = 0.0005 * 0.0005;
    plane_t plane;

    RT_CK_DBI(dbip);
    RT_CK_DB_INTERNAL(ip);

    if (!NEAR_EQUAL(MAGSQ(mirror_dir), 1.0, tol_dist_sq)) {
	bu_log("ERROR: mirror direction is invalid\n");
	return NULL;
    }

    if (!resp) {
	resp=&rt_uniresource;
    }

    /* not the best, but consistent until v6 */
    id = ip->idb_type;

    /* set up the plane direction */
    VUNITIZE(mirror_dir);
    VMOVE(plane, mirror_dir);

    /* determine the plane offset */
    plane[W] = VDOT(mirror_pt, mirror_dir);

    switch (id) {
	case ID_TOR: {
	    err = rt_tor_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_TGC:
	case ID_REC: {
	    err = rt_tgc_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_ELL:
	case ID_SPH: {
	    err = rt_ell_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_ARB8: {
	    err = rt_arb_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_HALF: {
	    err = rt_half_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_GRIP: {
	    err = rt_grip_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_POLY: {
	    err = rt_poly_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_BSPLINE: {
	    err = rt_nurb_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_ARBN: {
	    err = rt_arbn_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_PIPE: {
	    err = rt_pipe_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_PARTICLE: {
	    err = rt_particle_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_RPC: {
	    err = rt_rpc_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_RHC: {
	    err = rt_rhc_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_EPA: {
	    err = rt_epa_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_ETO: {
	    err = rt_eto_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_HYP: {
	    err = rt_hyp_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_NMG: {
	    err = rt_nmg_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_ARS: {
	    err = rt_ars_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_EBM: {
	    err = rt_ebm_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_DSP: {
	    err = rt_dsp_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_VOL: {
	    err = rt_vol_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_SUPERELL: {
	    err = rt_superell_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_COMBINATION: {
	    err = rt_comb_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	case ID_BOT: {
	    err = rt_bot_mirror(ip, plane);
	    return err ? NULL : ip;
	}
	default: {
	    bu_log("Unknown or unsupported object type (id==%d)\n", id);
	}
    }

    /* sanity in case object is unknown */
    return NULL;
}
Exemple #21
0
/**
 * R E C _ P R E P
 *
 * Given a pointer to a GED database record, and a transformation matrix,
 * determine if this is a valid REC,
 * and if so, precompute various terms of the formulas.
 *
 * Returns -
 * 0 REC is OK
 * !0 Error in description
 *
 * Implicit return - A struct rec_specific is created, and its
 * address is stored in stp->st_specific for use by rt_rec_shot().  If
 * the TGC is really an REC, stp->st_id is modified to ID_REC.
 */
int
rt_rec_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
{
    struct rt_tgc_internal *tip;
    struct rec_specific *rec;
    double magsq_h, magsq_a, magsq_b;
    double mag_h, mag_a, mag_b;
    mat_t R;
    mat_t Rinv;
    mat_t S;
    vect_t invsq;	/* [ 1/(|A|**2), 1/(|B|**2), 1/(|Hv|**2) ] */
    vect_t work;
    fastf_t f;

    if (!stp || !ip)
	return -1;
    RT_CK_SOLTAB(stp);
    RT_CK_DB_INTERNAL(ip);
    if (rtip) RT_CK_RTI(rtip);

    tip = (struct rt_tgc_internal *)ip->idb_ptr;
    RT_TGC_CK_MAGIC(tip);

    /* Validate that |H| > 0, compute |A| |B| |C| |D| */
    mag_h = sqrt(magsq_h = MAGSQ(tip->h));
    mag_a = sqrt(magsq_a = MAGSQ(tip->a));
    mag_b = sqrt(magsq_b = MAGSQ(tip->b));

    /* Check for |H| > 0, |A| > 0, |B| > 0 */
    if (NEAR_ZERO(mag_h, RT_LEN_TOL) || NEAR_ZERO(mag_a, RT_LEN_TOL)
	|| NEAR_ZERO(mag_b, RT_LEN_TOL)) {
	return 1;		/* BAD, too small */
    }

    /* Make sure that A == C, B == D */
    VSUB2(work, tip->a, tip->c);
    f = MAGNITUDE(work);
    if (! NEAR_ZERO(f, RT_LEN_TOL)) {
	return 1;		/* BAD, !cylinder */
    }
    VSUB2(work, tip->b, tip->d);
    f = MAGNITUDE(work);
    if (! NEAR_ZERO(f, RT_LEN_TOL)) {
	return 1;		/* BAD, !cylinder */
    }

    /* Check for A.B == 0, H.A == 0 and H.B == 0 */
    f = VDOT(tip->a, tip->b) / (mag_a * mag_b);
    if (! NEAR_ZERO(f, RT_DOT_TOL)) {
	return 1;		/* BAD */
    }
    f = VDOT(tip->h, tip->a) / (mag_h * mag_a);
    if (! NEAR_ZERO(f, RT_DOT_TOL)) {
	return 1;		/* BAD */
    }
    f = VDOT(tip->h, tip->b) / (mag_h * mag_b);
    if (! NEAR_ZERO(f, RT_DOT_TOL)) {
	return 1;		/* BAD */
    }

    /*
     * This TGC is really an REC
     */
    stp->st_id = ID_REC;		/* "fix" soltab ID */
    stp->st_meth = &rt_functab[ID_REC];

    BU_GET(rec, struct rec_specific);
    stp->st_specific = (genptr_t)rec;

    VMOVE(rec->rec_Hunit, tip->h);
    VUNITIZE(rec->rec_Hunit);

    VMOVE(rec->rec_V, tip->v);
    VMOVE(rec->rec_A, tip->a);
    VMOVE(rec->rec_B, tip->b);
    rec->rec_iAsq = 1.0/magsq_a;
    rec->rec_iBsq = 1.0/magsq_b;

    VSET(invsq, 1.0/magsq_a, 1.0/magsq_b, 1.0/magsq_h);

    /* Compute R and Rinv matrices */
    MAT_IDN(R);
    f = 1.0/mag_a;
    VSCALE(&R[0], tip->a, f);
    f = 1.0/mag_b;
    VSCALE(&R[4], tip->b, f);
    f = 1.0/mag_h;
    VSCALE(&R[8], tip->h, f);
    bn_mat_trn(Rinv, R);			/* inv of rot mat is trn */

    /* Compute S */
    MAT_IDN(S);
    S[ 0] = sqrt(invsq[0]);
    S[ 5] = sqrt(invsq[1]);
    S[10] = sqrt(invsq[2]);

    /* Compute SoR and invRoS */
    bn_mat_mul(rec->rec_SoR, S, R);
    bn_mat_mul(rec->rec_invRoS, Rinv, S);

    /* Compute bounding sphere and RPP */
    {
	fastf_t dx, dy, dz;	/* For bounding sphere */

	if (stp->st_meth->ft_bbox(ip, &(stp->st_min), &(stp->st_max), &(rtip->rti_tol))) return 1;

	VSET(stp->st_center,
	     (stp->st_max[X] + stp->st_min[X])/2,
	     (stp->st_max[Y] + stp->st_min[Y])/2,
	     (stp->st_max[Z] + stp->st_min[Z])/2);

	dx = (stp->st_max[X] - stp->st_min[X])/2;
	f = dx;
	dy = (stp->st_max[Y] - stp->st_min[Y])/2;
	if (dy > f) f = dy;
	dz = (stp->st_max[Z] - stp->st_min[Z])/2;
	if (dz > f) f = dz;
	stp->st_aradius = f;
	stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
    }
    return 0;			/* OK */
}
void
Do_subfigs()
{
    int i, j;
    int entity_type;
    struct wmember head1;
    struct wmember *wmem;

    if (RT_G_DEBUG & DEBUG_MEM_FULL)
	bu_mem_barriercheck();

    BU_LIST_INIT(&head1.l);

    for (i = 0; i < totentities; i++) {
	int subfigdef_de;
	int subfigdef_index;
	int no_of_members;
	int *members;
	char *name = NULL;
	struct wmember head2;
	double mat_scale[3];
	int non_unit;

	if (dir[i]->type != 408)
	    continue;

	if (RT_G_DEBUG & DEBUG_MEM_FULL)
	    bu_mem_barriercheck();

	if (dir[i]->param <= pstart) {
	    bu_log("Illegal parameter pointer for entity D%07d (%s)\n" ,
		   dir[i]->direct, dir[i]->name);
	    continue;
	}

	Readrec(dir[i]->param);
	Readint(&entity_type, "");
	if (entity_type != 408) {
	    bu_log("Expected Singular Subfigure Instance Entity, found %s\n",
		   iges_type(entity_type));
	    continue;
	}

	Readint(&subfigdef_de, "");
	subfigdef_index = (subfigdef_de - 1)/2;
	if (subfigdef_index >= totentities) {
	    bu_log("Singular Subfigure Instance Entity gives Subfigure Definition");
	    bu_log("\tEntity DE of %d, largest DE in file is %d\n",
		   subfigdef_de, (totentities * 2) - 1);
	    continue;
	}
	if (dir[subfigdef_index]->type != 308) {
	    bu_log("Expected Subfigure Definition Entity, found %s\n",
		   iges_type(dir[subfigdef_index]->type));
	    continue;
	}

	if (dir[subfigdef_index]->param <= pstart) {
	    bu_log("Illegal parameter pointer for entity D%07d (%s)\n" ,
		   dir[subfigdef_index]->direct, dir[subfigdef_index]->name);
	    continue;
	}
	Readrec(dir[subfigdef_index]->param);
	Readint(&entity_type, "");
	if (entity_type != 308) {
	    bu_log("Expected Subfigure Definition Entity, found %s\n",
		   iges_type(entity_type));
	    continue;
	}

	Readint(&j, "");	/* ignore depth */
	Readstrg("");		/* ignore subfigure name */

	wmem = mk_addmember(dir[subfigdef_index]->name, &head1.l, NULL, WMOP_UNION);
	non_unit = 0;
	for (j = 0; j < 3; j++) {
	    double mag_sq;

	    mat_scale[j] = 1.0;
	    mag_sq = MAGSQ(&(*dir[i]->rot)[j*4]);

	    /* FIXME: arbitrary undefined tolerance */
	    if (!NEAR_EQUAL(mag_sq, 1.0, 100.0*SQRT_SMALL_FASTF)) {
		mat_scale[j] = 1.0/sqrt(mag_sq);
		non_unit = 1;
	    }
	}

	if (non_unit) {
	    bu_log("Illegal transformation matrix in %s for member %s\n",
		   curr_file->obj_name, wmem->wm_name);
	    bu_log(" row vector magnitudes are %g, %g, and %g\n",
		   1.0/mat_scale[0], 1.0/mat_scale[1], 1.0/mat_scale[2]);
	    bn_mat_print("", *dir[i]->rot);
	    for (j = 0; j < 11; j++) {
		if ((j+1)%4 == 0)
		    continue;
		(*dir[i]->rot)[j] *= mat_scale[0];
	    }
	    bn_mat_print("After scaling:", *dir[i]->rot);

	}
	memcpy(wmem->wm_mat, *dir[i]->rot, sizeof(mat_t));

	Readint(&no_of_members, "");	/* get number of members */
	members = (int *)bu_calloc(no_of_members, sizeof(int), "Do_subfigs: members");
	for (j = 0; j < no_of_members; j++)
	    Readint(&members[j], "");

	BU_LIST_INIT(&head2.l);
	for (j = 0; j < no_of_members; j++) {
	    int idx;

	    idx = (members[j] - 1)/2;

	    if (idx >= totentities) {
		bu_log("Subfigure Definition Entity gives Member Entity");
		bu_log("\tDE of %d, largest DE in file is %d\n",
		       members[j], (totentities * 2) - 1);
		continue;
	    }
	    if (dir[idx]->param <= pstart) {
		bu_log("Illegal parameter pointer for entity D%07d (%s)\n" ,
		       dir[idx]->direct, dir[idx]->name);
		continue;
	    }

	    if (dir[idx]->type == 416) {
		struct file_list *list_ptr;
		char *file_name;
		int found = 0;

		/* external reference */

		Readrec(dir[idx]->param);
		Readint(&entity_type, "");

		if (entity_type != 416) {
		    bu_log("Expected External reference Entity, found %s\n",
			   iges_type(entity_type));
		    continue;
		}

		if (dir[idx]->form != 1) {
		    bu_log("External Reference Entity of form #%d found\n",
			   dir[idx]->form);
		    bu_log("\tOnly form #1 is currently handled\n");
		    continue;
		}

		Readname(&file_name, "");

		/* Check if this external reference is already on the list */
		for (BU_LIST_FOR(list_ptr, file_list, &iges_list.l)) {
		    if (BU_STR_EQUAL(file_name, list_ptr->file_name)) {
			found = 1;
			name = list_ptr->obj_name;
			break;
		    }
		}

		if (!found) {
		    /* Need to add this one to the list */
		    BU_ALLOC(list_ptr, struct file_list);

		    list_ptr->file_name = file_name;
		    if (no_of_members == 1)
			bu_strlcpy(list_ptr->obj_name, dir[subfigdef_index]->name, NAMESIZE+1);
		    else {
			bu_strlcpy(list_ptr->obj_name, "subfig", NAMESIZE+1);
			(void) Make_unique_brl_name(list_ptr->obj_name);
		    }


		    BU_LIST_APPEND(&curr_file->l, &list_ptr->l);

		    name = list_ptr->obj_name;
		} else
		    bu_free((char *)file_name, "Do_subfigs: file_name");

	    } else
		name = dir[idx]->name;

	    if (no_of_members > 1) {
		wmem = mk_addmember(name, &head2.l, NULL, WMOP_UNION);
		memcpy(wmem->wm_mat, dir[idx]->rot, sizeof(mat_t));
	    }
	}

	if (no_of_members > 1)
	    (void)mk_lcomb(fdout, dir[subfigdef_index]->name, &head2, 0,
			   (char *)NULL, (char *)NULL, (unsigned char *)NULL, 0);
    }
Exemple #23
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;
}
Exemple #24
0
/*
 * T R E E T H E R M _ R E N D E R
 *
 * This is called (from viewshade() in shade.c) once for each hit point
 * to be shaded.  The purpose here is to fill in values in the shadework
 * structure.
 */
int
tthrm_render(struct application *ap, const struct partition *pp, struct shadework *swp, genptr_t dp)


/* defined in material.h */
/* ptr to the shader-specific struct */
{
    register struct tthrm_specific *tthrm_sp =
	(struct tthrm_specific *)dp;
    struct rt_part_internal *part_p;

    point_t pt;
    vect_t pt_v;
    vect_t v;
    int solid_number;
    struct thrm_seg *thrm_seg;
    int best_idx;
    double best_val;
    double Vdot;
    int node;

    /* check the validity of the arguments we got */
    RT_AP_CHECK(ap);
    RT_CHECK_PT(pp);
    CK_tthrm_SP(tthrm_sp);

    /* We are performing the shading in "region" space.  We must
     * transform the hit point from "model" space to "region" space.
     * See the call to db_region_mat in tthrm_setup().
     */
    MAT4X3PNT(pt, tthrm_sp->tthrm_m_to_sh, swp->sw_hit.hit_point);

    if (rdebug&RDEBUG_SHADE)
	bu_log("tthrm_render(%s, %g %g %g)\n", tthrm_sp->tt_name,
	       V3ARGS(pt));


    solid_number = get_solid_number(pp);

    if (solid_number > tthrm_sp->tt_max_seg) {
	bu_log("%s:%d solid name %s has solid number higher than %ld\n",
	       __FILE__, __LINE__, tthrm_sp->tt_max_seg);
	bu_bomb("Choke! ack! gasp! wheeeeeeze.\n");
    }

    thrm_seg = &tthrm_sp->tt_segs[solid_number];
    CK_THRM_SEG(thrm_seg);


    /* Extract the solid parameters for the particle we hit,
     * Compare them to the values for the node extracted.  If they
     * don't match, then we probably have a mis-match between the
     * geometry and the treetherm output files.
     */
    if (pp->pt_inseg->seg_stp->st_id != ID_PARTICLE) {
	bu_log("%d != ID_PART\n", pp->pt_inseg->seg_stp->st_id);
	bu_bomb("");
    }
    part_p = (struct rt_part_internal *)pp->pt_inseg->seg_stp->st_specific;
    RT_PART_CK_MAGIC(part_p);
    VSUB2(v, part_p->part_V, thrm_seg->pt);
    if (MAGSQ(v) > 100.0) {
	double dist;
	dist = MAGNITUDE(v);
	/* Distance between particle origin and centroid of thermal
	 * segment nodes is > 10.0mm (1cm).  This suggests that
	 * they aren't related.
	 */
	bu_log(
	    "----------------------------- W A R N I N G -----------------------------\n\
%s:%d distance %g between origin of particle and thermal node centroid is\n\
too large.  Probable mis-match between geometry and thermal data\n",
	    __FILE__, __LINE__, dist);
	bu_bomb("");
    }
Exemple #25
0
/**
 * Find the square of the distance from a point P to a line segment described
 * by the two endpoints A and B.
 *
 *			P
 *		       *
 *		      /.
 *		     / .
 *		    /  .
 *		   /   . (dist)
 *		  /    .
 *		 /     .
 *		*------*--------*
 *		A      PCA	B
 *
 * There are six distinct cases, with these return codes -
 *	0	P is within tolerance of lseg AB.  *dist =  0.
 *	1	P is within tolerance of point A.  *dist = 0.
 *	2	P is within tolerance of point B.  *dist = 0.
 *	3	PCA is within tolerance of A. *dist = |P-A|**2.
 *	4	PCA is within tolerance of B. *dist = |P-B|**2.
 *	5	P is "above/below" lseg AB.  *dist=|PCA-P|**2.
 *
 * This routine was formerly called bn_dist_pt_lseg().
 * This is a special version that returns the square of the distance
 * and does not actually calculate PCA.
 *
 */
int
bn_distsq_pt3_lseg3(fastf_t *dist, const fastf_t *a, const fastf_t *b, const fastf_t *p, const struct bn_tol *tol)
{
    vect_t PtoA;		/* P-A */
    vect_t PtoB;		/* P-B */
    vect_t AtoB;		/* B-A */
    fastf_t P_A_sq;		/* |P-A|**2 */
    fastf_t P_B_sq;		/* |P-B|**2 */
    fastf_t B_A_sq;		/* |B-A|**2 */
    fastf_t t;		/* distance squared along ray of projection of P */
    fastf_t dot;

    BN_CK_TOL(tol);

    /* Check proximity to endpoint A */
    VSUB2(PtoA, p, a);
    P_A_sq = MAGSQ(PtoA);
    if (P_A_sq < tol->dist_sq) {
	/* P is within the tol->dist radius circle around A */
	*dist = 0.0;
	return 1;
    }

    /* Check proximity to endpoint B */
    VSUB2(PtoB, p, b);
    P_B_sq = MAGSQ(PtoB);
    if (P_B_sq < tol->dist_sq) {
	/* P is within the tol->dist radius circle around B */
	*dist = 0.0;
	return 2;
    }

    VSUB2(AtoB, b, a);
    B_A_sq = MAGSQ(AtoB);

    /* compute distance squared (in actual units) along line to PROJECTION of
     * point p onto the line: point pca
     */
    dot = VDOT(PtoA, AtoB);
    t = dot * dot / B_A_sq;

    if (t < tol->dist_sq) {
	/* PCA is at A */
	*dist = P_A_sq;
	return 3;
    }

    if (dot < -SMALL_FASTF && t > tol->dist_sq) {
	/* P is "left" of A */
	*dist = P_A_sq;
	return 3;
    }
    if (t < (B_A_sq - tol->dist_sq)) {
	/* PCA falls between A and B */
	register fastf_t dsq;

	/* Find distance from PCA to line segment (Pythagorus) */
	dsq = P_A_sq - t;
	if (dsq < tol->dist_sq) {
	    /* PCA is on lseg */
	    *dist = 0.0;
	    return 0;
	}

	/* P is above or below lseg */
	*dist = dsq;
	return 5;
    }

    /* P is "right" of B */
    *dist = P_B_sq;
    return 4;
}
Exemple #26
0
/**
 * Brute force through all possible plane intersections.
 * Generate all edge lines, then intersect the line with all
 * the other faces to find the vertices on that line.
 * If the geometry is correct, there will be no more than two.
 * While not the fastest strategy, this will produce an accurate
 * plot without requiring extra bookkeeping.
 * Note that the vectors will be drawn in no special order.
 */
int
rt_arbn_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol, const struct rt_view_info *UNUSED(info))
{
    struct rt_arbn_internal *aip;
    size_t i;
    size_t j;
    size_t k;

    BU_CK_LIST_HEAD(vhead);
    RT_CK_DB_INTERNAL(ip);
    aip = (struct rt_arbn_internal *)ip->idb_ptr;
    RT_ARBN_CK_MAGIC(aip);

    for (i = 0; i < aip->neqn - 1; i++) {
	for (j = i + 1; j < aip->neqn; j++) {
	    double dot;
	    int point_count;	/* # points on this line */
	    point_t a, b;		/* start and end points */
	    vect_t dist;

	    VSETALL(a, 0);
	    VSETALL(b, 0);

	    /* If normals are parallel, no intersection */
	    dot = VDOT(aip->eqn[i], aip->eqn[j]);
	    if (BN_VECT_ARE_PARALLEL(dot, tol)) continue;

	    /* Have an edge line, isect with all other planes */
	    point_count = 0;
	    for (k = 0; k < aip->neqn; k++) {
		size_t m;
		point_t pt;
		size_t next_k;

		next_k = 0;

		if (k == i || k == j) continue;
		if (bn_mkpoint_3planes(pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]) < 0) continue;

		/* See if point is outside arb */
		for (m = 0; m < aip->neqn; m++) {
		    if (i == m || j == m || k == m) continue;
		    if (VDOT(pt, aip->eqn[m])-aip->eqn[m][3] > tol->dist) {
			next_k = 1;
			break;
		    }
		}

		if (next_k != 0) continue;

		if (point_count <= 0) {
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_MOVE);
		    VMOVE(a, pt);
		} else if (point_count == 1) {
		    VSUB2(dist, pt, a);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);
		    VMOVE(b, pt);
		} else {
		    VSUB2(dist, pt, a);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    VSUB2(dist, pt, b);
		    if (MAGSQ(dist) < tol->dist_sq) continue;
		    bu_log("rt_arbn_plot() error, point_count=%d (>2) on edge %zu/%zu, non-convex\n",
			   point_count+1,
			   i, j);
		    VPRINT(" a", a);
		    VPRINT(" b", b);
		    VPRINT("pt", pt);
		    RT_ADD_VLIST(vhead, pt, BN_VLIST_LINE_DRAW);	/* draw it */
		}
		point_count++;
	    }
	    /* Point counts of 1 are (generally) not harmful,
	     * occurring on pyramid peaks and the like.
	     */
	}
    }
    return 0;
}