Subversion Repositories gelsvn

Rev

Rev 304 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
61 jab 1
#ifndef __THREEDDDA_H
2
#define __THREEDDDA_H
3
 
304 jab 4
#ifdef _MSC_VER 
5
typedef __int64 Integer64Bits;
6
#else
7
typedef int64_t Integer64Bits;
8
#endif
9
 
10
 
61 jab 11
#include "CGLA/Vec3f.h"
12
#include "CGLA/Vec3i.h"
13
 
14
namespace Geometry
15
{
16
 
17
 
89 jab 18
	/** \brief A ThreeDDDA is a class for traversing a grid of cells. 
19
 
20
      We wish to 
61 jab 21
			enumerate all cells pierced by the ray going from a point p0 to a 
22
			point p1. It is dangerous to use floating point arithmetic since rounding
23
			errors may accumulate entailing that the 3ddda misses the cell containing
24
			the end point of the ray.
25
 
26
			Daniel Cohen-Or devised a technique for exact ray traversal using only 
27
			integer arithmetic. Using integer arithmetic, the computations are
28
			exact, but the ray must start and terminate exactly at grid points.
29
			I.e. the ray must start and terminate in cell corners.
30
 
31
			To overcome this issue, I have implemented a scheme where the ray
32
			starts and terminates on a grid that is finer than the cell grid.
33
			This means that we have fast and exact computations, and the ray can
34
			travel between two almost arbitrary points.
35
 
36
			A central problem with this scheme was that - in order to simplify
37
			things during the iterative traversal - the ray direction vector
38
			is always mirrored into the first octant (+x +y +z).  If the fine
39
			grid used for the ray start and end points is a superset of the
40
			grid points of the cell grid, this mirroring is almost impossible
41
			to implement correctly. This is due to the fact that the first
42
			cell on the right side of the y axis is called 0,y whereas the
43
			first cell on the left is called -1,y. This lack of symmetry makes
44
			things very difficult, but by ensuring that the endpoints of a ray
45
			can never lie on an a corner, edge, or face of the cell grid, we
46
			can make the problems go away.
47
 
48
			Hence, in this implementation, the fine grid is obtained by dividing 
49
			the cell into NxNxN subcells, but the grid points	of the fine grid lie 
50
			at the CENTRES of these subcells.  
51
 
52
	*/
53
 
54
	class ThreeDDDA
55
	{
56
		/** Resolution of the grid. This number indicates how many subcells
57
				(along each axis) a cell is divided into. */
58
		const int PRECISION;
59
 
60
		/// Sign indicates which octant contains the direction vector.
61
		const CGLA::Vec3i sgn;
62
 
63
		/// Fine grid position where the ray begins
64
		const CGLA::Vec3i p0_int;
65
 
66
		// Fine grid position where the ray ends.
67
		const CGLA::Vec3i p1_int;
68
 
69
		/// The direction of the ray 
70
		const CGLA::Vec3i dir;
71
 
72
		/// The cell containing the initial point on the ray.
73
		const CGLA::Vec3i first_cell;
74
 
75
		/// The cell containing the last point on the ray.
76
		const CGLA::Vec3i last_cell;
77
 
78
		/** Number of steps. We can compute the number of steps that the
79
				ray will take in advance. */
80
		const int no_steps; 
81
 
82
		/** The direction vector, premultiplied by the step length.
83
				This constant is used to update the equations governing the
84
				traversal. */
85
		const CGLA::Vec3i dir_pre_mul;
86
 
87
		/** Discriminators. These values are delta[i]*dir[j] where delta[i]
88
				is the distance from the origin of the ray to the current position
89
				along the i axis multiplied by two). dir[j] is the direction vector
90
				coordinate j. */
91
 
304 jab 92
		Integer64Bits disc[3][3];
61 jab 93
 
94
		/** The current cell containing the ray. This value along with the 
95
				discriminators mentioned above represent the state of a ThreeDDDA. */
96
		CGLA::Vec3i cell;
97
 
98
 
99
		/** Return the position on the fine grid of a vector v. 
100
				We simply multiply by the precision and round down. Note that 
101
				it is necessary to use floor since simply clamping the value
102
				will always round toward zero.
103
		*/
104
		const CGLA::Vec3i grid_pos(const CGLA::Vec3f& v) const;
105
 
106
		/// Compute the cell containing a given fine grid position.
107
		CGLA::Vec3i get_cell(const CGLA::Vec3i& v) const;
108
 
109
		/// Mirror a fine grid position
110
		CGLA::Vec3i mirror(const CGLA::Vec3i& v) const;
111
 
112
 
113
	public:
114
 
115
		/** Create a 3DDDA based on the two end-points of the ray. An optional
116
				last argument indicates the resolution of the grid. */
117
		ThreeDDDA(const CGLA::Vec3f& p0, const CGLA::Vec3f& p1, 
118
							int _PRECISION = 0x100);
119
 
120
		/// Return the total number of steps the ray will traverse.
121
		int get_no_steps() const
122
		{
123
			return no_steps;
124
		}
125
 
126
		/// Yields the current cell containing the ray.
127
		const CGLA::Vec3i& get_current_cell() const
128
		{
129
			return cell;
130
		}
131
 
132
		/// Get the initial cell containing the ray.
133
		const CGLA::Vec3i& get_first_cell() const
134
		{
135
			return first_cell;
136
		}
137
 
138
		/// Get the last cell containing the ray.
139
		const CGLA::Vec3i& get_last_cell() const
140
		{
141
			return last_cell;
142
		}
143
 
144
		/// Get the initial point containing the ray.
145
		const CGLA::Vec3f get_first_point() const
146
		{
147
			return (CGLA::Vec3f(p0_int)+CGLA::Vec3f(0.5))/PRECISION;
148
		}
149
 
150
 
151
		/// Get the last cell containing the ray.
152
		const CGLA::Vec3f get_last_point() const
153
		{
154
			return (CGLA::Vec3f(p1_int)+CGLA::Vec3f(0.5))/PRECISION;
155
		}
156
 
157
		/// Returns true if we have reached the last cell.
158
		bool at_end() const
159
		{
160
			return cell == last_cell;
161
		}
162
 
163
		/// Take a step along the ray.
164
		void operator++()
165
		{
166
			int step_dir;
167
			if(disc[1][0] > disc[0][1])
168
				if(disc[2][0] > disc[0][2])
169
					step_dir = 0;
170
				else
171
					step_dir = 2;
172
			else
173
				if(disc[2][1] > disc[1][2])
174
					step_dir = 1;
175
				else
176
					step_dir = 2;
177
 
178
			const int k1 = (step_dir + 1) % 3;
179
			const int k2 = (step_dir + 2) % 3;
180
			cell[step_dir] += sgn[step_dir];
181
			disc[step_dir][k1] += dir_pre_mul[k1];
182
			disc[step_dir][k2] += dir_pre_mul[k2];
183
		}
184
 
185
		/// Get the initial point containing the ray.
186
			const CGLA::Vec3f step();
187
 
188
 
189
	};
190
}
191
 
192
#endif