Subversion Repositories gelsvn

Rev

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

Rev Author Line No. Line
595 jab 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
61 jab 7
#include <cmath>
8
#include <stdlib.h>
9
#include <iostream>
601 jab 10
#include "../CGLA/Vec3d.h"
61 jab 11
#include "ThreeDDDA.h"
12
 
13
using namespace std;
14
using namespace CGLA;
15
 
16
namespace Geometry
17
{
18
 
19
 
20
	/** Return the position on the fine grid of a vector v. 
21
			We simply multiply by the precision and round down. Note that 
22
			it is necessary to use floor since simply clamping the value
23
			will always round toward zero.
24
	*/
25
	const Vec3i ThreeDDDA::grid_pos(const Vec3f& v) const
26
	{
27
		Vec3i g;
28
		for(int i=0;i<3;++i)
29
			g[i] = static_cast<int>(floor(v[i]*PRECISION));
30
		return g;
31
	}
32
 
33
 
34
	/// Compute the cell containing a given fine grid position.
35
	Vec3i ThreeDDDA::get_cell(const Vec3i& v) const
36
	{
37
		Vec3i c;
38
		for(int i=0;i<3;++i)
39
			{
40
				// If we are on the right side of the axis
41
				if(v[i]>=0)
42
					// We simply divide by the precision.
43
					c[i] = (v[i])/PRECISION;
44
				else
45
					// If we are on the left side, we have to add one
46
					// before and subtract one after dividing. This reflects
47
					// the lack of symmetry.
48
					c[i] = (v[i]+1)/PRECISION-1;
49
			}
50
		return c;
51
	}
52
 
53
	/// Mirror a fine grid position
54
	Vec3i ThreeDDDA::mirror(const Vec3i& v) const
55
	{
56
		Vec3i m;
57
		for(int i=0;i<3;++i)
58
			{
59
				// Mirroring simply inverts the sign, however, 
60
				// to reflect the fact that the cells on either side of the
61
				// axis are numbered differently, we have to add one before flipping 
62
				// the sign.
63
				if(sgn[i]==-1)
64
					m[i] = -(v[i]+1);
65
				else
66
					m[i] = v[i];
67
			}
68
		return m;
69
	}
70
 
71
 
72
	/** Create a 3DDDA based on the two end-points of the ray. An optional
73
			last argument indicates the resolution of the grid. */
74
	ThreeDDDA::ThreeDDDA(const CGLA::Vec3f& p0, const CGLA::Vec3f& p1, 
75
											 int _PRECISION):
76
		PRECISION(_PRECISION),
77
		sgn(p1[0]>=p0[0] ? 1 : -1,
78
				p1[1]>=p0[1] ? 1 : -1,
79
				p1[2]>=p0[2] ? 1 : -1),
80
		p0_int(grid_pos(p0)),
81
		p1_int(grid_pos(p1)),
82
		dir(sgn*(p1_int-p0_int)),
83
		first_cell(get_cell(p0_int)),
84
		last_cell(get_cell(p1_int)),
85
		no_steps(dot(sgn, last_cell-first_cell)),
86
		dir_pre_mul(2*dir*PRECISION)
87
	{
88
		// Compute the mirrored position of the ray starting point
89
		const Vec3i p0_int_m = mirror(p0_int);
90
 
91
		// Compute the cell of the mirrored position.
92
		const Vec3i first_cell_m = get_cell(p0_int_m);
93
 
94
		/* Finally, compute delta = p - p0 where 
95
			 "p" is the position of the far,upper,right corner of the cell containing
96
			 the ray starting point and "p0" is the starting point (mirrored). 
97
			 Since the ray starts at a grid position + (0.5,0.5,0.5) we have to
98
			 add one half to each grid coordinate of p0. Since we are doing integer
99
			 arithmetic, we simply multiply everything by two instead.
100
		*/
101
		const Vec3i delta = 2*(first_cell_m*PRECISION+Vec3i(PRECISION))-
102
			(2*p0_int_m  + Vec3i(1));
103
 
104
		/* Compute the discriminators. These are (x-x0) * dir_y, (y-y0)*dir_x
105
			 and so on for all permutations. These will be updated in the course
106
			 of the algorithm. */ 
107
		for(int i=0;i<3;++i)
108
			{
109
				const int k1 = (i + 1) % 3;
110
				const int k2 = (i + 2) % 3;
304 jab 111
				disc[i][k1] = static_cast<Integer64Bits>(delta[i])*dir[k1];
112
				disc[i][k2] = static_cast<Integer64Bits>(delta[i])*dir[k2];
61 jab 113
			}
114
 
115
		// Finally, we set the cell position equal to the first_cell and we
116
		// are ready to iterate.
117
		cell = first_cell;
118
	}
119
 
120
	/// Get the initial point containing the ray.
121
	const CGLA::Vec3f ThreeDDDA::step() 
122
	{
123
		int step_dir;
124
		if(disc[1][0] > disc[0][1])
125
			if(disc[2][0] > disc[0][2])
126
				step_dir = 0;
127
			else
128
				step_dir = 2;
129
		else
130
			if(disc[2][1] > disc[1][2])
131
				step_dir = 1;
132
			else
133
				step_dir = 2;
134
 
135
		const int k1 = (step_dir + 1) % 3;
136
		const int k2 = (step_dir + 2) % 3;
137
 
138
		double delta;
139
		delta=cell[step_dir]+sgn[step_dir]-double(p0_int[step_dir]+0.5f)/PRECISION;
140
		Vec3f real_dir = get_last_point() - get_first_point();
141
		double ck1 = real_dir[k1]/real_dir[step_dir];
142
		double ck2 = real_dir[k2]/real_dir[step_dir];
143
 
144
		Vec3f p;
145
		p[step_dir] = delta;
146
		p[k1] = ck1 * delta;
147
		p[k2] = ck2 * delta;
148
 		p += get_first_point();
149
 
150
		cell[step_dir] += sgn[step_dir];
151
		disc[step_dir][k1] += dir_pre_mul[k1];
152
		disc[step_dir][k2] += dir_pre_mul[k2];
153
		return Vec3f(p);
154
	}
155
 
156
 
157
}