Line data Source code
1 : #include "SliceTraversal.h"
2 : #include "Error.h"
3 : #include "elsaDefines.h"
4 : #include "spdlog/fmt/fmt.h"
5 : #include "spdlog/fmt/ostr.h"
6 :
7 : namespace elsa
8 : {
9 : RealMatrix_t TransformToTraversal::create2DRotation(const real_t leadingCoeff,
10 : const index_t leadingAxisIndex)
11 1523 : {
12 1523 : auto createRotationMatrix = [](real_t radian) {
13 1522 : real_t c = std::cos(radian);
14 1522 : real_t s = std::sin(radian);
15 1522 : return RealMatrix_t({{c, -s}, {s, c}});
16 1522 : };
17 :
18 : // TODO: Does a closed form solution exist?
19 : // Use conversion to polar coordinates
20 1523 : if (leadingAxisIndex == 0 && leadingCoeff >= 0) {
21 : // Already identity, so do nothing
22 401 : return createRotationMatrix(0);
23 1122 : } else if (leadingAxisIndex == 0 && leadingCoeff < 0) {
24 : // create a 2D 180° rotation matrix
25 383 : return createRotationMatrix(pi_t);
26 739 : } else if (leadingAxisIndex == 1 && leadingCoeff >= 0) {
27 : // create a 2D 270° rotation matrix counter clockwise
28 366 : return createRotationMatrix(3 * pi_t / 2);
29 373 : } else if (leadingAxisIndex == 1 && leadingCoeff <= 0) {
30 : // create a 2D 90° rotation matrix counter clockwise
31 373 : return createRotationMatrix(pi_t / 2);
32 373 : }
33 0 : return createRotationMatrix(0);
34 0 : }
35 :
36 : RealMatrix_t TransformToTraversal::create3DRotation(const real_t leadingCoeff,
37 : const index_t leadingAxisIndex)
38 245 : {
39 245 : auto identity = []() { return RealMatrix_t({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}); };
40 :
41 : /*
42 : auto rotationX = [](real_t radian) {
43 : real_t c = std::cos(radian);
44 : real_t s = std::sin(radian);
45 : return RealMatrix_t({{1, 0, 0}, {0, c, -s}, {0, s, c}});
46 : };
47 : */
48 :
49 245 : auto rotationY = [](real_t radian) {
50 158 : real_t c = std::cos(radian);
51 158 : real_t s = std::sin(radian);
52 158 : return RealMatrix_t({{c, 0, s}, {0, 1, 0}, {-s, 0, c}});
53 158 : };
54 :
55 245 : auto rotationZ = [](real_t radian) {
56 8 : real_t c = std::cos(radian);
57 8 : real_t s = std::sin(radian);
58 8 : return RealMatrix_t({{c, -s, 0}, {s, c, 0}, {0, 0, 1}});
59 8 : };
60 :
61 : // TODO: Does a closed form solution exist?
62 : // Use conversion to polar coordinates
63 245 : if (leadingAxisIndex == 0 && leadingCoeff >= 0) {
64 : // Already identity, so do nothing
65 79 : return identity();
66 166 : } else if (leadingAxisIndex == 0 && leadingCoeff < 0) {
67 60 : return rotationY(pi_t); // flip x axis
68 106 : } else if (leadingAxisIndex == 1 && leadingCoeff >= 0) {
69 4 : return rotationZ(-0.5 * pi_t);
70 102 : } else if (leadingAxisIndex == 1 && leadingCoeff <= 0) {
71 4 : return rotationZ(0.5 * pi_t);
72 98 : } else if (leadingAxisIndex == 2 && leadingCoeff >= 0) {
73 54 : return rotationY(0.5 * pi_t);
74 54 : } else if (leadingAxisIndex == 2 && leadingCoeff <= 0) {
75 44 : return rotationY(-0.5 * pi_t);
76 44 : }
77 :
78 0 : return identity();
79 0 : }
80 :
81 : RealMatrix_t TransformToTraversal::createRotation(RealRay_t ray)
82 1778 : {
83 : // Get the leading axis, by absolute value
84 1778 : index_t leadingAxisIndex = 0;
85 1778 : ray.direction().array().abs().maxCoeff(&leadingAxisIndex);
86 :
87 : // Get the signed leading coefficient
88 1778 : const auto leadingCoeff = ray.direction()(leadingAxisIndex);
89 :
90 1778 : if (ray.dim() == 2) {
91 1527 : return create2DRotation(leadingCoeff, leadingAxisIndex);
92 1527 : } else if (ray.dim() == 3) {
93 245 : return create3DRotation(leadingCoeff, leadingAxisIndex);
94 245 : }
95 6 : throw Error("Can not create a {}-dimensional transformation for the slice traversal",
96 6 : ray.dim());
97 6 : }
98 :
99 : RealMatrix_t TransformToTraversal::createTransformation(const RealRay_t& ray,
100 : const RealVector_t& centerOfRotation)
101 1769 : {
102 1769 : const auto dim = ray.dim();
103 :
104 : // Setup translation
105 1769 : RealMatrix_t translation(dim + 1, dim + 1);
106 1769 : translation.setIdentity();
107 1769 : translation.block(0, dim, dim, 1) = -centerOfRotation;
108 :
109 : // Setup rotation
110 1769 : RealMatrix_t rotation(dim + 1, dim + 1);
111 1769 : rotation.setIdentity();
112 1769 : rotation.block(0, 0, dim, dim) = createRotation(ray);
113 :
114 1769 : return rotation * translation;
115 1769 : }
116 :
117 : TransformToTraversal::TransformToTraversal(const RealRay_t& ray,
118 : const RealVector_t& centerOfRotation)
119 : : transformation_(createTransformation(ray, centerOfRotation)),
120 : translation_(-centerOfRotation)
121 1778 : {
122 1778 : }
123 :
124 : RealRay_t TransformToTraversal::toTraversalCoordinates(RealRay_t ray) const
125 1669 : {
126 1669 : ray.origin() = *this * Point(ray.origin());
127 1669 : ray.direction() = *this * Vec(ray.direction());
128 1669 : return ray;
129 1669 : }
130 :
131 : BoundingBox TransformToTraversal::toTraversalCoordinates(BoundingBox aabb) const
132 1679 : {
133 : // Only translate, as the rotations are always 90, 180, 270 degrees,
134 : // TODO: this might be wrong, idk, what about non square things
135 1679 : aabb.min() = *this * Point(aabb.min());
136 1679 : aabb.max() = *this * Point(aabb.max());
137 1679 : aabb.recomputeBounds();
138 1679 : return aabb;
139 1679 : }
140 :
141 : RealMatrix_t TransformToTraversal::transformation() const
142 5039 : {
143 5039 : return transformation_;
144 5039 : }
145 :
146 : RealMatrix_t TransformToTraversal::invTransformation() const
147 0 : {
148 0 : return transformation().inverse();
149 0 : }
150 :
151 : RealMatrix_t TransformToTraversal::rotation() const
152 1758 : {
153 1758 : const auto dim = transformation_.rows();
154 1758 : return transformation_.block(0, 0, dim - 1, dim - 1);
155 1758 : }
156 :
157 : RealMatrix_t TransformToTraversal::invRotation() const
158 0 : {
159 0 : return rotation().transpose();
160 0 : }
161 :
162 : RealVector_t TransformToTraversal::translation() const
163 0 : {
164 0 : return translation_;
165 0 : }
166 :
167 : RealMatrix_t TransformToTraversal::linear() const
168 1711 : {
169 1711 : return rotation();
170 1711 : }
171 :
172 : RealVector_t TransformToTraversal::operator*(const Point<real_t>& point) const
173 5037 : {
174 5037 : return (transformation() * point.point_.homogeneous()).hnormalized();
175 5037 : }
176 :
177 : RealVector_t TransformToTraversal::operator*(const Vec<real_t>& vec) const
178 1690 : {
179 1690 : return linear() * vec.vec_;
180 1690 : }
181 :
182 : SliceTraversal::SliceTraversal(BoundingBox aabb, RealRay_t ray)
183 : : transformation_(ray, aabb.max().array() / 2), ray_(ray)
184 1669 : {
185 : // Transform ray and aabb to traversal coordinate space
186 1669 : ray = transformation_.toTraversalCoordinates(ray);
187 1669 : aabb = transformation_.toTraversalCoordinates(aabb);
188 :
189 : // TODO: We only want to shift in x direction by 0.5, not in y
190 1669 : auto hit = intersectXPlanes(aabb, ray);
191 :
192 : // Default init is sufficient if we don't hit, TODO: test that!
193 1669 : if (hit) {
194 1664 : const auto firstVoxel = ray.pointAt(hit->_tmin);
195 1664 : const auto lastVoxel = ray.pointAt(hit->_tmax);
196 :
197 1664 : endIndex_ = std::max<index_t>(
198 1664 : 1, static_cast<index_t>(std::ceil(lastVoxel[0] - firstVoxel[0] + 0.5f)));
199 :
200 1664 : tDelta_ = 1 / ray.direction()[0];
201 :
202 1664 : t_ = hit->_tmin;
203 1664 : }
204 1669 : }
205 :
206 : index_t SliceTraversal::leadingDirection() const
207 0 : {
208 0 : index_t idx = 0;
209 0 : ray_.direction().array().cwiseAbs().maxCoeff(&idx);
210 0 : return idx;
211 0 : }
212 :
213 : real_t SliceTraversal::t() const
214 43 : {
215 43 : return t_;
216 43 : }
217 :
218 : real_t SliceTraversal::tDelta() const
219 43 : {
220 43 : return tDelta_;
221 43 : }
222 :
223 : SliceTraversal::Iter SliceTraversal::begin() const
224 1669 : {
225 1669 : return {startIndex_, ray_.pointAt(t_), ray_.direction() * tDelta_};
226 1669 : }
227 :
228 : SliceTraversal::Iter SliceTraversal::end() const
229 1768 : {
230 1768 : return {endIndex_};
231 1768 : }
232 :
233 : index_t SliceTraversal::startIndex() const
234 0 : {
235 0 : return startIndex_;
236 0 : }
237 :
238 : index_t SliceTraversal::endIndex() const
239 43 : {
240 43 : return endIndex_;
241 43 : }
242 :
243 : SliceTraversal::Iter::value_type SliceTraversal::Iter::operator*() const
244 8031 : {
245 8031 : return cur_.template cast<index_t>();
246 8031 : }
247 :
248 : SliceTraversal::Iter& SliceTraversal::Iter::operator++()
249 8055 : {
250 8055 : ++pos_;
251 8055 : cur_ += dir_;
252 8055 : return *this;
253 8055 : }
254 :
255 : SliceTraversal::Iter SliceTraversal::Iter::operator++(int)
256 0 : {
257 0 : auto copy = *this;
258 0 : ++(*this);
259 0 : return copy;
260 0 : }
261 :
262 : bool operator==(const SliceTraversal::Iter& lhs, const SliceTraversal::Iter& rhs)
263 9686 : {
264 9686 : return lhs.pos_ == rhs.pos_;
265 9686 : }
266 :
267 : bool operator!=(const SliceTraversal::Iter& lhs, const SliceTraversal::Iter& rhs)
268 9706 : {
269 9706 : return !(lhs == rhs);
270 9706 : }
271 :
272 : } // namespace elsa
|