Index: src/rt/rtshot.c
===================================================================
--- src/rt/rtshot.c	(revision 63934)
+++ src/rt/rtshot.c	(working copy)
@@ -64,9 +64,12 @@
     bu_log(" -o #		Set onehit flag\n");
     bu_log(" -r #		Set ray length\n");
     bu_log(" -n #		Set number of rings for ray bundle\n");
-    bu_log(" -c #		Set number of rays per ring for ray bundle\n");
+    bu_log(" -c #		Set number of rays per <ring/radius/length> depending on bundle type\n");
     bu_log(" -R #		Set radius for ray bundle in mm\n");
     bu_log(" -g #		Set ray bundle grid size in mm(default 1mm)\n");
+    bu_log(" -A #		Set angle for conic/frustum ray bundle\n");
+    bu_log(" -B bundle_type	Set bundle type (one of conic/frustum/rect)\n");
+    bu_log(" -l # #		Set length for rect bundle type\n");
     bu_log(" -v \"attribute_name1 attribute_name2 ...\" Show attribute values\n");
 }
 
@@ -82,9 +85,10 @@
 vect_t at_vect;
 int overlap_claimant_handling = 0;
 fastf_t grid_size = -1.0; /* gridsize in mm */
-int rays_per_ring = 0;
+int rays_per = 0;
 int num_rings = 0;
 fastf_t bundle_radius = 0.0;
+fastf_t rect_length;
 
 extern int hit(struct application *ap, struct partition *PartHeadp, struct seg *segp);
 extern int miss(register struct application *ap);
@@ -105,6 +109,8 @@
     const char *argv0 = argv[0];
     int atoival;
     struct resource res = RT_RESOURCE_INIT_ZERO;
+    int bundle_type = 0;
+    fastf_t theta = 0.0;
 
     if (argc < 3) {
 	usage(argv0);
@@ -145,7 +151,7 @@
 	    case 'c':
 		atoival = atoi(argv[1]);
 		if (atoival > 0 && atoival < INT_MAX-1)
-		    rays_per_ring = atoival;
+		    rays_per = atoival;
 		else
 		    return 1;
 
@@ -294,6 +300,36 @@
 		}
 		continue;
 
+	    case 'A':
+		{
+		    theta = atof(argv[1]);
+		    argc -= 2;
+		    argv += 2;
+		}
+		continue;
+
+	    case 'B':
+		{
+		    if (BU_STR_EQUAL(argv[1], "conic")) {
+			bundle_type = 1;
+		    } else if (BU_STR_EQUAL(argv[1], "frustum")) {
+			bundle_type = 2;
+		    } else if (BU_STR_EQUAL(argv[1], "rect")) {
+			bundle_type = 3;
+		    }
+		    argc -= 2;
+		    argv += 2;
+		}
+		continue;
+
+	    case 'l':
+		{
+		    rect_length = atof(argv[1]);
+		    argc -= 2;
+		    argv += 2;
+		}
+		continue;
+
 	    default:
 	    err:
 		usage(argv0);
@@ -315,10 +351,10 @@
 	num_rings = 0;
     else if (num_rings > INT_MAX)
 	num_rings = INT_MAX;
-    if (rays_per_ring < 0)
-	rays_per_ring = 0;
-    else if (rays_per_ring > INT_MAX)
-	rays_per_ring = INT_MAX;
+    if (rays_per < 0)
+	rays_per = 0;
+    else if (rays_per > INT_MAX)
+	rays_per = INT_MAX;
     if (bundle_radius < 0.0)
 	bundle_radius = 0.0;
     else if (bundle_radius > INFINITY-1.0)
@@ -375,7 +411,7 @@
     }
     VUNITIZE(ap.a_ray.r_dir);
 
-    if (rays_per_ring) {
+    if (rays_per) {
 	bu_log("Central Ray:\n");
     }
     VPRINT("Pnt", ap.a_ray.r_pt);
@@ -396,24 +432,8 @@
     ap.a_hit = hit;
     ap.a_miss = miss;
 
-    if (rays_per_ring) {
+    if (rays_per || bundle_radius > 0.0 || bundle_type) {
 	vect_t avec, bvec;
-	struct xray *rp;
-
-	/* create orthogonal rays for basis of bundle */
-	bn_vec_ortho(avec, ap.a_ray.r_dir);
-	VCROSS(bvec, ap.a_ray.r_dir, avec);
-	VUNITIZE(bvec);
-
-	rp = (struct xray *)bu_calloc(sizeof(struct xray),
-				      (rays_per_ring * num_rings) + 1,
-				      "ray bundle");
-	rp[0] = ap.a_ray;	/* struct copy */
-	rp[0].magic = RT_RAY_MAGIC;
-	rt_raybundle_maker(rp, bundle_radius, avec, bvec, rays_per_ring, num_rings);
-	(void)rt_shootray_bundle(&ap, rp, (rays_per_ring * num_rings) + 1);
-    } else if (bundle_radius > 0.0) {
-	vect_t avec, bvec;
 	struct xray center_ray;
 	struct application_bundle b;
 	struct xrays *xr;
@@ -420,8 +440,8 @@
 
 	b.b_ap = ap;
 
-	/* to use default bundling routines set b.b_ap.a_hit
-	 * and b.b_ap.a_miss to NULL */
+	/* to use default bundling routines set b.b_ap.a_hit and
+	 * b.b_ap.a_miss to NULL */
 	b.b_ap.a_hit = NULL;
 	b.b_ap.a_miss = NULL;
 
@@ -429,19 +449,47 @@
 	b.b_hit = bundle_hit;
 	b.b_miss = bundle_miss;
 
-	if (grid_size <= 0.0)
-	    grid_size = 1.0;
-
 	/* create orthogonal rays for basis of bundle */
 	bn_vec_ortho(avec, ap.a_ray.r_dir);
 	VCROSS(bvec, ap.a_ray.r_dir, avec);
 	VUNITIZE(bvec);
 
-	center_ray = ap.a_ray;	/* struct copy */
-	(void)rt_gen_circular_grid(&b.b_rays, &center_ray, bundle_radius, avec, grid_size);
+	center_ray = ap.a_ray;
 
-	(void) rt_shootrays(&b);
+	if (bundle_type) {
+	    if (theta <= 0.0) {
+		theta = 45.0;
+	    }
+	    switch (bundle_type) {
+		case 1:
+		    (void)rt_gen_conic(&b.b_rays, &center_ray, theta, avec, rays_per);
+		    break;
+		case 2:
+		    (void)rt_gen_frustum(&b.b_rays, &center_ray, avec, bvec, theta, theta, rays_per, rays_per);
+		    break;
+		case 3:
+		    if (grid_size <= 0.0) {
+			grid_size = 1.0;
+		    }
+		    if (rect_length <= 0.0) {
+			rect_length = 1.0;
+		    }
+		    VSCALE(avec, avec, rect_length);
+		    VSCALE(bvec, bvec, rect_length);
+		    (void)rt_gen_rect(&b.b_rays, &center_ray, avec, bvec, grid_size, grid_size);
+		    break;
+	    }
+	} else if (rays_per) {
+	    (void)rt_raybundle_maker(&b.b_rays, &center_ray, bundle_radius, avec, bvec, rays_per, num_rings);
+	} else if (bundle_radius > 0.0) {
+	    if (grid_size <= 0.0) {
+		grid_size = 1.0;
+	    }
+	    (void)rt_gen_circular_grid(&b.b_rays, &center_ray, bundle_radius, avec, grid_size);
+	}
 
+	(void)rt_shootrays(&b);
+
 	while (BU_LIST_WHILE(xr, xrays, &(b.b_rays.l))) {
 	    BU_LIST_DEQUEUE(&(xr->l));
 	    bu_free(xr, "bundled ray");
Index: src/librt/mkbundle.c
===================================================================
--- src/librt/mkbundle.c	(revision 63934)
+++ src/librt/mkbundle.c	(working copy)
@@ -51,9 +51,9 @@
  */
 
 int
-rt_raybundle_maker(struct xray *rp, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring)
+rt_raybundle_maker(struct xrays *rays, const struct xray *center_ray, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring)
 {
-    register struct xray *rayp = rp+1;
+    register struct xrays *xrayp;
     int ring;
     double fraction = 1.0;
     double theta;
@@ -61,8 +61,12 @@
     double radial_scale;
     int count = 0;
 
-    rp[0].index = count++;
-    rp[0].magic =RT_RAY_MAGIC;
+    BU_ALLOC(xrayp, struct xrays);
+    VMOVE(xrayp->ray.r_pt, center_ray->r_pt);
+    VMOVE(xrayp->ray.r_dir, center_ray->r_dir);
+    xrayp->ray.index = count++;
+    xrayp->ray.magic = RT_RAY_MAGIC;
+    BU_LIST_APPEND(&rays->l, &xrayp->l);
 
     for (ring=0; ring < nring; ring++) {
 	register int i;
@@ -77,12 +81,13 @@
 	    /* pt = V + cos(theta) * A + sin(theta) * B */
 	    ct = cos(theta) * radial_scale;
 	    st = sin(theta) * radial_scale;
-	    VJOIN2(rayp->r_pt, rp[0].r_pt, ct, avec, st, bvec);
-	    VMOVE(rayp->r_dir, rp[0].r_dir);
-	    rayp->index = count++;
-	    rayp->magic = RT_RAY_MAGIC;
+	    BU_ALLOC(xrayp, struct xrays);
+	    VJOIN2(xrayp->ray.r_pt, center_ray->r_pt, ct, avec, st, bvec);
+	    VMOVE(xrayp->ray.r_dir, center_ray->r_dir);
+	    xrayp->ray.index = count++;
+	    xrayp->ray.magic = RT_RAY_MAGIC;
+	    BU_LIST_APPEND(&rays->l, &xrayp->l);
 	    theta += delta;
-	    rayp++;
 	}
     }
     return count;
@@ -190,13 +195,12 @@
     VCROSS(a_dir, orig_dir, up_vector);
     VUNITIZE(a_dir);
 
-    for (y = -radius; y <= radius; y += gridsize) {
-	vect_t tmp;
-	printf("y:%f\n", y);
-	VSCALE(tmp, b_dir, y);
-	printf("y_partofit: %f,%f,%f\n", V3ARGS(tmp));
-	for (x = -radius; x <= radius; x += gridsize) {
-	    if (((x*x)/rsq + (y*y)/rsq) <= 1) {
+    /* This adds BN_TOL_DIST to various conditions because in some
+     * cases, floating-point problems can make extremely close numbers
+     * compare incorrectly. */
+    for (y = -radius; y <= radius + BN_TOL_DIST; y += gridsize) {
+	for (x = -radius; x <= radius + BN_TOL_DIST; x += gridsize) {
+	    if (((x*x)/rsq + (y*y)/rsq) <= 1 + BN_TOL_DIST) {
 		BU_ALLOC(xrayp, struct xrays);
 		VMOVE(xrayp->ray.r_pt, start);
 		VJOIN2(xrayp->ray.r_dir, orig_dir, x, a_dir, y, b_dir);
@@ -217,7 +221,7 @@
 rt_gen_frustum(struct xrays *rays, const struct xray *center_ray,
 	       const vect_t a_vec, const vect_t b_vec,
 	       const fastf_t a_theta, const fastf_t b_theta,
-	       const fastf_t a_num, const fastf_t UNUSED(b_num))
+	       const fastf_t a_num, const fastf_t b_num)
 {
     int count;
 
@@ -229,6 +233,7 @@
     fastf_t a_length = tan(a_theta);
     fastf_t b_length = tan(b_theta);
     fastf_t a_inc = 2 * a_length / (a_num - 1);
+    fastf_t b_inc = 2 * b_length / (b_num - 1);
 
     vect_t a_dir, b_dir;
 
@@ -245,7 +250,7 @@
     /* This adds BN_TOL_DIST to the *_length variables in the
      * condition because in some cases, floating-point problems can
      * make extremely close numbers compare incorrectly. */
-    for (y = -b_length; y <= b_length + BN_TOL_DIST;) {
+    for (y = -b_length; y <= b_length + BN_TOL_DIST; y += b_inc) {
 	for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) {
 	    BU_ALLOC(xrayp, struct xrays);
 	    VMOVE(xrayp->ray.r_pt, start);
Index: include/raytrace.h
===================================================================
--- include/raytrace.h	(revision 63934)
+++ include/raytrace.h	(working copy)
@@ -2734,7 +2734,7 @@
  * PRIVATE: this is new API and should be considered private for the
  * time being.
  */
-RT_EXPORT extern int rt_raybundle_maker(struct xray *rp, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring);
+RT_EXPORT extern int rt_raybundle_maker(struct xrays *rays, const struct xray *center_ray, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring);
 
 /* Shoot a ray, returning the partition list */
 /**
