PolyVox  0.2.1
Open source voxel management library
Raycast.inl
Go to the documentation of this file.
1 /*******************************************************************************
2 Copyright (c) 2005-2009 David Williams
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12  1. The origin of this software must not be misrepresented; you must not
13  claim that you wrote the original software. If you use this software
14  in a product, an acknowledgment in the product documentation would be
15  appreciated but is not required.
16 
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19 
20  3. This notice may not be removed or altered from any source
21  distribution.
22 *******************************************************************************/
23 
24 namespace PolyVox
25 {
26  // This function is based on Christer Ericson's code and description of the 'Uniform Grid Intersection Test' in
27  // 'Real Time Collision Detection'. The following information from the errata on the book website is also relevent:
28  //
29  // pages 326-327. In the function VisitCellsOverlapped() the two lines calculating tx and ty are incorrect.
30  // The less-than sign in each line should be a greater-than sign. That is, the two lines should read:
31  //
32  // float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) / Abs(x2 - x1);
33  // float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) / Abs(y2 - y1);
34  //
35  // Thanks to Jetro Lauha of Fathammer in Helsinki, Finland for reporting this error.
36  //
37  // Jetro also points out that the computations of i, j, iend, and jend are incorrectly rounded if the line
38  // coordinates are allowed to go negative. While that was not really the intent of the code -- that is, I
39  // assumed grids to be numbered from (0, 0) to (m, n) -- I'm at fault for not making my assumption clear.
40  // Where it is important to handle negative line coordinates the computation of these variables should be
41  // changed to something like this:
42  //
43  // // Determine start grid cell coordinates (i, j)
44  // int i = (int)floorf(x1 / CELL_SIDE);
45  // int j = (int)floorf(y1 / CELL_SIDE);
46  //
47  // // Determine end grid cell coordinates (iend, jend)
48  // int iend = (int)floorf(x2 / CELL_SIDE);
49  // int jend = (int)floorf(y2 / CELL_SIDE);
50  //
51  // page 328. The if-statement that reads "if (ty <= tx && ty <= tz)" has a superfluous condition.
52  // It should simply read "if (ty <= tz)".
53  //
54  // This error was reported by Joey Hammer (PixelActive).
55 
71  template<typename VolumeType, typename Callback>
72  RaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback)
73  {
74  typename VolumeType::Sampler sampler(volData);
75 
76  //The doRaycast function is assuming that it is iterating over the areas defined between
77  //voxels. We actually want to define the areas as being centered on voxels (as this is
78  //what the CubicSurfaceExtractor generates). We add 0.5 here to adjust for this.
79  float x1 = v3dStart.getX() + 0.5f;
80  float y1 = v3dStart.getY() + 0.5f;
81  float z1 = v3dStart.getZ() + 0.5f;
82  float x2 = v3dEnd.getX() + 0.5f;
83  float y2 = v3dEnd.getY() + 0.5f;
84  float z2 = v3dEnd.getZ() + 0.5f;
85 
86  int i = (int)floorf(x1);
87  int j = (int)floorf(y1);
88  int k = (int)floorf(z1);
89 
90  int iend = (int)floorf(x2);
91  int jend = (int)floorf(y2);
92  int kend = (int)floorf(z2);
93 
94  int di = ((x1 < x2) ? 1 : ((x1 > x2) ? -1 : 0));
95  int dj = ((y1 < y2) ? 1 : ((y1 > y2) ? -1 : 0));
96  int dk = ((z1 < z2) ? 1 : ((z1 > z2) ? -1 : 0));
97 
98  float deltatx = 1.0f / std::abs(x2 - x1);
99  float deltaty = 1.0f / std::abs(y2 - y1);
100  float deltatz = 1.0f / std::abs(z2 - z1);
101 
102  float minx = floorf(x1), maxx = minx + 1.0f;
103  float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) * deltatx;
104  float miny = floorf(y1), maxy = miny + 1.0f;
105  float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) * deltaty;
106  float minz = floorf(z1), maxz = minz + 1.0f;
107  float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) * deltatz;
108 
109  sampler.setPosition(i,j,k);
110 
111  for(;;)
112  {
113  if(!callback(sampler))
114  {
116  }
117 
118  if(tx <= ty && tx <= tz)
119  {
120  if(i == iend) break;
121  tx += deltatx;
122  i += di;
123 
124  if(di == 1) sampler.movePositiveX();
125  if(di == -1) sampler.moveNegativeX();
126  } else if (ty <= tz)
127  {
128  if(j == jend) break;
129  ty += deltaty;
130  j += dj;
131 
132  if(dj == 1) sampler.movePositiveY();
133  if(dj == -1) sampler.moveNegativeY();
134  } else
135  {
136  if(k == kend) break;
137  tz += deltatz;
138  k += dk;
139 
140  if(dk == 1) sampler.movePositiveZ();
141  if(dk == -1) sampler.moveNegativeZ();
142  }
143  }
144 
146  }
147 
172  template<typename VolumeType, typename Callback>
173  RaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback)
174  {
175  Vector3DFloat v3dEnd = v3dStart + v3dDirectionAndLength;
176  return raycastWithEndpoints<VolumeType, Callback>(volData, v3dStart, v3dEnd, callback);
177  }
178 }