-
Notifications
You must be signed in to change notification settings - Fork 10
/
RayWalk.h
118 lines (95 loc) · 2.43 KB
/
RayWalk.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#ifndef __RAY_WALK_H__
#define __RAY_WALK_H__
#include <vector>
#include <ImathVec.h>
#include <ImathLine.h>
#include <ImathBox.h>
inline std::vector<Imath::V3i> walk_ray(const Imath::Line3d &ray, const Imath::Box3i &box)
{
std::vector<Imath::V3i> list;
if (box.isEmpty()) return list;
// setup
Imath::V3d p0=ray.pos;
Imath::V3d dp=ray.dir;
int stepX = (dp.x>=0) ? 1 : -1;
int stepY = (dp.y>=0) ? 1 : -1;
int stepZ = (dp.z>=0) ? 1 : -1;
Imath::V3d tdelta(fabs(dp.x), fabs(dp.y), fabs(dp.z));
tdelta.x = ((tdelta.x>tdelta.baseTypeEpsilon()) ? 1.0/tdelta.x : 1e30);
tdelta.y = ((tdelta.y>tdelta.baseTypeEpsilon()) ? 1.0/tdelta.y : 1e30);
tdelta.z = ((tdelta.z>tdelta.baseTypeEpsilon()) ? 1.0/tdelta.z : 1e30);
double tdx=tdelta.x;
double tdy=tdelta.y;
double tdz=tdelta.z;
// move to box if outside
Imath::V3d p=p0;
Imath::V3d bmin=Imath::V3d(box.min)-p, bmax=p-Imath::V3d(box.max+Imath::V3i(1));
Imath::V3d tb;
tb.x = ((dp.x>=0) ? bmin.x : bmax.x);
tb.y = ((dp.y>=0) ? bmin.y : bmax.y);
tb.z = ((dp.z>=0) ? bmin.z : bmax.z);
tb*=tdelta;
double t=0;
if (tb.x>t) t=tb.x;
if (tb.y>t) t=tb.y;
if (tb.z>t) t=tb.z;
p+=dp*t;
// more setup
int ix=int(floor(p.x));
int iy=int(floor(p.y));
int iz=int(floor(p.z));
double fx=p.x-ix;
double fy=p.y-iy;
double fz=p.z-iz;
int endX = (dp.x>=0) ? box.max.x+1 : box.min.x-1;
int endY = (dp.y>=0) ? box.max.y+1 : box.min.y-1;
int endZ = (dp.z>=0) ? box.max.z+1 : box.min.z-1;
if ((dp.x>=0 && ix>=endX) || (dp.x<0 && ix<=endX)) return list;
if ((dp.y>=0 && iy>=endY) || (dp.y<0 && iy<=endY)) return list;
if ((dp.z>=0 && iz>=endZ) || (dp.z<0 && iz<=endZ)) return list;
double tmx=((dp.x>=0) ? 1.0-fx : fx)*tdelta.x;
double tmy=((dp.y>=0) ? 1.0-fy : fy)*tdelta.y;
double tmz=((dp.z>=0) ? 1.0-fz : fz)*tdelta.z;
// walk grid
for (;;)
{
Imath::V3i ip(ix, iy, iz);
if (box.intersects(ip)) list.push_back(ip);
if (tmx<tmy)
{
if (tmx<tmz)
{
ix+=stepX;
if (ix==endX) break;
t=tmx;
tmx+=tdx;
}
else
{
iz+=stepZ;
if (iz==endZ) break;
t=tmz;
tmz+=tdz;
}
}
else
{
if (tmy<tmz)
{
iy+=stepY;
if (iy==endY) break;
t=tmy;
tmy+=tdy;
}
else
{
iz+=stepZ;
if (iz==endZ) break;
t=tmz;
tmz+=tdz;
}
}
}
return list;
}
#endif