/** * For a hit on the surface of an METABALL, return the (u, v) * coordinates of the hit point, 0 <= u, v <= 1. * * u = azimuth * v = elevation */ void rt_metaball_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct rt_metaball_internal *metaball = (struct rt_metaball_internal *)stp->st_specific; vect_t work, pprime; fastf_t r; if (ap) RT_CK_APPLICATION(ap); if (stp) RT_CK_SOLTAB(stp); if (hitp) RT_CK_HIT(hitp); if (!uvp) return; if (!metaball) return; /* stuff stolen from sph */ VSUB2(work, hitp->hit_point, stp->st_center); VSCALE(pprime, work, 1.0/MAGNITUDE(work)); /* Assert that pprime has unit length */ /* U is azimuth, atan() range: -pi to +pi */ uvp->uv_u = bn_atan2(pprime[Y], pprime[X]) * M_1_2PI; if (uvp->uv_u < 0) uvp->uv_u += 1.0; /* * V is elevation, atan() range: -pi/2 to +pi/2, because sqrt() * ensures that X parameter is always >0 */ uvp->uv_v = bn_atan2(pprime[Z], sqrt(pprime[X] * pprime[X] + pprime[Y] * pprime[Y])) * M_1_2PI; /* approximation: r / (circumference, 2 * pi * aradius) */ r = ap->a_rbeam + ap->a_diverge * hitp->hit_dist; uvp->uv_du = uvp->uv_dv = M_1_2PI * r / stp->st_aradius; return; }
int rt_obj_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead) { int id; const struct rt_functab *ft; if (!stp || !rp) return -1; RT_CK_SOLTAB(stp); RT_CK_RAY(rp); if (ap) RT_CK_APPLICATION(ap); id = stp->st_id; if (id < 0) return -2; ft = &OBJ[id]; if (!ft) return -3; if (!ft->ft_shot) return -4; return ft->ft_shot(stp, rp, ap, seghead); }
HIDDEN int raydiff_miss(struct application *ap) { RT_CK_APPLICATION(ap); return 0; }
int rt_obj_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { int id; const struct rt_functab *ft; if (!stp || !hitp || !uvp) return -1; RT_CK_SOLTAB(stp); RT_CK_HIT(hitp); if (ap) RT_CK_APPLICATION(ap); id = stp->st_id; if (id < 0) return -2; ft = &rt_functab[id]; if (!ft) return -3; if (!ft->ft_uv) return -4; ft->ft_uv(ap, stp, hitp, uvp); return 0; }
/** * Intersect a ray with a xxx. If an intersection occurs, a struct * seg will be acquired and filled in. * * Returns - * 0 MISS * >0 HIT */ int rt_xxx_shot(struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead) { struct xxx_specific *xxx; if (!stp) return -1; RT_CK_SOLTAB(stp); xxx = (struct xxx_specific *)stp->st_specific; if (!xxx) return -1; if (rp) RT_CK_RAY(rp); if (ap) RT_CK_APPLICATION(ap); if (!seghead) return -1; /* the EXAMPLE_NEW_SEGMENT block shows how one might add a new result * if the ray did hit the primitive. the segment values would need to * be adjusted accordingly to match real values instead of -1. */ #ifdef EXAMPLE_NEW_SEGMENT /* allocate a segment */ RT_GET_SEG(segp, ap->a_resource); segp->seg_stp = stp; /* stash a pointer to the primitive */ segp->seg_in.hit_dist = -1; /* XXX set to real distance to entry point */ segp->seg_out.hit_dist = -1; /* XXX set to real distance to exit point */ segp->seg_in.hit_surfno = -1; /* XXX set to a non-negative ID for entry surface */ segp->seg_out.hit_surfno = -1; /* XXX set to a non-negative ID for exit surface */ /* add segment to list of those encountered for this primitive */ BU_LIST_INSERT(&(seghead->l), &(segp->l)); return 2; /* num surface intersections == in + out == 2 */ #endif return 0; /* MISS */ }
/* don't care about misses */ HIDDEN int ignore_miss(struct application *app) { RT_CK_APPLICATION(app); //bu_log("miss!\n"); return 0; }
/* add all hit point info to info list */ HIDDEN int add_hit_pnts(struct application *app, struct partition *partH, struct seg *UNUSED(segs)) { struct partition *pp; struct soltab *stp; /*point_t hit_pnt; vect_t hit_normal;*/ struct rt_point_container *c = (struct rt_point_container *)(app->a_uptr); struct npoints *npt; if (c->pnt_cnt > c->capacity-1) { c->capacity *= 4; c->pts = (struct npoints *)bu_realloc((char *)c->pts, c->capacity * sizeof(struct npoints), "enlarge results array"); } RT_CK_APPLICATION(app); /*struct bu_vls *fp = (struct bu_vls *)(app->a_uptr);*/ /* add all hit points */ for (pp = partH->pt_forw; pp != partH; pp = pp->pt_forw) { npt = &(c->pts[c->pnt_cnt]); /* add "in" hit point info */ stp = pp->pt_inseg->seg_stp; /* hack fix for bad tgc surfaces */ if (bu_strncmp("rec", stp->st_meth->ft_label, 3) == 0 || bu_strncmp("tgc", stp->st_meth->ft_label, 3) == 0) { /* correct invalid surface number */ if (pp->pt_inhit->hit_surfno < 1 || pp->pt_inhit->hit_surfno > 3) { pp->pt_inhit->hit_surfno = 2; } if (pp->pt_outhit->hit_surfno < 1 || pp->pt_outhit->hit_surfno > 3) { pp->pt_outhit->hit_surfno = 2; } } VJOIN1(npt->in.p, app->a_ray.r_pt, pp->pt_inhit->hit_dist, app->a_ray.r_dir); RT_HIT_NORMAL(npt->in.n, pp->pt_inhit, stp, &(app->a_ray), pp->pt_inflip); npt->in.is_set = 1; //bu_vls_printf(fp, "%f %f %f %f %f %f\n", hit_pnt[0], hit_pnt[1], hit_pnt[2], hit_normal[0], hit_normal[1], hit_normal[2]); /* add "out" hit point info (unless half-space) */ stp = pp->pt_inseg->seg_stp; if (bu_strncmp("half", stp->st_meth->ft_label, 4) != 0) { VJOIN1(npt->out.p, app->a_ray.r_pt, pp->pt_outhit->hit_dist, app->a_ray.r_dir); RT_HIT_NORMAL(npt->out.n, pp->pt_outhit, stp, &(app->a_ray), pp->pt_outflip); npt->out.is_set = 1; //bu_vls_printf(fp, "%f %f %f %f %f %f\n", hit_pnt[0], hit_pnt[1], hit_pnt[2], hit_normal[0], hit_normal[1], hit_normal[2]); } c->pnt_cnt++; } return 1; }
/** * For a hit on the surface of an SUPERELL, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * u = azimuth * v = elevation */ void rt_superell_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { if (ap) RT_CK_APPLICATION(ap); if (!stp || !hitp || !uvp) return; RT_CK_SOLTAB(stp); RT_CK_HIT(hitp); bu_log("called rt_superell_uv()\n"); return; }
/** * R T _ P G _ U V */ void rt_pg_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { if (ap) RT_CK_APPLICATION(ap); if (stp) RT_CK_SOLTAB(stp); if (hitp) RT_CK_HIT(hitp); if (!uvp) return; /* Do nothing. Really, should do what ARB does. */ uvp->uv_u = uvp->uv_v = 0; uvp->uv_du = uvp->uv_dv = 0; }
/** * For a hit on the surface of an xxx, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * u = azimuth, v = elevation */ void rt_xxx_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct xxx_specific *xxx; if (ap) RT_CK_APPLICATION(ap); if (!stp || !uvp) return; RT_CK_SOLTAB(stp); if (hitp) RT_CK_HIT(hitp); xxx = (struct xxx_specific *)stp->st_specific; if (!xxx) return; }
/** * For a hit on a face of an ARB, return the (u, v) coordinates * of the hit point. 0 <= u, v <= 1. * u extends along the arb_U direction defined by B-A, * v extends along the arb_V direction defined by Nx(B-A). */ void rt_arbn_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct rt_arbn_internal *arbn = (struct rt_arbn_internal *)stp->st_specific; if (ap) RT_CK_APPLICATION(ap); RT_ARBN_CK_MAGIC(arbn); if (hitp) RT_CK_HIT(hitp); if (uvp) { uvp->uv_u = uvp->uv_v = 0; uvp->uv_du = uvp->uv_dv = 0; } }
/** * For a hit on the surface of an hyp, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * * u = azimuth * v = elevation */ void rt_hyp_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct hyp_specific *hyp = (struct hyp_specific *)stp->st_specific; if (ap) RT_CK_APPLICATION(ap); /* u = (angle from semi-major axis on basic hyperboloid) / (2*pi) */ uvp->uv_u = M_1_2PI * (atan2(-hitp->hit_vpriv[X] * hyp->hyp_r2, hitp->hit_vpriv[Y] * hyp->hyp_r1) + M_PI); /* v ranges (0, 1) on each plate */ switch (hitp->hit_surfno) { case HYP_NORM_BODY: /* v = (z + Hmag) / (2*Hmag) */ uvp->uv_v = (hitp->hit_vpriv[Z] + hyp->hyp_Hmag) / (2.0 * hyp->hyp_Hmag); break; case HYP_NORM_TOP: uvp->uv_v = 1.0 - sqrt( ((hitp->hit_vpriv[X]*hitp->hit_vpriv[X])*hyp->hyp_rx + (hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y])*hyp->hyp_ry) / (1 + (hitp->hit_vpriv[Z]*hitp->hit_vpriv[Z])*hyp->hyp_rz)); break; case HYP_NORM_BOTTOM: uvp->uv_v = sqrt( ((hitp->hit_vpriv[X]*hitp->hit_vpriv[X])*hyp->hyp_rx + (hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y])*hyp->hyp_ry) / (1 + (hitp->hit_vpriv[Z]*hitp->hit_vpriv[Z])*hyp->hyp_rz)); break; } /* sanity checks */ if (uvp->uv_u < 0.0) uvp->uv_u = 0.0; else if (uvp->uv_u > 1.0) uvp->uv_u = 1.0; if (uvp->uv_v < 0.0) uvp->uv_v = 0.0; else if (uvp->uv_v > 1.0) uvp->uv_v = 1.0; /* copied from g_ehy.c */ uvp->uv_du = uvp->uv_dv = 0; }
/** * For a hit on the surface of an revolve, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * u = azimuth, v = elevation */ void rt_revolve_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct revolve_specific *rev = (struct revolve_specific *)stp->st_specific; point_t hitpoint; fastf_t angle; uint32_t *lng; struct line_seg *lsg; /* struct carc_seg *csg; struct nurb_seg *nsg; struct bezier_seg *bsg; */ if (ap) RT_CK_APPLICATION(ap); VJOIN1(hitpoint, hitp->hit_rayp->r_pt, hitp->hit_dist, hitp->hit_rayp->r_dir); switch (hitp->hit_surfno) { case START_FACE_POS: case START_FACE_NEG: case END_FACE_POS: case END_FACE_NEG: uvp->uv_u = fabs((hitp->hit_vpriv[X] - rev->bounds[0]) / (rev->bounds[1] - rev->bounds[0])); uvp->uv_v = fabs((hitp->hit_vpriv[Y] - rev->bounds[2]) / (rev->bounds[3] - rev->bounds[2])); break; case HORIZ_SURF: hitpoint[Z] = 0; /* Y is the angle: [0, 2pi] */ uvp->uv_u = hitp->hit_vpriv[Y] / rev->ang; /* X is the coord of the endpoint that we're connecting to the revolve axis */ uvp->uv_v = fabs((MAGNITUDE(hitpoint) - hitp->hit_vpriv[Z]) / (hitp->hit_vpriv[X]- hitp->hit_vpriv[Z])); /* bu_log("\tmin: %3.2f\tmax: %3.2f\n", hitp->hit_vpriv[Z], hitp->hit_vpriv[X]); */ break; default: angle = atan2(hitp->hit_vpriv[Y], hitp->hit_vpriv[X]); if (angle < 0) angle += M_2PI; uvp->uv_u = angle / rev->ang; lng = (uint32_t *)rev->skt->curve.segment[hitp->hit_surfno]; switch (*lng) { case CURVE_LSEG_MAGIC: lsg = (struct line_seg *)lng; if (ZERO(1.0/hitp->hit_vpriv[Z])) { /* use hitpoint radius and sketch's X values */ hitpoint[Z] = 0; uvp->uv_v = (MAGNITUDE(hitpoint) - rev->skt->verts[lsg->end][X]) / (rev->skt->verts[lsg->start][X] - rev->skt->verts[lsg->end][X]); } else { /* use hitpoint Z and sketch's Y values */ uvp->uv_v = (hitpoint[Z] - rev->skt->verts[lsg->end][Y]) / (rev->skt->verts[lsg->start][Y] - rev->skt->verts[lsg->end][Y]); } break; case CURVE_CARC_MAGIC: /* csg = (struct carc_seg *)lng; */ break; case CURVE_BEZIER_MAGIC: /* bsg = (struct bezier_seg *)lng; */ break; case CURVE_NURB_MAGIC: /* nsg = (struct nurb_seg *)lng; */ break; default: bu_log("rt_revolve_prep: ERROR: unrecognized segment type!\n"); break; } break; } if (uvp->uv_v > 1 || uvp->uv_v < 0 || uvp->uv_u > 1 || uvp->uv_u < 0) { bu_log("UV error:\t%d\t%2.2f\t%2.2f\t", hitp->hit_surfno, uvp->uv_u, uvp->uv_v); bu_log("\tX: (%3.2f, %3.2f)\tY: (%3.2f, %3.2f)\n", rev->bounds[0], rev->bounds[1], rev->bounds[2], rev->bounds[3]); } /* sanity checks */ if (uvp->uv_u < 0.0) uvp->uv_u = 0.0; else if (uvp->uv_u > 1.0) uvp->uv_u = 1.0; if (uvp->uv_v < 0.0) uvp->uv_v = 0.0; else if (uvp->uv_v > 1.0) uvp->uv_v = 1.0; }
/** * R E C _ U V * * For a hit on the surface of an REC, return the (u, v) coordinates * of the hit point, 0 <= u, v <= 1. * * u is the rotation around the cylinder, and * v is the displacement along H. */ void rt_rec_uv(struct application *ap, struct soltab *stp, struct hit *hitp, struct uvcoord *uvp) { struct rec_specific *rec = (struct rec_specific *)stp->st_specific; vect_t work; vect_t pprime; fastf_t len; fastf_t ratio; if (ap) RT_CK_APPLICATION(ap); /* hit_point is on surface; project back to unit cylinder, * creating a vector from vertex to hit point. */ VSUB2(work, hitp->hit_point, rec->rec_V); MAT4X3VEC(pprime, rec->rec_SoR, work); switch (hitp->hit_surfno) { case REC_NORM_BODY: /* Skin. x, y coordinates define rotation. radius = 1 */ ratio = pprime[Y]; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = pprime[Z]; /* height */ break; case REC_NORM_TOP: /* top plate */ len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]); ratio = pprime[Y]/len; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = len; /* rim v = 1 */ break; case REC_NORM_BOT: /* bottom plate */ len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]); ratio = pprime[Y]/len; if (ratio > 1.0) ratio = 1.0; if (ratio < -1.0) ratio = -1.0; uvp->uv_u = acos(ratio) * bn_inv2pi; uvp->uv_v = 1 - len; /* rim v = 0 */ break; } /* Handle other half of acos() domain */ if (pprime[X] < 0) uvp->uv_u = 1.0 - uvp->uv_u; if (uvp->uv_u < 0) uvp->uv_u = 0; else if (uvp->uv_u > 1) uvp->uv_u = 1; if (uvp->uv_v < 0) uvp->uv_v = 0; else if (uvp->uv_v > 1) uvp->uv_v = 1; /* XXX uv_du should be relative to rotation, uv_dv relative to height */ uvp->uv_du = uvp->uv_dv = 0; }
/** * R E C _ V S H O T * * This is the Becker vector version */ void rt_rec_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap) /* An array of solid pointers */ /* An array of ray pointers */ /* array of segs (results returned) */ /* Number of ray/object pairs */ { int i; struct rec_specific *rec; vect_t dprime; /* D' */ vect_t pprime; /* P' */ fastf_t k1, k2; /* distance constants of solution */ vect_t xlated; /* translated vector */ struct hit hits[3]; /* 4 potential hit points */ struct hit *hitp; /* pointer to hit point */ fastf_t b; /* coeff of polynomial */ fastf_t root; /* root of radical */ fastf_t dx2dy2; if (ap) RT_CK_APPLICATION(ap); /* for each ray/right_elliptical_cylinder pair */ for (i = 0; i < n; i++) { if (stp[i] == 0) continue; /* stp[i] == 0 signals skip ray */ rec = (struct rec_specific *)stp[i]->st_specific; hitp = &hits[0]; /* out, Mat, vect */ MAT4X3VEC(dprime, rec->rec_SoR, rp[i]->r_dir); VSUB2(xlated, rp[i]->r_pt, rec->rec_V); MAT4X3VEC(pprime, rec->rec_SoR, xlated); if (ZERO(dprime[X]) && ZERO(dprime[Y])) goto check_plates; /* Find roots of eqn, using formula for quadratic w/ a=1 */ b = 2 * (dprime[X]*pprime[X] + dprime[Y]*pprime[Y]) * (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y])); if ((root = b*b - 4 * dx2dy2 * (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0) goto check_plates; root = sqrt(root); k1 = (root-b) * 0.5; k2 = (root+b) * (-0.5); /* * k1 and k2 are potential solutions to intersection with side. * See if they fall in range. */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime); /* hit' */ if (hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0) { hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_BODY; /* compute N */ hitp++; } /* * Check for hitting the end plates. */ check_plates: if (hitp < &hits[2] && !ZERO(dprime[Z])) { /* 0 or 1 hits so far, this is worthwhile */ k1 = -pprime[Z] / dprime[Z]; /* bottom plate */ k2 = (1.0 - pprime[Z]) / dprime[Z]; /* top plate */ VJOIN1(hitp->hit_vpriv, pprime, k1, dprime);/* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_dist = k1; hitp->hit_surfno = REC_NORM_BOT; /* -H */ hitp++; } VJOIN1(hitp->hit_vpriv, pprime, k2, dprime);/* hit' */ if (hitp->hit_vpriv[X] * hitp->hit_vpriv[X] + hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0) { hitp->hit_dist = k2; hitp->hit_surfno = REC_NORM_TOP; /* +H */ hitp++; } } if (hitp != &hits[2]) { RT_REC_SEG_MISS(segp[i]); /* MISS */ } else { segp[i].seg_stp = stp[i]; if (hits[0].hit_dist < hits[1].hit_dist) { /* entry is [0], exit is [1] */ VMOVE(segp[i].seg_in.hit_vpriv, hits[0].hit_vpriv); segp[i].seg_in.hit_dist = hits[0].hit_dist; segp[i].seg_in.hit_surfno = hits[0].hit_surfno; VMOVE(segp[i].seg_out.hit_vpriv, hits[1].hit_vpriv); segp[i].seg_out.hit_dist = hits[1].hit_dist; segp[i].seg_out.hit_surfno = hits[1].hit_surfno; } else { /* entry is [1], exit is [0] */ VMOVE(segp[i].seg_in.hit_vpriv, hits[1].hit_vpriv); segp[i].seg_in.hit_dist = hits[1].hit_dist; segp[i].seg_in.hit_surfno = hits[1].hit_surfno; VMOVE(segp[i].seg_out.hit_vpriv, hits[0].hit_vpriv); segp[i].seg_out.hit_dist = hits[0].hit_dist; segp[i].seg_out.hit_surfno = hits[0].hit_surfno; } } } }