00001
00004 #include <iostream>
00005 #include "Cyl.h"
00006 #include "BoundingBox.h"
00007 #include "HitRecord.h"
00008 #include "Point.h"
00009 #include "Plane.h"
00010 #include "Ray.h"
00011 #include "Vector.h"
00012 #include <math.h>
00013 #include <stdlib.h>
00014 #include <float.h>
00015
00016 Cyl::Cyl(Material* material, const Point & b, const Point & t, const float rad)
00017 : Primitive(material), base(b), top(t), radius(rad)
00018 {
00019 A = top - base;
00020 topPlane = new Plane(material, A, t);
00021 basePlane = new Plane(material, -A, b);
00022
00023 A.normalize();
00024 }
00025
00026
00027 Cyl::~Cyl()
00028 {
00029 delete basePlane;
00030 delete topPlane;
00031 }
00032
00033 void Cyl::getBounds(BoundingBox& bbox) const
00034 {
00035 }
00036
00037
00038 void Cyl::normal(Vector& normal, const RenderContext&, const Point& hitpos,
00039 const Ray& ray, const HitRecord& hit) const
00040 {
00041 Vector BH = hitpos - base;
00042 Vector N;
00043
00044 switch (hit.scratchdata[0]) {
00045 case 0:
00046 N = BH - (Dot(BH, A) * A);
00047 N = N / radius;
00048
00049 normal = N;
00050 break;
00051 case 1:
00052
00053 normal = -A;
00054 break;
00055 case 2:
00056
00057 normal = A;
00058 break;
00059 }
00060 }
00061
00062
00063 void Cyl::intersect(HitRecord& hit, const RenderContext& context, const Ray& ray) const
00064 {
00065 Vector D = Cross(ray.direction(), A);
00066
00067 D.normalize();
00068
00069 Vector BrMinusBc = ray.origin() - base;
00070
00071 float d = Abs( Dot(BrMinusBc, D) );
00072
00073 if (d > radius)
00074 return;
00075
00076 Vector RcrossA = Cross(ray.direction(), A);
00077
00078 float t_pca = Dot(Cross(BrMinusBc, A), RcrossA) / RcrossA.length2();
00079 t_pca *= -1.0;
00080
00081
00082 Vector O = Cross(D, A);
00083 O.normalize();
00084
00085 float s = sqrt((radius*radius)-(d*d))/Dot(ray.direction(), O);
00086
00087 float tmin = t_pca-s;
00088 float tmax = t_pca+s;
00089
00090 if (tmin > tmax) {
00091 tmin = t_pca+s;
00092 tmax = t_pca-s;
00093 }
00094
00095 int max_surf, min_surf;
00096 max_surf = min_surf = 0;
00097
00098 double t_plane;
00099
00100
00101
00102 #if 1
00103 HitRecord baseHit(DBL_MAX);
00104 basePlane->intersect(baseHit, context, ray);
00105 t_plane = baseHit.minT();
00106 if (Dot(-A, ray.direction()) >= 0) {
00107
00108 if (t_plane < tmax) {
00109 tmax = t_plane;
00110 max_surf = 1;
00111 }
00112 } else {
00113
00114 if (t_plane > tmin) {
00115 tmin = t_plane;
00116 min_surf = 1;
00117 }
00118 }
00119 #endif
00120
00121 HitRecord topHit(DBL_MAX);
00122 topPlane->intersect(topHit, context, ray);
00123 t_plane = topHit.minT();
00124 if (Dot(A, ray.direction()) >= 0) {
00125
00126 if (t_plane < tmax) {
00127 tmax = t_plane;
00128 max_surf = 2;
00129 }
00130 } else {
00131
00132 if (t_plane > tmin) {
00133 tmin = t_plane;
00134 min_surf = 2;
00135 }
00136 }
00137
00138
00139 if (tmin > tmax)
00140 return;
00141
00142 if (hit.hit(tmin, this, matl)) {
00143 hit.scratchdata[0] = min_surf;
00144 } else if (hit.hit(tmax, this, matl)) {
00145 hit.scratchdata[0] = max_surf;
00146 }
00147 }