* @see ca.eandb.jmist.framework.geometry.PrimitiveGeometry#intersect(ca.eandb.jmist.math.Ray3, ca.eandb.jmist.framework.IntersectionRecorder)
*/
public void intersect(Ray3 ray, IntersectionRecorder recorder) {
Interval I = recorder.interval();
Point3 p;
double t;
// first check for intersection of ray with the caps on the ends of the cylinder
// check bottom cap
t = (this.base.y() - ray.origin().y()) / ray.direction().y();
if (I.contains(t))
{
p = ray.pointAt(t);
if (this.base.squaredDistanceTo(p) < this.radius * this.radius)
{
Intersection x = super.newIntersection(ray, t, (ray.direction().y() > 0.0), CYLINDER_SURFACE_BASE)
.setLocation(p);
recorder.record(x);
}
}
// check top cap
t = (this.base.y() + this.height - ray.origin().y()) / ray.direction().y();
if (I.contains(t))
{
p = ray.pointAt(t);
double r = (p.x() - this.base.x()) * (p.x() - this.base.x()) + (p.z() - this.base.z()) * (p.z() - this.base.z());
if (r < this.radius * this.radius)
{
Intersection x = super.newIntersection(ray, t, (ray.direction().y() < 0.0), CYLINDER_SURFACE_TOP)
.setLocation(p);
recorder.record(x);
}
}
// now check for intersection of ray with the body
Vector3 orig = this.base.vectorTo(ray.origin());
Vector3 dir = ray.direction();
Polynomial f = new Polynomial(
orig.x() * orig.x() + orig.z() * orig.z() - this.radius * this.radius,
2.0 * (orig.x() * dir.x() + orig.z() * dir.z()),
dir.x() * dir.x() + dir.z() * dir.z()
);
double[] x = f.roots();
if (x.length == 2)
{
// for each solution, make sure the point lies between the base and the apex
p = ray.pointAt(x[0]);
if (MathUtil.inRangeOO(p.y(), this.base.y(), this.base.y() + this.height))
{
Intersection isect = super.newIntersection(ray, x[0], (x[0] < x[1]), CYLINDER_SURFACE_BODY)
.setLocation(p);
recorder.record(isect);
}
p = ray.pointAt(x[1]);
if (MathUtil.inRangeOO(p.y(), this.base.y(), this.base.y() + this.height))
{
Intersection isect = super.newIntersection(ray, x[1], (x[0] > x[1]), CYLINDER_SURFACE_BODY)
.setLocation(p);
recorder.record(isect);