d421525ec6a3b110f5156c045f0e923a173695a8
[MicroTrace.git] / Box.cxx
1 #include "Box.hxx"
2 #include "InfinitePlane.hxx"
3
4 Box::Box() : m_min(Infinity, Infinity, Infinity),
5 m_max(-Infinity, -Infinity, -Infinity)
6 {
7 }
8
9 Box::Box(Vec3f min, Vec3f max) : m_min(min), m_max(max)
10 {
11 }
12
13 Box::~Box()
14 {
15 }
16
17 Box::Box(const Box& b)
18 {
19 m_min = b.m_min;
20 m_max = b.m_max;
21 }
22
23 Box&
24 Box::operator=(const Box& b)
25 {
26 m_min = b.m_min;
27 m_max = b.m_max;
28 return *this;
29 }
30
31 void
32 Box::Clear()
33 {
34 }
35
36 void
37 Box::Extend(const Vec3f& a)
38 {
39 // for all three coordinates, move m_max or m_min to the point
40 for(size_t i = 0; i < 3; i++) {
41 if(a[i] > m_max[i]) {
42 m_max[i] = a[i];
43 } else if(a[i] < m_min[i]) {
44 m_min[i] = a[i];
45 } // else: do nothing, coordinate is inside the box
46 }
47 }
48
49 void
50 Box::Extend(const Box& box)
51 {
52 }
53
54 bool Box::OverlapsHelper(Box b) const {
55 bool overlaps = true;
56 for(size_t i = 0; i < 3; i++) {
57 overlaps &=
58 (m_min[i] < b.min()[i] && b.min()[i] < m_max[i]) ||
59 (m_min[i] < b.max()[i] && b.min()[i] < m_max[i]) ||
60 (m_min[i] > b.min()[i] && b.min()[i] > m_max[i]) ||
61 (m_min[i] > b.max()[i] && b.min()[i] > m_max[i]);
62 }
63 return overlaps;
64 }
65
66 bool
67 Box::Overlaps(const Box& b) const
68 {
69 // Boxes overlap if b.m_min or b.m_max are between our m_max and m_min
70 // for all dimensions
71 bool overlaps = OverlapsHelper(b);
72
73 // if that is not enough, swap y coordinates, we could have the following
74 // (sample for 2-dimensional case):
75 // o----------
76 // | | + denotes crossing,
77 // -----+----o | o denotes min/max point
78 // | | | |
79 // | -----+----o
80 // | |
81 // o----------
82 if(!overlaps) {
83 Vec3f min = b.min();
84 Vec3f max = b.max();
85 Vec3f new_min(min[0], max[1], min[2]);
86 Vec3f new_max(max[0], min[1], max[2]);
87 Box new_y_box(new_min, new_max);
88 overlaps = OverlapsHelper(new_y_box);
89
90 // and now for y and z coordinates also
91 if(!overlaps) {
92 min = new_y_box.min();
93 max = new_y_box.max();
94 new_min = Vec3f(min[0], min[1], max[2]);
95 new_max = Vec3f(max[0], max[1], min[2]);
96 Box new_yz_box(new_min, new_max);
97 overlaps = OverlapsHelper(new_yz_box);
98
99 // and now for only z coordinates
100 if(!overlaps) {
101 min = new_y_box.min();
102 max = new_y_box.max();
103 new_min = Vec3f(min[0], max[1], min[2]);
104 new_max = Vec3f(max[0], min[1], max[2]);
105 Box new_z_box(new_min, new_max);
106 overlaps = OverlapsHelper(new_z_box);
107 // at this point, we do not need to swap further, as either m_max or
108 // m_min has been tested inside b.
109 }
110 }
111 }
112
113 return overlaps;
114 }
115
116 void
117 Box::Clip(const Ray& ray, float& tnear, float& tfar) const
118 {
119 // Note: equations here are the same as in InfinitePlane::Intersect()
120 // t = ((o-a)*n) / (d*n)
121 // o = ray.origin(), d = ray.direction(),
122 // n = surface normal of plane, a = anchor point of plane
123 Vec3f diff_min = m_min - ray.origin(); // o-a
124 Vec3f diff_max = m_max - ray.origin();
125
126 float cos_theta, temp;
127 float tx_near = -Infinity, tx_far = Infinity,
128 ty_near = -Infinity, ty_far = Infinity,
129 tz_near = -Infinity, tz_far = Infinity;
130
131 // clip along x axis
132 if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0) // if not parallel...
133 tx_near = diff_min.dot(Vec3f(1,0,0)) / cos_theta;
134 if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0)
135 tx_far = diff_max.dot(Vec3f(1,0,0)) / cos_theta;
136
137 // we don't know which is nearer, m_min or m_max, so swap them if neccessary
138 if(tx_near > tx_far) {
139 temp = tx_near;
140 tx_near = tx_far;
141 tx_far = temp;
142 }
143
144 // do the same for y axis
145 if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
146 ty_near = diff_min.dot(Vec3f(0,1,0)) / cos_theta;
147 if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
148 ty_far = diff_max.dot(Vec3f(0,1,0)) / cos_theta;
149 if(ty_near > ty_far) {
150 temp = ty_near;
151 ty_near = ty_far;
152 ty_far = temp;
153 }
154
155 // ...and for z axis
156 if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
157 tz_near = diff_min.dot(Vec3f(0,0,1)) / cos_theta;
158 if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
159 tz_far = diff_max.dot(Vec3f(0,0,1)) / cos_theta;
160 if(tz_near > tz_far) {
161 temp = tz_near;
162 tz_near = tz_far;
163 tz_far = temp;
164 }
165
166 // now the maximum of "near"s is the entry point of the ray, the minimum
167 // of "far"s is the ray's exit point. Visually speaking: the ray must cross
168 // all three "near" planes before it can be inside the box.
169 // Note: If t_near_max > t_far_min, the ray does not intersect the box
170 tnear = fmax(fmax(tx_near, ty_near), tz_near);
171 tfar = fmin(fmin(tx_far, ty_far), tz_far);
172 }
173
174 const Vec3f&
175 Box::min() const
176 {
177 return m_min;
178 }
179
180 const Vec3f&
181 Box::max() const
182 {
183 return m_max;
184 }
This page took 0.049063 seconds and 3 git commands to generate.